Java基础 自学讲义 9. Swing用户界面组件

目录
一. 设计模式
二. 布局管理

  1. 流布局FlowLayout
  2. 边框布局BoderLayout
  3.网格布局GridLayout

三. 文本输入

  1. 文本域
  2.标签和标签组件
  3.密码域
  4.文本区
  5.滚动窗格

四. 选择组件

  1. 复选框
  2.单选钮
  3. 边框
  4.组合框
  5.滑动条

五. 菜单

  1. 菜单创建
  2. 菜单项中的图标
  3. 复选框和单选钮菜单项
  4.弹出菜单(pop-up menu)
  5.快捷键和加速器
  6.启用和禁用菜单项
  7.工具栏
  8.工具提示

六. 复杂的布局管理
七. 对话框

  1.选项对话框
  2.创建对话框
  3.数据交换
  4.文件对话框
  5.颜色选择器

八. GUI程序排错

  1.调试技巧
  2.让Robot机器人完成工作

航航说Swing可以少学一些, 不是太有用, 所以学快一点啦~嘤嘤嘤

一. 设计模式

每个组件都有三要素: 内容, 外观, 行为
Swing采用的设计模式(Design Pattern)是: 模型-视图-控制器设计模式(Model-View-Controller) 即MVC模式
在MVC模式中要求我们实现三个独立的类:

模型:存储内容
视图:显示内容
控制器: 控制用户输入

重要的是在model中没有任何关于外观界面的事, 只负责存储内容, 所以在MVC模式有一个优点就是可以为一个模型开发多个视图;
控制器用于处理用户的输入, 比如按键, 鼠标动作等等, 然后决定是否把这个动作转化成对模型或视图的改变, 如果改变了就通知模型或者视图进行更新, 在模型和视图端是不知道为什么要更新的;
三者之间的交互过程如下:

对于大多数组件都有一个以Model结尾的模型类, 比如JButton对应的是ButtonModel, 可以这样定义:

ButtonModel greenButtonModel = greenButton.getModel();
greenButtonModel.setPressed(true);

可以传递给视图一些信息:

二. 布局管理



1.流布局FlowLayout

如果不指定布局方式, 默认采取的就是流布局 , 就是能放下就顺着放下去, 不够位置放了就换行;

2.边框布局BoderLayout


可以这样设置边框布局:

this.add(myWindow, BorderLayout.SOUTH);

BoderLayout可以指定几种位置:CENTER, NORTH, SOUTH, WEST, EAST五种;
如果没有提供值会默认用CENTER;
当窗口被Resize的时候, CENTER的组件大小会随着改变, 处于边缘的组件大小不会改变;

3.网格布局GridLayout

使用网格布局要指定行和列, 效果大概这样:

panel.setLayout(new GridLayout(4, 4));

三.文本输入

1.文本域

文本域可以用JTextField, JPassword或者JTextArea来实现;
JTextField只能输入一行, 可以设置默认值, 设置列数;
JTextArea可以设置行和列,默认值;
JPassword特点是输入的内容会加密显示;

JTextField aTextField = new JTextField("DefaultInformation",20);
JPasswordField aPasswordField = new JPasswordField("DefaultInformation",20);
JTextArea aTextArea = new JTextArea("DefaultInformation",10,20);

这些类都有set和get这些基本的方法, 要注意的是如果用setColumns改变了一个组件的大小, 一定要用revalidate方法去刷新这个组件, 否则会没有效果;

2.标签和标签组件

可以使用JLabel加一个标签, 同时可以设置标签的内容和对齐方式,像这样:

JLabel aLabel = new JLabel("DefaultInformation", JLabel.RIGHT);

然后也可以通过setText和setIcon方法对这个标签进行设置;
label里的内容也可以是一个完整的html文本;

3.密码域

4.文本区

前面的TextArea写过了, 要注意可以使用textArea.setLineWrap(true);来设置自动换行, 但是自动换行只是视觉效果, 实际获得的String里面是没有\n的;
JTextArea 组件只显示无格式的文本, 没有特殊字体或者格式设置。如果想要显示 格式化文本(如 HTML), 就需要使用 JEditorPane 类。

5.滚动窗格

给TextArea加上滚动条:

        JTextArea aTextArea = new JTextArea("DefaultInformation",10,30);
        aTextArea.setLineWrap(false);
        JScrollPane aScrollPane = new JScrollPane(aTextArea);
        myWindow.add(aScrollPane, BorderLayout.CENTER);

要注意的是加上滚动条之后加入到Panel中的就不是aTextArea了而应该是aScrollPane

四. 选择组件

1.复选框

复选框可以用JCheckbox来设置, 每个checkbox必定会对应一个text文本来提示这个复选框的内容, 然后有一个isSelected方法来表示这个复选框是否被选中了;
现在做了一个选择复选框然后改变上面的text字体的东西:

代码如下:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;

public class MyFrame extends JFrame {
    public MyFrame(){
        this.setTitle("Zilean's Quotes");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setSize(new Dimension(400,150));
        JPanel checkWindow = new JPanel();
        JLabel text = new JLabel("The way is always the same.");
        text.setFont(new Font("Serif",Font.PLAIN,30));
        JCheckBox boldBox = new JCheckBox("Bold");
        JCheckBox italyBox = new JCheckBox("Italy");
        ActionListener listener = event->{
            int mode = Font.PLAIN;
            if(boldBox.isSelected()) mode+=Font.BOLD;
            if(italyBox.isSelected()) mode+=Font.ITALIC;
            text.setFont(new Font("Serif",mode,30));
        };
        boldBox.addActionListener(listener);
        italyBox.addActionListener(listener);
        this.add(text,BorderLayout.CENTER);
        checkWindow.add(boldBox);
        checkWindow.add(italyBox);
        this.add(checkWindow,BorderLayout.SOUTH);
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}

都写了这么多了, 懂得自然懂QAQ

2.单选钮

可以用JRadioButton表示单选钮, 一旦有了单选钮肯定对应要有一个ButtonGroup, 在同一个ButtonGroup里的单选钮同一时间只能选择一个;
下面写了一个测试程序, 选择单选钮会自动生成对应的字体大小:

代码如下:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;

public class MyFrame extends JFrame {
    private JLabel text;
    private ButtonGroup sizeButtonGroup = new ButtonGroup();
    private JPanel sizePanel = new JPanel();
    private static final int DEFAULT_SIZE=20;

    public MyFrame(){
        this.setTitle("Zilean's Quotes");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setSize(new Dimension(400,150));
        text = new JLabel("The way is always the same.");
        text.setFont(new Font("Serif",Font.PLAIN,DEFAULT_SIZE));
        this.add(text,BorderLayout.CENTER);
        this.addRadioButton("Small",14);
        this.addRadioButton("Medium",20);
        this.addRadioButton("Large",26);
        this.addRadioButton("ExtraLarge",32);
        this.add(sizePanel,BorderLayout.SOUTH);

    }
    private void addRadioButton(String name, int size){
        boolean selected = size==DEFAULT_SIZE;
        JRadioButton aRadioButton = new JRadioButton(name, selected);
        aRadioButton.addActionListener(event->{
            this.text.setFont(new Font("Serif",Font.PLAIN,size));
        });
        sizeButtonGroup.add(aRadioButton);
        sizePanel.add(aRadioButton);
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}

要注意的是ButtonGroup的作用仅在于限制同一时间可选的单选框, 不需要加入到视图中;
可能会有这样的需求, 在某个时刻我希望知道某个ButtonGroup正被选中的单选框是哪个, 我们可能会想用ButtonGroup的getSelection方法, ,但是这个方法返回的仅仅是一个ButtonModel, 与我们而言并没有什么用, 但是似乎可以用model的getActionCommand方法来获取一些信息, 这需要我们在加入按钮的时候就设置了绑定的ActionCommandaRadioButton.setActionCommand(name);, 然后用sizeButtonGroup.getSelection().getActionCommand()方法获取对应的单选框的信息;

3.边框

可以给任何继承了JComponent的组件添加边框, 比如我给前一个写的RadioButton的sizePanel加了一个边框, 效果如下:

代码加上这样一句就可以了:

        sizePanel.setBorder(BorderFactory.createTitledBorder(
                BorderFactory.createEtchedBorder(),"Set Szie:"));

java内置了很多边框样式, 有的边框可以自己选一些颜色之类的属性, 还可以用createCompoundBorder来组合各种边框;

4.组合框

有的时候单选框不能满足我们的需求, 需要组合框JComboBox<>, 这是一个泛型类,;
比如实现下面这样的效果, 选择字号设置字体大小:

代码如下:

import javax.swing.*;
import java.awt.*;

public class MyFrame extends JFrame {
    private JLabel text;
    private static final int DEFAULT_SIZE=72;

    public MyFrame(){
        this.setTitle("Zilean's Quotes");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        text = new JLabel("The way is always the same.");
        text.setFont(new Font("Serif",Font.PLAIN,DEFAULT_SIZE));
        this.add(text,BorderLayout.CENTER);
        JPanel comboPanel = new JPanel();
        JComboBox<Integer> aComboBox = new JComboBox<>();
        DefaultComboBoxModel<Integer> aComboBoxModel = new DefaultComboBoxModel<>();
        for(int i=14;i<=72;i++){
            aComboBoxModel.addElement(i);
        }
        aComboBox.setModel(aComboBoxModel);
        aComboBox.addActionListener(event->{
            text.setFont(new Font("Serif",Font.PLAIN,aComboBox.getItemAt(aComboBox.getSelectedIndex())));
        });
        aComboBox.setSelectedItem(Integer.valueOf(72));
        comboPanel.add(aComboBox);
        this.add(comboPanel,BorderLayout.SOUTH);
        this.pack();
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}

说三个注意的点:
1.在向组合框中加入元素的时候可以直接用addItem方法加入元素:

        JComboBox<Integer> aComboBox = new JComboBox<>();
        for(int i=14;i<=72;i++){
            aComboBox.addItem(i);
        }

也可以

        JComboBox<Integer> aComboBox = new JComboBox<>();
        DefaultComboBoxModel<Integer> aComboBoxModel = new DefaultComboBoxModel<>();
        for(int i=14;i<=72;i++){
            aComboBoxModel.addElement(i);
        }
        aComboBox.setModel(aComboBoxModel);

但是CoreJava建议当加入到组合框中的内容比较多的时候用后者, 性能更好;
2.在获得组合框所选的内容时, 可以采用aComboBox.getSelectedItem()来获得选择的内容, 但是这里有个坑, 我设置的内容是Integer, 这里我自然地认为Java这里会使用自动拆箱, 将或得到的Integer对象自动拆箱成int类型, 但是实际发现并没有这么做, 查阅资料发现, 原来自动装箱和自动拆箱都只是一个语法糖, 只能发生在编译器编译阶段, 自动操作, 比如发现一个应该是int数据的地方, 传入了一个Integer对象, 此时编译器会自动使用intValue方法把它自动拆箱, 但是这只是一个语法糖, 在运行阶段是不能使用的, 所以这里如果使用了getSelectedItem就需要做强制类型转化成(int)aComboBox.getSelectedItem()才可以;
3. 可以设置组合框的值自己设定aComboBox.setEditable(true);但是如果前面采用了aComboBox.getItemAt(aComboBox.getSelectedIndex())这种方式来获取选框内容, 在设定的时候值不能超过选项范围, 否则会报异常(要异常处理), 如果希望可编辑, 可以用aComboBox.getSelectedItem(), 但是这样其实也很危险, 因为用户行为可能会输入一个奇怪的值进来;

5.滑动条

花里胡哨的, 随便写了个测试代码玩玩, 需要用的时候再说吧, 好多装饰滑动条的东西, 没细看;
获取滑动条的监听器不是ActionListener, 要用ChangeListener, 测试代码如下:

import javax.swing.*;
import java.awt.*;

public class MyFrame extends JFrame {
    private JLabel text;
    private static final int DEFAULT_SIZE=20;

    public MyFrame(){
        this.setTitle("Zilean's Quotes");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        text = new JLabel("The way is always the same.");
        text.setFont(new Font("Serif",Font.PLAIN,DEFAULT_SIZE));
        this.add(text,BorderLayout.CENTER);
        JSlider aslider = new JSlider();
        aslider.setMajorTickSpacing(20);
        aslider.setMinorTickSpacing(5);
        aslider.setPaintLabels(true);
        aslider.setPaintTicks(true);
        aslider.setPaintTrack(true);
        aslider.addChangeListener(event->{
            JSlider a = (JSlider)event.getSource();
            int value = a.getValue();
            text.setFont(new Font("Serif",Font.PLAIN,value));
        });

        this.add(aslider,BorderLayout.SOUTH);
        this.pack();
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}

效果如下, 拉滑动条可以改变上面的文字的大小:

五. 菜单

1.菜单创建

可以先创建一个JMenuBar, 然后可以向这个JMenuBar中加入一些JMenu, 然后每个JMenu里面可以有一些JMenuItem, 每个JMenuItem可以加监听器, 还可以在几个JMenuItem之间插入分隔符fileMenu.addSeparator();;
要把菜单加入到框架中可以用this.add(aBar)但是最好用this.setJMenuBar(aBar)

2.菜单项中的图标

可以用JMenuItem中的setIcon为菜单项设置图标, 也可以初始化的时候用new JMenuItem("菜单", new ImageIcon("blur_ball.gif"))直接传入一个图标;
如果是用Action来新建JMenuItem也可以直接为Action传进去一个图标, 这个图标就会自动成为这个Item的图标, 这样:

		Action openAction = new AbstractAction("Open",new ImageIcon("ace.gif")) {
            @Override
            public void actionPerformed(ActionEvent e) {
                //Some Action to perform should be written here.
            }
        };
        JMenuItem openItem = new JMenuItem(openAction);

效果大概是这样的:

3.复选框和单选钮菜单项

在菜单项中也可以使用复选框和单选钮, 叫JCheckBoxMenuItemJRadioButtonMenuItem, 和前面的用法都差不多, 我写了个例子:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class MyFrame extends JFrame {
    public MyFrame(){
        this.setTitle("Zilean");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        JLabel text = new JLabel("The way is always the same");
        text.setFont(new Font("serif",Font.PLAIN,20));
        JMenuBar aBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        JCheckBoxMenuItem colorItem = new JCheckBoxMenuItem("Red");
        colorItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(colorItem.isSelected()) text.setForeground(Color.RED);
                else text.setForeground(Color.BLACK);
            }
        });
        JRadioButtonMenuItem boldItem = new JRadioButtonMenuItem("Bold");
        JRadioButtonMenuItem plainItem = new JRadioButtonMenuItem("Plain");
        boldItem.addActionListener(event->{
            text.setFont(new Font("serif",Font.BOLD,20));
        });
        plainItem.addActionListener(event->{
            text.setFont(new Font("serif",Font.PLAIN,20));
        });
        ButtonGroup aGroup = new ButtonGroup();
        aGroup.add(boldItem);
        aGroup.add(plainItem);
        fileMenu.add(boldItem);
        fileMenu.add(plainItem);
        fileMenu.add(colorItem);
        aBar.add(fileMenu);
        this.add(aBar,BorderLayout.NORTH);
        this.add(text,BorderLayout.CENTER);
        this.pack();
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}

Bold和Plain是一个ButtonGroup的单选钮, Red是一个复选框, 但是好像样式看起来是一样的;
写监听的时候也是一样用isSelected方法

4.弹出菜单(pop-up menu)

可以设置右键弹出这样的触发式菜单, 比如下面我这样的, 点击这个label就会弹出一个触发式菜单:

代码:

import javax.swing.*;
import java.awt.*;

public class MyFrame extends JFrame {
    public MyFrame(){
        this.setTitle("Zilean");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        JLabel text = new JLabel("The way is always the same");
        text.setFont(new Font("serif",Font.PLAIN,20));
        JPopupMenu aPopMenu = new JPopupMenu();
        JMenuItem redItem = new JMenuItem("red");
        redItem.addActionListener(e->{
            text.setForeground(Color.RED);
        });
        aPopMenu.add(redItem);
        aPopMenu.show(this,10,10);
        this.add(text,BorderLayout.CENTER);
        this.pack();
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}

在这里插入图片描述setInheritsPopupMenu这个方法设置的继承属性如果设置成true那么这个组件会继承来自这个组件的容器的弹出式菜单;
注意如果用show只能出现一次这个菜单, 不需要右键点击, 还不知道怎么用呜呜

5.快捷键和加速器

可以为菜单项设置快捷键和加速器, 测试代码如下:

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;

public class MyFrame extends JFrame {
    public MyFrame(){
        this.setTitle("Zilean");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        JLabel text = new JLabel("The way is always the same");
        text.setFont(new Font("serif",Font.PLAIN,20));
        JMenuBar aBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        aBar.add(fileMenu);
        JMenuItem aItem  = new JMenuItem("Blue",'B');
        aItem.setMnemonic('B');
        aItem.setDisplayedMnemonicIndex(0);
        JMenuItem bItem  = new JMenuItem("Red");
        bItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
        aItem.addActionListener(e->text.setForeground(Color.BLUE));
        bItem.addActionListener(e->text.setForeground(Color.RED));
        fileMenu.add(aItem);
        fileMenu.add(bItem);
        this.add(aBar,BorderLayout.NORTH);
        this.add(text,BorderLayout.CENTER);
        this.pack();
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}

我设置了B键为Blue菜单项的快捷键, 设置了command+R为Red的快捷键, 效果如下:

在这里插入图片描述
有一个问题是mac上似乎没有快捷键下划线这个东西, 所以setDisplayedMnemonicIndex似乎是无效的;

6.启用和禁用菜单项

菜单项可以设置禁用和启用, 这样做:

aItem.setEnabled(false);

要适当的把这句话加到适当的地方, 还有另一种方法, 就是在弹出菜单项之后再禁用某个菜单项, 要为每个菜单项设置支持MenuListener接口, 而且如果设置了加速键还会遇到麻烦, 我认为这是个很蠢逼的方法, 不管他了, 放张书上的图;
在这里插入图片描述

7. 工具栏

除了可以设置菜单之外还可以设置工具栏, 效果这样:
在这里插入图片描述
设置了一个工具栏, 默认是水平的, 我这里设置了默认是垂直的, 工具栏和菜单栏一样也可以加分隔符aToolBar.addSeparator()
设置完工作栏之后是可以用户自己拉动工具栏自动贴靠到合适的四边的位置, 但是这个功能只能用于支持NORTH, SOUTH这些东西的布局中;
代码:

import javax.swing.*;
import java.awt.*;

public class MyFrame extends JFrame {
    public MyFrame(){
        this.setTitle("Zilean");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        JLabel text = new JLabel("The way is always the same");
        text.setFont(new Font("serif",Font.PLAIN,20));
        JToolBar aToolBar = new JToolBar("ColorBar",SwingConstants.VERTICAL);
        JButton redButton = new JButton("Red",new ImageIcon("ace.gif"));
        redButton.addActionListener(e->text.setForeground(Color.RED));
        aToolBar.add(redButton);
        aToolBar.add(new JButton("Blue",new ImageIcon("ace.gif")));
        this.add(aToolBar);
        this.pack();
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}

8.工具提示

往往工具栏里面都只有一个图标, 没有文字说明, 用户很可能不知道这个工具是什么意思, 所以我们可以为一个JButton加一个小Tip, 这样做

redButton.setToolTipText("Set Color to Red");

如果这个Button是由一个Action添加来的, 那也可以用Action自带的SHORT_DESCRIPTION;
这样做 exitAction.putValue(Action.SHORTJESCRIPnON, "Exit");

关于工具栏, 传一些常用的方法:

六.复杂的布局管理

网格组布局(GridBagLayout), 算了, 挺烦的, 假装没看见吧;
组布局(GroupLayout), 打扰了,Matisse GUI 构造器;

不使用布局管理器

还是这种方法看起来比较和善, 对每个组件都用决定位置来定位;
自己定义自己的布局管理, 但是要支持这个接口LayOoutManager, 这个接口有五个方法在这里插入图片描述
在这里插入图片描述

遍历顺序

组件的遍历顺序是按照 从左到右, 从上到下的顺序来进行遍历的, 如果希望某个组件不能被称为交点, 可以设置setFocusable(false)即可;
在这里插入图片描述

七. 对话框

1.选项对话框

可以使用自带的JOptionPane来创建一个对话框, 有很多种类型, 比如我写的showConfirmDialog其实还有比如Input之类的, 组合如下:
在这里插入图片描述

主要代码如下:

        JLabel text = new JLabel("The way is always the same");
        text.setFont(new Font("serif",Font.PLAIN,20));
        JButton aButton = new JButton("Button");
        aButton.addActionListener(e->{
            JOptionPane.showConfirmDialog(this, text);
        });
        this.add(aButton);

效果如下:

2.创建对话框

可以继承自JDialog创建一个自己的对话框,
效果:

代码:


import javax.swing.*;
import java.awt.*;

public class MyFrame extends JFrame {
    private JDialog aDialog;
    
    public MyFrame(){
        this.setTitle("Zilean");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        JLabel text = new JLabel("The way is always the same");
        text.setFont(new Font("serif",Font.PLAIN,20));
        JButton aButton = new JButton("Button");
        aButton.addActionListener(e->{
            aDialog = new myDialog(this);
            aDialog.setVisible(true);
        });
        this.add(aButton);
        this.pack();
    }

    private class myDialog extends JDialog{
        public myDialog(JFrame owner){
            super(owner, "Warning!",true);
            JPanel aPanel = new JPanel();
            aPanel.add(new JLabel("<html><h1>Zilean<h1><hr><h2>ChronoKeeper<h2></html>"));
            JButton aButton = new JButton("OK");
            aButton.addActionListener(e->{
                this.setVisible(false);
            });
            aPanel.add(aButton);
            this.add(aPanel);
            this.pack();
        }
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}

继承JDialog的时候注意它的构造函数中的最后一个参数modal, 如果设置为true, 在Dialog窗口关闭之前, 父对话框是锁死的, 只有关闭了Dialog才能操作父对话框:

3.数据交换

在弹出对话框的时候我们希望能获取到用户的输入数据, 我们可以在用户点击一个默认按键触发器的时候, 传回数据, 这样去设置默认按键(大部分情况下是ENTER键)dialog.getRootPane().setDefaultButton(okButton), 这个时候由你自己定义的Dialog里面提供一个这样的方法来获取到数据即可
有一个技巧是在写Dialog的时候可以先继承JPanel, 然后这样做来弹出一个JDialog:

dialog = new JDialog(owner, true);
dialog.add(this);
dialog.getRootPane().setDefaultButton(okButton);
dialog.pack();

别忘了设置DefaultButton

4.文件对话框

懒的搞了, 大概自己试了一下:
做了这些东西: 首先创建了一个JFileChooser做文件选择器, 然后获取到用户的选择文件, 在文件选择器里面定制加入了一个JPanel来显示文件预览, 然后在原来的JFrame中把这个图片画出来, 画出来的时候让框体自适应图片大小;
界面大概这样:

代码:

import javafx.util.Pair;
import javax.swing.*;
import java.awt.*;
import java.io.File;

public class MyFrame extends JFrame {
    String filename = "";
    myComponent acom = new myComponent();

    public MyFrame(){
        this.setTitle("Zilean");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        JFileChooser chooser = new JFileChooser();
        chooser.setCurrentDirectory(new File(""));
        chooser.setMultiSelectionEnabled(true);
        chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        chooser.setAccessory(new preview(chooser));
        JButton aButton = new JButton("OpenFile");
        aButton.addActionListener(e->{
            chooser.showOpenDialog(aButton);
            filename = chooser.getSelectedFile().getPath();
            System.out.println(filename);
            Pair im = acom.update(filename);
            this.revalidate();
            this.setSize((int)im.getKey(),(int)im.getValue());
        });
        this.add(aButton,BorderLayout.NORTH);
        this.add(acom);
        this.setSize(300,300);
    }

    class preview extends JLabel{
        public preview(JFileChooser chooser)
        {
            setPreferredSize(new Dimension(100, 100));
            setBorder(BorderFactory.createEtchedBorder());

            chooser.addPropertyChangeListener(event -> {
                if (event.getPropertyName() == JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)
                {
                    // the user has selected a new file
                    File f = (File) event.getNewValue();
                    if (f == null)
                    {
                        setIcon(null);
                        return;
                    }

                    // read the image into an icon
                    ImageIcon icon = new ImageIcon(f.getPath());

                    // if the icon is too large to fit, scale it
                    if (icon.getIconWidth() > getWidth())
                        icon = new ImageIcon(icon.getImage().getScaledInstance(
                                getWidth(), -1, Image.SCALE_DEFAULT));

                    setIcon(icon);
                }
            });
        }
    }


    public static void main(String[] args) {
        new MyFrame();
    }
}

class myComponent extends JComponent{
    ImageIcon image;
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(image!=null) g.drawImage(image.getImage(),0,0,image.getIconWidth(),image.getIconHeight(),this);
    }
    public Pair<Integer, Integer> update(String filename){
        image = new ImageIcon(filename);
        repaint();
        return new Pair<>(image.getIconWidth(),image.getIconHeight());
    }
}

吐槽! 似乎Java中并没有表示一个数据对的Pair数据结构, 真不方便!

5. 颜色选择器

使用JColorChooser
算了懒的搞, 用到再说吧;

八. GUI程序排错

1.调试技巧

可以在JFrame构造器的最后加上这一句看到慢速的绘图过程:

RepaintManager.currentManager(getRootPane()).setDoubleBufferingEnabled(false);
((JComponent) this.getContentPane()).setDebugGraphicsOptions(DebugGraphics.FLASH_OPTION);
2.让Robot机器人完成工作

robot机器人可以向任何AWT程序发送按键和鼠标操作, 用于测试界面;
具体操作没细看…

终于学完Swing了 呜呜呜!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值