代码实现效果如下

JAVA 热替换代码 java替换tab_java gui tab切换

主界面的类如下

import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import test.ButtonTabComponent;
public class TabComponentsDemo extends JFrame{
private JTabbedPane pane = new JTabbedPane();
private JMenuItem scrollTabItem ;
private JMenuItem componentTabItem;
private final int numTab = 5;
public TabComponentsDemo(String title) {
//设置frame标题名
super(title);
//设置关闭方式
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//创建菜单栏
initMenu();
//将tabpane添加到frame中
add(pane);
}
//初始化tabpanel相关配置,并且用于resize的调用
public void runTest() {
//设置有关闭按键的标签
componentTabItem.setSelected(true);
//设置标签
for(int i = 0 ; i < numTab ; i++)
{
//标签名
String name = "tab "+i;
//创建标签
pane.add(name,createContent(name));
//初始化标签上的文字和Button
initTabComponent(i);
}
//设置frame的大小
setSize(new Dimension(500,500));
//将frame放到屏幕的正中央
setLocationRelativeTo(null);
//显示frame
setVisible(true);
}
//创建标签内容部分
private Component createContent(String name) {
//创建一个panel,并设置布局为一个分块
JPanel panel = new JPanel(new GridLayout(1,1));
//创建一个label
JLabel label = new JLabel(name);
//设置label的文本格式
label.setHorizontalAlignment(JLabel.CENTER);
//将label放入panel中
panel.add(label);
return panel;
}
//初始化带有关闭按钮的标签头部
private void initTabComponent(int i) {
//用这个函数可以初始化标签的头部
pane.setTabComponentAt(i, new ButtonTabComponent(pane));
}
//创建菜单栏
private void initMenu() {
//创建一个菜单条
JMenuBar mb = new JMenuBar();
//创建重叠tab选项
scrollTabItem = new JCheckBoxMenuItem("重叠tab");
//设置快捷键
scrollTabItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,InputEvent.CTRL_MASK));
//设置监听事件
scrollTabItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
if(pane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
pane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
else
pane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
}
});
//设置可关闭的标签的菜单
componentTabItem = new JCheckBoxMenuItem("设置可关闭的tab");
componentTabItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,InputEvent.CTRL_MASK));
componentTabItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for(int i = 0 ; i < numTab ; i++)
{
if(componentTabItem.isSelected())
initTabComponent(i);
else
pane.setTabComponentAt(i, null);
}
}
});
//设置重置标签
JMenuItem reSetItem = new JMenuItem("重置");
reSetItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,InputEvent.CTRL_MASK));
reSetItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
runTest();
}
});
//创建菜单
JMenu menu = new JMenu("选项");
//添加菜单项
menu.add(componentTabItem);
menu.add(scrollTabItem);
menu.add(reSetItem);
//添加菜单
mb.add(menu);
//添加菜单条(注意一个frame只能有一个菜单条,所以用set)
setJMenuBar(mb);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TabComponentsDemo("可关闭的tab测试").runTest();
}
});
}
}

会用到的另一个类如下:

package test;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.plaf.basic.BasicButtonUI;
public class ButtonTabComponent extends JPanel{
private final JTabbedPane pane;
public ButtonTabComponent(final JTabbedPane pane) {
//设置标签头要水平的,从左向右的排列组件,并且组件的间距为0(横向和纵向)
super(new FlowLayout(FlowLayout.LEFT, 0, 0));
if(pane == null)
throw new NullPointerException("pane can not be null");
this.pane = pane;
//不画出panel的边界
setOpaque(false);
//创建标签头的文字内容
JLabel label = new JLabel(){
//重写方法,返回pane指定位置的名字,这里有点绕,可以好好理解理解
//为什么不直接设置标签的内容,而是通过重写函数来修改标签内容
//可能是希望业务逻辑尽量不要散落在外部
@Override
public String getText() {
//可以获得当前panel在tab中的位置
int i = pane.indexOfTabComponent(ButtonTabComponent.this);
if(i != -1)
//得到当前panel的名字(实际是tab的名字)
return pane.getTitleAt(i);
return null;
}
};
label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
add(label);
//创建关闭按钮(就是那个差按键)
JButton button = new TabButton();
add(button);
setBorder(BorderFactory.createEmptyBorder(2,0,0,0));
}
private class TabButton extends JButton implements ActionListener{
public TabButton() {
//设置按键的大小
final int size = 17;
setPreferredSize(new Dimension(size,size));
//设置按键的提示信息
setToolTipText("关闭窗口");
//设置按键的绘制于普通按键相同
setUI(new BasicButtonUI());
//不对Button进行填充,就是按键是透明的
setContentAreaFilled(false);
//按键不能获得焦点
setFocusable(false);
//设置按键的边框为雕刻样式
setBorder(BorderFactory.createEtchedBorder());
//系统不自动绘制按键边界(这个边界在鼠标放上去之后才绘制)
setBorderPainted(false);
//添加按键点击事件
addActionListener(TabButton.this);
//添加鼠标事件(主要是mouseover 和 mouse exit)
addMouseListener(mouseListener);
}
//重写Button的绘制函数
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//创建一个graphics2D,因为需要在Button上画差
Graphics2D g2 = (Graphics2D) g.create();
//设置画笔,宽度为2
g2.setStroke(new BasicStroke(2));
//设置画笔颜色
g2.setColor(Color.BLACK);
//当鼠标移动到Button上时,画笔为紫色
if(getModel().isRollover())
g2.setColor(Color.PINK);
//绘制差
int delta = 6;
g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1);
g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1);
//释放画笔资源
g2.dispose();
}
@Override
public void actionPerformed(ActionEvent arg0) {
//当按键被点击,关闭当前标签页
int i = pane.indexOfTabComponent(ButtonTabComponent.this);
if(i != -1)
pane.remove(i);
}
private final MouseListener mouseListener = new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent event) {
//鼠标移入按键,绘制按键边界
Component c = event.getComponent();
if(c instanceof AbstractButton)
((AbstractButton)c).setBorderPainted(true);
}
@Override
public void mouseExited(MouseEvent event) {
//鼠标移出按键,不绘制按键边界
Component c = event.getComponent();
if(c instanceof AbstractButton)
((AbstractButton)c).setBorderPainted(false);
}
};
}
}