其实标题并不准确,但是一般人们都这样称呼它们为标题。文章最后贴了最新发现的bug
其实是JFrame的memuBar部分。
JFram由充满布局的glassPanel(负责切屏大小事件)和充满布局的JComponent组成。
JComponent负责添加组件。JComponent由memuBar和下部JComponent组成.
当没有memuBar时下部JComponent充满。
此文讨论的其实就是修改 memuBar部分。通常包含一个popupMemu 、标题、最小化、最大化、关闭按钮。
由于java内部JFrame的实现机制,JFrame的memuBar 是 MetalTitlePane类型,这个类是不支持外部访问的。 所以要修改 memuBar 只能另谋出路。我是按如下方式实现的:
在 JFrame内加 如下代码(其中全屏时会把任务栏也覆盖了,可以不使用JFrame状态,改用size来解决)
this.setUndecorated(true); // 去掉窗口的装饰 this.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);// 采用指定的窗口装饰风格 JLayeredPane jpanel2 = (JLayeredPane) this.rootPane.getComponents()[1]; JComponent bar = (JComponent) jpanel2.getComponent(1);//获取MetalTitlePane,只能强转为上一级 System.out.println(jpanel2.getComponent(1));
//我为了采用这三个按钮的样式,所以沿袭了系统的。 也可以不获取,在新的jpanel中自己定义。 JButton minBtn = (JButton) bar.getComponent(1);//最小化按钮 JButton maxBtn = (JButton) bar.getComponent(2);//最大化按钮 JButton closeBtn = (JButton) bar.getComponent(3);//关闭按钮
jpanel2.remove(1);//删除MetalTitlePane
//新的顶部jpanel,取代了MetalTitlePane的位置。
TopBarPanel topJpanel = new TopBarPanel(minBtn, maxBtn, closeBtn);
jpanel2.add(topJpanel, 1);
注意:TopBarPanel 没有任何事件,内部按钮也没有事件,这些都需要自己添加:
TopBarPanel 代码如下 ,有些代码没有进一步提精,可以自己提纯。
/* * Copyright (c) 2010 CCX(China) Co.,Ltd. All Rights Reserved. * * This software is the confidential and proprietary information of * CCX(China) Co.,Ltd. ("Confidential Information"). * It may not be copied or reproduced in any manner without the express * written permission of CCX(China) Co.,Ltd. * * @author wangyx * Date: 2010-5-25 上午10:29:25 */ package com.ccxc.indexfuture.frame;
import java.awt.Color; import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.InputStream;
import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel;
import com.ccxc.indexfuture.service.FrameMotionListener;
/* * 最顶部的标题和按钮panel,自适应窗口拖拽宽度 */ @SuppressWarnings("serial") public class TopBarPanel extends JPanel {
JButton minBtn = null; JButton maxBtn = null; JButton closeBtn = null;
private Integer oldX; private Integer oldY;
FrameMotionListener frameListener; // 主frame JFrame frame;
/** * Create the application */ public TopBarPanel(JButton minbtn, JButton maxbtn, JButton closebtn) { super(); try { // 初始化最小化、最大化、关闭按钮 this.minBtn = minbtn; this.maxBtn = maxbtn; this.closeBtn = closebtn; jbInit(); } catch (Throwable e) { e.printStackTrace(); }
}
// 重绘事件 public void paintComponent(Graphics g) { super.paintComponent(g); Dimension dimension = this.getParent().getSize(); // 获得屏幕大小 // 获取原窗口的宽高 int w = this.getWidth(); int h = this.getHeight(); // 获取改变的宽度差 double width = dimension.getWidth() - w; // 设置窗口和屏幕宽度相同 dimension.setSize(dimension.getWidth(), h); this.setSize(dimension);
// 更改按钮位置 int childNum = this.getComponentCount(); for (int i = 0; i < childNum; i++) { JComponent child = (JComponent) this.getComponent(i); // 获取右侧的按钮 if (child instanceof JButton) { Point p = child.getLocation(); // 修改按钮横向位置 p.setLocation(p.getX() + width, p.getY()); child.setLocation(p); // child.revalidate(); } } this.revalidate(); // } }
// 初始化面板的属性 private void jbInit() throws Exception { System.currentTimeMillis(); this.setBounds(0, 0, 1000, 22); this.setBackground(Color.BLACK);
this.add(minBtn); this.add(minBtn); this.add(minBtn);
this.setLayout(null); // 读取背景图片 InputStream in = getClass().getResourceAsStream("zcx.jpg"); if (in == null) { System.err.println("Image not found."); return; } byte[] buffer = new byte[in.available()]; in.read(buffer); Image m_image = Toolkit.getDefaultToolkit().createImage(buffer); // 加图片 JLabel img = new JLabel(new ImageIcon(m_image)); // 加背景 JLabel jb = new JLabel("中诚信金融信息服务平台"); // 图片位置 img.setBounds(1, 1, 33, 20); // 标题位置 jb.setBounds(35, 0, 300, 20); jb.setForeground(Color.white);
// img.setOpaque(false);
this.add(img); this.add(jb);
// 按钮位置 minBtn.setBounds(923, 1, 22, 20); this.add(minBtn); maxBtn.setBounds(948, 1, 22, 20); maxBtn.setText(""); this.add(maxBtn); closeBtn.setBounds(973, 1, 22, 20); this.add(closeBtn);
frame = MainMenu.getMapJFrame().get("showFrame");
// 注册主frame拖揣事件 addFrameMotionEvent(); // 注册最大化、最小化、和关闭按钮事件 buttonEvent(); // 注册双击本面板 事件 myDbClickedEvent(); }
// 窗口追随鼠标按住移动事件 private void addFrameMotionEvent() { final JPanel this_Panel = this; // 添加鼠标点击事件 this.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) { // 获取鼠标位置 oldX = e.getX(); oldY = e.getY(); // 添加鼠标拖动事件 frameListener = new FrameMotionListener(oldX, oldY); this_Panel.addMouseMotionListener(frameListener); }
});
this.addMouseListener(new MouseAdapter() { // 删除鼠标拖动事件 public void mouseReleased(MouseEvent e) { this_Panel.removeMouseMotionListener(frameListener); }
}); }
private void buttonEvent() {
// 最小化按钮事件 minBtn.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) { // 最小化操作 frame.setState(Frame.ICONIFIED); } });
// 最大化按钮事件 maxBtn.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) { changeFrameState() ; } });
// 关闭按钮事件 closeBtn.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) { // 关闭操作 System.exit(0); } }); }
// 双击面板更改窗口状态事件 private void myDbClickedEvent() { this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) { if(e.getClickCount() == 2 ){ changeFrameState(); } } }); }
//修改frame显示状态 private void changeFrameState(){ if (frame.getExtendedState() == Frame.MAXIMIZED_BOTH) { // 恢复操作 frame.setExtendedState(Frame.NORMAL); } else { // 最大化操作 frame.setExtendedState(Frame.MAXIMIZED_BOTH); } } }
//主JFrame事件类
/* * Copyright (c) 2010 CCX(China) Co.,Ltd. All Rights Reserved. * * This software is the confidential and proprietary information of * CCX(China) Co.,Ltd. ("Confidential Information"). * It may not be copied or reproduced in any manner without the express * written permission of CCX(China) Co.,Ltd. * * @author wangyx * Date: 2010-5-25 下午01:35:01 */ package com.ccxc.indexfuture.service;
import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import com.ccxc.indexfuture.frame.MainMenu;
/** * 添加主frame的鼠标拖揣移动事件 * @author wangyx * */ public class FrameMotionListener implements MouseMotionListener {
private JFrame frame; private Integer oldX; private Integer oldY;
public FrameMotionListener(Integer oldX, Integer oldY) { //获取主frame frame = MainMenu.getMapJFrame().get("showFrame"); //拖动前的鼠标位置 this.oldX = oldX; this.oldY = oldY; }
//拖动事件 @Override public void mouseDragged(MouseEvent e) { int newX = e.getX(); int newY = e.getY(); //后去frame的原位置是 Point p = frame.getLocation(); //更新frame位置 p.setLocation(p.getX() + newX - oldX, p.getY() + newY - oldY); frame.setLocation(p); }
@Override public void mouseMoved(MouseEvent e) { }
}
补:今天发现最大化按钮和双击面板之间切换窗口大小时会有冲突,等有时间改下,换成修改JFrame size,另做static变量来保存原来的size就可以。