JAVA Swing 图形化界面编程

JAVA Swing 图形化界面编程


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相比改动:
  1. 下拉选择框
	String [] choice = {"红色","绿色","蓝色"}
	JComboBox<String> jComboBox = new JComboBox<String>(choice);
  1. 单选组件
 	ButtonGroup buttonGroup = new ButtonGroup();
    JRadioButtonMenuItem manButtonMenuItem  = new JRadioButtonMenuItem("男");
    JRadioButtonMenuItem womanButtonMenuItem  = new JRadioButtonMenuItem("女");
  1. 右键菜单(单选)
    ButtonGroup popupButtonGroup = new ButtonGroup()
    JRadioButtonMenuItem metalItem = new JRadioButtonMenuItem("Metal 风格",false);
    JRadioButtonMenuItem nimbusItem = new JRadioButtonMenuItem("Nimbus 风格",false);
  1. 右键菜单显示,不用监听
	jTextArea.setComponentPopupMenu(popupMenu);
  1. 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 工具条

创建工具条:

  1. 创建JToolBar的对象
  2. 创建Action,参数:(可显示的文本,图标地址)
  3. JToolBar.add(Action对象)
  4. 如果想要显示文本,则需要将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使用步骤:

  1. 创建JFileChooser对象:
JFileChooser chooser = new JFileChooser("D:\\a");//指定默认打开的本地磁盘路径
  1. 调用JFileChooser的一系列可选方法,进行初始化
setSelectedFile(File file)/setSelectedFiles(File[] selectedFiles):设定默认选中的文件
setMultiSelectionEnabled(boolean b):设置是否允许多选,默认是单选
setFileSelectionMode(int mode):设置可以选择内容,例如文件、文件夹等,默认只能选择文件
  1. 打开文件对话框
showOpenDialog(Component parent):打开文件加载对话框,并指定父组件
showSaveDialog(Component parent):打开文件保存对话框,并指定父组件
  1. 获取用户选择的结果
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使用步骤:

  1. 创建JSplitPane对象
通过如下构造方法可以创建JSplitPane对象
JSplitPane(int newOrientation, Component newLeftComponent,Component newRightComponent)
    newOrientation:指定JSplitPane容器的分割方向:
    	如果值为JSplitPane.VERTICAL_SPLIT,为纵向分割;
    	如果值为JSplitPane.HORIZONTAL_SPLIT,为横向分割;
    	
    newLeftComponent:左侧或者上侧的组件;
    newRightComponent:右侧或者下侧的组件;
  1. 设置是否开启连续布局的支持(可选)
setContinuousLayout(boolean newContinuousLayout):
	默认是关闭的,如果设置为true,则打开连续布局的支持,但由于连续布局支持需要不断的重绘组件,所以效率会低一些
  1. 设置是否支持"一触即展"的支持(可选)
setOneTouchExpandable(boolean newValue):
	默认是关闭的,如果设置为true,则打开"一触即展"的支持
  1. 其他设置
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在窗口上创建标签页 ,则可以按如下步骤进行:

  1. 创建JTabbedPane对象
 JTabbedPane(int tabPlacement, int tabLayoutPolicy):
	tabPlacement:
		指定标签标题的放置位置,可以选择 SwingConstants中的四个常量:TOP、LEFT、BOTTOM、RIGHT
	tabLaoutPolicy:
		指定当窗口不能容纳标签页标题时的布局策略,可以选择JTabbedPane.WRAP_TAB_LAYOUT和JTabbedPane.SCROLL_TAB_LAYOUT
  1. 通过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:删除哪个索引处的标签
  1. 设置当前显示的标签页
setSelectedIndex(int index):设置哪个索引处的标签被选中
  1. 设置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): 设置指定位置标签页的提示文本 。
  1. 为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创建进度条的步骤:

  1. 创建JProgressBar对象
public JProgressBar(int orient, int min, int max):
	orint:方向
	min:最小值
	max:最大值
  1. 设置属性
setBorderPainted(boolean b):设置进度条是否有边框
setIndeterminate(boolean newValue):设置当前进度条是不是进度不确定的进度条,如果是,则将看到一个滑块在进度条中左右移动
setStringPainted(boolean b):设置进度条是否显示当前完成的百分比
  1. 获取和设置当前进度条的进度状态
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()

案例:

  1. 创建子线程
  2. JCheckBox的使用和监听
  3. Timer定时器
  4. 子线程中的变量如何被访问

在这里插入图片描述

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实现简单列表框的步骤:

  1. 创建JList或JComboBox对象
JList(final E[] listData):创建JList对象,把listData数组中的每项内容转换成一个列表项展示
JList(final Vector<? extends E> listData):创建JList对象,把listData数组中的每项内容转换成一个列表项展示
JComboBox(E[] items):
JComboBox(Vector<E> items):
  1. 设置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):根据列表项的值,设置默认选中项
  1. 设置监听器,监听列表项的变化,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绘制列表项的外观

  1. 创建ListCellRenderer 的实现类ImageCellRenderer。
  2. 设置JList使用ImageCellRenderer作为列表项绘制器 List.setCellRenderer(new ImageCellRenderer());
  3. 在类方法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继承体系及使用
  1. 创建出所有节点:DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");
  2. 将子节点依次添加到父节点:root.add(guangdong);
  3. 为根节点创建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

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(): 返回此结点的父结点 。 如果此结点没有父结点,则返回nullTreeNode[] getPath(): 返回从根结点到达此结点的所有结点组成的数组。
DefaultMutableTreeNode getPreviousSibling(): 返回此结点的上一个兄弟结点。
TreeNode getRoot(): 返回包含此结点的树的根结点 。
TreeNode getSharedAncestor(DefaultMutableTreeNode aNode): 返回此结点和aNode最近的共同祖先 。
int getSiblingCount(): 返回此结点的兄弟结点数 。
boolean isLeaf(): 返回该结点是否是叶子结点 。
boolean isNodeAncestor(TreeNode anotherNode): 判断anotherNode是否是当前结点的祖先结点(包括父结点)boolean isNodeChild(TreeNode aNode): 如果aNode是此结点的子结点,则返回trueboolean isNodeDescendant(DefaultMutableTreeNode anotherNode): 如果 anotherNode 是此结点的后代,包括是此结点本身、此结点的子结点或此结点的子结点的后代,都将返回trueboolean isNodeRelated(DefaultMutableTreeNode aNode) : 当aNode和当前结点位于同一棵树中时返回 trueboolean isNodeSibling(TreeNode anotherNode): 返回anotherNode是否是当前结点的兄弟结点 。
boolean isRoot(): 返回当前结点是否是根结点 。
Enumeration pathFromAncestorEnumeration(TreeNode ancestor): 返回从指定祖先结点到当前结点的所有结点组成的枚举对象 。

5.2 编辑树的结点

5.2.1 编辑树的结点
  • 树的结点默认是不可编辑的,设置编辑:JTree.setEditable(boolean b)

编辑树结点的步骤:

  1. 获取当前被选中的结点

获取当前被选中的结点,会有两种方式:

  1. 首先通过JTree对象的某些方法,例如 TreePath selectionPath = JTree.getSelectionPath();等,得到一个TreePath对象selectionPath,包含了从根结点到当前结点的路径,然后调用TreePath对象selectionPath.getLastPathComponent()方法,得到当前选中结点。
  2. 调用JTree对象的 Object getLastSelectedPathComponent() 方法获取当前被选中的结点
  1. 调用DefaultTreeModel数据模型有关增删改的一系列方法完成编辑,方法执行完后,会自动重绘JTree。
  • 下面程序中使用到的方法:

获得JTree的数据模型ModelDefaultTreeModel model = (DefaultTreeModel) JTree.getModel();

  1. 寻找当前结点的父结点: TreeNode parent = 当前结点.getParent();
  2. 获得当前结点在父结点中的索引:int index = 父结点.getIndex(当前结点);
  3. 在索引前插入结点:model .insertNodeInto(在索引前要插入的结点, 父结点, 父结点的索引);
  4. 当前结点到根结点的结点集合:TreeNode[] pathToRoot = model.getPathToRoot(当前结点);
  5. 根据结点集合找到路径:TreePath treePath = new TreePath(pathToRoot);
  6. 获得当前结点的子节点数:int index = 当前结点.getChildCount();
  7. 删除当前结点:model .removeNodeFromParent(当前结点);
  8. 当前结点可编辑:树.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拖动树的结点

在这里插入图片描述

  • 知识点:
  1. boolean isOrNo= APath.isDescendant(BPath);BPath路径的结点是不是APath路径结点的后代;
  2. 移动时,先删除原路径的结点,再向新位置添加结点。
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的选择模式:

  1. 获得用于保存JTree选中状态的Model对象:jTree.getSelectionModel();
  2. 通过Model对象的setSelectionMode(int mode);方法修改JTree的选择模式。
    Model的模式有以下3种:
    TreeSelectionModel.CONTIGUOUS_TREE_SELECTION: 可 以连续选中多个 TreePath 。
    TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION : 该选项对于选择没有任何限制 。
    TreeSelectionModel.SINGLE_TREE_SELECTION: 每次只能选择一个 TreePath 。
  3. 默认是无限制模式

为JTree添加监听器:

  1. addTreeExpansionListener(TreeExpansionListener tel) : 添加树节点展开/折叠事件的监听器。
  2. 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改变结点外观

  1. 创建结点对象new DefaultMutableTreeNode(obj);时,DefaultMutableTreeNode类的构造函数会将参数obj赋值给对象的userObject属性。
    DefaultMutableTreeNode类的构造函数
  2. 结点在窗体显示时,会调用DefaultTreeCellRenderer类对象的getTreeCellRendererComponent()方法绘制
    DefaultTreeCellRendere类的getTreeCellRendererComponent()方法
  3. getTreeCellRendererComponent()方法中的参数value就是结点对象
  4. Object类型的value,通过类型的强制转换,转换为DefaultMutableTreeNode类型:DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
  5. node.getUserObject();方法,把结点对象中第一步传入的参数取出,并强制转换为自己定义的数据类型
  6. 至此就可以通过创建结点对象时传入的参数来重绘结点的组件
    在这里插入图片描述
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实现简单表格

  1. 创建一个一维数组存放标题行。
  2. 创建一个二维数组存放表格数据。
  3. 创建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();
    }
}

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值