最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?Swing實現自定義窗口CusFrame

 更新時間:2026年05月19日 09:14:39   作者:RainCity  
文章介紹了自定義Swing窗口CusFrame的核心功能,包括移除系統(tǒng)默認標題欄、實現圓角矩形形狀、支持拖拽移動和調整大小、多屏幕適配以及窗口狀態(tài)管理等功能,最后文章提供了使用示例和注意事項,有需要的小伙伴可以參考下

一、背景

Swing 原生窗口 JFrame 的標題欄是系統(tǒng)自帶的,樣式陳舊且無法自定義。不同操作系統(tǒng)下標題欄風格不一致,也不支持圓角、自定義顏色、自定義按鈕等現代 UI 元素。 CusFrame 的作用就是:移除系統(tǒng)裝飾,自己繪制標題欄和窗口邊框,實現統(tǒng)一的窗口風格。同時支持窗口拖拽移動、調整大小、最小化、最大化、還原、多屏幕適配等功能。

二、類源碼

import lombok.Setter;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import java.util.function.BiConsumer;

/**
 * 自定義窗口框架類
 * 實現圓角窗口和自定義標題欄,支持拖拽移動、調整大小、最小化、最大化和關閉功能
 *  * 使用示例:
 * CusFrame frame = new CusFrame("窗口標題");
 * frame.setSize(800, 600);
 * frame.setVisible(true);
 */
public class CusFrame extends JFrame {
    private static final String ICON_PATH = "icons/logo.png";
    /** 標題欄面板 */
    private JPanel titlePanel;
    /** 鼠標點擊初始位置,用于窗口拖拽 */
    private Point initialClick;
    /** 窗口是否最大化標志 */
    @Setter
    private boolean maximized = false;
    /** 窗口是否已最大化 */
    private boolean isMaximized = false;
    private boolean maximizedDisable = false;
    /** 窗口正常狀態(tài)下的邊界 */
    private Rectangle normalBounds;
    /** 圖標和標題面板 */
    JPanel iconTitlePanel;
    /** 標題標簽 */
    private JLabel titleLabel;
    /** 最小化按鈕 */
    private JLabel minButton;
    /** 最大化/還原按鈕 */
    private JLabel maxButton;
    /** 關閉按鈕 */
    private JLabel closeButton;
    /** 關閉按鈕事件 */
    private Runnable closeAction;
    /** 圓角半徑 */
    private int cornerRadius = 15;
    /** 是否正在調整窗口大小 */
    private boolean isResizing = false;
    /** 邊界檢測區(qū)域寬度 */
    @Setter
    private int resizeBorder = 10;
    /** 當前調整方向 */
    private int resizeDirection = 0;
    /** 調整方向常量 */
    private static final int NONE = 0;
    private static final int TOP = 1;
    private static final int BOTTOM = 2;
    private static final int LEFT = 4;
    private static final int RIGHT = 8;
    private static final int TOP_LEFT = TOP | LEFT;
    private static final int TOP_RIGHT = TOP | RIGHT;
    private static final int BOTTOM_LEFT = BOTTOM | LEFT;
    private static final int BOTTOM_RIGHT = BOTTOM | RIGHT;
    /** 當前窗口所在的屏幕設備 */
    private GraphicsDevice currentScreenDevice;
    /** 父窗口引用,用于新窗口跟隨 */
    @Setter
    private CusFrame parentFrame;
    /** 記錄窗口是否已經初始化位置 */
    private boolean locationInitialized = false;
    /** 記錄窗口的原始位置 */
    private Point originalLocation;
    /** 記錄窗口的原始大小 */
    private Dimension originalSize;

    /**
     * 默認構造函數
     */
    public CusFrame() throws HeadlessException {
        this(null, null);
    }

    /**
     * 帶標題的構造函數
     * @param title 窗口標題
     */
    public CusFrame(String title) throws HeadlessException {
        this(title, null);
    }

    /**
     * 帶標題和父窗口的構造函數
     * @param title 窗口標題
     * @param parentFrame 父窗口
     */
    public CusFrame(String title, CusFrame parentFrame) throws HeadlessException {
        this.parentFrame = parentFrame;
        // 移除默認標題欄
        setUndecorated(true);
        // 設置窗口初始大小
        setSize(new Dimension(800, 600));
        // 創(chuàng)建自定義標題欄
        createCustomTitleBar(title);
        // 設置內容區(qū)域
        setupContentArea();
        // 設置圓角
        setShape(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), cornerRadius, cornerRadius));
        // 設置默認關閉方式
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 注:這里獲取圖片 需自行實現
        setIconImage(xxxxxx);
        // 保存正常狀態(tài)下的邊界
        normalBounds = getBounds();
        // 初始化當前屏幕設備
        updateCurrentScreenDevice();
        // 添加窗口大小變化監(jiān)聽器,更新圓角形狀
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                setShape(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), cornerRadius, cornerRadius));
            }
            @Override
            public void componentMoved(ComponentEvent e) {
                updateCurrentScreenDevice();
            }
            @Override
            public void componentShown(ComponentEvent e) {
                if (maximized) {
                    SwingUtilities.invokeLater(() -> {
                        toggleMaximize();
                        maximized = false;
                    });
                }
            }
        });
    }

    /**
     * 更新當前窗口所在的屏幕設備
     */
    private void updateCurrentScreenDevice() {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice[] screens = ge.getScreenDevices();
        Rectangle windowBounds = getBounds();
        int centerX = windowBounds.x + windowBounds.width / 2;
        int centerY = windowBounds.y + windowBounds.height / 2;
        for (GraphicsDevice screen : screens) {
            Rectangle screenBounds = screen.getDefaultConfiguration().getBounds();
            if (screenBounds.contains(centerX, centerY)) {
                currentScreenDevice = screen;
                break;
            }
        }
        if (currentScreenDevice == null) {
            currentScreenDevice = ge.getDefaultScreenDevice();
        }
    }

    /**
     * 獲取當前窗口所在的屏幕設備
     * @return 當前屏幕設備
     */
    public GraphicsDevice getCurrentScreenDevice() {
        if (currentScreenDevice == null) {
            updateCurrentScreenDevice();
        }
        return currentScreenDevice;
    }

    /**
     * 創(chuàng)建自定義標題欄
     * @param title 標題文本
     */
    private void createCustomTitleBar(String title) {
        // 創(chuàng)建標題欄主面板
        titlePanel = new JPanel(new BorderLayout());
        // 左側:圖標和標題
        iconTitlePanel = new JPanel(new BorderLayout());
        iconTitlePanel.setOpaque(false);
        iconTitlePanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
        // 初始化標題標簽
        titleLabel = new JLabel(title);
        titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 16));
        titleLabel.setForeground(Color.BLACK);
        titleLabel.setBorder(BorderFactory.createEmptyBorder(8, 5, 5, 5));
        // 使用包裝面板確保垂直居中
        JPanel titleWrapper = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
        titleWrapper.setOpaque(false);
        titleWrapper.add(titleLabel);
        iconTitlePanel.add(titleWrapper, BorderLayout.CENTER);
        // 右側:窗口控制按鈕
        JPanel buttonPanel = new JPanel(new BorderLayout());
        buttonPanel.setOpaque(false);
        buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
        JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
        rightPanel.setOpaque(false);
        // 最小化按鈕,圖片只是實例
        minButton = createWindowBtn("icons/window/minimize.png", () -> setState(JFrame.ICONIFIED));
        // 最大化/還原按鈕
        maxButton = createWindowBtn("icons/window/maximize.png", this::toggleMaximize);
        // 關閉按鈕
        closeButton = createWindowBtn("icons/window/close.png", () -> {
            if (null != closeAction) {
                closeAction.run();
            } else {
                dispose();
            }
        });
        rightPanel.add(minButton);
        rightPanel.add(maxButton);
        rightPanel.add(closeButton);
        // 使用包裝面板確保按鈕垂直居中
        JPanel buttonWrapper = new JPanel(new BorderLayout());
        buttonWrapper.setOpaque(false);
        buttonWrapper.add(rightPanel, BorderLayout.CENTER);
        buttonPanel.add(buttonWrapper, BorderLayout.CENTER);
        // 添加拖拽功能
        addDragFunctionality(titlePanel);
        // 將左右面板添加到標題欄
        titlePanel.add(iconTitlePanel, BorderLayout.WEST);
        titlePanel.add(buttonPanel, BorderLayout.EAST);
        // 將標題欄添加到窗口頂部
        getContentPane().add(titlePanel, BorderLayout.NORTH);
    }

    /**
     * 關閉按鈕監(jiān)聽事件
     * @param closeAction 關閉事件
     */
    public void addCloseAction(Runnable closeAction) {
        this.closeAction = closeAction;
    }

    /**
     * 關閉按鈕監(jiān)聽事件(帶圖標)
     * @param iconPath 圖標路徑
     * @param closeAction 關閉事件
     */
    public void addCloseAction(String iconPath, Runnable closeAction) {
        // 注:根據iconPath獲取圖片需自行實現
        ImageIcon icon = xxxxxx;
        closeButton.setIcon(icon);
        this.closeAction = closeAction;
    }

    /**
     * 創(chuàng)建窗口控制按鈕
     * @param iconPath 圖標路徑
     * @param runnable 按鈕點擊時執(zhí)行的操作
     * @return 創(chuàng)建的按鈕標簽
     */
    private static JLabel createWindowBtn(String iconPath, Runnable runnable) {
        // 注:根據iconPath獲取圖片需自行實現
        ImageIcon icon = xxxxxx;
        JLabel button = new JLabel(icon);
        JLabel button = new JLabel();
        button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        button.setBorder(BorderFactory.createEmptyBorder(8, 5, 8, 5));
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (null != runnable) {
                    runnable.run();
                }
            }
        });
        return button;
    }

    /**
     * 設置內容區(qū)域并添加邊界調整監(jiān)聽器
     */
    private void setupContentArea() {
        // 創(chuàng)建內容面板
        JPanel contentPanel = new JPanel(new BorderLayout());
        getContentPane().add(contentPanel, BorderLayout.CENTER);
        // 創(chuàng)建邊界調整監(jiān)聽器實例
        ResizeMouseListener resizeListener = new ResizeMouseListener();
        ResizeMouseMotionListener resizeMotionListener = new ResizeMouseMotionListener();
        // 為整個窗口添加邊界調整監(jiān)聽器
        addMouseListener(resizeListener);
        addMouseMotionListener(resizeMotionListener);
        // 為內容面板添加邊界調整監(jiān)聽器
        contentPanel.addMouseListener(resizeListener);
        contentPanel.addMouseMotionListener(resizeMotionListener);
        // 為標題面板添加邊界調整監(jiān)聽器
        titlePanel.addMouseListener(resizeListener);
        titlePanel.addMouseMotionListener(resizeMotionListener);
        // 為根面板添加邊界調整監(jiān)聽器
        getRootPane().addMouseListener(resizeListener);
        getRootPane().addMouseMotionListener(resizeMotionListener);
    }

    /**
     * 為面板添加拖拽功能
     * @param panel 要添加拖拽功能的面板
     */
    private void addDragFunctionality(JPanel panel) {
        MouseAdapter ma = new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                if (resizeDirection == NONE) {
                    initialClick = e.getPoint();
                }
            }
            @Override
            public void mouseDragged(MouseEvent e) {
                if (isResizing) {
                    handleResize(e);
                } else if (resizeDirection == NONE && !maximizedDisable) {
                    // 如果窗口是最大化的,先還原再移動
                    if (isMaximized) {
                        toggleMaximize();
                        int x = e.getXOnScreen() - getWidth() / 2;
                        int y = e.getYOnScreen() - titlePanel.getHeight() / 2;
                        setLocation(x, y);
                        initialClick = new Point(getWidth() / 2, titlePanel.getHeight() / 2);
                    }
                    int thisX = getLocation().x;
                    int thisY = getLocation().y;
                    int xMoved = e.getX() - initialClick.x;
                    int yMoved = e.getY() - initialClick.y;
                    setLocation(thisX + xMoved, thisY + yMoved);
                }
            }
            @Override
            public void mouseClicked(MouseEvent e) {
                // 雙擊標題欄最大化/還原
                if (e.getClickCount() == 2 && resizeDirection == NONE && !maximizedDisable) {
                    toggleMaximize();
                }
            }
        };
        panel.addMouseListener(ma);
        panel.addMouseMotionListener(ma);
    }

    /**
     * 切換窗口最大化/還原狀態(tài)
     */
    public void toggleMaximize() {
        if (isMaximized) {
            // 還原到正常大小
            setBounds(normalBounds);
            isMaximized = false;
            // 注:獲取圖片需自行實現
            ImageIcon icon = xxxxxx;
            maxButton.setIcon(icon);
        } else {
            // 保存當前位置和大小
            normalBounds = getBounds();
            originalLocation = getLocation();
            // 獲取當前屏幕的最大可用邊界
            GraphicsConfiguration config = getCurrentScreenDevice().getDefaultConfiguration();
            Rectangle screenBounds = config.getBounds();
            Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(config);
            int x = screenBounds.x + screenInsets.left;
            int y = screenBounds.y + screenInsets.top;
            int width = screenBounds.width - screenInsets.left - screenInsets.right;
            int height = screenBounds.height - screenInsets.top - screenInsets.bottom;
            setBounds(x, y, width, height);
            isMaximized = true;
            // 注:獲取圖片需自行實現
            ImageIcon icon = xxxxxx;
            maxButton.setIcon(icon);
        }
    }

    /**
     * 禁用最大化功能
     */
    public void setMaximizedDisable() {
        maximizedDisable = true;
    }

    /**
     * 設置窗口圖標
     * @param imagePath 圖標路徑
     * @param width 圖標寬度
     * @param height 圖標高度
     */
    public void setIcon(String imagePath, int width, int height) {
        // 注:根據imagePath獲取圖片需自行實現
        ImageIcon icon = xxxxxx;
        titleLabel.setIcon(icon);
        titleLabel.setHorizontalTextPosition(SwingConstants.RIGHT);
        titleLabel.setVerticalTextPosition(SwingConstants.CENTER);
        titleLabel.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 5));
        int margin = (Math.max(height, 24) - 24) / 2;
        minButton.setBorder(BorderFactory.createEmptyBorder(margin, 5, margin, 5));
        maxButton.setBorder(BorderFactory.createEmptyBorder(margin, 5, margin, 5));
        closeButton.setBorder(BorderFactory.createEmptyBorder(margin, 5, margin, 5));
        iconTitlePanel.revalidate();
        iconTitlePanel.repaint();
    }

    /**
     * 設置窗口標題
     * @param title 標題文本
     */
    @Override
    public void setTitle(String title) {
        titleLabel.setText(title);
        titleLabel.setVisible(true);
        iconTitlePanel.revalidate();
        iconTitlePanel.repaint();
    }

    /**
     * 設置窗口標題和字體
     * @param title 標題文本
     * @param font 字體
     */
    public void setTitle(String title, Font font) {
        titleLabel.setText(title);
        titleLabel.setFont(font);
        titleLabel.setVisible(true);
        iconTitlePanel.revalidate();
        iconTitlePanel.repaint();
    }

    /**
     * 設置標題欄樣式
     * @param operate 自定義操作
     */
    public void setTitleStyle(BiConsumer<JPanel, JLabel> operate) {
        if (null != operate) {
            operate.accept(titlePanel, titleLabel);
        }
    }

    /**
     * 設置標題欄下劃線(默認顏色)
     */
    public void setUnderLine() {
        setUnderLine(new Color(0, 183, 195));
    }

    /**
     * 設置標題欄下劃線顏色
     * @param color 下劃線顏色
     */
    public void setUnderLine(Color color) {
        setUnderLine(color, 1);
    }

    /**
     * 設置標題欄下劃線
     * @param color 下劃線顏色
     * @param thickness 下劃線厚度
     */
    public void setUnderLine(Color color, int thickness) {
        titlePanel.setBorder(BorderFactory.createMatteBorder(0, 0, thickness, 0, color));
    }

    /**
     * 隱藏最小化和最大化按鈕
     */
    public void hideMinMax() {
        minButton.setVisible(false);
        maxButton.setVisible(false);
    }

    /**
     * 設置圓角半徑
     * @param radius 圓角半徑
     */
    public void setCornerRadius(int radius) {
        this.cornerRadius = radius;
        setShape(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), cornerRadius, cornerRadius));
        repaint();
    }

    /**
     * 邊界調整大小的鼠標監(jiān)聽器
     */
    private class ResizeMouseListener extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            if (resizeDirection != NONE) {
                isResizing = true;
            }
        }
        @Override
        public void mouseReleased(MouseEvent e) {
            isResizing = false;
            resizeDirection = NONE;
            setCursor(Cursor.getDefaultCursor());
        }
    }

    /**
     * 邊界調整大小的鼠標移動監(jiān)聽器
     */
    private class ResizeMouseMotionListener extends MouseMotionAdapter {
        @Override
        public void mouseDragged(MouseEvent e) {
            if (isResizing) {
                handleResize(e);
            }
        }
        @Override
        public void mouseMoved(MouseEvent e) {
            updateCursor(e.getPoint());
        }
    }

    /**
     * 更新鼠標光標
     * @param p 鼠標位置點
     */
    private void updateCursor(Point p) {
        if (isMaximized) {
            setCursor(Cursor.getDefaultCursor());
            resizeDirection = NONE;
            return;
        }
        int x = p.x;
        int y = p.y;
        int width = getWidth();
        int height = getHeight();
        boolean top = y < resizeBorder;
        boolean bottom = y > height - resizeBorder - titlePanel.getHeight();
        boolean left = x < resizeBorder;
        boolean right = x > width - resizeBorder;
        if (top && left) {
            setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
            resizeDirection = TOP_LEFT;
        } else if (top && right) {
            setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
            resizeDirection = TOP_RIGHT;
        } else if (bottom && left) {
            setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
            resizeDirection = BOTTOM_LEFT;
        } else if (bottom && right) {
            setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
            resizeDirection = BOTTOM_RIGHT;
        } else if (top) {
            setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
            resizeDirection = TOP;
        } else if (bottom) {
            setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
            resizeDirection = BOTTOM;
        } else if (left) {
            setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
            resizeDirection = LEFT;
        } else if (right) {
            setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
            resizeDirection = RIGHT;
        } else {
            setCursor(Cursor.getDefaultCursor());
            resizeDirection = NONE;
        }
    }

    /**
     * 處理調整大小
     * @param e 鼠標事件
     */
    private void handleResize(MouseEvent e) {
        if (!isResizing) {
            return;
        }
        int x = getX();
        int y = getY();
        int width = getWidth();
        int height = getHeight();
        int newX = x;
        int newY = y;
        int newWidth = width;
        int newHeight = height;
        if ((resizeDirection & LEFT) != 0) {
            newX = e.getXOnScreen();
            newWidth = width - (e.getXOnScreen() - x);
        }
        if ((resizeDirection & RIGHT) != 0) {
            newWidth = e.getXOnScreen() - x;
        }
        if ((resizeDirection & TOP) != 0) {
            newY = e.getYOnScreen();
            newHeight = height - (e.getYOnScreen() - y);
        }
        if ((resizeDirection & BOTTOM) != 0) {
            newHeight = e.getYOnScreen() - y;
        }
        int minWidth = 400;
        int minHeight = 300;
        if (newWidth < minWidth) {
            if ((resizeDirection & LEFT) != 0) {
                newX = x + width - minWidth;
            }
            newWidth = minWidth;
        }
        if (newHeight < minHeight) {
            if ((resizeDirection & TOP) != 0) {
                newY = y + height - minHeight;
            }
            newHeight = minHeight;
        }
        setBounds(newX, newY, newWidth, newHeight);
    }

    @Override
    public void setVisible(boolean visible) {
        if (visible) {
            if (!locationInitialized) {
                if (parentFrame != null) {
                    setLocationRelativeTo(parentFrame);
                } else {
                    setLocationRelativeTo(null);
                }
                locationInitialized = true;
            } else {
                if (originalLocation != null) {
                    setLocation(originalLocation);
                }
            }
            originalLocation = getLocation();
            originalSize = getSize();
        } else {
            originalLocation = getLocation();
            originalSize = getSize();
        }
        super.setVisible(visible);
    }

    /**
     * 在指定屏幕居中顯示
     * @param screenDevice 目標屏幕設備
     */
    public void setLocationToScreen(GraphicsDevice screenDevice) {
        if (screenDevice != null) {
            Rectangle screenBounds = screenDevice.getDefaultConfiguration().getBounds();
            int x = screenBounds.x + (screenBounds.width - getWidth()) / 2;
            int y = screenBounds.y + (screenBounds.height - getHeight()) / 2;
            setLocation(x, y);
            currentScreenDevice = screenDevice;
            originalLocation = getLocation();
            locationInitialized = true;
        }
    }

    /**
     * 確保窗口在當前屏幕顯示
     */
    public void ensureOnCurrentScreen() {
        if (originalLocation != null) {
            setLocation(originalLocation);
        } else if (currentScreenDevice != null) {
            setLocationToScreen(currentScreenDevice);
        }
    }

    /**
     * 保存當前位置信息
     */
    public void saveCurrentLocation() {
        this.originalLocation = getLocation();
        this.originalSize = getSize();
        updateCurrentScreenDevice();
    }

    /**
     * 快速顯示窗口(帶內容組件)
     * @param component 內容組件
     * @param closeAction 關閉回調
     */
    public void showFrame(JComponent component, Runnable closeAction) {
        add(component);
        setSize(new Dimension(1300, 800));
        setTitleStyle((titlePanel, titleLabel) -> {
            titlePanel.setOpaque(true);
            titlePanel.setBackground(Color.decode("#CDE6E6"));
            titlePanel.setBorder(BorderFactory.createEmptyBorder(5, 50, 5, 10));
            // 注:獲取圖片需自行實現
            ImageIcon icon = xxxxxx;
            titleLabel.setIcon(icon);
            titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 20));
        });
        hideMinMax();
        addCloseAction("icons/window/goback.png", () -> {
            if (null != closeAction) {
                closeAction.run();
            }
        });
        setMaximized(true);
        if (parentFrame != null) {
            setLocationToScreen(parentFrame.getCurrentScreenDevice());
        } else {
            ensureOnCurrentScreen();
        }
        setVisible(true);
    }

    /**
     * 創(chuàng)建跟隨父窗口的新窗口
     * @param title 窗口標題
     * @return 新的CusFrame實例
     */
    public CusFrame createChildFrame(String title) {
        CusFrame childFrame = new CusFrame(title, this);
        childFrame.setLocationToScreen(this.getCurrentScreenDevice());
        return childFrame;
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setColor(new Color(0, 183, 195));
        g2d.setStroke(new BasicStroke(1));
        g2d.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, cornerRadius, cornerRadius);
        g2d.dispose();
    }
}

三、核心功能說明

窗口裝飾:

  • setUndecorated(true):移除系統(tǒng)默認標題欄
  • setShape(new RoundRectangle2D.Double(...)):設置圓角矩形形狀
  • paint(Graphics g):繪制圓角邊框

自定義標題欄:

  • 左側:圖標 + 標題文字
  • 右側:最小化、最大化/還原、關閉按鈕
  • 支持拖拽移動窗口
  • 支持雙擊標題欄最大化/還原

窗口調整大?。?/strong>

  • 鼠標移動到窗口邊緣時自動改變光標樣式
  • 支持八個方向的拖拽調整(上、下、左、右、四個角)
  • 置了最小寬度400px、最小高度300px

多屏幕適配:

  • updateCurrentScreenDevice():檢測窗口當前所在的屏幕
  • setLocationToScreen():在指定屏幕居中顯示
  • ensureOnCurrentScreen():確保窗口在當前屏幕內可見

窗口狀態(tài)管理:

  • toggleMaximize():切換最大化/還原,最大化時排除系統(tǒng)任務欄區(qū)域
  • setMaximizedDisable():禁用最大化功能
  • saveCurrentLocation():保存窗口位置,用于重新顯示時恢復

四、使用示例

4.1 創(chuàng)建基本窗口

CusFrame frame = new CusFrame("我的應用");
frame.setSize(1000, 700);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);

4.2 設置窗口圖標

// 注:圖片獲取需自行實現
frame.setIcon("icons/my_logo.png", 32, 32);

4.3 自定義標題欄樣式

frame.setTitleStyle((titlePanel, titleLabel) -> {
    titlePanel.setBackground(new Color(50, 50, 80));
    titleLabel.setForeground(Color.WHITE);
    titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 18));
});
frame.setUnderLine(new Color(100, 150, 200), 2);

4.4 禁用最大化

frame.setMaximizedDisable();
frame.hideMinMax();

4.5 設置關閉回調

frame.addCloseAction(() -> {
    int result = JOptionPane.showConfirmDialog(frame, "確認退出?", "提示", JOptionPane.YES_NO_OPTION);
    if (result == JOptionPane.YES_OPTION) {
        System.exit(0);
    }
});

4.6 多窗口跟隨(子窗口跟隨父窗口屏幕)

CusFrame mainFrame = new CusFrame("主窗口");
mainFrame.setSize(1200, 800);
mainFrame.setVisible(true);

CusFrame childFrame = mainFrame.createChildFrame("子窗口");
childFrame.setSize(600, 400);
childFrame.setVisible(true);

五、注意事項

  1. 代碼中涉及圖標加載的地方已注釋,需要讀者自行實現或替換
  2. 代碼中所有png圖片均為實例,可自行從網上下載
  3. 圓角邊框:最大化時會暫時禁用圓角(避免系統(tǒng)任務欄區(qū)域顯示異常)
  4. 線程安全:窗口操作已在 EDT 中執(zhí)行,無需額外處理
  5. 多屏幕:最大化時只在當前屏幕內最大化,不會跨屏幕

到此這篇關于Java Swing實現自定義窗口CusFrame的文章就介紹到這了,更多相關Java Swing自定義窗口內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • RocketMQ消費冪概念與使用分析

    RocketMQ消費冪概念與使用分析

    如果有?個操作,多次執(zhí)?與?次執(zhí)?所產?的影響是相同的,我們就稱這個操作是冪等的。當出現消費者對某條消息重復消費的情況時,重復消費的結果與消費?次的結果是相同的,并且多次消費并未對業(yè)務系統(tǒng)產?任何負?影響,那么這整個過程就可實現消息冪等
    2023-02-02
  • Java查看線程運行狀態(tài)的方法詳解

    Java查看線程運行狀態(tài)的方法詳解

    這篇文章主要為大家詳細介紹了Java語言如何查看線程運行狀態(tài)的方法,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2022-08-08
  • Java Socket通信之聊天室功能

    Java Socket通信之聊天室功能

    這篇文章主要為大家詳細介紹了Java Socket通信之聊天室功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • 基于SpringAop中JoinPoint對象的使用說明

    基于SpringAop中JoinPoint對象的使用說明

    這篇文章主要介紹了基于SpringAop中JoinPoint對象的使用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 使用Java8進行分組(多個字段的組合分組)

    使用Java8進行分組(多個字段的組合分組)

    本文主要介紹了使用Java8進行分組(多個字段的組合分組),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • SpringBoot集成Apache POI實現Excel的導入導出

    SpringBoot集成Apache POI實現Excel的導入導出

    Apache POI是一個流行的Java庫,用于處理Microsoft Office格式文件,包括Excel文件,本文主要介紹了SpringBoot集成Apache POI實現Excel的導入導出,具有一定的參考價值,感興趣的可以了解一下
    2024-06-06
  • SpringBoot多環(huán)境打包與配置文件排除實踐記錄

    SpringBoot多環(huán)境打包與配置文件排除實踐記錄

    本文介紹了SpringBoot項目多環(huán)境打包與配置文件排除實踐,包括多環(huán)境配置的實現方法、打包時排除配置文件的方法以及動態(tài)加載外部配置文件的最佳實踐,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Java實現一個順序表的完整代碼

    Java實現一個順序表的完整代碼

    順序表是用一段物理地址連續(xù)的存儲單元依次存儲數據元素的線性結構,一般采用數組存儲。在數組上完成數據的增刪減改。順序表的底層是一個數組
    2021-04-04
  • Spring的@Transactional嵌套解讀

    Spring的@Transactional嵌套解讀

    本文通過詳細測試,探究了Spring的@Transactional注解在事務嵌套和局部回滾場景下的行為表現,文中通過多個測試案例,闡述了不同傳播行為(如REQUIRES_NEW)對事務嵌套處理的影響,以及rollbackFor屬性在異常管理中的作用和限制,通過實驗總結
    2024-11-11
  • 實例展示使用Java壓縮和解壓縮7z文件的方法

    實例展示使用Java壓縮和解壓縮7z文件的方法

    這篇文章主要介紹了實例展示使用Java壓縮和解壓縮7z文件的方法,用到了7-zip的開源項目7-zip-JBinding,需要的朋友可以參考下
    2015-11-11

最新評論

西峡县| 贵定县| 天等县| 龙里县| 南召县| 冀州市| 东山县| 广平县| 天台县| 凤城市| 搜索| 正安县| 梓潼县| 成武县| 海门市| 崇礼县| 开远市| 达拉特旗| 五台县| 遂平县| 新和县| 舒城县| 涿鹿县| 昆明市| 曲周县| 长泰县| 于都县| 莱州市| 汉源县| 汕尾市| 三穗县| 施甸县| 柞水县| 靖远县| 凯里市| 横山县| 那曲县| 宁南县| 西乡县| 大冶市| 北京市|