超级详细的Swing学习笔记

Swing学习笔记

写在前面

这个笔记是我在B站学习的时候写的一些笔记(https://www.bilibili.com/video/BV1h7411v7Mq)

如果有什么不对的地方欢迎指正!

框架代码

照此框架即可

import javax.swing.*;
import java.awt.*;
public class SwingDemo
{
     
	private static void createGUI()
	{
     
		// JFrame指一个窗口,构造方法的参数为窗口标题
		JFrame frame = new JFrame("Swing Demo");
		
		// 当关闭窗口时,退出整个程序 (不懂的话没事,照抄即可,这一行不是重点)
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		// JFrame创建时自带了一个根容器,称为ContentPane,但一般我们会自己创建一个JPanel(后面有演示)
		Container contentPane = frame.getContentPane();
		contentPane.setLayout(new FlowLayout());
		
		// 向内容面板里添加控件 , 如 JLabel, JButton
		contentPane.add(new JLabel("Hello,World"));
		contentPane.add(new JButton("测试"));
        //JLabel和JButton都是可以通过构造方法设置他显示的内容,也可以用setText()方法
		
		// 设置窗口的其他参数,如窗口大小
		frame.setSize(400, 300);
		
		// 显示窗口
		frame.setVisible(true);
	}
	
	public static void main(String[] args)
	{
     
		// 此段代码间接地调用了 createGUI(),具体原理在 Swing高级篇 里讲解
		// 初学者先照抄此代码框架即可
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
     
			public void run()
			{
     
				createGUI();
			}
		});

	}
}

框架代码+

上面的CreateGUI()方法里面比较乱,所以自己实现一个MyFrame类,窗口里面各种布局的设置都是MyFrame类里面完成,这样才不显得乱。(以后都这样做,照搬SwingDemo类,只需改写MyFrame类)

import java.awt.Container;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class MyFrame extends JFrame {
     
	/**
	 * 序列化UID
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * 引用父类的构造方法,并且所有的控件都在这里定义,免得SwingDemo那个类比较乱
	 * @param nameString
	 */
	public MyFrame(String nameString) {
     
		super(nameString);
		Container contentPane = getContentPane();
		contentPane.setLayout(new FlowLayout());
		// 向内容面板里添加控件 , 如 JLabel, JButton
		contentPane.add(new JLabel("Hello,World"));
		contentPane.add(new JButton("测试"));
	}
}
public class SwingDemo
{
     
	private static void createGUI()
	{
     
		MyFrame frame = new MyFrame("Swing Demo");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(400, 300);
		frame.setVisible(true);
	}
	public static void main(String[] args)
	{
     
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
     
			public void run()
			{
     
				createGUI();
			}
		});
	}
}

Swing和AWT

1、Swing是基于AWT的,所以在Swing项目中,可以看到会引入java.awt.*下的内容。

2、两套控件,AWT的是Label、Button、…,Swing的是JLabel、JButton、…,我们用的都是Swing的控件。Swing是一套轻量化的实现。

监听器Listener

监听器是Swing里界面事件处理的一种方式。

1、新建一个类,实现ActionListener接口

class MyButtonListener implements ActionListener{
     
	@Override
	public void actionPerformed(ActionEvent e) {
     
		// TODO Auto-generated method stub
		System.out.println("按钮被点击了。");
	}
}

2、创建监听器对象

MyButtonListener myButtonListener = new MyButtonListener();

3、将监听器对象交给按钮

JButton jButton2 = new JButton("按钮");//新建一个按钮
contentPane.add(jButton2);
jButton2.addActionListener(myButtonListener);//绑定Listener

4、当按钮被点击时,Swing框架会调用监听器对象里的方法,进行处理。

◆一般都采用匿名内部类的写法,才不显得那么啰嗦。

JButton jButton = new JButton("按钮名称"); //创建一个按钮
jButton.addActionListener(new ActionListener() {
     	
	@Override
	public void actionPerformed(ActionEvent e) {
     
		System.out.println("按钮被点击了");
	}
});

◆或者采用Lambda表达式。

JButton jButton = new JButton("按钮名称"); //创建一个按钮
jButton.addActionListener((e)->{
     
	System.out.println("按钮被点击了");
});

控件

JComponent类

JComponent是除顶层容器外所有 Swing 组件的基类。

公用方法:

void setOpaque(boolean isOpaque) 
          设置是否不透明,如果为 true,则该组件绘制其边界内的所有像素。 
void setPreferredSize(Dimension preferredSize) 
          设置此组件的首选大小(注意不是setSize(),setSize()是Component类的方法(com.awt包下))。
void setToolTipText(String text) 
          注册要在工具提示中显示的文本(鼠标停靠在上面时显示的文本)。 
void setVisible(boolean aFlag) 
          使该组件可见或不可见。 
void setFont(Font font) 
          设置此组件的字体。 
void setForeground(Color fg) 
          设置此组件的前景色。 
void setBackground(Color bg) 
          设置此组件的背景色。 (注:如果是JLabel,必须先调用setOpaque(true))
void setEnabled(boolean enabled) 
          设置是否启用此组件。 

标签JLabel

构造方法:
JLabel(String text) 
          创建具有指定文本的 JLabel 实例。
普通方法:
String getText() 
          返回该标签所显示的文本字符串。 
void setText(String text) 
          定义此组件将要显示的单行文本。 
void setHorizontalAlignment(int alignment) 
          设置标签内容沿 X 轴的对齐方式。 
void setVerticalAlignment(int alignment) 
          设置标签内容沿 Y 轴的对齐方式。 
 setHorizontalAlignment中alignment的参数可以为:
 	SwingConstants.CENTER、SwingConstants.LEFT、SwingConstants.RIGHT
 setVerticalAlignment中alignment的参数可以为:
  	SwingConstants.CENTER、SwingConstants.TOP、SwingConstants.BOTTOM
JLabel jLabel = new JLabel();
jLabel.setText("这是一个标签");
jLabel.setFont(new Font("微软雅黑",Font.PLAIN,16));
/*
Font的构造方法:Font("字体名称",样式,大小);
样式可以是 PLAIN(常规)、BOLD(粗体)、ITALIC(斜体) 或 BOLD+ITALIC(粗体加斜体)。
*/
jLabel.setForeground(Color.BLUE);
/*
颜色可以是Color.XXX或者Color.xxx,
也可以用构造方法new Color(int r,int g,int b);参数范围0-255
*/
jLabel.setToolTipText("标签提示");
contentPane.add(jLabel);

文本框JTextField

继承关系:JComponent–JTextComponent–JTextField

构造方法:
new JTextField(int columns);  构造一个具有指定列数的新的空 TextField。
new JTextField(String text) 构造一个用指定文本初始化的新 TextField。 
new JTextField(String text, int columns) 构造一个用指定文本和列初始化的新 TextField。 
普通方法(继承自JTextComponent):
String getText() 
          返回此 TextComponent 中包含的文本。 
String getText(int offs, int len) 
          获取由组件表示的文本部分。 
void setEditable(boolean b) 
          设置指定的 boolean 变量,以指示此 TextComponent 是否应该为可编辑的。 
void setText(String t) 
          将此 TextComponent 文本设置为指定文本。 
普通方法(类本身的):
int getColumns() 
          返回此 TextField 中的列数。 
void setColumns(int columns) 
          设置此 TextField 中的列数,然后验证布局。 
/*
实现功能:有一个标签一个文本框一个按钮,点击按钮就弹出一个消息框,显示刚刚输入的内容
*/
JLabel jLabel = new JLabel("请输入:");      //新建一个标签,显示的文字为“请输入”
JTextField jTextField = new JTextField(16); //设置宽度为16
JButton jButton = new JButton("确定");      //新建一个按钮,显示的文字为“确定”
jButton.addActionListener(new ActionListener() {
     
    @Override
    public void actionPerformed(ActionEvent e) {
     
        String str = jTextField.getText();
        JOptionPane.showMessageDialog(MyFrame.this,"输入了:" + str);
        /*
        JOptionPane的静态方法
static void showMessageDialog(Component parentComponent, Object message) 
          调出标题为 "Message" 的信息消息对话框。 
static void showMessageDialog(Component parentComponent, Object message, String title, int messageType) 
          调出对话框,它显示使用由 messageType 参数确定的默认图标的 message。 
static void showMessageDialog(Component parentComponent, Object message, String title, int messageType, Icon icon) 
          调出一个显示信息的对话框,为其指定了所有参数。 

        */
    }
});
contentPane.add(jLabel);
contentPane.add(jTextField);
contentPane.add(jButton);

单选框JRadioButton

继承关系:
javax.swing.JComponent
-javax.swing.AbstractButton
--javax.swing.JToggleButton
---javax.swing.JRadioButton
方法和下面复选框的类似!

▲▲注:需要另外创建一个 ButtonGroup 对象配合使用才能实现单选效果。

复选框JCheckBox

继承关系:

javax.swing.JComponent
–javax.swing.AbstractButton
---- javax.swing.JToggleButton
------- javax.swing.JCheckBox

构造方法:
new JCheckBox(String text) 
          创建一个带文本的、最初未被选定的复选框。 
new JCheckBox(String text, boolean selected) 
          创建一个带文本的复选框,并指定其最初是否处于选定状态。
普通方法:
isSelect()/setSelect() : 获取/设置选中状态
setText():选项文字

下拉列表框JComboBox

1 创建 JComoboBox
JComboBox colorList = new JComboBox<>();
可见,JComboBox 是一个泛型,参数类型T 表示是的数据项的类型

2 添加数据项
colorList.addItem("红色");
colorList.addItem("蓝色");
colorList.addItem("绿色");
addItem ( T ) ,T的类型在创建时指定,这里是 String 类型,也就是每一项Item的数据类型是String

3 按索引访问
getSelectedIndex() : 获取选中项的索引
setSelectedIndex() : 设置选中项
remove (index) :按索引删除

4 按数据项访问
getSelectedItem() 
setSelectedItem()
remove ( item )

5 事件处理
单击: ActionListener
选项改变:ItemListener,但这个事件总会执行2次,解决办法,加if判断:
if(e.getStateChange() == ItemEvent.SELECTED)
/*
实现功能:左边下拉列表框,右边标签,左边选好颜色后右边变成相应的颜色。
*/
JComboBox<String> jComboBox = new JComboBox<>();
jComboBox.addItem("红色");
jComboBox.addItem("绿色");
jComboBox.addItem("蓝色");
JLabel jLabel = new JLabel("这是一个示例 This is a simple example!");
jComboBox.setSelectedIndex(0);  //默认选中第一个(红色)
jLabel.setForeground(Color.RED); //默认是红色
contentPane.add(jComboBox);
contentPane.add(jLabel);
jComboBox.addActionListener(new ActionListener() {
     
    @Override
    public void actionPerformed(ActionEvent e) {
     
        Color color = null;
        switch (jComboBox.getSelectedIndex()){
     
            case 0:
                color = Color.RED;
                break;
            case 1:
                color = Color.GREEN;
                break;
            case 2:
                color = Color.BLUE;
                break;
            default:
                color = Color.BLACK;
        }
        jLabel.setForeground(color);
    }
});

列表框JList

JList是一个泛型类(和JComboBox类似)

构造方法:
JList() 构造一个具有空的、只读模型的 JList。 
JList(ListModel dataModel) 根据指定的非 null 模型构造一个显示元素的 JList。 
JList(Object[] listData) 构造一个 JList,使其显示指定数组中的元素。 
普通方法:
(查API)

■我发现JList是只读的,没有像JComboBox的addItem()方法,所以只能在构造方法中传入数组。

示例:

JList<String> jList = new JList<>(new String[]{
     "选项1","选项2"});
contentPane.add(jList);

根据我上网查后发现,如果想实现动态添加,那么应该使用ListModel(这是接口,使用的是他的实现类DefaultListModel)【JComboBox也有相对应的ComboModel】

DefaultListModel<String> defaultListModel= new DefaultListModel<>();
defaultListModel.addElement("选项1");
defaultListModel.addElement("选项2");
JList<String> jList = new JList<>(defaultListModel);//通过构造方法把ListModel传进去
contentPane.add(jList);

默认是不显示水平和垂直滚动条的,即使列表满了,如果要显示滚动条,还应该使用JScrollPane【不是JScrollBar,这个组件就单纯是创建一个滚动条而已,不起什么作用】

DefaultListModel<String> defaultListModel= new DefaultListModel<>();
defaultListModel.addElement("选项1");
defaultListModel.addElement("选项2");
JList<String> jList = new JList<>(defaultListModel);//通过构造方法把ListModel传进去
//contentPane.add(jList);
JScrollPane jScrollPane = new JScrollPane(jList);//构造方法中绑定要显示滚动条的部件(注:只有显示满了才会显示)
contentPane.add(jScrollPane);//绑定之后,往容器里加的是JScrollPane对象了而不再是JList,contentPane.add(jList)已不起作用!

注:如果部件绑定滚动条之后,想要设置组件大小,不能通过被绑定的部件来设置,如

jList.setPreferredSize(new Dimension(300,500));
/*
经过测试,这样子设,不起作用,反而还出问题
*/

正确代码

jScrollPane.setPreferredSize(new Dimension(300,500));

★另:改变列表中每一项显示的样式,可以使用ListCellRenderer

例子:

这里使用JLabel来绘制列表中的每一项,也可以使用其他的,只要最后return回去就行了。注意:使用这个的意思并不是将JLabel控件放到JList上面,而是将JLabel的显示效果复制到JList上面去而已。

private static class MyListCellRenderer implements ListCellRenderer<String>{
     
    @Override
    public Component getListCellRendererComponent(JList<? extends String> list, //使用这个CellRenderer的列表对象
                                                  String value,//每一项的值
                                                  int index, //索引
                                                  boolean isSelected,//是否被选中状态
                                                  boolean cellHasFocus //不知道,和上面的差不多
) {
     
        JLabel jLabel = new JLabel();
        jLabel.setText(value); //要显示的文本
        jLabel.setHorizontalAlignment(SwingConstants.CENTER);//居中显示
        jLabel.setFont(new Font("微软雅黑",Font.BOLD,18));
        jLabel.setBackground(Color.white);
        jLabel.setForeground(Color.RED);
        jLabel.setOpaque(true);
        if(isSelected){
     
            //当被选中时呈现的效果
            jLabel.setBackground(Color.CYAN);
        }
        return jLabel;
    }
}
//然后把这个CellRenderer放到JList上面。
jList.setCellRenderer(new MyListCellRenderer()); //设置CellRenderer(也可以使用匿名内部类的写法)

表格控件JTable

和JList一样,也需要一个Model来负责数据的管理,即TableModel(使用其实现类DefaultTableModel)。为了显示出滚动条,也需要被绑在JScrollPane里。

通过我的实验发现,直接往容器里添加JTable是不显示表头的,必须要用JScrollPane才能显示表头。

DefaultTableModel的方法:

void addColumn(Object columnName) 
          添加列头
void addRow(Object[] rowData) 
          添加一行
void addRow(Vector rowData) 
          添加一行

表格控件里的常用方法:

Object getValueAt(int row, int column) 
          返回 row 和 column 位置的单元格值。 
void setRowHeight(int rowHeight) 
          设置单元格高度
void setColumnSelectionAllowed(boolean columnSelectionAllowed) 
          是否是整行选择,默认true
int getSelectedColumn() 
          返回第一个选定列的索引;如果没有选定的列,则返回 -1。 
int[] getSelectedColumns() 
          返回所有选定列的索引。 
int getSelectedRow() 
          返回第一个选定行的索引;如果没有选定的行,则返回 -1。 
int[] getSelectedRows() 
          返回所有选定行的索引。 

★用TableCellRenderer可以自定义单元格的显示,和ListCellRenderer一样。

但是绘制器只能一列一列地设置

TableColumn column = jTable.getColumnModel().getColumn(列数);//获取某一列的对象
column.setCellRenderer(...);    //设置TableCellRenderer
column.setHeaderRenderer(...);    //设置标题的样式

转盘控件JSpinner

这个是可以将数字微调的控件,通常提供一对带小箭头的按钮以便逐步遍历序列元素。

◆构造方法:
JSpinner() 构造一个 spinner,使其具有初始值为 0 并且无任何最小值或者最大值限制
JSpinner(SpinnerModel model) 构造具有一对 next/previous 按钮和 SpinnerModel 编辑器的完整 spinner。 
▲SpinnerModel是一个接口,如果是数字的话就使用它的实现类SpinnerNumberModel
如:new JSpinner(new SpinnerNumberModel(值,最小值,最大值,步长));

◆普通方法:
void setModel(SpinnerModel model)  更改表示此 spinner 值的模型。 
SpinnerModel getModel() 返回定义此 spinner 值序列的 SpinnerModel。 
void setValue(Object value) 更改模型的当前值,通常此值是 editor 所显示的值。 
Object getValue() 返回模型的当前值,通常此值是 editor 所显示的值。 
注:获取当前值也可以getModel().getValue()

其他控件

这里是一些其他比较常用的控件,具体使用方法自己查API文档:

  1. JTabbedPane:选项卡

  2. JTree:树

    e.g.

    DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode("根");
    JTree jTree = new JTree(treeNode);
    DefaultMutableTreeNode treeNode1 = new DefaultMutableTreeNode("子1");
    DefaultMutableTreeNode treeNode11 = new DefaultMutableTreeNode("子子1");
    DefaultMutableTreeNode treeNode2 = new DefaultMutableTreeNode("子2");
    DefaultMutableTreeNode treeNode3 = new DefaultMutableTreeNode("子3");
    treeNode.add(treeNode1);
    treeNode.add(treeNode2);
    treeNode.add(treeNode3);
    treeNode1.add(treeNode11);
    contentPane.add(jTree);
    

彩色标签案例

JLabel jLabel1 = new JLabel("标签1");
jLabel1.setOpaque(true);    //设置为不透明,这样才能显示出背景色
jLabel1.setBackground(Color.BLUE);   //设置背景色为蓝色
jLabel1.setHorizontalAlignment(SwingConstants.CENTER);  //水平居中
jLabel1.setPreferredSize(new Dimension(40,30));  //设置组件的首选大小
contentPane.add(jLabel1);

布局(实现LayoutManager接口)

流布局FlowLayout

特点:从左到右逐个排列,当一行占满时挪到下一行

//上面的代码在创建窗口的时候就设置了布局模式
Container contentPane = frame.getContentPane();
contentPane.setLayout(new FlowLayout());

方法:

void setAlignment(int align)  设置此布局的对齐方式。 
--可以取的值有:
FlowLayout.LEFT 左对齐
FlowLayout.RIGHT  右对齐
FlowLayout.CENTER  居中
FlowLayout.LEADING  与容器方向的开始边对齐
FlowLayout.TRAILING  与容器方向的结束边对齐

void setHgap(int hgap) 设置组件之间以及组件与 Container 的边之间的水平间隙。 
void setVgap(int vgap) 设置组件之间以及组件与 Container 的边之间的垂直间隙。
void setAlignment(int align) 设置此布局的对齐方式。 

构造方法:
new FlowLayout(int align) 
          构造一个新的 FlowLayout,它具有指定的对齐方式,默认的水平和垂直间隙是 5 个单位。 
new FlowLayout(int align, int hgap, int vgap) 
          创建一个新的流布局管理器,它具有指定的对齐方式以及指定的水平和垂直间隙。 

边界布局BorderLayout

特点:把布局分为上、下、左、右、中 五个区域

方法:

构造方法:
BorderLayout() 构造一个组件之间没有间距的新边框布局。 
BorderLayout(int hgap, int vgap) 构造一个具有指定组件间距的边框布局。 
普通方法:
 void setHgap(int hgap) 设置组件之间的水平间距。 
 void setVgap(int vgap) 设置组件之间的垂直间距。 
常量:
static String CENTER 中间区域的布局约束(容器中央)。 
static String EAST 东区域的布局约束(容器右边)。 
static String NORTH 北区域的布局约束(容器顶部)。 
static String SOUTH 南区域的布局约束(容器底部)。 
static String WEST 西区域的布局约束(容器左边)。 
用于add方法的第二个参数,表示将组件添加到布局的哪个位置上
contentPane.add(组件1,BorderLayout.EAST); //添加到左边
contentPane.add(组件2,BorderLayout.WEST);  //添加到右边
contentPane.add(组件3,BorderLayout.NORTH);  //添加到上边
contentPane.add(组件4,BorderLayout.SOUTH);//添加到下边
contentPane.add(组件5,BorderLayout.CENTER); //添加到中间

注意:任何一个组件,添加到某个区域,那都是一定会占满整块区域的,所以如果直接调用contentPane.add(new JButton(“按钮”),BorderLayout.EAST);是不可取的,这个按钮会占满一整块区域。所以正确的做法是向这5个区域再分别放一个容器,组件就放到这些容器里面。

这个容器就是JPanel,它是一个轻量级容器。注意:JPanel容器内部采用的布局默认是流布局FlowLayout

实例代码:

public class MyFrame extends JFrame {
     

    public MyFrame(String frameName) throws HeadlessException {
     
        super(frameName);
        Container contentPane = getContentPane();
        contentPane.setLayout(new BorderLayout());
        JPanel left = new JPanel();
        JPanel right = new JPanel();
        JPanel top = new JPanel();
        JPanel bottom = new JPanel();
        JPanel center = new JPanel();
        left.add(new JButton("左边的按钮"));
        right.add(new JButton("右边的按钮"));
        top.add(new JButton("上面的按钮"));
        bottom.add(new JButton("下面的按钮"));
        center.add(new JButton("中间的按钮"));
        //下面往顶层容器添加JPanel容器
        contentPane.add(left,BorderLayout.EAST);
        contentPane.add(right,BorderLayout.WEST);
        contentPane.add(top,BorderLayout.NORTH);
        contentPane.add(bottom,BorderLayout.SOUTH);
        contentPane.add(center,BorderLayout.CENTER);
    }
}

卡片布局CardLayout

犹如多张叠在一起的卡片,每次只显示一张卡片的内容。

如果一个容器设置了卡片布局,那么往里面添加控件,一定会占满整个窗口!

所以类似上面,也要添加一个JPanel容器再往JPanel里面加组件

//添加容器时要指定名字
contentPane.add(jPanel,"名字");
//切换容器时需要用到名字
cardLayout.show(父容器,"要显示的容器的名字");

示例代码:

public class MyFrame extends JFrame {
     

    public MyFrame(String frameName) throws HeadlessException {
     
        super(frameName);
        Container contentPane = getContentPane();
        CardLayout cardLayout =new CardLayout();
        contentPane.setLayout(cardLayout);
        JPanel jPanel1 = new JPanel();   //创建一个新容器
        contentPane.add(jPanel1,"1");  //添加,设置他的名字为“1”
        JPanel jPanel2 = new JPanel();   //创建一个新容器
        contentPane.add(jPanel2,"2");  //添加,设置他的名字为“2”
        //注:所以顶层容器里面添加了2个子容器,但这两个子容器都是占满整个窗口,所以肯定会有一个被覆盖掉
        jPanel1.add(new JLabel("这个第一张卡片"));
        JButton jButton1 = new JButton("切换到第二张卡片");
        jPanel1.add(jButton1);   //将按钮添加到第一张卡片

        jPanel2.add(new JLabel("这个第二张卡片"));
        JButton jButton2 = new JButton("切换到第一张卡片");
        jPanel2.add(jButton2);   //将按钮添加到第二张卡片

        //给按钮添加事件
        jButton1.addActionListener(new ActionListener() {
     
            @Override
            public void actionPerformed(ActionEvent e) {
     
                cardLayout.show(contentPane,"2");   //显示第二张卡片,参数:父容器,add方法已经设置的名字
            }
        });
        jButton2.addActionListener(new ActionListener() {
     
            @Override
            public void actionPerformed(ActionEvent e) {
     
                cardLayout.show(contentPane,"1");   //显示第一张卡片,参数:父容器,add方法已经设置的名字
            }
        });

    }

}

网格布局GridLayout

构造方法:
GridLayout() 
          创建具有默认值的网格布局,即每个组件占据一行一列。 
GridLayout(int rows, int cols) 
          创建具有指定行数和列数的网格布局。 
GridLayout(int rows, int cols, int hgap, int vgap) 
          创建具有指定行数和列数的网格布局。 
普通方法:
void setRows(int rows) 
          将此布局中的行数设置为指定值。 
void setColumns(int cols) 
          将此布局中的列数设置为指定值。 
void setHgap(int hgap) 
          将组件之间的水平间距设置为指定值。 
void setVgap(int vgap) 
          将组件之间的垂直间距设置为指定值。 

自定义布局

窗口坐标:左上角为(0,0),向右横坐标增长,向下纵坐标增长。注:标题栏也占据一定的坐标。

示例代码:

public class MyFrame extends JFrame {
     
    public MyFrame(String frameName) throws HeadlessException {
     
        super(frameName);
        Container contentPane = getContentPane();
        contentPane.setLayout(null); //第一步:取消布局
        JButton jButton = new JButton("按钮");
        jButton.setBounds(new Rectangle(20,20,150,150));
        //需要为每个控件指定坐标
        //setBound(new Rectangle(起始横坐标,起始纵坐标,占据宽度,占据高度));
        contentPane.add(jButton);
    }
}

自定义布局器

需要实现LayoutManager接口,重写里面的LayoutContainer方法,当窗口大小改变时,会调用这个方法重新布局。

一般都用在需要动态设置组件位置的时候,比如改变窗口大小时需要动态改变窗口里面的布局。

示例代码:

//改变窗口大小时,始终保证按钮在窗口最中间的位置。
public class MyFrame extends JFrame {
     

    public MyFrame(String frameName) throws HeadlessException {
     
        super(frameName);
        Container contentPane = getContentPane();
        JButton jButton = new JButton("我是一个按钮");
        contentPane.setLayout(new LayoutManager() {
     
            @Override
            public void addLayoutComponent(String name, Component comp) {
     
			//当父容器调用add()方法添加容器时会调用这里的方法,comp为添加进来的组件(add方法的第一个参数),name为父容器调用add方法时的第二个参数(为字符串)
             //如果add()的第二个参数传的是Object类型,也想获取到,那么可以使用LayoutManager2接口。
            }

            @Override
            public void removeLayoutComponent(Component comp) {
     

            }

            @Override
            public Dimension preferredLayoutSize(Container parent) {
     
                return null;
            }

            @Override
            public Dimension minimumLayoutSize(Container parent) {
     
                return null;
            }

            @Override
            public void layoutContainer(Container parent) {
     
                int h = parent.getHeight();
                int w = parent.getWidth();
                int btnH = jButton.getPreferredSize().height;
                int btnW = jButton.getPreferredSize().width;
                int btnX = w/2 - btnW/2;  //计算横坐标
                int btnY = h/2 - btnH /2;  //计算纵坐标
                jButton.setBounds(new Rectangle(btnX,btnY,btnW,btnH));
            }
        });

        jButton.setFont(new Font("微软雅黑",Font.PLAIN,16));
        jButton.setPreferredSize(new Dimension(160,45));
        contentPane.add(jButton);
    }
}

边框

Border类是一个接口,使用Border可以使用JComponent类的方法

void setBorder(Border border) 
          设置此组件的边框。 

使用(边框的属性(比如颜色)需要在构造方法中指定,没有一堆的set方法)

Border border = new LineBorder(Color.BLUE,1);
//或Border border = BorderFactory.createLineBorder(Color.BLUE,1); //通过工厂类创建
jLabel.setBorder(border);

常用边框

  • LineBorder:线性边框
  • EtchedBorder:蚀刻边框(一条灰灰的线)
    new EtchedBorder()或new EtchedBorder(EtchedBorder.LOWERED) 阴刻
    new EtchedBorder(EtchedBorder.RAISED) 阳刻
  • BevelBorder:斜面边框
    new BevelBorder(BevelBorder.LOWERED) 或BorderFactory.createLoweredBevelBorder()凹入类型
    new BevelBorder(BevelBorder.RAISED) 或BorderFactory.createRaisedBevelBorder()凸出类型
  • TitledBorder:带标题的边框(需绑定一个其他边框)
  • CompoundBorder:复合边框(需绑定2个边框,一个内一个外)
  • EmptyBorder:空边框

空边框的作用:给其他边框设置边距,如:

public class MyFrame extends JFrame {
     
    public MyFrame(String frameName) throws HeadlessException {
     
        super(frameName);
        JPanel jPanel = new JPanel();
        jPanel.setLayout(new GridLayout(5,1));
        this.setContentPane(jPanel);  //重新设置顶层容器,因为原来的没有设置边框的功能。
        jPanel.setBorder(new EmptyBorder(8,8,8,8));  //给顶层容器设置一个空边框
        JLabel jLabel = new JLabel("标签1");
        jLabel.setBorder(new EtchedBorder());  //蚀刻边框
        jLabel.setForeground(Color.BLUE);
        jLabel.setOpaque(true);
        jLabel.setBackground(Color.CYAN);
        jLabel.setFont(new Font("微软雅黑",Font.PLAIN,16));
        jLabel.setHorizontalAlignment(SwingConstants.CENTER);
        jPanel.add(jLabel);
    }
}

效果:(标签1的边框和顶层容器之间有一定的间距,而不是紧凑在一起)

超级详细的Swing学习笔记_第1张图片

图标

注:只支持jpg/jpeg/png格式,不支持缩放。

使用方法:

//1、在src下创建专门用于存放图标的文件夹(我这里是icon)
//2、使用类加载器读取文件路径
URL url = SwingDemo.class.getResource("/icon/cool.png");
//3、使用ImageIO类的静态方法,读取图片,转换为Image对象(image是一个抽象类,读取到的其实是他的子类BufferedImage)
Image image = ImageIO.read(url);
//4、设置窗口的图标
frame.setIconImage(image);

■我发现设置窗口的图标用的是setIconImage()方法,里面传入一个Image对象。如果是普通控件需要设置一个图标,那么用的是setIcon()方法,传入的是Icon对象。

以JLabel为例(我发现好像也只有JLabel和JButton能设置图标):

URL url = SwingDemo.class.getResource("/icon/cool.png");
JLabel jLabel = new JLabel("标签");
Icon icon = new ImageIcon(url);  //Icon类是一个接口,ImageIcon是其实现类,构造方法中传入URL
jLabel.setIcon(icon);
contentPane.add(jLabel);

Image和ImageIcon也可以互转,如ImageIcon里的方法:

ImageIcon转Image:
	Image getImage()
Image转ImageIcon:
	new ImageIcon(Image)

Image图像也可以缩放

 Image getScaledInstance(int width, int height, int hints) 
          创建此图像的缩放版本。 
 width和height只要其中有一个为负数,那么表示保持长宽比缩放。
 hints参数不知干啥的

绘制图形

绘制图形需要用到自己写一个类,继承要绘图的控件的类,重写paintComponent()方法。(必须要这样,我测试过了,通过getGraphics()获取的画笔来绘画是没有用的)(重写paint()也行,但是不建议这样做,我也不知道为啥,好像是因为不怎么稳定)

绘制时直接使用paintComponent()里面的参数Graphics来绘制。

【注意!!!是paintComponent不是printComponent,被坑了】

绘制前,可以先设置颜色
	setColor(Color.red);
可以通过一堆FillXxxx()和DrawXxxx()来绘制或填充(具体查阅API文档,我懒得赘述)

示例代码:

public class SwingDemo {
     
    private static void createGUI()
    {
     
        JFrame frame = new JFrame("Swing Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        MyPanel myPanel = new MyPanel();
        frame.setContentPane(myPanel);
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
     
        SwingUtilities.invokeLater(new Runnable() {
     
            public void run()
            {
     
                createGUI();
            }
        });
    }
	//内部类,继承JPanel
    static class MyPanel extends JPanel{
     
        @Override
        protected void paintComponent(Graphics g) {
     
            //当窗口被显示时,Swing框架内部会调用每个控件 paintComponent()来绘制
            super.paintComponent(g);
            g.clearRect(0, 0, this.getWidth(), this.getHeight());//清空显示(没有使用布局时获取高度和宽度用的是getWidth()和getHeight())
            g.setColor(Color.red);
            g.fillRect(100,100,300,300);
        }
    }
}

绘制图片:

用drawImage()方法。
boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) 
          绘制指定图像中已缩放到适合指定矩形内部的图像。 一般ImageObserver这个参数置空(没什么用)
Image对象可以使用ImageIO从文件中读取。
给图片添加遮罩的效果,可以
g.setColor(new Color(255,255,255,200));//最后一个参数是不透明度
g.fillRect(0,0,getWidth(),getHeight());

鼠标事件

可以添加3类监听器(Listener):

1.addMouseListener() :点击、按下、抬起、移入、移出

2.addMouseMotionListener():移动、拖动

3.addMouseWheelListener():鼠标滚轮转动

MouseEvent类的用法:

int getX() 返回事件相对于源组件的水平 x 坐标。 
int getY() 返回事件相对于源组件的垂直 y 坐标。 
int getXOnScreen() 返回事件的绝对水平 x 坐标。 
int getYOnScreen() 返回事件的绝对垂直 y 坐标。 
Object getSource() 返回被点中的对象
int getButton() 返回按下的鼠标按键(左键、中键和右键)。 
	返回4个常量之一:NOBUTTON、BUTTON1、BUTTON2、BUTTON3
int getClickCount() 返回鼠标单击次数(单击、双击)。 

鼠标适配器(MouseAdapter):同时实现了三个接口,并同时空实现了所有方法。在添加鼠标事件时可以直接

addMouseListener(new MouseAdapter(){
     });

然后重写自己需要的方法就行了(避免了实现接口的匿名内部类方法冗余的问题)

菜单栏JMenuBar

涉及3个类:JMenuBar(菜单栏)、JMenu(菜单)、JMenuItem(菜单项)

示例代码:

public class SwingDemo1 {
     
    private static void createGUI()
    {
     
        JFrame frame = new JFrame("Swing Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setVisible(true);

        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new FlowLayout());

        JMenuBar jMenuBar = new JMenuBar(); //创建一个菜单栏对象
        frame.setJMenuBar(jMenuBar);  //给窗口设置成指定的菜单栏

        JMenu jMenu1 = new JMenu("文件");  //新建一个菜单对象
        JMenu jMenu2 = new JMenu("帮助");  //新建一个菜单对象
        jMenuBar.add(jMenu1);  //将菜单添加到菜单栏
        jMenuBar.add(jMenu2);

        JMenuItem jMenuItem1 = new JMenuItem("新建"); //菜单项
        JMenuItem jMenuItem2 = new JMenuItem("打开"); //菜单项
        JMenuItem jMenuItem3 = new JMenuItem("保存"); //菜单项
        JMenuItem jMenuItem4 = new JMenuItem("另存为"); //菜单项
        JMenuItem jMenuItem5 = new JMenuItem("退出"); //菜单项
        JMenuItem jMenuItem6 = new JMenuItem("帮助"); //菜单项
        JMenuItem jMenuItem7 = new JMenuItem("关于"); //菜单项

        jMenu1.add(jMenuItem1); //将菜单项添加到菜单
        jMenu1.add(jMenuItem2);
        jMenu1.add(jMenuItem3);
        jMenu1.add(jMenuItem4);
        jMenu1.addSeparator();  //添加一个分隔符
        jMenu1.add(jMenuItem5);
        jMenu2.add(jMenuItem6);
        jMenu2.add(jMenuItem7);
    }

    public static void main(String[] args)
    {
     
        SwingUtilities.invokeLater(new Runnable() {
     
            public void run()
            {
     
                createGUI();
            }
        });

    }
}

JMenu是JMenuItem的子类,区别在于JMenu相对于一个文件夹,里面放很多文件,而JMenuItem就是那些文件。所以如果要实现多级菜单,可以add(JMenu对象)。

工具栏JToolBar

一般往工具栏里加按钮JButton

示例代码:

public class SwingDemo1 {
     
    private static void createGUI()
    {
     
        JFrame frame = new JFrame("Swing Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setVisible(true);

        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new BorderLayout());  //使用边界布局

        JToolBar jToolBar = new JToolBar();
        jToolBar.add(new JButton("按钮1"));
        jToolBar.add(new JButton("按钮2"));
        jToolBar.add(new JButton("按钮3"));
        jToolBar.addSeparator();//分隔符
        jToolBar.add(new JButton("按钮4"));

        contentPane.add(jToolBar,BorderLayout.BEFORE_FIRST_LINE);
    }
    public static void main(String[] args)
    {
     
        SwingUtilities.invokeLater(new Runnable() {
     
            public void run()
            {
     
                createGUI();
            }
        });
    }
}

弹出菜单JPopupMenu

比如右键菜单。通过add()把一个JMenuItem插到菜单后面,show()方法显示菜单。show()的参数分别为调用者、x坐标、y坐标。

示例代码

public class SwingDemo1 {
     
    private static void createGUI()
    {
     
        JFrame frame = new JFrame("Swing Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setVisible(true);

        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new FlowLayout());

        JPopupMenu popupMenu = new JPopupMenu();
        popupMenu.add(new JMenuItem("选项1"));//添加菜单项
        popupMenu.add(new JMenuItem("选项2"));
        popupMenu.add(new JMenuItem("选项3"));
        popupMenu.addSeparator();  //分隔符
        popupMenu.add(new JMenuItem("选项4"));

        contentPane.addMouseListener(new MouseListener() {
     
            @Override
            public void mouseClicked(MouseEvent e) {
     
                if(e.getButton() == MouseEvent.BUTTON3){
     
                    //如果是右键被按下
                    popupMenu.show(e.getComponent(),e.getX(),e.getY());//显示菜单
                }
            }

            @Override
            public void mousePressed(MouseEvent e) {
     

            }

            @Override
            public void mouseReleased(MouseEvent e) {
     

            }

            @Override
            public void mouseEntered(MouseEvent e) {
     

            }

            @Override
            public void mouseExited(MouseEvent e) {
     

            }
        });
    }
    public static void main(String[] args)
    {
     
        SwingUtilities.invokeLater(new Runnable() {
     
            public void run()
            {
     
                createGUI();
            }
        });
    }
}

对话框

普通对话框

使用JOptionPane类的静态方法。

方法名 描述
showConfirmDialog 询问一个确认问题,如 yes/no/cancel。
showInputDialog 提示要求某些输入。如果使用其重载版本,传入数组,则是选择框。
showMessageDialog 告知用户某事已发生。
showOptionDialog 上面三个的统一

文件选择对话框

使用JFileChooser类可以弹出文件选择对话框。

弹出窗口的方法:

int showOpenDialog(Component parent) 
          弹出一个 "Open File" 文件选择器对话框。 
int showSaveDialog(Component parent) 
          弹出一个 "Save File" 文件选择器对话框。 
返回值为以下值:
JFileChooser.CANCEL_OPTION  点击了取消
JFileChooser.APPROVE_OPTION 确定
JFileChooser.ERROR_OPTION   如果发生错误或者该对话框已被解除 

其他设置的方法:

void setSelectedFile(File file) 
          设置选中的文件。 
void setMultiSelectionEnabled(boolean b) 
          设置是否可以选择多个文件
void setFileFilter(FileFilter filter) 
          设置文件过滤器。 
void setFileSelectionMode(int mode) 
          设置文件选择模式,值只能为以下值的一中:
            JFileChooser.FILES_ONLY  只选择文件
            JFileChooser.DIRECTORIES_ONLY 只选择文件夹
            JFileChooser.FILES_AND_DIRECTORIES 选择文件或文件夹
void setCurrentDirectory(File dir) 
          设置一打开时默认所处的目录
void setDialogTitle(String dialogTitle) 
          设置窗口标题

文件过滤器FileFilter是抽象类,使用它的子类FileNameExtensionFilter(文件扩展名过滤器)

构造方法:
FileNameExtensionFilter(String description, String... extensions) 
          使用指定的描述和文件扩展名创建一个 FileNameExtensionFilter。

自定义对话框

使用JDialog类即可实现自定义对话框。使用方法和Frame一样,都是先设ContentPane再往里加布局、加控件。

构造方法:
JDialog(Frame owner, String title, boolean modal) 
          创建一个具有指定标题、所有者 Frame 和模式的对话框。

和Frame的区别在于JDialog可设置是否模态(构造方法的第三个参数)【划重点!!】

如果为true:调用setVisible(true)后会进入阻塞状态,直到对话框关闭。

示例代码:

public class SwingDemo1 {
     
    private static void createGUI() {
     
        JFrame frame = new JFrame("Swing Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new FlowLayout());

        JButton jButton = new JButton("显示对话框");
        contentPane.add(jButton);
        jButton.addActionListener(new ActionListener() {
     
            @Override
            public void actionPerformed(ActionEvent e) {
     
                JDialog jDialog = new JDialog(frame,"对话框",true); //拥有者为frame,标题为“对话框”,模态为true
                jDialog.setSize(200,100);
                jDialog.setLocationRelativeTo(null);  //默认居中显示
                Container contentPane1 = jDialog.getContentPane(); //和JFrame一样
                contentPane1.setLayout(new FlowLayout());
                JTextField jTextField = new JTextField(10);
                JButton jButton1 = new JButton("确定");
                contentPane1.add(jTextField);
                contentPane1.add(jButton1);
                jButton1.addActionListener(new ActionListener() {
     
                    @Override
                    public void actionPerformed(ActionEvent e) {
     
                        jDialog.setVisible(false);   //按确定按钮关闭窗口
                    }
                });
                jDialog.setVisible(true); //显示对话框,同时代码运行到这里将阻塞。
                //关闭对话框后执行以下语句
                System.err.println("输入了:" + jTextField.getText());
            }
        });
    }
    public static void main(String[] args) throws Exception {
     
        String lookAndFeel = UIManager.getSystemLookAndFeelClassName();
        UIManager.setLookAndFeel(lookAndFeel);
        SwingUtilities.invokeLater(new Runnable() {
     
            public void run() {
     
                createGUI();
            }
        });
    }
}

程序发布

1.先生成jar包,idea的方法是

点开Project Structure,左边的面板那里选Artifacts,然后点加号,选第一个(JAR),然后选From modules …,选择Main Class,然后下面选copy to the output directory and …,关闭面板,在菜单栏的Build,点击Build Artifacts即可。

2.然后把jar移到某个目录下,在到jdk安装目录拷贝jre文件夹到这个目录。

如果没有jre文件夹,那就在JDK安装目录,按住Shift,鼠标右键,打开PowerShell,输入

bin\jlink.exe --module-path jmods --add-modules java.desktop --output jre

3.最后在jar所在的目录创建一个bat文件,内容为

@echo off

cd /d %~dp0

start jre\bin\javaw.exe -jar jar文件名.jar

完成之后,点击那个bat即可运行程序。

你可能感兴趣的:(Java基础,swing,gui,java)