自定义窗口 --- CusFrame
一、背景
Swing 原生窗口 JFrame 的标题栏是系统自带的,样式陈旧且无法自定义。不同操作系统下标题栏风格不一致,也不支持圆角、自定义颜色、自定义按钮等现代 UI 元素。 CusFrame 的作用就是:移除系统装饰,自己绘制标题栏和窗口边框,实现统一的窗口风格。同时支持窗口拖拽移动、调整大小、最小化、最大化、还原、多屏幕适配等功能。
二、类源码
java
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;
/** 窗口正常状态下的边界 */
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;
/** 边界检测区域宽度 */
@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));
// 创建自定义标题栏
createCustomTitleBar(title);
// 设置内容区域
setupContentArea();
// 设置圆角
setShape(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), cornerRadius, cornerRadius));
// 设置默认关闭方式
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 注:这里获取图片 需自行实现
setIconImage(xxxxxx);
// 保存正常状态下的边界
normalBounds = getBounds();
// 初始化当前屏幕设备
updateCurrentScreenDevice();
// 添加窗口大小变化监听器,更新圆角形状
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;
}
/**
* 创建自定义标题栏
* @param title 标题文本
*/
private void createCustomTitleBar(String title) {
// 创建标题栏主面板
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);
}
/**
* 关闭按钮监听事件
* @param closeAction 关闭事件
*/
public void addCloseAction(Runnable closeAction) {
this.closeAction = closeAction;
}
/**
* 关闭按钮监听事件(带图标)
* @param iconPath 图标路径
* @param closeAction 关闭事件
*/
public void addCloseAction(String iconPath, Runnable closeAction) {
// 注:根据iconPath获取图片需自行实现
ImageIcon icon = xxxxxx;
closeButton.setIcon(icon);
this.closeAction = closeAction;
}
/**
* 创建窗口控制按钮
* @param iconPath 图标路径
* @param runnable 按钮点击时执行的操作
* @return 创建的按钮标签
*/
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;
}
/**
* 设置内容区域并添加边界调整监听器
*/
private void setupContentArea() {
// 创建内容面板
JPanel contentPanel = new JPanel(new BorderLayout());
getContentPane().add(contentPanel, BorderLayout.CENTER);
// 创建边界调整监听器实例
ResizeMouseListener resizeListener = new ResizeMouseListener();
ResizeMouseMotionListener resizeMotionListener = new ResizeMouseMotionListener();
// 为整个窗口添加边界调整监听器
addMouseListener(resizeListener);
addMouseMotionListener(resizeMotionListener);
// 为内容面板添加边界调整监听器
contentPanel.addMouseListener(resizeListener);
contentPanel.addMouseMotionListener(resizeMotionListener);
// 为标题面板添加边界调整监听器
titlePanel.addMouseListener(resizeListener);
titlePanel.addMouseMotionListener(resizeMotionListener);
// 为根面板添加边界调整监听器
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);
}
/**
* 切换窗口最大化/还原状态
*/
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();
}
/**
* 边界调整大小的鼠标监听器
*/
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());
}
}
/**
* 边界调整大小的鼠标移动监听器
*/
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);
}
/**
* 创建跟随父窗口的新窗口
* @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):移除系统默认标题栏
- setShape(new RoundRectangle2D.Double(...)):设置圆角矩形形状
- paint(Graphics g):绘制圆角边框
自定义标题栏:
- 左侧:图标 + 标题文字
- 右侧:最小化、最大化/还原、关闭按钮
- 支持拖拽移动窗口
- 支持双击标题栏最大化/还原
窗口调整大小:
- 鼠标移动到窗口边缘时自动改变光标样式
- 支持八个方向的拖拽调整(上、下、左、右、四个角)
- 置了最小宽度400px、最小高度300px
多屏幕适配:
- updateCurrentScreenDevice():检测窗口当前所在的屏幕
- setLocationToScreen():在指定屏幕居中显示
- ensureOnCurrentScreen():确保窗口在当前屏幕内可见
窗口状态管理:
- toggleMaximize():切换最大化/还原,最大化时排除系统任务栏区域
- setMaximizedDisable():禁用最大化功能
- saveCurrentLocation():保存窗口位置,用于重新显示时恢复
四、使用示例
4.1 创建基本窗口
java
CusFrame frame = new CusFrame("我的应用");
frame.setSize(1000, 700);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
4.2 设置窗口图标
java
// 注:图片获取需自行实现
frame.setIcon("icons/my_logo.png", 32, 32);
4.3 自定义标题栏样式
java
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 禁用最大化
java
frame.setMaximizedDisable();
frame.hideMinMax();
4.5 设置关闭回调
java
frame.addCloseAction(() -> {
int result = JOptionPane.showConfirmDialog(frame, "确认退出?", "提示", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
System.exit(0);
}
});
4.6 多窗口跟随(子窗口跟随父窗口屏幕)
java
CusFrame mainFrame = new CusFrame("主窗口");
mainFrame.setSize(1200, 800);
mainFrame.setVisible(true);
CusFrame childFrame = mainFrame.createChildFrame("子窗口");
childFrame.setSize(600, 400);
childFrame.setVisible(true);
五、注意事项
- 代码中涉及图标加载的地方已注释,需要读者自行实现或替换
- 代码中所有png图片均为实例,可自行从网上下载
- 圆角边框:最大化时会暂时禁用圆角(避免系统任务栏区域显示异常)
- 线程安全:窗口操作已在 EDT 中执行,无需额外处理
- 多屏幕:最大化时只在当前屏幕内最大化,不会跨屏幕