一、 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
+ " 说:\n" + inputTextArea.getText() + "\n\n");
// 添加内容后,使滚动条自动滚动到最底端
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() + " 对我说:\n"
+ new String(p.getData(), 0, p.getLength())
+ "\n\n");
// 使滚动条自动滚动到最底端
centerTextArea.setCaretPosition(centerTextArea
.getText().length());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
public GuiChat() {
setUpUI();
initSocket();
setListener();
}
public static void main(String[] args) {
new GuiChat();
}
}