图18.28 主界面(不含菜单)及其变量命名
图 18.29快捷键编辑器
此时初步完成后的菜单界面如图18.30所示。其中图(1)为大纲视图的内容,图(2)为三个菜单展开后所显示的外观的合成图。读者可注意到三个单选按钮都是被选中状态的,这是
(1)
(2)
图18.30 初步完成后的菜单设计
不符合单选按钮的状态的,也就是说同一时间只能有一个单选钮被选中。这种情况下,我们可以用SwingControls目录下的
46
Button Group控件来解决这个难题。首先把它放到主窗
刘长炯著
体上,然后只能在Outline视图的Other Components下面看到它,因为这个组件本身是不可见的,属于辅助类,它用来将一组按钮(包括普通按钮,单选钮,复选钮)作为一个组来管理,这些组中的按钮将具有互斥状态。将它的变量名在Outline视图中修改为buttonGroupLAF,随后把三个单选钮菜单项的buttonGroup属性的值都设置为buttonGroupLAF,此修改可以通过下拉框进行,如图18.31所示。抹一把额头的汗水,菜单的设计总算真正的完成了。
图18.31设置单选钮菜单项的buttonGroup属性
界面设计好之后,后续的工作,并非是立即是给所有的组件加入事件处理代码,而是先撰写好功能代码,具体包括:更换界面,聊天相关的操作――加入,离开,读取聊天信息的线程等。下面来一一介绍。 第一个功能,就是换肤的代码,可以参考18.3.3 调整生成代码一节最末的介绍,据此封装一个根据外观类名换肤的方法,如下所示: /**
* 根据外观类名更换界面风格。 * @param lafClassName 外观类名 */
void changeLookAndFeel(String lafClassName) {
try {
javax.swing.UIManager.setLookAndFeel(lafClassName); javax.swing.SwingUtilities.updateComponentTreeUI(this);
} catch (Exception e) {
try {
e.printStackTrace();
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getCrossPlatformLookAndFeelClassName());
javax.swing.SwingUtilities.updateComponentTreeUI(this);
}
}
} catch (Exception e1) { }
e1.printStackTrace();
。 第二个功能就是和聊天有关的模块了,先看相关的变量定义:
47
private InetAddress group = null;// 多播地址
private MulticastSocket socket = null;// 多播套接字 private String username;// 用户名
刘长炯著
private int port;// 端口
随后是接收消息的线程:
// 接收数据的线程 class ReaderThread extends Thread { public void run() { while (socket != null) { try {
byte[] buf = new byte[1024]; DatagramPacket recv = new DatagramPacket(buf, buf.length); socket.receive(recv); addChatText(new String(recv.getData())); } catch (Exception ex) { } } }
}
,另外添加了一个向聊天历史区添加信息的方法,在添加消息之前,先将字符串中的ASCII编码为0的字符串滤除,然后添加时间戳后,将其添加到聊天历史的文本区中: /** * 向聊天区域添加信息,加上时间戳。 * * @param text * 要添加的文字信息 */ private void addChatText(String text) { if (text != null) { text = text.replaceAll(\\ } DateFormat df = DateFormat.getDateTimeInstance(); String msg = df.format(new java.util.Date()) + \ jTextAreaHistory.append(msg); System.out.println(msg); }
。随后是和聊天有关的几个功能方法:
// 加入聊天室 void join() { username = this.jTextFieldUsername.getText(); if (username.equals(\{
addChatText(\请你务必首先输入一个名字.\ return; } try {
48
刘长炯著
addChatText(\尝试进入聊天室...\ group = InetAddress.getByName(jTextFieldIP.getText()); port = Integer.parseInt(jTextFieldPort.getText()); socket = new MulticastSocket(port); socket.joinGroup(group); String message = username + \ + \进入聊天室 \端口号\ + \ DatagramPacket hi = new DatagramPacket(message.getBytes(), message .getBytes().length, group, port); socket.send(hi);
jTextFieldUsername.setEditable(false); jButtonSend.setEnabled(true); new ReaderThread().start(); } catch (Exception ex) {
addChatText(\无法进入聊天室:\ ex.printStackTrace(); } }
// 发送聊天信息 void send() { if (socket == null) return; try { String message = username + \ + \: \+ jTextFieldMessage.getText(); DatagramPacket hi = new DatagramPacket(message.getBytes(), message .getBytes().length, group, port); socket.send(hi);
jTextFieldMessage.requestFocus(); jTextFieldMessage.selectAll(); } catch (Exception ex) {
addChatText(\无法发送消息:\ } }
// 离开聊天室 void leave() { if (socket == null) return; try {
addChatText(\尝试离开聊天室...\ String message = username + \已经离开了聊天室 \
49
刘长炯著
DatagramPacket hi = new DatagramPacket(message.getBytes(), message .getBytes().length, group, port); socket.send(hi);
socket.leaveGroup(group); socket.close(); socket = null;
jTextFieldUsername.setEditable(true); jButtonSend.setEnabled(false); addChatText(\你已经离开了聊天室!\ } catch (Exception ex) {
addChatText(\无法离开聊天室:\ ex.printStackTrace(); } }
然后是调节启动时外观为Office2003的代码,加在构造器的代码中: /** Creates new form UDPChatFrame */ public UDPChatFrame() { initComponents(); setIconImage(new javax.swing.ImageIcon(getClass().getResource( \ // 启动时默认显示 Office 2003 外观
changeLookAndFeel(\ jRadioButtonMenuItemOffice2003.setSelected(true); }
。随后,在界面设计器中将功能代码和每个组件的事件处理方法连接起来,具体过程我们就不再赘述,最后完成的事件方法有下面这些:
// 在消息输入框按下回车,全选文字并调用发送消息方法 private void jTextFieldMessageActionPerformed(java.awt.event.ActionEvent evt) { jTextFieldMessage.selectAll(); send(); }
// 菜单 帮助 > 关于 private void jMenuItemAboutActionPerformed(java.awt.event.ActionEvent evt) { javax.swing.JOptionPane.showMessageDialog(this, \1.0 by BeanSoft\\n2008年5月\关于 UDPChat\ javax.swing.JOptionPane.INFORMATION_MESSAGE);
}
// 菜单 帮助 > 帮助内容 private void jMenuItemHelpContentsActionPerformed( java.awt.event.ActionEvent evt) { String helpContents = \地址范围: 224.0.0.1 ~ 239.255.255.255,端口范围 1 ~
50
刘长炯著