一、 Swing相关的概念:
- 1. GUI:(Graphical User Interface):图形化用户界面,通过图形化的方式提供与用户交互的平台,向用户展示信息、收集用户提交的数据。
- 2. Swing:是Java用于开发图形化用户界面的一个模块,其中提供了类似于HTML的一些组件,如:按钮、输入框、文本域等。
- 3. JFrame:是一个容器,是在进行Swing组件开发时的一个组织管理其他组件的特殊类,类似于Windows中的窗口,具体使用过程中可以通过“继承他”、“创建它的对象”访问其属性和方法。
- 4. JPanel:面板,若将整个JFrame窗口设计为一种单一的布局模式,不能满足我们设计的需求,因此会将组件(如:按钮、输入框、文本域等)放置到JPanel中,再将JPanel放置到JFrame中。
二、 Swing中常用的组件:
- 1. 按钮组件(JButton)
- 2. 文本框(JTextField)
- 3. 密码框(JPasswordField)
- 4. 文本域(JTextArea)
- 5. 标签(JLabel)
- 6. 单选按钮(JRadioButton)
- 7. 复选按钮(JCheckBox)
- 8. 下拉按钮(JComboBox)
- 9. 列表框(JList)
- 10. 滚动窗体组件(JScrollPane)容器类组件
- 11. 面板(JPanel)容器类组件
三、 流式布局管理器:(FlowLayout)
流式布局管理器就像流水一样,也像打字时从上到下,从左到右依次排列。
代码参见:com.oop.ch14.FlowLayoutTest
package com.oop.ch14; import java.awt.FlowLayout; import javax.swing.JButton; import javax.swing.JFrame; /** * 练习流式布局管理器的使用,从上到下,从左到右 */ public class FlowLayoutTest extends JFrame { private static final long serialVersionUID = 1L; public static void main(String[] args) { FlowLayoutTest flowLayoutTest = new FlowLayoutTest(); flowLayoutTest.view(); } private void view() { //1、创建组件元素(以按钮为例) JButton jb1,jb2,jb3,jb4,jb5; jb1 = new JButton("按钮1"); jb2 = new JButton("按钮2"); jb3 = new JButton("按钮3"); jb4 = new JButton("按钮4"); jb5 = new JButton("按钮5"); //2、将以上创建号的组件元素放置到JFrame窗体中 this.add(jb1); this.add(jb2); this.add(jb3); this.add(jb4); this.add(jb5); //3、设置JFrame窗体的一些参数 //设置布局管理器为流式布局,对齐方式、行间距、列间距 this.setLayout(new FlowLayout(FlowLayout.CENTER,5,10)); //设置在关闭窗体时默认要执行的操作,通常时退出程序本身 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置窗体起始位置、宽高 this.setBounds(200, 150, 200, 300); //设置窗体可见性 this.setVisible(true); //设置窗体标题 this.setTitle("流式布局管理器"); } }
四、 网格布局管理器:(GridLayout)
网格布局管理器与HTML中的table表格一样,需要设置行数、列数、行间距、列间距
代码参见:com.oop.ch14. GridLayoutTest
package com.oop.ch14; import java.awt.GridLayout; import javax.swing.JButton; import javax.swing.JFrame; /** * 练习网格布局管理器GridLayout * 需要设置行数、列数、行间距、列间距 * */ public class GridLayoutTest { public static void main(String[] args) { JFrame jFrame = new JFrame("网格布局管理器"); //1、创建组件元素(以按钮为例) JButton jb1,jb2,jb3,jb4,jb5; jb1 = new JButton("按钮1"); jb2 = new JButton("按钮2"); jb3 = new JButton("按钮3"); jb4 = new JButton("按钮4"); jb5 = new JButton("按钮5"); //2、将以上创建号的组件元素放置到JFrame窗体中 jFrame.add(jb1); jFrame.add(jb2); jFrame.add(jb3); jFrame.add(jb4); jFrame.add(jb5); //3、设置JFrame窗体的一些参数 //设置布局管理器为网格布局,需要设置行数、列数、列间距、行间距 jFrame.setLayout(new GridLayout(4,3,10,15)); //设置在关闭窗体时默认要执行的操作,通常时退出程序本身 jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置窗体起始位置、宽高 jFrame.setBounds(200, 150, 200, 300); //设置窗体可见性 jFrame.setVisible(true); } }
五、 边界布局管理器:(BorderLayout)
将容器分为东、南、西、北、中五个组成部分,通过String类型的静态常量可以设置组件元素放置在容器的哪个位置,是默认的布局管理器。
代码参见:com.oop.ch14. BorderLayoutTest
package com.oop.ch14; import java.awt.BorderLayout; import javax.swing.JButton; import javax.swing.JFrame; /** * 练习使用边界 布局管理器BorderLayout *将容器分为东、南、西、北、中五个组成部分, *通过String类型的静态常量可以设置组件元素放置在容器的哪个位置,是默认的布局管理器。 */ public class BorderLayoutTest { public static void main(String[] args) { JFrame jFrame = new JFrame("边界布局管理器"); //1、创建组件元素(以按钮为例) JButton jb1,jb2,jb3,jb4,jb5; jb1 = new JButton("按钮1"); jb2 = new JButton("按钮2"); jb3 = new JButton("按钮3"); jb4 = new JButton("按钮4"); jb5 = new JButton("按钮5"); //2、将以上创建号的组件元素放置到JFrame窗体中 //通过String类型的静态常量可以设置组件元素放置在容器的哪个位置 jFrame.add(jb1,BorderLayout.EAST); jFrame.add(jb2,BorderLayout.SOUTH); jFrame.add(jb3,BorderLayout.WEST); jFrame.add(jb4,BorderLayout.NORTH); jFrame.add(jb5,BorderLayout.CENTER); //3、设置JFrame窗体的一些参数 //设置在关闭窗体时默认要执行的操作,通常时退出程序本身 jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置窗体起始位置、宽高 jFrame.setBounds(200, 150, 300, 300); //设置窗体可见性 jFrame.setVisible(true); } }
六、 使用面板布局(JPanel):
以上是将组件元素直接放置在窗体JFrame中,整个窗体就是一种布局管理器,不利于完成更复杂的布局,因此需要使用JPanel面板。使用的流程:组件==》面板==》窗体。
代码参见:com.oop.ch14. JPanelTest
package com.oop.ch14; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.GridLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; /** * 练习使用面板JPanel * 以上是将组件元素直接放置在窗体JFrame中,整个窗体就是一种布局管理器, * 不利于完成更复杂的布局,因此需要使用JPanel面板。 * * 使用的流程:组件==》面板==》窗体。 * */ public class JPanelTest { public static void main(String[] args) { JFrame jFrame = new JFrame("面板布局"); //1、创建组件元素:按钮、输入框、密码框 JButton jb1,jb2,jb3,jb4,jb5; jb1 = new JButton("按钮1"); jb2 = new JButton("按钮2"); jb3 = new JButton("按钮3"); jb4 = new JButton("按钮4"); jb5 = new JButton("按钮5"); JLabel jLabel1 ; JLabel jLabel2; jLabel1 = new JLabel("用户名:"); jLabel2 = new JLabel("密 码:"); //可写30个字符 JTextField jTextField = new JTextField(30); JPasswordField jPasswordField = new JPasswordField(30); //2、创建面板:用于放置上中下三块内容 JPanel jPanel1 = new JPanel() ; JPanel jPanel2 = new JPanel() ; JPanel jPanel3 = new JPanel() ; //设置面板布局 jPanel1.setLayout(new GridLayout(3,2,10,5)); jPanel2.setLayout(new FlowLayout(FlowLayout.LEFT,5,10)); jPanel3.setLayout(new BorderLayout(5,5)); //组件放入面板 jPanel1.add(jb1); jPanel1.add(jb2); jPanel1.add(jb3); jPanel1.add(jb4); jPanel1.add(jb5); jPanel2.add(jLabel1); jPanel2.add(jTextField); jPanel3.add(jLabel2,BorderLayout.WEST); jPanel3.add(jPasswordField); //面板放入窗体 jFrame.add(jPanel1); jFrame.add(jPanel2); jFrame.add(jPanel3); //设置窗体布局 jFrame.setLayout(new FlowLayout(FlowLayout.CENTER,5,10)); //设置在关闭窗体时默认要执行的操作,通常是退出程序本身 jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置窗体起始位置、宽高 jFrame.setBounds(200, 150, 400, 300); //设置窗体可见性 jFrame.setVisible(true); } }
七、 使用卡片布局管理器(CardLayout):
是将组件元素放置在同一个位置,通过“事件”触发切换。
代码参见:com.oop.ch14. CardLayoutTest
package com.oop.ch14; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; /** *练习使用卡片布局管理器 * *将组件元素放置在同一个位置,通过“事件”触发切换。 */ public class CardLayoutTest { static CardLayout cardLayout = new CardLayout(); static JPanel jp_images = new JPanel(cardLayout); public static void main(String[] args) { JFrame jFrame = new JFrame("卡片布局管理器"); //1、定义需要的组件元素:面板、按钮 JPanel jp_image1,jp_image2,jp_image3; jp_image1 = new JPanel(); jp_image2 = new JPanel(); jp_image3 = new JPanel(); //设置图片面板的背景,模拟在卡片上放置一张图片 jp_image1.setBackground(Color.RED); jp_image2.setBackground(Color.GREEN); jp_image3.setBackground(Color.BLUE); //创建放置卡片的面板,同时将卡片布局管理器传入其中 //jp_images = new JPanel(cardLayout); //将放置了图片的子面板放置到jp_iamges中 jp_images.add(jp_image1); jp_images.add(jp_image2); jp_images.add(jp_image3); //定义jp_button面板放置按钮 JPanel jp_button; jp_button = new JPanel(); //准备两个按钮 JButton jb_pre,jb_next; jb_pre = new JButton("上一张"); jb_next = new JButton("下一张"); //将按钮放置到面板中 jp_button.add(jb_pre,BorderLayout.WEST); jp_button.add(jb_next,BorderLayout.EAST); //2、将已经包含了组件元素的两个面板放置到窗体中 jFrame.add(jp_images); jFrame.add(jp_button, BorderLayout.SOUTH); //3、设置JFrame窗体的一些参数 //设置在关闭窗体时默认要执行的操作,通常时退出程序本身 jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置窗体起始位置、宽高 jFrame.setBounds(200, 150, 400, 300); //设置窗体可见性 jFrame.setVisible(true); /** * 4、给上一张、下一张两个按钮添加点击事件 * 具体实施时需要通过”匿名内部类“来完成 * “匿名内部类”是一个方法中的一个类 * 但它没有名字,他要实现ActionListener接口,并实现其中的监听方法 */ jb_pre.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { cardLayout.previous(jp_images); } }); jb_next.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { cardLayout.next(jp_images); } }); } /* //如果实现ActionListener接口可以用实现方法的方式做 @Override public void actionPerformed(ActionEvent e) { }*/ }
使用Swing和网络编程实现的demo,可以在不同主机上进行聊天
package com.oop.ch14; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.io.IOException; import java.net.*; public class GuiChat extends JFrame { private static final int DEFAULT_PORT = 8899; // 把主窗口分为NORTH、CENTER和SOUTH三个部分 private JLabel stateLB; // 显示监听状态 private JTextArea centerTextArea; // 显示聊天记录 private JPanel southPanel; // 最下面的面板 private JTextArea inputTextArea; // 聊天输入框 private JPanel bottomPanel; // 放置 IP输入框,按钮等 private JTextField ipTextField; // IP输入框 private JTextField remotePortTF; // 端口号输入框 private JButton sendBT; // 发送按钮 private JButton clearBT; // 清除聊天记录按钮 private DatagramSocket datagramSocket; // 用于后面功能的实现 private void setUpUI() { // 初始化Swing窗口 // 初始化窗口 setTitle("GUI聊天"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400, 400); // 设置窗口的大小 setResizable(false); // 窗口大小不可调整 setLocationRelativeTo(null); // 窗口居中 // 窗口的NORTH部分 stateLB = new JLabel("当前还未启动监听"); stateLB.setHorizontalAlignment(JLabel.RIGHT); // 窗口的CENTER部分 centerTextArea = new JTextArea(); // 聊天记录显示区域 centerTextArea.setEditable(false); centerTextArea.setBackground(new Color(211, 211, 211)); // 窗口的SOUTH部分 southPanel = new JPanel(new BorderLayout()); inputTextArea = new JTextArea(5, 20);// 内容输入区域 bottomPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5)); ipTextField = new JTextField("127.0.0.1", 8); remotePortTF = new JTextField(String.valueOf(DEFAULT_PORT), 3); sendBT = new JButton("发送"); clearBT = new JButton("清屏"); bottomPanel.add(ipTextField); bottomPanel.add(remotePortTF); bottomPanel.add(sendBT); bottomPanel.add(clearBT); southPanel.add(new JScrollPane(inputTextArea), BorderLayout.CENTER); southPanel.add(bottomPanel, BorderLayout.SOUTH); // 添加窗口NORTH、CENTER、SOUTH部分的组件 add(stateLB, BorderLayout.NORTH); add(new JScrollPane(centerTextArea), BorderLayout.CENTER); add(southPanel, BorderLayout.SOUTH); setVisible(true); } private void setListener() { // 为sendBT按钮添加事件监听器 sendBT.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // 获取发送的目标ip地址和端口号 final String ipAddress = ipTextField.getText(); final String remotePort = remotePortTF.getText(); // 判断ip地址和端口号是否为空 if (ipAddress == null || ipAddress.trim().equals("") || remotePort == null || remotePort.trim().equals("")) { JOptionPane.showMessageDialog(GuiChat.this, "请输入IP地址和端口号"); return; } if (datagramSocket == null || datagramSocket.isClosed()) { JOptionPane.showMessageDialog(GuiChat.this, "监听不成功"); return; } // 获得需要发送的内容 String sendContent = inputTextArea.getText(); byte[] buf = sendContent.getBytes(); try { // 将发送的内容显示在自己的聊天记录中 centerTextArea.append("我对 " + ipAddress + ":" + remotePort + " 说: " + inputTextArea.getText() + " "); // 添加内容后,使滚动条自动滚动到最底端 centerTextArea.setCaretPosition(centerTextArea.getText() .length()); // 发送数据 datagramSocket.send(new DatagramPacket(buf, buf.length, InetAddress.getByName(ipAddress), Integer .parseInt(remotePort))); inputTextArea.setText(""); } catch (IOException e1) { JOptionPane.showMessageDialog(GuiChat.this, "出错了,发送不成功"); e1.printStackTrace(); } }; }); // 为clearBT按钮添加事件监听器 clearBT.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { centerTextArea.setText(""); // 清空聊天记录的内容 } }); } private void initSocket() { int port = DEFAULT_PORT; while (true) { try { if (datagramSocket != null && !datagramSocket.isClosed()) { datagramSocket.close(); } try { // 判断端口号是否在1-65535之间 port = Integer.parseInt(JOptionPane.showInputDialog(this, "请输入端口号", "端口号", JOptionPane.QUESTION_MESSAGE)); if (port < 1 || port > 65535) { throw new RuntimeException("端口号超出范围"); } } catch (Exception e) { JOptionPane.showMessageDialog(null, "你输入的端口不正确,请输入1-65535之间的数"); continue; // 端口不正确重新填写 } // 启动DatagramSocket datagramSocket = new DatagramSocket(port); startListen(); // 调用startListen方法 // 在stateLB中显示程序监听的端口号 stateLB.setText("已在 " + port + " 端口监听"); break; } catch (SocketException e) { // 端口号被占用重新填写 JOptionPane.showMessageDialog(this, "端口已被占用,请重新设置端口"); stateLB.setText("当前还未启动监听"); } } } private void startListen() { new Thread() { private DatagramPacket p; public void run() { byte[] buf = new byte[1024]; // 创建DatagramPacket p = new DatagramPacket(buf, buf.length); while (!datagramSocket.isClosed()) { try { datagramSocket.receive(p); // 接收聊天消息 // 添加到聊天记录框 centerTextArea.append(p.getAddress().getHostAddress() + ":" + ((InetSocketAddress) p.getSocketAddress()) .getPort() + " 对我说: " + new String(p.getData(), 0, p.getLength()) + " "); // 使滚动条自动滚动到最底端 centerTextArea.setCaretPosition(centerTextArea .getText().length()); } catch (IOException e) { e.printStackTrace(); } } } }.start(); } public GuiChat() { setUpUI(); initSocket(); setListener(); } public static void main(String[] args) { new GuiChat(); } }