Java基础 项目实例五 简易聊天系统
项目实例五 简易聊天系统
- 一、前置知识
- 二、AWT的基础使用
- 三、实现cardPanel卡片布局----卡片切换
- 四、聊天界面实现前置知识
- 五、GuiChat简易聊天系统(一个成熟的聊天代码)
- 六、WeiChat简易聊天系统(一个不成熟的聊天代码)
一、前置知识
- AWT与Swing
AWT:抽象窗口工具包,重量级控件。
Swing:AWT基础上,建立的一套图形界面系统,轻量级空间。(较之AWT界面更为美观)
轻量级组件的缺点则是执行速度较慢,优点就是可以在所有平台上采用统一的行为。 - AWT事件监听:
事件源(组件)、事件(Event)、监听器(Listener)、事件处理(引发事件后处理方式–处理代码)。 - public void windowOpened(windowEvent e):方法,窗口启动时自动执行。
(注:可以实现弹出窗口,若要关闭窗口则关闭程序;可以实现启动时加载文字信息;可以实现弹出提示信息。) - 流程布局将组件布置在定向流中,流向由容器的componentOrientation属性确定,可以是两个值之一:
- ComponentOrientation.LEFT_TO_RIGHT
- ComponentOrientation.RIGHT_TO_LEFT
- 流程布局通常用于布置面板中的按钮。 它可以水平排列按钮,直到不再有按钮在同一行上。 线对齐由align属性确定。 可能的值是:
LEFT、RIGHT、CENTER、LEADING、TRAILING - 监听器有:窗口监听器、键盘监听器、鼠标监听器、动作监听器。
- 五种布局管理器:
- FlowLayout、BorderLayout、GridLayout、GridBagLayout、CardLayout。
- FlowLayout:基本布局,从左到右,从上至下。
- BorderLayout:边界布局管理器,东西南北中,五个方位。
- GridLayout:网格布局,划分区块大小相同。
- GridBagLayout:网格包布局,网格布局升级,划分区块大小可不一致。
- CardLayout:卡片布局。切换程序。(常用:卡片布局注册到监听器中,监听器绑定按钮,实现切换程序页面。)
二、AWT的基础使用
package cn.itcast.test4; import java.awt.*; import java.awt.event.*; public class Javatest7 {/***@Title Javatest7.java*@description TODO*@time 2020-4-20 上午12:14:49*@author 羽落清泫*@version 1.0**/public static void main(String[] args) {//创建窗体对象final Frame f= new Frame("AWT窗口绘制"); //创建一个名为AWT窗口绘制的窗体//设置窗体属性// 设置窗体中的布局管理器为FlowLayout,所有组件左对齐,水平间距为20,垂直间距为30f.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 30)); //LEFT、RIGHT、CENTER、LEADING、TRAILING // f.setTitle("关闭窗口"); //该窗口名设置,比Frame定义名优先级要高f.setSize(800,600); //f.setSize(600,800);// 设置窗体大小f.setLocation(550,270); //f.setLocation(550,270);// 设置窗体显示的位置 //------------------------------------------------- //适配器类,实现重写方法,点右上×,可关闭窗口//个人理解:一个窗口监听器,点击窗口关闭则关闭f.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){System.exit(0);}});TextField tf = new TextField(40); //单行文本框,长度40f.add(tf);//一个键盘事件监听,tf.addKeyListener(new KeyAdapter() {public void keyPressed(KeyEvent e){ //键盘监听int code = e.getKeyCode(); //getKeyChar():处理的是比较高层的事件,返回的是每欠敲击键盘后得到的字符(中文输入法下就是汉字)。//getKeyCode()键盘上每一个按钮都有对应码(Code),可用来查知用户按了什么键//getKeyModifiersText()方法可返回修饰键的字符串,如返回“Shift”字符串或是“Ctrl+Shift”字符串, 不过你要先传入modifiers参数。if(!(code>=KeyEvent.VK_0 && code<=KeyEvent.VK_9)){ //VK_0 && VK_9:定义数据字符0~9System.out.println("必须是0-9数字"); //经测试有Bug:当中文输入法时,按出一串字符,以回车方式输入文本框中将不会提示[必须是0-9数字].}}}); //-----------------------------------------------f.setVisible(true); // 设置窗体可见} }
三、实现cardPanel卡片布局----卡片切换
package cn.itcast.test4; import java.awt.*; import java.awt.event.*; public class Javatest8 {/***@Title Javatest8.java*@description 简易聊天系统--(swing体系)*@time 2020-4-20 下午2:53:14*@author 羽落清泫*@version 1.0**/public static void main(String[] args) {new Chat();} } //定义Chat继承Frame类,实现ActionListener接口 class Chat extends Frame implements ActionListener {private static final long serialVersionUID = 1L;Button but1,but2; //定义两个按钮,实现点击按钮,面板切换Panel p1=new Panel(); //p1面板:实现页面内容展示Panel p2=new Panel(); //p2面板,封装按钮,实现展示按钮CardLayout cardLayout = new CardLayout();// 定义卡片布局对象public Chat(){ // 定义构造方法,设置(卡片布局管理器的)属性setTitle("简易聊天系统--(Swing体系)"); //设置窗口名setSize(800, 600); // 设置窗体大小setLocation(550,270); //f.setLocation(550,270);// 设置窗体显示的位置setVisible(true);// 为窗口添加关闭事件监听器this.addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) {Chat.this.dispose();}});p1.setLayout(cardLayout); // 调用定义的布局对象,设置p1面板对象为卡片布局 //-------------------------------------------------------// 在cardPanel面板对象中添加2个文本标签Label b1=new Label("第一个界面", Label.CENTER);p1.add(b1);// 创建两个按钮对象but1 = new Button("第一张卡片");but2 = new Button("第二张卡片");//按钮对象绑定动作监听器but1.addActionListener(this);but2.addActionListener(this);//按钮绑定面板p2.add(but1);p2.add(but2);// 将p1面板放置在窗口边界布局的中间,窗口默认为边界布局this.add(p1, BorderLayout.CENTER);// 将p2面板放置在窗口边界布局的北区,this.add(p2, BorderLayout.NORTH); //NORTH、SOUTH、CUNTER、EAST、WEAST} //------------------------------------------//实现按钮的监听触发,并对触发事件做出相应的处理(动作监听器)public void actionPerformed(ActionEvent e) {// // 切换p1面板中当前组件后一个面板,若当前面板为最后一个组件,则显示第一个面板。 // if(e.getSource()==but1){// cardLayout.next(p1); // } // 切换p1面板中当前组件前一个面板 // if(e.getSource()==but2){// cardLayout.previous(p1); // }if(e.getSource()==but1){cardLayout.first(p1);this.setTitle("聊天页");}if(e.getSource()==but2){cardLayout.last(p1);this.setTitle("展示信息页");}} //------------------------------------------ }
四、聊天界面实现前置知识
- . 网络模型:OSI(开放系统互连)
- IP地址:网络中设备的地址(数字或主机名)(InetAddress)
- 端口号:用于表示进程的逻辑地址,有效端口:0-65535。(0-1024为系统保留端口。)
- UDP:不建立连接,不可靠协议,速度快。
TCP:建立连接,形成传输数据的通道。 - UDP方法:
- DatagramPacket:UDP发送端方法。
- DatagramSocket:UDP接收端方法。
五、GuiChat简易聊天系统(一个成熟的聊天代码)
package cn.test; import java.io.*; import java.net.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GuiChat extends JFrame{private static final long serialVersionUID = 1L; 赋予一个UID,消除GuiChat黄色警告private static final int DEFAULT_PORT = 8899;// 把主窗口分为NORTH、CEMTER和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; // 端口不正确重新填写}// 启动DatagramSocketInetAddress localAddress = null;datagramSocket = new DatagramSocket(port);startListen(); // 调用startListen方法// 在stateLB中显示程序监听的端口号try {localAddress = InetAddress.getLocalHost();} catch (UnknownHostException e) {// TODO Auto-generated catch blocke.printStackTrace();}stateLB.setText("本机IP为:"+localAddress.getHostAddress()+","+"已在 " + 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];// 创建DatagramPacketp = 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();} }
六、WeiChat简易聊天系统(一个不成熟的聊天代码)
package cn.itcast.test4; import java.awt.*; import java.awt.event.*; import javax.swing.*;import java.io.*; import java.net.*; public class Javatest9 {/***@Title Javatest9.java*@description 简易聊天系统*@time 2020-4-20 下午5:03:54*@author 羽落清泫*@version 1.0**/public static void main(String[] args) {// 实例化Chat,调用new WeiChat();new ServerDemo(); } } class WeiChat{// private static final long serialVersionUID = 1L;//赋予一个UID,消除Chat黄色警告private DatagramSocket datagramSocket; // 用于后面功能的实现private JTextArea jt1;public WeiChat(){JFrame f = new JFrame("简易聊天系统--发送端"); // f.setTitle("Swing体系--简易聊天系统");f.setSize(400, 600); // 设置窗体大小f.setLocation(750,270); //f.setLocation(550,270);// 设置窗体显示的位置 // setResizable(false); // 窗口大小不可调整 // setLocationRelativeTo(null); // 窗口居中 // // 设置流式布局管理器 // f.setLayout(new FlowLayout()); //--------------------------------------//创建菜单项JMenuBar menuBar = new JMenuBar(); // 创建菜单栏f.setJMenuBar(menuBar); // 将菜单栏添加到JFrame窗口中JMenu menu = new JMenu("操作"); // 创建菜单JMenu menu2 = new JMenu("测试1"); // 创建菜单menuBar.add(menu); // 将菜单添加到菜单栏上menuBar.add(menu2);// 创建菜单项JMenuItem item1 = new JMenuItem("弹出窗口");JMenuItem item2 = new JMenuItem("关闭");JMenuItem item3 = new JMenuItem("模态对话框");JMenuItem item4 = new JMenuItem("非模态对话框");menu.add(item1);menu.add(item2);menu2.add(item3);menu2.addSeparator(); // 添加一个分隔符menu2.add(item4); //--------------------------------------//-------------窗口NORTH---------------------JLabel jl1=new JLabel("标签"); // 显示监听状态jl1.setHorizontalAlignment(JLabel.RIGHT); //文本设置左右对齐方法f.add(jl1,BorderLayout.NORTH);//-------------窗口CONTER--------------------jt1 = new JTextArea("在此处显示聊天内容:",80, 20);jt1.setEditable(false); //设置文本域只显示,不可编辑jt1.setMargin(new Insets(5, 5, 5, 5)); //设置文本(聊天信息)在文本域内显示的边距jt1.setBackground(new Color(222, 222, 222)); //颜色最大值(255,255,255)jt1.setSize(100,300);f.add(new JScrollPane(jt1), BorderLayout.CENTER);//-------------窗口SOUTH-----------JPanel jl0=new JPanel(new BorderLayout()); //用于装所有组件,放到窗口南部JPanel jl2 = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5)); //按流式布局装入按钮等组件final JTextArea jt2=new JTextArea(5, 10); //用于文本输入 // jt2.setPreferredSize(new Dimension (30,30)); //final JTextField ipTextF = new JTextField("192.168.151.161", 8); //设置默认IP地址为:"127.0.0.1"final JTextField remotePort = new JTextField(String.valueOf("8859"), 3); //设置默认端口号为:8859JButton but11 = new JButton("发送");jl2.add(ipTextF);jl2.add(remotePort);jl2.add(but11);jl0.add(new JScrollPane(jt2),BorderLayout.CENTER);jl0.add(jl2,BorderLayout.SOUTH);f.add(jl0,BorderLayout.SOUTH);//遇到的问题,当窗口长宽过大时,窗口内文本(域)标签会自适应窗口,无法设置文本标签与窗口之间的(间隔)留白--边框间距问题---------//试解决方案1:设置空的标签组件,设置BorderLayout布局为EAST、WEST,是否解决(待定)//试解决方案2:设置其它面板,按方案一的方法,试解决边框间距问题(待定)// 设置点击关闭按钮时的默认操作f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);f.setVisible(true); //---------------------------------------- //--------------------------------------final JLabel label = new JLabel();final JDialog dialog = new JDialog(f, "Dialog"); // 定义一个JDialog对话框final JButton btn3 = new JButton("确定"); // 创建按钮对象dialog.add(btn3); // 在对话框的内容面板添加按钮// 为"模态对话框"按钮添加点击事件item3.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {dialog.setSize(220, 150); // 设置对话框大小dialog.setLocation(830, 500); // 设置对话框位置dialog.setLayout(new FlowLayout()); // 设置布局管理器// 设置对话框为模态dialog.setModal(true);// 如果JDialog窗口中没有添加了JLabel标签,就把JLabel标签加上if (dialog.getComponents().length == 1) {dialog.add(label);}// 否则修改标签的内容label.setText("模式对话框,点击确定按钮关闭");// 显示对话框dialog.setVisible(true);}});// 为"模态对话框"按钮添加点击事件item4.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {dialog.setSize(220, 150); // 设置对话框大小dialog.setLocation(830, 500); // 设置对话框位置dialog.setLayout(new FlowLayout()); // 设置布局管理器// 设置对话框为非模态dialog.setModal(false);// 如果JDialog窗口中没有添加了JLabel标签,就把JLabel标签加上if (dialog.getComponents().length == 1) {dialog.add(label);}// 否则修改标签的内容label.setText("模式对话框,点击确定按钮关闭");// 显示对话框dialog.setVisible(true);}});// 为对话框中的按钮添加点击事件btn3.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {dialog.dispose();}});//item1功能:弹出窗口item1.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {// 创建一个JDialog窗口dialog.setTitle("弹出窗口,测试使用...");dialog.setSize(400, 200);dialog.setLocation(730, 500);dialog.setVisible(true);}});//item2功能:关闭窗体item2.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {System.exit(0);}}); //---------------------------------------//消息发出与接收代码//1. 消息发出but11.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){//获取信息发送的ip地址与端口String ipAddress=ipTextF.getText();String remote=remotePort.getText();//一般来说此处需要验证ip地址与端口号是否正确try {//获得发送的内容String sendConent =jt2.getText();//获得内容放入一个数组中—————转换成ByteBuf后发送 byte[]byte[] buf=sendConent.getBytes(); //byte[] buf=sendConent.getBytes("UTF-8");//将信息展示到自己的聊天界面jt1.append("\n"+"本地"+ipAddress+":"+remote+"说:"+" "+jt2.getText()+"\n");//发送数据-------datagramSocket方法需要抛出异常datagramSocket=new DatagramSocket();datagramSocket.send(new DatagramPacket(buf, buf.length,InetAddress.getByName(ipAddress), Integer.parseInt(remote)));//datagramSocket.send(new DatagramPacket(buf, buf.length,InetAddress.getByName(ipAddress), Integer.parseInt(remotePort)));//设置发送后,输入框清空jt2.setText(null);//------------以下为异常抛出,原因暂不知-----------} catch (SocketException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} catch (NumberFormatException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} catch (UnknownHostException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}});//2. 设置监听的端口,默认为8859int port = 8859;while(true){try{ // 判断端口号是否在1-65535之间port = Integer.parseInt(JOptionPane.showInputDialog(f,"请输入端口号","端口号",JOptionPane.QUESTION_MESSAGE));if (port < 1 || port > 65535) { //JOptionPane:可以轻松地弹出一个标准对话框,提示用户获取值或通知他们某些东西 //QUESTION_MESSAGE:用于问题。 throw new RuntimeException("端口号超出范围");}}catch(Exception e){JOptionPane.showMessageDialog(null,"你输入的端口不正确,请输入1-65535之间的数");continue; // 端口不正确重新填写}//启动DatagramSocketInetAddress localAddress = null; //表示Internet协议(IP)地址。try {datagramSocket = new DatagramSocket(port);startChat();} catch (SocketException e2) {// TODO Auto-generated catch blocke2.printStackTrace();}try {localAddress = InetAddress.getLocalHost(); //获取本机IP地址} catch (UnknownHostException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}jl1.setText("本机IP为:"+localAddress.getHostAddress()+","+"已在 " + port + " 端口监听");break;} } //-----------------------------------------//3. 定义一个接收消息的方法,可被调用private void startChat(){new Thread(){private DatagramPacket p;//DatagramPacket:实现无连接分组传送服务,每个消息从一台机器路由到另一台机器public void run(){byte[] buf=new byte[1024];//调用DatagramPacket,并与数组绑定p=new DatagramPacket(buf,buf.length);while(!datagramSocket.isClosed()){try {datagramSocket.receive(p); // 接收聊天消息// 添加到聊天记录框jt1.append(p.getAddress().getHostAddress()+ ":"+ ((InetSocketAddress) p.getSocketAddress()).getPort() + " 对我说:\n"+ new String(p.getData(), 0, p.getLength())+ "\n\n");// 使滚动条自动滚动到最底端jt1.setCaretPosition(jt1.getText().length());} catch (IOException e) {e.printStackTrace();}}}}.start();}; } class ServerDemo {// private static final long serialVersionUID = 1L;//赋予一个UID,消除Chat黄色警告private DatagramSocket datagramSocket; // 用于后面功能的实现private JTextArea jt1;public ServerDemo(){JFrame f = new JFrame("简易聊天系统--发送端"); // f.setTitle("Swing体系--简易聊天系统");f.setSize(400, 600); // 设置窗体大小f.setLocation(250,270); //f.setLocation(550,270);// 设置窗体显示的位置 // setResizable(false); // 窗口大小不可调整 // setLocationRelativeTo(null); // 窗口居中 // // 设置流式布局管理器 // f.setLayout(new FlowLayout()); //--------------------------------------//创建菜单项JMenuBar menuBar = new JMenuBar(); // 创建菜单栏f.setJMenuBar(menuBar); // 将菜单栏添加到JFrame窗口中JMenu menu = new JMenu("操作"); // 创建菜单JMenu menu2 = new JMenu("测试1"); // 创建菜单menuBar.add(menu); // 将菜单添加到菜单栏上menuBar.add(menu2);// 创建菜单项JMenuItem item1 = new JMenuItem("弹出窗口");JMenuItem item2 = new JMenuItem("关闭");JMenuItem item3 = new JMenuItem("模态对话框");JMenuItem item4 = new JMenuItem("非模态对话框");menu.add(item1);menu.add(item2);menu2.add(item3);menu2.addSeparator(); // 添加一个分隔符menu2.add(item4); //--------------------------------------//-------------窗口NORTH---------------------JLabel jl1=new JLabel("标签"); // 显示监听状态jl1.setHorizontalAlignment(JLabel.RIGHT); //文本设置左右对齐方法f.add(jl1,BorderLayout.NORTH);//-------------窗口CONTER--------------------jt1 = new JTextArea("在此处显示聊天内容:",80, 20);jt1.setEditable(false); //设置文本域只显示,不可编辑jt1.setMargin(new Insets(5, 5, 5, 5)); //设置文本(聊天信息)在文本域内显示的边距jt1.setBackground(new Color(222, 222, 222)); //颜色最大值(255,255,255)jt1.setSize(100,300);f.add(new JScrollPane(jt1), BorderLayout.CENTER);//-------------窗口SOUTH-----------JPanel jl0=new JPanel(new BorderLayout()); //用于装所有组件,放到窗口南部JPanel jl2 = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5)); //按流式布局装入按钮等组件final JTextArea jt2=new JTextArea(5, 10); //用于文本输入 // jt2.setPreferredSize(new Dimension (30,30)); //final JTextField ipTextF = new JTextField("192.168.151.161", 8); //设置默认IP地址为:"127.0.0.1"final JTextField remotePort = new JTextField(String.valueOf("11111"), 3); //设置默认端口号为:11111JButton but11 = new JButton("发送");jl2.add(ipTextF);jl2.add(remotePort);jl2.add(but11);jl0.add(new JScrollPane(jt2),BorderLayout.CENTER);jl0.add(jl2,BorderLayout.SOUTH);f.add(jl0,BorderLayout.SOUTH);//遇到的问题,当窗口长宽过大时,窗口内文本(域)标签会自适应窗口,无法设置文本标签与窗口之间的(间隔)留白--边框间距问题---------//试解决方案1:设置空的标签组件,设置BorderLayout布局为EAST、WEST,是否解决(待定)//试解决方案2:设置其它面板,按方案一的方法,试解决边框间距问题(待定)// 设置点击关闭按钮时的默认操作f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);f.setVisible(true); //---------------------------------------- //-------------------------------------- // final JLabel label = new JLabel();final JDialog dialog = new JDialog(f, "Dialog"); // 定义一个JDialog对话框final JButton btn3 = new JButton("确定"); // 创建按钮对象dialog.add(btn3); // 在对话框的内容面板添加按钮//item2功能:关闭窗体item2.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {System.exit(0);}}); //---------------------------------------//消息发出与接收代码//1. 消息发出but11.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){//获取信息发送的ip地址与端口String ipAddress=ipTextF.getText();String remote=remotePort.getText();//一般来说此处需要验证ip地址与端口号是否正确try {//获得发送的内容String sendConent =jt2.getText();//获得内容放入一个数组中—————转换成ByteBuf后发送 byte[]byte[] buf=sendConent.getBytes(); //byte[] buf=sendConent.getBytes("UTF-8");//将信息展示到自己的聊天界面jt1.append("\n"+"本地"+ipAddress+":"+remote+"说:"+" "+jt2.getText()+"\n");//发送数据-------datagramSocket方法需要抛出异常datagramSocket=new DatagramSocket();datagramSocket.send(new DatagramPacket(buf, buf.length,InetAddress.getByName(ipAddress), Integer.parseInt(remote)));//datagramSocket.send(new DatagramPacket(buf, buf.length,InetAddress.getByName(ipAddress), Integer.parseInt(remotePort)));//设置发送后,输入框清空jt2.setText(null);//------------以下为异常抛出,原因暂不知-----------} catch (SocketException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} catch (NumberFormatException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} catch (UnknownHostException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}});//2. 设置监听的端口,默认为11111int port = 11111;while(true){try{ // 判断端口号是否在1-65535之间port = Integer.parseInt(JOptionPane.showInputDialog(f,"请输入端口号","端口号",JOptionPane.QUESTION_MESSAGE));if (port < 1 || port > 65535) { //JOptionPane:可以轻松地弹出一个标准对话框,提示用户获取值或通知他们某些东西 //QUESTION_MESSAGE:用于问题。 throw new RuntimeException("端口号超出范围");}}catch(Exception e){JOptionPane.showMessageDialog(null,"你输入的端口不正确,请输入1-65535之间的数");continue; // 端口不正确重新填写}//启动DatagramSocketInetAddress localAddress = null; //表示Internet协议(IP)地址。try {datagramSocket = new DatagramSocket(port);} catch (SocketException e2) {// TODO Auto-generated catch blocke2.printStackTrace();}startChat();try {localAddress = InetAddress.getLocalHost(); //获取本机IP地址} catch (UnknownHostException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}jl1.setText("本机IP为:"+localAddress.getHostAddress()+","+"已在 " + port + " 端口监听");break;} } //-----------------------------------------//3. 定义一个接收消息的方法,可被调用private void startChat(){new Thread(){private DatagramPacket p;//DatagramPacket:实现无连接分组传送服务,每个消息从一台机器路由到另一台机器public void run(){byte[] buf=new byte[1024];//调用DatagramPacket,并与数组绑定p=new DatagramPacket(buf,buf.length);while(!datagramSocket.isClosed()){try {datagramSocket.receive(p); // 接收聊天消息// 添加到聊天记录框jt1.append(p.getAddress().getHostAddress()+ ":"+ ((InetSocketAddress) p.getSocketAddress()).getPort() + " 对我说:\n"+ new String(p.getData(), 0, p.getLength())+ "\n\n");// 使滚动条自动滚动到最底端jt1.setCaretPosition(jt1.getText().length());} catch (IOException e) {e.printStackTrace();}}}}.start();}; } //--------------其他测试:可删除----------------------------- //public class test6 {// /** // *@Title test6.java // *@description TODO // *@time 2020-4-20 下午9:07:57 // *@author 羽落清泫 // *@version 1.0 // * @throws IOException // **/ // public static void main(String[] args) throws IOException {// // TODO Auto-generated method stub // InetAddress localAddress = InetAddress.getLocalHost(); // InetAddress remoteAddress = InetAddress.getByName("www.baidu.com"); // System.out.println("本机的IP地址:" + localAddress.getHostAddress()); // System.out.println("itcast的IP地址:" + remoteAddress.getHostAddress()); // System.out.println("itcast的主机名为:" + remoteAddress.getHostName()); // } //} //该代码BUG待更新中......emmmm......
End.
Java基础 项目实例五 简易聊天系统相关推荐
- Java校招笔试题-Java基础部分(五)
导语 Java 面试题集2021版 Java基础部分五 47.String 和String Buffer的区别 48.StringBuffer和StringBuilder的区别 49.数组有没有l ...
- Java实习生常规技术面试题每日十题Java基础(五)
目录 1.启动一个线程是用run()还是start()? . 2.线程的基本状态以及状态之间的关系. 3.Set和List的区别,List和Map的区别? 4.同步方法.同步代码块区别? 5.描述Ja ...
- Java基础系列五 面向对象程序设计
Java基础系列第一章 初识Java语言 Java基础系列第二章 Java语言基础 Java基础系列第三章 Java流程控制 Java基础系列第四章 Java数组与字符串 Java基础系列第五章 面向 ...
- Java基础知识(五) 字符串与数组
Java基础知识 字符串与数组 1. 字符串的创建与存储的机制是什么 2. "==".equals和hashCode有什么区别 3. String.StringBuffer.Str ...
- Java基础(五)-类的特性
文章首发及后续更新:https://mwhls.top/1277.html 新的更新内容请到mwhls.top查看. 无图/无目录/格式错误/更多相关请到上方的文章首发页面查看. Java基础目录 这 ...
- java基础知识五、六、七、八
第五章 在较大的数之前先增加较小数是减小误差的一种方法. 第六章 方法签名(Method Signature)指方法名称.参数类型和参数数量.java编译器根据方法签名决定使用哪个方法. 调用方法时, ...
- Java基础 第五节 第七课
Stream 流 概述 传统集合的多步遍历代码 循环遍历的弊端 Stream 的更优写法 流式思想概述 步骤方案 元素队列 获取流 根据 Collection 获取流 根据 Map 获取流 根据数组获 ...
- Java基础 第五节 第九课
方法引用 概述 冗余的 Lambda 场景 用方法改进代码 问题分析 代码展示 方法引用符 语义分析 推导与省略 通过对象名成员方法 通过类名称引用静态方法 通过 super 引用成员方法 通过 th ...
- Java基础系列五之API
对象数组 定义:用来存储对象的数组 Student[] student = new Student[5] ; Arrays:针对数组操作的工具类 (提供了针对数组排序的方法和二分搜索法) publi ...
最新文章
- (JavaWeb)ServletContext对象
- Windows Mobile 6 中为开发人员提供的新功能(1)
- JAVA——Windows双击jar包为可执行操作
- [导入]PHP通用分页类
- scrapy架构解析
- 是什么样的骚操作让应用上线节省90%的时间 1
- Java基础篇2——运算符
- 【OpenCV】OpenCV函数精讲之 -- 颜色空间缩减及LUT函数
- 交换机的RTU License 华为S5700交换机
- Zabbix5 安装教程
- ubuntu-创建桌面快捷方式
- Python函数combination
- UEditor自定义表情包
- DDIM代码详细解读(1):数据集加载、类别条件信息读取、关键超参数解析
- 华为交换机5720常用命令
- 【Python】在Anaconda中设置清华镜像站并解决“http error“问题
- 让工作快乐起来500强企业推崇的新理念
- 经典黑白搭配 现代简约风格设计美学精神
- Cadence OrCAD Capture 如何批量替换元器件
- 队列BlockingQueue