目录
- 1.组件
- 1.1 基本组件
- 1.2. 组件边框
- 1.3. JToolBar 工具条
- 1.4 JColorChooser 颜色选择器
- 1.5 JFileChooser 文件选择器
- 1.6 JOptionPane 对话框
- 1. MessageDialog 消息对话框
- 2. ConfirmDialog 确认对话框
- 3. InputDialog 输入对话框
- 4. OptionDialog 选择对话框
- 2. 特殊布局
- 2.1 JSplitPane 分隔容器
- 2.2 JTabbedPane 标签页容器
- 3. 进度条
- 3.1 JProcessBar
- 3.1.1 Model模型
- 3.2 进度条提示框
- 4. JList、JComboBox实现列表框
- 4.1 简单列表框
- 4.2 不强制存储列表项的ListModel和ComboBoxModel
- 4.3 强制存储列表项的DefaultListModel和DefaultComboBoxModel
- 4.4 使用ListCellRenderer绘制列表项的外观
- 5. JTree、TreeModel实现树
- 5.1 创建简单的树
- 5.1.1 **JTree常用构造方法**
- 5.1.2 **TreeNode继承体系及使用**
- 5.1.3 外观
- 5.1.4 JTree的基本方法
- 5.2 编辑树的结点
- 5.2.1 编辑树的结点
- 5.2.1拖动树的结点
- 5.2.2 监听结点事件
- 5.3 扩展DefaultTreeCellRenderer改变结点外观
- 6. JTable、JTableModel实现表格
- 6.1 JTable实现简单表格
- 6.2 TableModel和监视器
Swing组件继承体系图:
Swing组件按照功能来分类:
1. 顶层容器: JFrame、JApplet、JDialog 和 JWindow 。
2. 中间容器: JPanel 、 JScrollPane 、 JSplitPane 、 JToolBar 等 。
3. 特殊容器:在用户界面上具有特殊作用的中间容器,如 JIntemalFrame 、 JRootPane 、 JLayeredPane和 JDestopPane 等 。
4. 基本组件 : 实现人机交互的组件,如 JButton、 JComboBox 、 JList、 JMenu、 JSlider 等 。
5. 不可编辑信息的显示组件:向用户显示不可编辑信息的组件,如JLabel 、 JProgressBar 和 JToolTip等。
6. 可编辑信息的显示组件:向用户显示能被编辑的格式化信息的组件,如 JTable 、 JTextArea 和JTextField 等 。
7. 特殊对话框组件:可以直接产生特殊对话框的组件 , 如 JColorChooser 和 JFileChooser 等。
1.组件
1.1 基本组件
- 和AWT相比改动:
- 下拉选择框
String [] choice = {"红色","绿色","蓝色"}
JComboBox<String> jComboBox = new JComboBox<String>(choice);
- 单选组件
ButtonGroup buttonGroup = new ButtonGroup();
JRadioButtonMenuItem manButtonMenuItem = new JRadioButtonMenuItem("男");
JRadioButtonMenuItem womanButtonMenuItem = new JRadioButtonMenuItem("女");
- 右键菜单(单选)
ButtonGroup popupButtonGroup = new ButtonGroup()
JRadioButtonMenuItem metalItem = new JRadioButtonMenuItem("Metal 风格",false);
JRadioButtonMenuItem nimbusItem = new JRadioButtonMenuItem("Nimbus 风格",false);
- 右键菜单显示,不用监听
jTextArea.setComponentPopupMenu(popupMenu);
- MenuItem之间的隔断
editMenu.addSeparator();
import javax.swing.*
import java.awt.*;
import java.awt.event.ActionListener;
public class SwingComponentDemo {
JFrame jFrame = new JFrame("Swing组件");
JPanel jPanelBottom = new JPanel();
JTextField jTextField = new JTextField(20);
JButton jButton = new JButton("确定");
JMenuItem commentMenuItem = new JMenuItem("注释");
JMenuItem cancelCommentMenuItem = new JMenuItem("取消注释");
JMenuItem autoMenuItem = new JMenuItem("自动换行");
JMenuItem copyMenuItem = new JMenuItem("复制",new ImageIcon("./img/component/copy.png"));
JMenuItem pasteMenuItem = new JMenuItem("粘贴",new ImageIcon("./img/component/paste.png"));
JMenu formatMenu = new JMenu("格式");
JMenu textMenu = new JMenu("文本");
JMenu editMenu = new JMenu("编辑");
JMenuBar jMenuBar = new JMenuBar();
Box boxH = Box.createHorizontalBox();
JTextArea jTextArea = new JTextArea(8,20);
// 下拉选择框
String [] choice = {"红色","绿色","蓝色"};
JComboBox<String> jComboBox = new JComboBox<String>(choice);
//单选组件
ButtonGroup buttonGroup = new ButtonGroup();
JRadioButtonMenuItem manButtonMenuItem = new JRadioButtonMenuItem("男");
JRadioButtonMenuItem womanButtonMenuItem = new JRadioButtonMenuItem("女");
//复选框
JCheckBox marryCheckBox = new JCheckBox("是否已婚",true);
//
JList<String> colorList = new JList<String>(choice);
//容器
Box boxTopLeft = Box.createVerticalBox();
Box boxTop = Box.createHorizontalBox();
//右键菜单
JPopupMenu popupMenu = new JPopupMenu();
ButtonGroup popupButtonGroup = new ButtonGroup();
//定义五个单选按钮菜单项,用于设置程序风格
JRadioButtonMenuItem metalItem = new JRadioButtonMenuItem("Metal 风格",false);
JRadioButtonMenuItem nimbusItem = new JRadioButtonMenuItem("Nimbus 风格",false);
JRadioButtonMenuItem windowsItem = new JRadioButtonMenuItem("Windows 风格",true);
JRadioButtonMenuItem classicItem = new JRadioButtonMenuItem("Windows 经典风格",false);
JRadioButtonMenuItem motifItem = new JRadioButtonMenuItem("Motif 风格",false);
//菜单增加点击事件
ActionListener popupActionListener = e -> {
String command = e.getActionCommand();
try {
changeFlavor(command);
} catch (Exception e1) {
e1.printStackTrace();
}
};
private void init(){
//页面底部
jButton.setIcon(new ImageIcon("./img/component/ok.png"));
jPanelBottom.add(jTextField);
jPanelBottom.add(jButton);
jFrame.add(jPanelBottom, BorderLayout.SOUTH);
//组装menubar
commentMenuItem.setToolTipText("将程序注释");
formatMenu.add(commentMenuItem);
formatMenu.add(cancelCommentMenuItem);
editMenu.add(autoMenuItem);
editMenu.addSeparator();
editMenu.add(copyMenuItem);
editMenu.add(pasteMenuItem);
editMenu.addSeparator();
editMenu.add(formatMenu);
jMenuBar.add(textMenu);
jMenuBar.add(editMenu);
jFrame.setJMenuBar(jMenuBar);
//组装单选组件
buttonGroup.add(manButtonMenuItem);
buttonGroup.add(womanButtonMenuItem);
//
boxH.add(jComboBox);
boxH.add(manButtonMenuItem);
boxH.add(womanButtonMenuItem);
boxH.add(marryCheckBox);
boxTopLeft.add(jTextArea);
boxTopLeft.add(boxH);
//文本域的右键菜单
//加入一个组,单选
popupButtonGroup.add(metalItem);
popupButtonGroup.add(nimbusItem);
popupButtonGroup.add(windowsItem);
popupButtonGroup.add(metalItem);
popupButtonGroup.add(classicItem);
popupButtonGroup.add(motifItem);
popupMenu.add(metalItem);
popupMenu.add(nimbusItem);
popupMenu.add(windowsItem);
popupMenu.add(metalItem);
popupMenu.add(classicItem);
popupMenu.add(motifItem);
metalItem.addActionListener(popupActionListener);
nimbusItem.addActionListener(popupActionListener);
windowsItem.addActionListener(popupActionListener);
classicItem.addActionListener(popupActionListener);
motifItem.addActionListener(popupActionListener);
//设置右键菜单,简单多了
jTextArea.setComponentPopupMenu(popupMenu);
boxTop.add(boxTopLeft);
boxTop.add(colorList);
jFrame.add(boxTop);
jFrame.pack();
jFrame.setVisible(true);
}
//定义一个方法,用于改变界面风格
private void changeFlavor(String command) throws Exception {
switch (command) {
case "Metal 风格":
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
break;
case "Nimbus 风格":
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
break;
case "Windows 风格":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
break;
case "Windows 经典风格":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
break;
case "Motif 风格":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
break;
}
//更新f窗口内顶级容器以及所有组件的UI
SwingUtilities.updateComponentTreeUI(jFrame.getContentPane());
//更新mb菜单条及每部所有组件UI
SwingUtilities.updateComponentTreeUI(jMenuBar);
//更新右键菜单及内部所有菜单项的UI
SwingUtilities.updateComponentTreeUI(popupMenu);
}
public static void main(String[] args) {
new SwingComponentDemo().init();
}
}
1.2. 组件边框
1.3. JToolBar 工具条
创建工具条:
- 创建JToolBar的对象
- 创建Action,参数:(可显示的文本,图标地址)
- JToolBar.add(Action对象)
- 如果想要显示文本,则需要将Action放入JButton
- TextArea增加滚动条:
使用JScrollPan:要在创建对象时就将需要滚动的组件放入到参数中,不能使用add来增加
JScrollPane jScrollPane = new JScrollPane(jTextArea);
// 不能使用
// jScrollPane.add(jTextArea)
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class JToolBarDemo {
JFrame jFrame = new JFrame("JToolBar播放器");
JTextArea jTextArea = new JTextArea(10,20);
//JScrollPane 作用:增加滚动条,但是只能以下面这种方式增加
JScrollPane jScrollPane = new JScrollPane(jTextArea);
// 创建工具条:
// 1. 创建JToolBar的对象
// 2.创建Action,参数:(可显示的文本,图标地址)
// 3. JToolBar.add(Action对象)
// 4.如果想要显示文本,则不要将Action放入JButton
JToolBar jToolBar = new JToolBar("播放器");
Action start = new AbstractAction("播放",new ImageIcon("./img/start32.png")) {
@Override
public void actionPerformed(ActionEvent e) {
jTextArea.append("开始播放\n");
}
};
Action pause = new AbstractAction("暂停",new ImageIcon("./img/pause32.png")) {
@Override
public void actionPerformed(ActionEvent e) {
jTextArea.append("暂停\n");
}
};
Action next = new AbstractAction("下一曲",new ImageIcon("./img/next32.png")) {
@Override
public void actionPerformed(ActionEvent e) {
jTextArea.append("下一曲\n");
}
};
JButton startButton = new JButton(start);
JButton pauseButton = new JButton(pause);
JButton nextButton = new JButton(next);
private void init(){
jToolBar.add(startButton);
jToolBar.add(pauseButton);
jToolBar.add(nextButton);
jFrame.add(jScrollPane);
jFrame.add(jToolBar, BorderLayout.NORTH);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new JToolBarDemo().init();
}
}
1.4 JColorChooser 颜色选择器
- 参数(父窗口,标题,默认选中的颜色)
Color color = JColorChooser.showDialog(jFrame, "选择颜色", Color.white);
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class ColorDialogDemo {
JFrame jFrame = new JFrame();
JButton jButton = new JButton(new AbstractAction("选择背景颜色",new ImageIcon("./img/start32.png")) {
@Override
public void actionPerformed(ActionEvent e) {
//参数(父窗口,标题,默认选中的颜色)
Color color = JColorChooser.showDialog(jFrame, "选择颜色", Color.white);
jTextArea.setBackground(color);
}
});
JTextArea jTextArea = new JTextArea(8,20);
private void init(){
jFrame.add(jTextArea);
jFrame.add(jButton, BorderLayout.SOUTH);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new ColorDialogDemo().init();
}
}
1.5 JFileChooser 文件选择器
JFileChooser使用步骤:
- 创建JFileChooser对象:
JFileChooser chooser = new JFileChooser("D:\\a");//指定默认打开的本地磁盘路径
- 调用JFileChooser的一系列可选方法,进行初始化
setSelectedFile(File file)/setSelectedFiles(File[] selectedFiles):设定默认选中的文件
setMultiSelectionEnabled(boolean b):设置是否允许多选,默认是单选
setFileSelectionMode(int mode):设置可以选择内容,例如文件、文件夹等,默认只能选择文件
- 打开文件对话框
showOpenDialog(Component parent):打开文件加载对话框,并指定父组件
showSaveDialog(Component parent):打开文件保存对话框,并指定父组件
- 获取用户选择的结果
File getSelectedFile():获取用户选择的一个文件
File[] getSelectedFiles():获取用户选择的多个文件
案例:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class JFileChooserDemo {
JFrame jFrame = new JFrame();
JMenuBar jMenuBar = new JMenuBar();
JMenu jMenu = new JMenu("文件");
JFileChooser jFileChooser = new JFileChooser();
BufferedImage image;
//Swing的JPanel取代了AWT中Canves
private class MyJpanel extends JPanel {
@Override
public void paint(Graphics g) {
g.drawImage(image, 0, 0, null);
}
}
MyJpanel myJpanel = new MyJpanel();
JTextArea jTextArea = new JTextArea(8, 20);
//打开图片,并显示在myJpanel
JMenuItem multipleChoiceItem = new JMenuItem(new AbstractAction("打开图片") {
@Override
public void actionPerformed(ActionEvent e) {
//设置要打开的默认路径
jFileChooser.setCurrentDirectory(new File("."));
//是否允许多选,默认是false单选
jFileChooser.setMultiSelectionEnabled(false);
//模式:0-文件,1-文件夹,2-文件或文件夹
jFileChooser.setFileSelectionMode(0);
jFileChooser.showOpenDialog(jFrame);
File selectedFile = jFileChooser.getSelectedFile();
try {
image = ImageIO.read(selectedFile);
autoWindow();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
myJpanel.repaint();
}
});
//选择多个文件,并将文件的绝对路径显示在TextArea中
JMenuItem multiSelectItem = new JMenuItem(new AbstractAction("选择多个文件") {
@Override
public void actionPerformed(ActionEvent e) {
//设置要打开的默认路径
jFileChooser.setCurrentDirectory(new File("."));
//是否允许多选,默认是false单选
jFileChooser.setMultiSelectionEnabled(true);
//模式:0-文件,1-文件夹,2-文件或文件夹
jFileChooser.setFileSelectionMode(0);
jFileChooser.showOpenDialog(jFrame);
File[] selectedFiles = jFileChooser.getSelectedFiles();
jFrame.remove(myJpanel);
for (File file : selectedFiles) {
jTextArea.append(file.getPath() + "\n");
}
jFrame.add(jTextArea);
jFrame.pack();
}
});
//选择文件夹
JMenuItem folderItem = new JMenuItem(new AbstractAction("选择文件夹") {
@Override
public void actionPerformed(ActionEvent e) {
//设置要打开的默认路径
jFileChooser.setCurrentDirectory(new File("."));
//是否允许多选,默认是false单选
jFileChooser.setMultiSelectionEnabled(false);
//模式:0-文件,1-文件夹,2-文件或文件夹
jFileChooser.setFileSelectionMode(1);
jFileChooser.showOpenDialog(jFrame);
File selectedFile = jFileChooser.getSelectedFile();
jFrame.remove(myJpanel);
jTextArea.append(selectedFile.getPath() + "\n");
jFrame.add(jTextArea);
jFrame.pack();
}
});
//将图片另存为,通过绑定的方式增加Action
JMenuItem saveItem = new JMenuItem();
Action saveItemAction = new AbstractAction("另存为") {
@Override
public void actionPerformed(ActionEvent e) {
jFileChooser.showSaveDialog(jFrame);
File file = jFileChooser.getSelectedFile();
if (image != null){
System.out.println(file);
try {
ImageIO.write(image,"jpeg",file);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
};
private void autoWindow() {
if (image != null) {
myJpanel.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
jFrame.pack();
}
}
private void init() {
saveItem.setAction(saveItemAction);
jMenu.add(multipleChoiceItem);
jMenu.add(multiSelectItem);
jMenu.add(folderItem);
jMenu.add(saveItem);
jMenuBar.add(jMenu);
jFrame.setJMenuBar(jMenuBar);
jFrame.add(myJpanel);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new JFileChooserDemo().init();
}
}
1.6 JOptionPane 对话框
通过 JOptionPane 可以非常方便地创建一些简单的对话框, Swing 已经为这些对话框添加了相应的组件,无须程序员手动添加组件 。 JOptionPane 提供了如下 4 个方法来创建对话框 。
方法名称 | 方法功能 |
showMessageDialog/showInternalMessageDialog | 消息对话框 ,告知用户某事己发生 , 用户只能单击"确定"按钮 , 类似于 JavaScript 的 alert 函数 。 |
showConfirmDialog/showInternalConfirmDialog | 确认对话框,向用户确认某个问题,用户可以选择 yes 、 no ~ cancel 等选项 。 类似于 JavaScript 的 comfirm 函数 。该方法返回用户单击了 哪个按钮 |
showInputDialog/showInternalInputDialog | 输入对话框,提示要求输入某些信息,类似于 JavaScript的 prompt 函数。该方法返回用户输入的字符串 。 |
showOptionDialog/showInternalOptionDialog | 自定义选项对话框 ,允许使用自 定义选项 ,可以取代showConfirmDialog 所产生的对话框,只是用起来更复杂 。 |
上述方法都有都有很多重载形式,选择其中一种最全的形式,参数解释如下:
showXxxDialog(Component parentComponent,
Object message,
String title,
int optionType,
int messageType,
ImageIcon icon,
Object[] options,
Object initialValue)
--参数解释:
parentComponent:当前对话框的父组件
message:对话框上显示的信息,信息可以是字符串、组件、图片等
title:当前对话框的标题
optionType:当前对话框上显示的按钮类型:DEFAULT_OPTION、YES_NO_OPTION、YES_NO_CANCEL_OPTION、OK_CANCEL_OPTION
messageType:当前对话框的类型:ERROR_MESSAGE、INFORMATION_MESSAGE、WARNING_MESSAGE、QUESTION_MESSAGE、PLAIN_MESSAGE
icon:当前对话框左上角的图标
options:自定义下拉列表的选项
initialValue:自定义选项中的默认选中项
当用户与对话框交互结束后,不同类型对话框的返回值如下:
- showMessageDialog: 无返回值 。
- showlnputDialog: 返回用户输入或选择的字符串 。
- showConfirmDialog: 返回 一个整数代表用户选择的选项 。
- showOptionDialog : 返回 一个整数代表用户选择的选项,如果用户选择第一项,则返回 0; 如果选择第二项,则返回1……依此类推 。
对 showConfirmDialog 所产生的对话框,有如下几个返回值:
- YES OPTION: 用户 单击了 "是"按钮后返回 。
- NO OPTION: 用 户单击了"否"按钮后返回 。
- CANCEL OPTION: 用户单击了"取消"按钮后返回 。
- OK OPTION : 用户单击了"确定"按钮后返回 。
- CLOSED OPTION: 用户 单击了对话框右上角的 " x" 按钮后返回。
1. MessageDialog 消息对话框
JOptionPane.showMessageDialog(jFrame, jTextArea.getText(),title,counter,new ImageIcon("./img/component/female.png"));
- 参数中默认的4个图标很难看,还是自己弄一个吧
- 参数:父窗口,提示消息内容,标题,系统提供的图标,自定义图标
package Component.JOptionPane;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class MessageDialog {
JFrame jFrame = new JFrame("对话框演示");
int counter = 0;
String title = "第"+counter+"个消息";
JTextArea jTextArea = new JTextArea(8,20);
JButton jButton = new JButton();
Action action = new AbstractAction("消息提示框") {
@Override
public void actionPerformed(ActionEvent e) {
title = "第"+counter+"个消息";
jTextArea.setText(title);
//参数:父窗口,提示消息内容,标题,默认的图标,自定义图标
JOptionPane.showMessageDialog(jFrame, jTextArea.getText(),title,counter,new ImageIcon("./img/component/female.png"));
counter ++;
}
};
private void init(){
jTextArea.append("Hello World");
jButton.setAction(action);
jFrame.add(jButton, BorderLayout.SOUTH);
jFrame.add(jTextArea);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new MessageDialog().init();
}
}
2. ConfirmDialog 确认对话框
JOptionPane.showConfirmDialog(jFrame, jTextArea.getText(), "确认对话框", JOptionPane.YES_NO_CANCEL_OPTION, 2, new ImageIcon("./img/component/female.png"));
参数:父窗口,显示的提示信息,标题,显示的按钮类型共4种,系统提供的图标4种,自定义图标
按钮类型:
1. 默认:DEFAULT_OPTION = -1 只有确定按钮
2. YES_NO_OPTION = 0; 是、否两个按钮
3. YES_NO_CANCEL_OPTION = 1;是、否、取消三个按钮
4. OK_CANCEL_OPTION = 2; 确定、取消两个按钮
返回值:
1. JOptionPane.YES_OPTION:确认和是都返回0
2. JOptionPane.NO_OPTION:否返回1
3. JOptionPane.CANCEL_OPTION:取消返回2
4. JOptionPane.OK_OPTION:确定返回0
5. JOptionPane. CLOSED_OPTION:直接关闭对话框返回-1
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class ConfirmDialog {
JFrame jFrame = new JFrame("对话框演示");
JTextArea jTextArea = new JTextArea(8, 20);
JButton jButton = new JButton();
Action action = new AbstractAction("消息提示框") {
@Override
public void actionPerformed(ActionEvent e) {
//
int reslt = JOptionPane.showConfirmDialog(jFrame, jTextArea.getText(), "确认对话框", JOptionPane.YES_NO_CANCEL_OPTION, 2, new ImageIcon("./img/component/female.png"));
switch (reslt) {
case JOptionPane.YES_OPTION:
jTextArea.append("点击 确定 按钮\n");
break;
case JOptionPane.NO_OPTION:
jTextArea.append("点击 否 按钮\n");
break;
case JOptionPane.CANCEL_OPTION:
jTextArea.append("点击 取消 按钮\n");
break;
case JOptionPane.CLOSED_OPTION:
jTextArea.append("点击 关闭对话框 按钮\n");
break;
}
}
};
private void init() {
jTextArea.append("Hello World");
jButton.setAction(action);
jFrame.add(jButton, BorderLayout.SOUTH);
jFrame.add(jTextArea);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new ConfirmDialog().init();
}
}
3. InputDialog 输入对话框
手动输入内容:参数:(父窗口, 提示信息, 标题, 系统图标),返回String
下拉选择输入:参数:(父窗口, 提示信息, 标题, 系统图标,自定义图标,数组,默认选择),返回Object对象
直接关闭对话框返回:null
package Component.JOptionPane;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class InputDialog {
JFrame jFrame = new JFrame("对话框演示");
JTextArea jTextArea = new JTextArea(8, 20);
JButton jButton = new JButton();
String[] selectValus = {"1","2"};
Action action = new AbstractAction("对话框") {
@Override
public void actionPerformed(ActionEvent e) {
// String result = JOptionPane.showInputDialog(jFrame, "请输入卡号", "输入对话框", 1);
String result = (String) JOptionPane.showInputDialog(jFrame, "请输入卡号", "输入对话框", 1,new ImageIcon("./img/component/female.png"),selectValus,selectValus[0]);
jTextArea.append(result+"\n");
}
};
private void init() {
jButton.setAction(action);
jFrame.add(jButton, BorderLayout.SOUTH);
jFrame.add(jTextArea);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new InputDialog().init();
}
}
4. OptionDialog 选择对话框
参数:(父窗口, 提示信息, 标题, 系统图标,自定义图标,数组,默认选择),返回Int类型数组下标
如果直接关闭对话框返回:-1
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class OptionDialog {
JFrame jFrame = new JFrame("对话框演示");
JTextArea jTextArea = new JTextArea(8, 20);
JButton jButton = new JButton();
String[] selectValus = {"1", "2", "3"};
Action action = new AbstractAction("对话框") {
@Override
public void actionPerformed(ActionEvent e) {
int result = JOptionPane.showOptionDialog(jFrame, "请选择", "选择对话框", 1, 1, new ImageIcon("./img/component/female.png"), selectValus, selectValus[0]);
if (result != -1)
jTextArea.append(selectValus[result] + "\n");
}
};
private void init() {
jButton.setAction(action);
jFrame.add(jButton, BorderLayout.SOUTH);
jFrame.add(jTextArea);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new OptionDialog().init();
}
}
2. 特殊布局
2.1 JSplitPane 分隔容器
JSplitPane使用步骤:
- 创建JSplitPane对象
通过如下构造方法可以创建JSplitPane对象
JSplitPane(int newOrientation, Component newLeftComponent,Component newRightComponent)
newOrientation:指定JSplitPane容器的分割方向:
如果值为JSplitPane.VERTICAL_SPLIT,为纵向分割;
如果值为JSplitPane.HORIZONTAL_SPLIT,为横向分割;
newLeftComponent:左侧或者上侧的组件;
newRightComponent:右侧或者下侧的组件;
- 设置是否开启连续布局的支持(可选)
setContinuousLayout(boolean newContinuousLayout):
默认是关闭的,如果设置为true,则打开连续布局的支持,但由于连续布局支持需要不断的重绘组件,所以效率会低一些
- 设置是否支持"一触即展"的支持(可选)
setOneTouchExpandable(boolean newValue):
默认是关闭的,如果设置为true,则打开"一触即展"的支持
- 其他设置
setDividerLocation(double proportionalLocation):设置分隔条的位置为JSplitPane的某个百分比
setDividerLocation(int location):通过像素值设置分隔条的位置
setDividerSize(int newSize):通过像素值设置分隔条的大小
setLeftComponent(Component comp)/setTopComponent(Component comp)/setRightComponent(Component comp)/setBottomComponent(Component comp):设置指定位置的组件
案例:
JSplitPane参数:(方向,第一个组件/容器,第二个组件/容器)
JSplitPane.VERTICAL_SPLIT:垂直
JSplitPane.HORIZONTAL_SPLIT:水平JList中如果是对象时,通过调用对象类中的toString()方法直接在组件中显示选项
JList选项选中时,调用JList.getSelectedValue(),返回值就是选中的对文本域增加滚动条:JScrollPane scrollPanenew = new JScrollPane(TextArea);
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
public class SplitPane {
JFrame jFrame = new JFrame("特殊容器SplitPane");
Book[] books = {
new Book("java自学宝典", new ImageIcon("./img/container/java.png"), "java自学宝典"),
new Book("java自学宝典1", new ImageIcon("./img/container/android.png"), "java自学宝典"),
new Book("java自学宝典2", new ImageIcon("./img/container/jQuery.png"), "java自学宝典")
};
//直接在参数种装入books,在显示时会调用对象的toString()方法
JList<Book> bookList = new JList<Book>(books);
JLabel labelCover = new JLabel();
JTextArea bookDesc = new JTextArea();
private void init(){
//给组件设置大小
bookList.setPreferredSize(new Dimension(150,400));
labelCover.setPreferredSize(new Dimension(220,300));
bookDesc.setPreferredSize(new Dimension(220,100));
//list添加点击事件
bookList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
//获得选择的选项不能使用e,使用getSelectedValue()方法
Book book = bookList.getSelectedValue();
labelCover.setIcon(book.getImage());
bookDesc.setText(book.getDesc());
}
});
//文本域增加滚动条
JSplitPane left = new JSplitPane(JSplitPane.VERTICAL_SPLIT,labelCover,new JScrollPane(bookDesc));
//开启连续布局
left.setContinuousLayout(true);
//开启一触即展
left.setOneTouchExpandable(true);
JSplitPane all = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,left,bookList);
jFrame.add(all);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new SplitPane().init();
}
}
2.2 JTabbedPane 标签页容器
如果需要使用JTabbedPane在窗口上创建标签页 ,则可以按如下步骤进行:
- 创建JTabbedPane对象
JTabbedPane(int tabPlacement, int tabLayoutPolicy):
tabPlacement:
指定标签标题的放置位置,可以选择 SwingConstants中的四个常量:TOP、LEFT、BOTTOM、RIGHT
tabLaoutPolicy:
指定当窗口不能容纳标签页标题时的布局策略,可以选择JTabbedPane.WRAP_TAB_LAYOUT和JTabbedPane.SCROLL_TAB_LAYOUT
- 通过JTabbedPane对象堆标签进行增删改查
addTab(String title, Icon icon, Component component, String tip):添加标签
title:标签的名称
icon:标签的图标
component:标签对应的组件
tip:光标放到标签上的提示
insertTab(String title, Icon icon, Component component, String tip, int index):插入标签页
title:标签的名称
icon:标签的图标
component:标签对应的组件
tip:光标放到标签上的提示
index:在哪个索引处插入标签页
setComponentAt(int index, Component component):修改标签页对应的组件
index:修改哪个索引处的标签
component:标签对应的组件
removeTabAt(int index):
index:删除哪个索引处的标签
- 设置当前显示的标签页
setSelectedIndex(int index):设置哪个索引处的标签被选中
- 设置JTabbedPane的其他属性
setDisabledIconAt(int index, Icon disabledIcon): 将指定位置的禁用图标设置为 icon,该图标也可以是null表示不使用禁用图标。
setEnabledAt(int index, boolean enabled): 设置指定位置的标签页是否启用。
setTitleAt(int index, String title): 设置指定位置标签页的标题为 title,该title可以是null,这表明设置该标签页的标题为空。
setToolTipTextAt(int index, String toolTipText): 设置指定位置标签页的提示文本 。
- 为JTabbedPane设置监听器
addChangeListener(ChangeListener l)
案例:
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TabbedPanel {
JFrame frame = new JFrame("JTabbedPane 标签页容器");
//参数:(标签页位置,标签页滚动)
JTabbedPane jTabbedPane = new JTabbedPane(JTabbedPane.LEFT,JTabbedPane.SCROLL_TAB_LAYOUT);
private void init(){
//jTabbedPane容器添加标签
//参数:(标签显示的文字,图标,该标签对应的组件,提示信息)
jTabbedPane.addTab("用户管理",null,null,"您没有权限");
jTabbedPane.addTab("商品管理",new ImageIcon("./img/container/open.gif"),new JList<String>(new String[]{"用户一","用户二","用户三"}),"商品管理");
jTabbedPane.addTab("商品管理",null,new JList<String>(new String[]{"订单一","订单二","订单三"}),"订单管理");
//默认选中指定索引的标签
jTabbedPane.setSelectedIndex(1);
//设置指定索引的标签禁用
jTabbedPane.setEnabledAt(0,false);
//如果标签禁用,则添加指定的图标
jTabbedPane.setDisabledIconAt(0,new ImageIcon(".\\img\\component\\exit.png"));
//设置指定索引的标签的标题(初始化标签时可以设置)
jTabbedPane.setTitleAt(1,"商品管理标题");
//设置指定索引的标签的提示信息(初始化时可以设置)
jTabbedPane.setToolTipTextAt(2,"订单管理的提示文本");
//标签选择改变时
jTabbedPane.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int selectedIndex = jTabbedPane.getSelectedIndex();
JOptionPane.showMessageDialog(jTabbedPane,"点击了第 "+(selectedIndex + 1)+ "标签");
}
});
frame.setBounds(200,200,400,400);
frame.add(jTabbedPane);
frame.setVisible(true);
}
public static void main(String[] args) {
new TabbedPanel().init();
}
}
3. 进度条
3.1 JProcessBar
使用JProgressBar创建进度条的步骤:
- 创建JProgressBar对象
public JProgressBar(int orient, int min, int max):
orint:方向
min:最小值
max:最大值
- 设置属性
setBorderPainted(boolean b):设置进度条是否有边框
setIndeterminate(boolean newValue):设置当前进度条是不是进度不确定的进度条,如果是,则将看到一个滑块在进度条中左右移动
setStringPainted(boolean b):设置进度条是否显示当前完成的百分比
- 获取和设置当前进度条的进度状态
setValue(int n):设置当前进度值
double getPercentComplete():获取进度条的完成百分比
String getStrin():返回进度字符串的当前值
3.1.1 Model模型
Swing 组件大都将外观显示和 内部数据分离 , JProgressBar 也不例外, JProgressBar 组件有一个内置的用于保存其状态数据的Model对象 , 这个对象由BoundedRangeModel对象表示,程序调用JProgressBar对象的方法完成进度百分比的设置,监听进度条的数据变化,其实都是通过它内置的BoundedRangeModel对象完成的。下面的代码是对之前代码的改进,通过BoundedRangeModel完成数据的设置,获取与监听。
//获取进度条数据模型对象:Model
BoundedRangeModel model = jProgressBar.getModel();
//通过Model对象来操作
model.setValue(progressThread.getCurrent());
model.getMaximum()
案例:
- 创建子线程
- JCheckBox的使用和监听
- Timer定时器
- 子线程中的变量如何被访问
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ProgressBar {
JFrame jFrame = new JFrame();
JCheckBox progressBox = new JCheckBox("不确定进度");
JCheckBox borderBox = new JCheckBox("不绘制边框");
Box verticalBox = Box.createVerticalBox();
//创建进度条,参数:(进度条的方向,最大值,最小值)
JProgressBar jProgressBar = new JProgressBar(JProgressBar.HORIZONTAL, 0, 100);
//获取数据模型对象:Model
BoundedRangeModel model = jProgressBar.getModel();
private void init() {
//选择框组件
progressBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
boolean selected = progressBox.isSelected();
//进度条是不是不确定进度的进度条
jProgressBar.setIndeterminate(selected)
}
});
borderBox.addActionListener(e -> {
boolean selected = borderBox.isSelected();
//进度条时候有边框
jProgressBar.setBorderPainted(!selected);
});
//进度条显示百分比
jProgressBar.setStringPainted(true);
//创建线程对象
progressThread progressThread = new progressThread(jProgressBar.getMaximum());
//创建线程,并运行
new Thread(progressThread).start();
//设置定时器,间隔读取线程中current,设置进度条的当前进度
Timer timer = new Timer(300, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// jProgressBar.setValue(progressThread.getCurrent());
//model对象
model.setValue(progressThread.getCurrent());
System.out.println(progressThread.getCurrent());
}
});
timer.start();
//监听进度条的变化,当前进度>最大进度时,停止计时器
jProgressBar.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
// if (jProgressBar.getMaximum() <= progressThread.getCurrent()) {
//model对象
if (model.getMaximum() <= progressThread.getCurrent()) {
timer.stop();
System.out.println("计时器停止");
}
}
});
verticalBox.add(progressBox);
verticalBox.add(borderBox);
jFrame.setLayout(new FlowLayout());
jFrame.add(verticalBox);
jFrame.add(jProgressBar);
jFrame.pack();
jFrame.setVisible(true)
}
//线程任务
public class progressThread extends Thread {
//进度条最大值
private int amount;
//当前进度值
//volatile关键字,内存可见,能保证该变量可以被别的线程访问
private volatile int current = 0
public progressThread(int amount) {
this.amount = amount;
}
public int getCurrent() {
return current;
}
@Override
public void run() {
while (amount > current) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
current++;
}
}
}
public static void main(String[] args) {
new ProgressBar().init();
}
}
3.2 进度条提示框
不依赖于窗口,可单独显示
点击提示框的取消按钮: ProgressMonitor.isCanceled()
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ProgressMonitorTest {
//参数(父窗口,提示信息,提示信息,最小值,最大值)
ProgressMonitor progressMonitor = new ProgressMonitor(null, "请等待任务完成","现在进度:",0,100);
//模拟下载的子线程
ProgressThread progressThread = new ProgressThread(100);
//定时器
Timer timer = new Timer(200, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//设置当前进度条的进度
progressMonitor.setProgress(progressThread.getCurrent());
//点击对话框的取消按钮
if (progressMonitor.isCanceled()){
timer.stop();
//中断进程
progressThread.interrupt();
}
}
});
public static void main(String[] args) {
ProgressMonitorTest progressMonitorTest = new ProgressMonitorTest();
progressMonitorTest.progressThread.start();
progressMonitorTest.timer.start();
}
}
4. JList、JComboBox实现列表框
4.1 简单列表框
使用JList或JComboBox实现简单列表框的步骤:
- 创建JList或JComboBox对象
JList(final E[] listData):创建JList对象,把listData数组中的每项内容转换成一个列表项展示
JList(final Vector<? extends E> listData):创建JList对象,把listData数组中的每项内容转换成一个列表项展示
JComboBox(E[] items):
JComboBox(Vector<E> items):
- 设置JList或JComboBox的外观行为
---------------------------JList----------------------------------------------
addSelectionInterval(int anchor, int lead):在已经选中列表项的基础上,增加选中从anchor到lead索引范围内的所有列表项
setFixedCellHeight(int height)/setFixedCellWidth(int width):设置列表项的高度和宽度
setLayoutOrientation(int layoutOrientation):设置列表框的布局方向
setSelectedIndex(int index):设置默认选中项
setSelectedIndices(int[] indices):设置默认选中的多个列表项
setSelectedValue(Object anObject,boolean shouldScroll):设置默认选中项,并滚动到该项显示
setSelectionBackground(Color selectionBackground):设置选中项的背景颜色
setSelectionForeground(Color selectionForeground):设置选中项的前景色
setSelectionInterval(int anchor, int lead):设置从anchor到lead范围内的所有列表项被选中
setSelectionMode(int selectionMode):设置选中模式,默认没有限制,也可以设置为单选或者区域选中
setVisibleRowCount(int visibleRowCount):设置列表框的可是高度足以显示多少行列表项
---------------------------JComboBox----------------------------------------------
setEditable(boolean aFlag):设置是否可以直接修改列表文本框的值,默认为不可以
setMaximumRowCount(int count):设置列表框的可是高度足以显示多少行列表项
setSelectedIndex(int anIndex):设置默认选中项
setSelectedItem(Object anObject):根据列表项的值,设置默认选中项
- 设置监听器,监听列表项的变化,JList通过addListSelectionListener完成,JComboBox通过addItemListener完成
案例:
用方法来创建按钮
Box创建的容器,内部组件会填充整个容器。
JPanel创建的容器,内部组件不会填充整个容器。
import javax.swing.*;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import java.awt.*;
public class ListText1 {
JFrame jFrame = new JFrame("列表框测试");
String[] books = {"java自学宝典", "轻量级javaEE企业应用实战", "Android基础教程", "jQuery实战教程", "SpringBoot企业级开发"};
Box vBox = Box.createVerticalBox();
Box hBox = Box.createHorizontalBox();
JPanel jPanelLeft1 = new JPanel();
JPanel jPanelLeft2 = new JPanel();
JPanel jPanelRight = new JPanel();
ButtonGroup buttonGroup1 = new ButtonGroup();
ButtonGroup buttonGroup2 = new ButtonGroup();
JList<String> list = new JList<>(books);
JComboBox comboBox = new JComboBox<>(books);
JTextArea textArea = new JTextArea();
//用方法创建单选按钮和选择事件
private void addBtnPanelLeft1(String name, int orientation) {
JRadioButton jRadioButton = new JRadioButton(name);
buttonGroup1.add(jRadioButton);
jPanelLeft1.add(jRadioButton);
// 当组中只有一个组件时,设置为默认选中
if (buttonGroup1.getButtonCount() == 1) {
jRadioButton.setSelected(true);
}
jRadioButton.addActionListener(e -> {
list.setLayoutOrientation(orientation);
});
}
//用方法创建单选按钮
private void addBtnPanelLeft2(String name, int select) {
JRadioButton jRadioButton = new JRadioButton(name);
buttonGroup2.add(jRadioButton);
jPanelLeft2.add(jRadioButton);
if (buttonGroup2.getButtonCount() == 1) {
jRadioButton.setSelected(true);
}
jRadioButton.addActionListener(e -> {
list.setSelectionMode(select);
});
}
private void init() {
// 列表选择框显示3项
list.setVisibleRowCount(3);
// 列表选择框,默认2-4选中
list.setSelectionInterval(2, 4);
// 选中项的背景色
list.setSelectionBackground(Color.cyan);
// 选中项的字体颜色
list.setSelectionForeground(Color.red);
//设置边框,参数:(创建标题边框匿名对象(作用:线条比较深,标题))
jPanelLeft1.setBorder(new TitledBorder(new EtchedBorder(), "确定选项布局"));
addBtnPanelLeft1("纵向滚动", JList.VERTICAL);
addBtnPanelLeft1("纵向换行", JList.VERTICAL_WRAP);
addBtnPanelLeft1("横向换行", JList.HORIZONTAL_WRAP);
//
jPanelLeft2.setBorder(new TitledBorder(new EtchedBorder(), "确定选择模式"));
addBtnPanelLeft2("单选", ListSelectionModel.SINGLE_SELECTION);
addBtnPanelLeft2("单范围", ListSelectionModel.SINGLE_INTERVAL_SELECTION);
addBtnPanelLeft2("无限制", ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
// JList选择框的事件
list.addListSelectionListener(e -> {
textArea.setText("");
for (String s : list.getSelectedValuesList()) {
textArea.append(s+"\n");
}
});
// 下拉选择框
// 下拉框中显示多少行
comboBox.setMaximumRowCount(3);
// 是否可以直接修改文本框里的值
comboBox.setEditable(true);
// 下拉选择框选择事件
comboBox.addItemListener(e -> {
int selectedIndex = comboBox.getSelectedIndex();
textArea.setText(books[selectedIndex]);
});
//文本框
textArea.setBorder(new TitledBorder(new EtchedBorder(),"最喜欢的图书"));
textArea.setRows(4);
jPanelRight.setBorder(new TitledBorder(new EtchedBorder(),"下拉"));
vBox.add(new JScrollPane(list));
vBox.add(jPanelLeft1);
vBox.add(jPanelLeft2);
jPanelRight.add(comboBox);
hBox.add(vBox);
hBox.add(jPanelRight);
jFrame.add(hBox);
jFrame.add(textArea,BorderLayout.SOUTH);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new ListText1().init();
}
}
4.2 不强制存储列表项的ListModel和ComboBoxModel
与JProgressBar一样,JList和JComboBox也采用了MVC的设计模式,JList和JComboBox只负责外观的显示,而组件底层的状态数据则由对应的Model来维护。JList对应的Model是ListModel接口,JComboBox对应的Model是ComboBox接口,其代码如下:
public interface ListModel<E>{
int getSize();
E getElementAt(int index);
void addListDataListener(ListDataListener l);
void removeListDataListener(ListDataListener l);
}
public interface ComboBoxModel<E> extends ListModel<E> {
void setSelectedItem(Object anItem);
Object getSelectedItem();
}
从上面接口来看,这个 ListMode l 不管 JList 里的所有列表项的存储形式,它甚至不强制存储所有的列表项,只要 ListModel的实现类提供了getSize()和 getElementAt()两个方法 , JList 就可以根据该ListModel 对象来生成列表框 。ComboBoxModel 继承了 ListModel ,它添加了"选择项"的概念,选择项代表 JComboBox 显示区域内可见的列表项 。
在使用JList和JComboBox时,除了可以使用jdk提供的Model实现类,程序员自己也可以根据需求,自己定义Model的实现类,实现对应的方法使用。
4.3 强制存储列表项的DefaultListModel和DefaultComboBoxModel
前面只是介绍了如何创建 JList 、 JComboBox 对象, 当 调用 JList 和 JComboBox构造方法时时传入数组或 Vector 作为参数,这些数组元素或集合元素将会作为列表项。当使用JList 或 JComboBox 时 常常还需要动态地增加、删除列表项,例如JCombox提供了下列方法完成增删操作:
addItem(E item):添加一个列表项
insertItemAt(E item, int index):向指定索引处插入一个列表项
removeAllItems():删除所有列表项
removeItem(Object anObject):删除指定列表项
removeItemAt(int anIndex):删除指定索引处的列表项
JList 并没有提供这些类似的方法。如果需要创建一个可以增加、删除列表项的 JList 对象,则应该在创建 JLi st 时显式使用 DefaultListModel作为构造参数 。因为 DefaultListModel 作为 JList 的 Model,它负责维护 JList 组件的所有列表数据,所以可以通过向 DefaultListModel 中添加、删除元素来实现向 JList 对象中增加 、删除列表项 。DefaultListModel 提供了如下几个方法来添加、删除元素:
add(int index, E element): 在该 ListModel 的指定位置处插入指定元素 。
addElement(E obj): 将指定元素添加到该 ListModel 的末尾 。
insertElementAt(E obj, int index): 在该 ListModel 的指定位置处插入指定元素 。
Object remove(int index): 删除该 ListModel 中指定位置处的元素
removeAllElements(): 删 除该 ListModel 中的所有元素,并将其的大小设置为零 。
removeElement(E obj): 删除该 ListModel 中第一个与参数匹配的元素。
removeElementAt(int index): 删除该 ListModel 中指定索引处的元素 。
removeRange(int 企omIndex , int toIndex): 删除该 ListModel 中指定范围内的所有元素。
set(int index, E element) : 将该 ListModel 指定索引处的元素替换成指定元素。
setElementAt(E obj, int index): 将该 ListModel 指定索引处的元素替换成指定元素。
案例:
通过DefaultListModel操作JList中的元素
import javax.swing.*;
import java.awt.*;
public class DefaultListModeTest {
JFrame jFrame = new JFrame("强制存储列表项");
JList<String> jList;
JPanel jPanel = new JPanel();
JTextField jTextField = new JTextField(30);
JButton addButton = new JButton("增加图书");
JButton delButton = new JButton("删除选中图书");
//1. 创建DefaultListModel的对象
DefaultListModel<String> bookModel = new DefaultListModel<>();
public DefaultListModeTest() {
// 2. 用Model构造JList
jList = new JList<String>(bookModel);
}
public void init(){
//3. Model添加数据
bookModel.addElement("第一本书");
bookModel.addElement("第二本书");
bookModel.addElement("第三本书");
bookModel.addElement("第四本书");
bookModel.addElement("第五本书");
bookModel.addElement("第六本书");
jList.setVisibleRowCount(4);
addButton.addActionListener(e -> {
//Model添加元素
bookModel.addElement(jTextField.getText());
});
delButton.addActionListener(e -> {
int selectedIndex = jList.getSelectedIndex();
if ( selectedIndex != -1) {
// Model删除元素
bookModel.removeElementAt(selectedIndex);
}
});
jPanel.add(jTextField);
jPanel.add(addButton);
jPanel.add(delButton);
jFrame.add(new JScrollPane(jList));
jFrame.add(jPanel, BorderLayout.SOUTH);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new DefaultListModeTest().init();
}
}
4.4 使用ListCellRenderer绘制列表项的外观
- 创建ListCellRenderer 的实现类ImageCellRenderer。
- 设置JList使用ImageCellRenderer作为列表项绘制器 List.setCellRenderer(new ImageCellRenderer());
- 在类方法public Component getListCellRendererComponent中绘制列表项的内容,然会返回,返回值是容器
JPanel容器内组件默认居中排列
Box容器内组件默认靠左排列
- 类方法:
public interface ListCellRenderer<E>
{
Component getListCellRendererComponent(
JList<? extends E> list,//列表组件
E value,//当前列表项的值
int index,//当前列表项的索引
boolean isSelected,//当前列表项是否被选中
boolean cellHasFocus);//当前列表项是否获取了焦点
}
package listBox;
import javax.swing.*;
import java.awt.*;
public class ListCellRendererTest {
private JFrame jFrame = new JFrame("好友列表");
private String[] friends = {
"李清照",
"苏格拉底",
"李白",
"弄玉",
"虎头"
};
//定义一个JList对象
JList friendsList = new JList(friends);
public void init() {
//设置JList使用ImageCellRenderer作为列表项绘制器
friendsList.setCellRenderer(new ImageCellRenderer());
jFrame.add(new JScrollPane(friendsList));
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new ListCellRendererTest().init();
}
class ImageCellRenderer implements ListCellRenderer {
private ImageIcon icon;
private String name;
//定义绘制单元格的背景色
private Color background;
//定义绘制单元格的前景色
private Color foreground
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
//容器各种套娃,为的就是把图片和文字垂直居中,每次返回的只是一组头像和文字,有多少组就返回多少次
this.icon = new ImageIcon("./img/list/"+value+".gif");
this.name = value.toString();
this.background = isSelected ? list.getSelectionBackground() : list.getBackground();
this.foreground = isSelected ? list.getSelectionForeground() : list.getForeground();
Box vBox = Box.createVerticalBox();
JPanel jPanel1 = new JPanel();
JPanel jPanel2 = new JPanel();
JLabel jLabel1 = new JLabel(this.icon);
JLabel jLabel2 = new JLabel(this.name);
jPanel1.setBackground(this.background);
jPanel2.setBackground(this.background);
jPanel1.add(jLabel1);
jPanel2.add(jLabel2);
vBox.add(jPanel1);
vBox.add(jPanel2);
//返回当前vBox对象,作为列表项绘制器
return vBox;
}
}
}
5. JTree、TreeModel实现树
5.1 创建简单的树
5.1.1 JTree常用构造方法
JTree(TreeModel newModel):使用指定 的数据模型创建 JTree 对象,它默认显示根结点。
JTree(TreeNode root): 使用 root 作为根节 点创建 JTree 对象,它默认显示根结点 。
JTree(TreeNode root, boolean asksAllowsChildren):
使用root作为根结点创建JTree对象,它默认显示根结点。
asksAllowsChildren 参数控制怎样的结点才算叶子结点,如果该参数为 true ,则只有当程序使用 setAllowsChildren(false)显式设置某个结点不允许添加子结点时(以后也不会拥有子结点) ,该结点才会被 JTree当成叶子结点:如果该参数为 false ,则只要某个结点当时没有子结点(不管以后是否拥有子结点) ,该结点都会被 JTree 当成叶子结点。
5.1.2 TreeNode继承体系及使用
- 创建出所有节点:
DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");
- 将子节点依次添加到父节点:
root.add(guangdong);
- 为根节点创建JTree对象:
jTree = new JTree(root);
package tree;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
public class SimpleJTree {
JFrame jFrame = new JFrame("简单树的演示");
JTree jTree ;
private void init(){
//创建所有节点
DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");
DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");
DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");
DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");
DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");
DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");
DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");
//给父节点添加子节点
root.add(guangdong);
root.add(guangxi);
guangdong.add(foshan);
guangdong.add(shantou);
guangxi.add(guilin);
guangxi.add(nanning);
//为根节点创建Tree
jTree = new JTree(root);
// 设置外观
// jTree.putClientProperty( "JTree.lineStyle", "None");
// jTree .putClientProperty("JTree.lineStyle" , "Horizontal");
// jTree .setShowsRootHandles(true);
jTree .setRootVisible(false);
jFrame.add(jTree);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new SimpleJTree().init();
}
}
5.1.3 外观
设置结点之间没有连接线
jTree .putClientProperty( "JTree.lineStyle", "None");
设置结点之间只有水平分割线
jTree .putClientProperty("JTree.lineStyle" , "Horizontal");
设置根结点有"展开、折叠"图标
jTree .setShowsRootHandles(true);
隐藏根结点
jTree .setRootVisible(false);
5.1.4 JTree的基本方法
Enumeration breadthFirstEnumerationO/preorderEnumeration(): 按广度优先的顺序遍历以此结点为根的子树,并返回所有结点组成的枚举对象 。
Enumeration depthFirstEnumerationO/postorderEnumeration(): 按深度优先的顺序遍历以此结点为根的子树,并返回所有结点组成的枚举对象 。
DefaultMutableTreeNode getNextSibling(): 返回此结点的下一个兄弟结点 。
TreeNode getParent(): 返回此结点的父结点 。 如果此结点没有父结点,则返回null 。
TreeNode[] getPath(): 返回从根结点到达此结点的所有结点组成的数组。
DefaultMutableTreeNode getPreviousSibling(): 返回此结点的上一个兄弟结点。
TreeNode getRoot(): 返回包含此结点的树的根结点 。
TreeNode getSharedAncestor(DefaultMutableTreeNode aNode): 返回此结点和aNode最近的共同祖先 。
int getSiblingCount(): 返回此结点的兄弟结点数 。
boolean isLeaf(): 返回该结点是否是叶子结点 。
boolean isNodeAncestor(TreeNode anotherNode): 判断anotherNode是否是当前结点的祖先结点(包括父结点) 。
boolean isNodeChild(TreeNode aNode): 如果aNode是此结点的子结点,则返回true。
boolean isNodeDescendant(DefaultMutableTreeNode anotherNode): 如果 anotherNode 是此结点的后代,包括是此结点本身、此结点的子结点或此结点的子结点的后代,都将返回true 。
boolean isNodeRelated(DefaultMutableTreeNode aNode) : 当aNode和当前结点位于同一棵树中时返回 true 。
boolean isNodeSibling(TreeNode anotherNode): 返回anotherNode是否是当前结点的兄弟结点 。
boolean isRoot(): 返回当前结点是否是根结点 。
Enumeration pathFromAncestorEnumeration(TreeNode ancestor): 返回从指定祖先结点到当前结点的所有结点组成的枚举对象 。
5.2 编辑树的结点
5.2.1 编辑树的结点
- 树的结点默认是不可编辑的,设置编辑:
JTree.setEditable(boolean b)
编辑树结点的步骤:
- 获取当前被选中的结点
获取当前被选中的结点,会有两种方式:
- 首先通过JTree对象的某些方法,例如
TreePath selectionPath = JTree.getSelectionPath();
等,得到一个TreePath对象selectionPath
,包含了从根结点到当前结点的路径,然后调用TreePath对象selectionPath.getLastPathComponent()
方法,得到当前选中结点。- 调用JTree对象的 Object
getLastSelectedPathComponent()
方法获取当前被选中的结点
- 调用
DefaultTreeModel
数据模型有关增删改的一系列方法完成编辑,方法执行完后,会自动重绘JTree。
- 下面程序中使用到的方法:
获得JTree的数据模型Model
DefaultTreeModel model = (DefaultTreeModel) JTree.getModel();
- 寻找当前结点的父结点:
TreeNode parent = 当前结点.getParent();
- 获得当前结点在父结点中的索引:
int index = 父结点.getIndex(当前结点);
- 在索引前插入结点:
model .insertNodeInto(在索引前要插入的结点, 父结点, 父结点的索引);
- 当前结点到根结点的结点集合:
TreeNode[] pathToRoot = model.getPathToRoot(当前结点);
- 根据结点集合找到路径:
TreePath treePath = new TreePath(pathToRoot);
- 获得当前结点的子节点数:
int index = 当前结点.getChildCount();
- 删除当前结点:
model .removeNodeFromParent(当前结点);
- 当前结点可编辑:
树.startEditingAtPath(要编辑结点的路径);
package tree;
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
public class EditSimpleJTree {
JFrame jFrame = new JFrame("可编辑树");
Box vBox = Box.createHorizontalBox();
JTree jTree;
DefaultTreeModel model;
JButton addBrotherButton = new JButton("添加兄弟结点");
JButton addChildButton = new JButton("添加子结点");
JButton delButton = new JButton("删除结点");
JButton editButton = new JButton("编辑结点");
private void init() {
//创建所有节点
DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");
DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");
DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");
DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");
DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");
DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");
DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");
//给父节点添加子节点
root.add(guangdong);
root.add(guangxi);
guangdong.add(foshan);
guangdong.add(shantou);
guangxi.add(guilin);
guangxi.add(nanning);
//为根节点创建Tree
jTree = new JTree(root);
//树可编辑
jTree.setEditable(true);
//获取jTree对象的数据模型对象
model = (DefaultTreeModel) jTree.getModel();
//添加兄弟结点,必须要找到父结点
addBrotherButton.addActionListener(e -> {
//1. 获取当前选中结点
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) jTree.getLastSelectedPathComponent();
if (selectNode == null) return;
//2. 找到选中结点的父结点
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selectNode.getParent();
if (parent == null) return;
//3. 创建一个新结点
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");
//4. 在当前选中结点之前添加新结点
int index = parent.getIndex(selectNode);//获取当前结点的在父节点的索引
model.insertNodeInto(newNode, parent, index);//在索引前插入新结点,参数:(新节点,父结点,索引)
//5. 在窗口中展示新添加的结点
TreeNode[] pathToRoot = model.getPathToRoot(newNode);//新结点到根结点的路径,返回路径上所有结点的组成的数组
TreePath treePath = new TreePath(pathToRoot);//根据结点数组找到路径
jTree.scrollPathToVisible(treePath);//滚动到这个路径,在窗口展示
//6. 重绘jTree
// jTree.updateUI();//使用model方法,不需要手动刷新UI
});
//添加子结点
addChildButton.addActionListener(e -> {
//1. 获取当前选中结点
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) jTree.getLastSelectedPathComponent();
if (selectNode == null) return;
//2. 创建一个新结点
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("子结点");
//3. 在当前选中结点的子节点的最后添加结点
int index = selectNode.getChildCount();//获取当前结点子结点的数量
model.insertNodeInto(newNode, selectNode, index);//在索引前插入新结点,参数:(新节点,父结点,索引)
//5. 在窗口中展示新添加的结点
TreeNode[] pathToRoot = model.getPathToRoot(newNode);//新结点到根结点的路径,返回路径上所有结点的组成的数组
TreePath treePath = new TreePath(pathToRoot);//根据结点数组找到路径
System.out.println("结点的路径:"+treePath);
jTree.scrollPathToVisible(treePath);//滚动到这个路径,在窗口展示
//6. 重绘jTree
// jTree.updateUI();//使用model方法,不需要手动刷新UI
});
//删除选中结点
delButton.addActionListener(e -> {
//1. 获取当前选中结点
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) jTree.getLastSelectedPathComponent();
//选中的结点是根结点、有子结点则不能删除
if (selectNode == null || selectNode.isRoot() || selectNode.getChildCount() > 0) return;
// 2. 删除结点(要从父结点删除)
model.removeNodeFromParent(selectNode);
});
//编辑结点
editButton.addActionListener(e -> {
//1. 获取当前选中结点的路径
TreePath selectionPath = jTree.getSelectionPath();
if (selectionPath != null){
jTree.startEditingAtPath(selectionPath);
}
});
vBox.add(addBrotherButton);
vBox.add(addChildButton);
vBox.add(delButton);
vBox.add(editButton);
jFrame.add(new JScrollPane(jTree));
jFrame.add(vBox,BorderLayout.SOUTH);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new EditSimpleJTree().init();
}
}
5.2.1拖动树的结点
- 知识点:
boolean isOrNo= APath.isDescendant(BPath);
BPath路径的结点是不是APath路径结点的后代;- 移动时,先删除原路径的结点,再向新位置添加结点。
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class MoveJTree {
JFrame jFrame = new JFrame("简单树的演示");
JTree jTree;
DefaultTreeModel model;
private void init() {
//创建所有节点
DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");
DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");
DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");
DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");
DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");
DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");
DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");
//给父节点添加子节点
root.add(guangdong);
root.add(guangxi);
guangdong.add(foshan);
guangdong.add(shantou);
guangxi.add(guilin);
guangxi.add(nanning);
//为根节点创建Tree
jTree = new JTree(root);
//可编辑
jTree.setEditable(true);
//获取model模型
model = (DefaultTreeModel) jTree.getModel();
jTree.addMouseListener(new moveNodeListener(jTree, model));
jFrame.add(new JScrollPane(jTree));
jFrame.pack();
jFrame.setVisible(true);
}
//拖动结点到另一结点中,此类可复用
public static class moveNodeListener extends MouseAdapter {
DefaultTreeModel model;
TreePath movePath;
JTree jTree;
public moveNodeListener(JTree jTree, DefaultTreeModel model){
this.jTree = jTree;
this.model = model;
}
//当鼠标按下时,由坐标取得结点的路径
@Override
public void mousePressed(MouseEvent e) {
//获得鼠标按下时的结点路径
TreePath pathForLocation = jTree.getPathForLocation(e.getX(), e.getY());
if (pathForLocation != null) movePath = pathForLocation;
}
//当鼠标抬起时,将结点放入
@Override
public void mouseReleased(MouseEvent e) {
//获得鼠标抬起时的结点路径
TreePath pathForLocation = jTree.getPathForLocation(e.getX(), e.getY());
//不能移动到自己的后代中(pathForLocation是movePath的后代)
if (pathForLocation == null || movePath == null || movePath.isDescendant(pathForLocation)) return;
//鼠标按下时的结点
DefaultMutableTreeNode pressedComponent = (DefaultMutableTreeNode) movePath.getLastPathComponent();
//根据路径获得鼠标抬起时结点
DefaultMutableTreeNode releasedComponent = (DefaultMutableTreeNode) pathForLocation.getLastPathComponent();
//根据路径删除原来的结点
model.removeNodeFromParent(pressedComponent);
int index = releasedComponent.getChildCount();
//插入到抬起时结点的子节点中
model.insertNodeInto(pressedComponent, releasedComponent, index);
//展示
TreeNode[] pathToRoot = model.getPathToRoot(pressedComponent);
TreePath treePath = new TreePath(pathToRoot);//根据结点数组找到路径
jTree.scrollPathToVisible(treePath);//滚动到这个路径,在窗口展示
// jTree.updateUI();
}
}
public static void main(String[] args) {
new MoveJTree().init();
}
}
5.2.2 监听结点事件
修改JTree的选择模式:
- 获得用于保存JTree选中状态的Model对象:
jTree.getSelectionModel();
- 通过Model对象的
setSelectionMode(int mode);
方法修改JTree的选择模式。
Model的模式有以下3种:TreeSelectionModel.CONTIGUOUS_TREE_SELECTION: 可 以连续选中多个 TreePath 。
TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION : 该选项对于选择没有任何限制 。
TreeSelectionModel.SINGLE_TREE_SELECTION: 每次只能选择一个 TreePath 。
- 默认是无限制模式
为JTree添加监听器:
-
addTreeExpansionListener(TreeExpansionListener tel)
: 添加树节点展开/折叠事件的监听器。 addTreeSelectionListener(TreeSelectionListener tsl)
: 添加树节点选择事件的监听器。
package tree;
import javax.swing.*;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeSelectionModel;
public class ListenerModel {
JFrame jFrame = new JFrame("监听结点事件");
JTree jTree ;
Box hBox = Box.createHorizontalBox();
JTextArea jTextArea = new JTextArea(10,20);
private void init(){
//创建所有节点
DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");
DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");
DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");
DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");
DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");
DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");
DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");
//给父节点添加子节点
root.add(guangdong);
root.add(guangxi);
guangdong.add(foshan);
guangdong.add(shantou);
guangxi.add(guilin);
guangxi.add(nanning);
//为根节点创建Tree
jTree = new JTree(root);
//创建
TreeSelectionModel selectionModel = jTree.getSelectionModel();
//设置单选模式
selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
//监听点击的结点发生改变
jTree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
if (e.getOldLeadSelectionPath()!=null)
jTextArea.append("上一次的选择:"+e.getOldLeadSelectionPath().toString()+"\n");
jTextArea.append("当前的选择:"+e.getNewLeadSelectionPath().toString()+"\n");
}
});
//监听结点展开/折叠事件
jTree.addTreeExpansionListener(new TreeExpansionListener() {
@Override
//结点展开时调用
public void treeExpanded(TreeExpansionEvent event) {
jTextArea.append("结点被展开:"+event.getPath().toString()+"\n");
}
//结点折叠时调用
@Override
public void treeCollapsed(TreeExpansionEvent event) {
jTextArea.append("结点被折叠:"+event.getPath().toString()+"\n");
}
});
hBox.add(new JScrollPane(jTree));
hBox.add(new JScrollPane(jTextArea));
jFrame.add(hBox);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new ListenerModel().init();
}
}
5.3 扩展DefaultTreeCellRenderer改变结点外观
- 创建结点对象
new DefaultMutableTreeNode(obj);
时,DefaultMutableTreeNode
类的构造函数会将参数obj
赋值给对象的userObject
属性。 - 结点在窗体显示时,会调用
DefaultTreeCellRenderer
类对象的getTreeCellRendererComponent()
方法绘制 -
getTreeCellRendererComponent()
方法中的参数value就是结点对象 - 把
Object
类型的value
,通过类型的强制转换,转换为DefaultMutableTreeNode
类型:DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
- 用
node.getUserObject();
方法,把结点对象中第一步传入的参数取出,并强制转换为自己定义的数据类型 - 至此就可以通过创建结点对象时传入的参数来重绘结点的组件
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;
public class ExtendsDefaultCellTreeRenderer {
JFrame jf = new JFrame("根据结点类型定义图标");
JTree jTree;
ImageIcon rootIcon = new ImageIcon("./img/tree/root.gif");
ImageIcon databaseIcon = new ImageIcon("img\\tree\\database.gif");
ImageIcon tableIcon = new ImageIcon("img\\tree\\table.gif");
ImageIcon columnIcon = new ImageIcon("img\\tree\\column.gif");
ImageIcon indexIcon = new ImageIcon("img\\tree\\index.gif");
//定义几个初始结点
DefaultMutableTreeNode root = new DefaultMutableTreeNode(new NodeData(rootIcon, "数据库导航"));
DefaultMutableTreeNode salaryDb = new DefaultMutableTreeNode(new NodeData(databaseIcon, "公司工资数据库"));
DefaultMutableTreeNode customerDb = new DefaultMutableTreeNode(new NodeData(databaseIcon, "公司客户数据库"));
DefaultMutableTreeNode employee = new DefaultMutableTreeNode(new NodeData(tableIcon, "员工表"));
DefaultMutableTreeNode attend = new DefaultMutableTreeNode(new NodeData(tableIcon, "考勤表"));
DefaultMutableTreeNode concat = new DefaultMutableTreeNode(new NodeData(tableIcon, "联系方式表"));
DefaultMutableTreeNode id = new DefaultMutableTreeNode(new NodeData(indexIcon, "员工ID"));
DefaultMutableTreeNode name = new DefaultMutableTreeNode(new NodeData(columnIcon, "姓名"));
DefaultMutableTreeNode gender = new DefaultMutableTreeNode(new NodeData(columnIcon, "性别"));
public void init() {
//通过结点的add方法,建立结点的父子关系
root.add(salaryDb);
root.add(customerDb);
salaryDb.add(employee);
salaryDb.add(attend);
customerDb.add(concat);
concat.add(id);
concat.add(name);
concat.add(gender);
jTree = new JTree(root);
//重绘结点
jTree.setCellRenderer(new MyRenderer());
/* //设置使用windows外观风格
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
//更新JTree的UI外观
SwingUtilities.updateComponentTreeUI(jTree);*/
jf.add(new JScrollPane(jTree));
jf.pack();
jf.setVisible(true);
}
public static void main(String[] args) {
new ExtendsDefaultCellTreeRenderer().init();
}
//结点的外观
class NodeData {
ImageIcon image;
String name;
public NodeData(ImageIcon image,String name){
this.image = image;
this.name = name;
}
@Override
public String toString() {
return "NodeData{" +
"image=" + image +
", name='" + name + '\'' +
'}';
}
}
//重绘结点组件
class MyRenderer extends DefaultTreeCellRenderer{
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel,
boolean expanded,
boolean leaf, int row,
boolean hasFocus){
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
NodeData nodeData = (NodeData)node.getUserObject();
System.out.println(nodeData);
this.setIcon(nodeData.image);
this.setText(nodeData.name);
return this;
}
}
}
6. JTable、JTableModel实现表格
6.1 JTable实现简单表格
- 创建一个一维数组存放标题行。
- 创建一个二维数组存放表格数据。
- 创建JTable的对象,并将上述的两个数组作为参数传入
package table;
import javax.swing.*;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class SimpleTable {
JFrame jFrame = new JFrame("简单表格");
JTable jTable;
//定义二维数组作为表格数据
Object[][] tableData = {
new Object[]{"李清照",29,"女"},
new Object[]{"苏格拉底",56,"男"},
new Object[]{"李白",35,"男"},
new Object[]{"弄玉",18,"女"},
new Object[]{"虎头",2,"男"},
};
//定义一个一维数组,作为列标题
Object[] columnTitle = {"姓名","年龄","性别"};
private void init(){
jTable = new JTable(tableData,columnTitle);
//获取jTable的Model模型,修改选择模式
ListSelectionModel selectionModel = jTable.getSelectionModel();
selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);//单选,只能选择一行
selectionModel.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);//多选,必须是连续的行
selectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);//无限制
//获得列,并设置宽度
TableColumn tableColumn0 = jTable.getColumn(columnTitle[0]);
tableColumn0.setMaxWidth(60);
TableColumn tableColumn2 = jTable.getColumn(columnTitle[2]);
tableColumn2.setMinWidth(40);
jFrame.add(new JScrollPane(jTable));
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new SimpleTable().init();
}
}
6.2 TableModel和监视器
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
public class JTableModel {
JFrame jFrame = new JFrame("JTableModel表格");
JPanel jPanel = new JPanel();
//定义二维数组作为表格数据
Object[][] tableData = {
new Object[]{"李清照", 29, "女"},
new Object[]{"苏格拉底", 56, "男"},
new Object[]{"李白", 35, "男"},
new Object[]{"弄玉", 18, "女"},
new Object[]{"虎头", 2, "男"},
};
//定义一个一维数组,作为列标题
Object[] columnTitle = {"姓名", "年龄", "性别"};
JTable jTable = new JTable();
//数据必须通过Model来传递
DefaultTableModel defaultTableModel = new DefaultTableModel(tableData, columnTitle);
JButton addRow = new JButton("增加一行");
JButton delRow = new JButton("删除一行");
JButton addColum = new JButton("增加一列");
private void init() {
//设置Model为jTable数据管理
jTable.setModel(defaultTableModel);
addRow.addActionListener(e -> {
// 根据上面定义的数据类型,传入参数
defaultTableModel.addRow(new Object[]{"柳岩", "18", "女"});
});
delRow.addActionListener(e -> {
// 获得选中行的行号
int selectedRow = jTable.getSelectedRow();
if (selectedRow > 0)
defaultTableModel.removeRow(selectedRow);
});
addColum.addActionListener(e -> {
defaultTableModel.addColumn("职业");
});
jPanel.add(addColum);
jPanel.add(addRow);
jPanel.add(delRow);
jFrame.add(new JScrollPane(jTable));
jFrame.add(jPanel, BorderLayout.SOUTH);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
new JTableModel().init();
}
}