基本窗体的设计
一、前言
注:本系列几篇文章展示了“简易版飞鸽传书”的编写过程,该程序可实现在局域网内收发文字信息和文件的功能。希望可以通过这个样例让读者对java网络编程和IO编程有所了解。其中,主要参考了李刚的《疯狂java讲义》,有一些代码直接拷贝自该书第17章,头像图片来源于网络,特此说明。另外需要说明的是:本程序在jdk1.8下开发,在笔者的局域网环境下测试通过,能实现发送文字消息和传输小文件的功能,但笔者并不能保证能在你的环境下也一定可以测试通过~ O__O “…
本文为该系列文章的第一篇。我们在这一篇中,将实现这个程序的几个窗口,当然在这里我们先是简单地实现它们,在之后的编写过程中可能还会有所修改,之后的所有的类都会是这个过程。首先来看下效果。
登录窗口:
用户登录成功后跳转到好友列表窗口:
当在某个好友头像上双击后将打开一个与该好友聊天的窗口:
二、登录窗口
首先来实现登录窗口。我们可以让它继承一个JDialog ,用GridLayout 放上相应的控件即可。需要说明的是我们要在JComboBox 中显示一些头像给用户来选择作为他们自己的头像。另外,点击登录按钮后,要打开一个好友列表的窗口。
为了能让JComboBox 显示图片,我们需要实现一个 ListCellRenderer 。
class IconListRender extends JLabel implements ListCellRenderer{ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { // TODO 自动生成的方法存根 ImageIcon image=null; if (value instanceof Object[]) { Object[] values = (Object[]) value; image = (ImageIcon)values[0]; } if (image != null) { this.setIcon(image); } return this; } }
头像选择下拉框iconList 的相应代码如下:
private JComboBox iconList; //头像选择列表 Object[][] icons = { {new ImageIcon("icon/0.jpg")}, {new ImageIcon("icon/1.jpg")}, {new ImageIcon("icon/2.jpg")}, {new ImageIcon("icon/3.jpg")}, {new ImageIcon("icon/4.jpg")}, {new ImageIcon("icon/5.jpg")}, {new ImageIcon("icon/6.jpg")}, {new ImageIcon("icon/7.jpg")}, {new ImageIcon("icon/8.jpg")}, {new ImageIcon("icon/9.jpg")}, }; iconList = new JComboBox(icons); iconList.setPreferredSize(new Dimension(224, 40)); iconList.setRenderer(new IconListRender());
我们把头像图片放在icon 目录下,命名为0.jpg 1.jpg ... ... 。这样有个好处是根据getSelectedIndex()方法,就能知道用户选择的是哪个头像。另外,在所有人的好友列表中都会首先放上一个“所有人”,意思是打开一个所有人的聊天窗口实际上就是打开了一个群聊窗口,所有人都可以看到其中的信息。最终的登录窗口代码如下:
package com.myipmsg.frame; import java.awt.Component; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.ListCellRenderer; import com.myipmsg.bean.User; /** * 登录窗口 * @author ThinkPad * */ public class LoginFrame extends JDialog { /** * */ private static final long serialVersionUID = -1578751340255443641L; private JTextField userNameField; private JComboBox iconList; private JButton loginBtn; public LoginFrame(){ super(); setLayout(new GridLayout(3, 1)); //用户名输入框 userNameField = new JTextField("zhutulang" , 20); userNameField.setPreferredSize(new Dimension(224, 40)); add(getPanel("用户名", userNameField)); //头像选择列表 Object[][] icons = { {new ImageIcon("icon/0.jpg")}, {new ImageIcon("icon/1.jpg")}, {new ImageIcon("icon/2.jpg")}, {new ImageIcon("icon/3.jpg")}, {new ImageIcon("icon/4.jpg")}, {new ImageIcon("icon/5.jpg")}, {new ImageIcon("icon/6.jpg")}, {new ImageIcon("icon/7.jpg")}, {new ImageIcon("icon/8.jpg")}, {new ImageIcon("icon/9.jpg")}, }; iconList = new JComboBox(icons); iconList.setPreferredSize(new Dimension(224, 40)); iconList.setRenderer(new IconListRender()); add(getPanel("头 像", iconList)); //登录按钮 loginBtn = new JButton("登录"); loginBtn.addActionListener(new LoginBtnActionListener(this)); JPanel loginPanel = new JPanel(); loginPanel.add(loginBtn); add(loginPanel); pack(); setTitle("用户登录"); //设置居中显示 setLocationRelativeTo(null); setDefaultCloseOperation(DISPOSE_ON_CLOSE); setVisible(true); } // 工具方法,该方法将一个字符串和组件组合成JPanel对象 private JPanel getPanel(String name , JComponent jf) { JPanel jp = new JPanel(); jp.add(new JLabel(name + ":")); jp.add(jf); return jp; } class IconListRender extends JLabel implements ListCellRenderer{ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { // TODO 自动生成的方法存根 ImageIcon image=null; if (value instanceof Object[]) { Object[] values = (Object[]) value; image = (ImageIcon)values[0]; } if (image != null) { this.setIcon(image); } return this; } } // 定义登录按钮事件监听器 class LoginBtnActionListener implements ActionListener { private LoginFrame loginFrame; public LoginBtnActionListener(LoginFrame loginFrame) { this.loginFrame = loginFrame; } @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub //显示好友列表窗口 FriendListFrame friendListFrame = new FriendListFrame(); friendListFrame.addUser(new User(userNameField.getText(), iconList.getSelectedIndex()+".jpg")); loginFrame.setVisible(false); } } public static void main(String[] args) { LoginFrame loginFrame = new LoginFrame(); } }
三、好友列表窗口
这部分主要是将登录用户的头像、用户名绘制在窗体上,代码基本上就是拷贝自李刚的《疯狂java讲义》了,主要是实现一个 ListCellRenderer 。在这个类中涉及到了用户类 User 。User类的代码如下:
package com.myipmsg.bean; /** * 用户类 * @author ThinkPad * */ public class User { //用户名 private String name; //用户头像 private String icon; public User(String name,String icon){ this.name = name; this.icon = icon; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } } 好友列表窗口类如下: package com.myipmsg.frame; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Toolkit; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.DefaultListModel; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ListCellRenderer; import com.myipmsg.bean.User; /** * 好友列表窗口 * @author ThinkPad * */ public class FriendListFrame extends JFrame { /** * */ private static final long serialVersionUID = 5200439274745789016L; private DefaultListModel<User> listModel = new DefaultListModel<>(); //好友列表 private JList<User> friendList = new JList<>(listModel); // ------对ListModel的包装------ // 向好友列表中添加用户 public void addUser(User user) { listModel.addElement(user); } // 从好友列表中删除用户 public void removeUser(int pos) { listModel.removeElementAt(pos); } // 获取该好友列表的用户数量 public int getUserNum() { return listModel.size(); } public FriendListFrame(){ super("好友列表"); addUser(new User("所有人", "all.jpg")); friendList.setCellRenderer(new ImageCellRenderer()); friendList.addMouseListener(new ShowChatFrameListener()); add(new JScrollPane(friendList)); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds( (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth()-200, 5, 200 , 600); setVisible(true); } //实现JList上的鼠标双击事件的监听器 class ShowChatFrameListener extends MouseAdapter{ public void mouseClicked(MouseEvent e) { //双击 if(e.getClickCount() >= 2){ User user = friendList.getSelectedValue(); ChatFrame chatFrame = new ChatFrame(user); } } } public static void main(String[] args) { // TODO Auto-generated method stub FriendListFrame frame = new FriendListFrame(); } } //定义用于改变JList列表项外观的类 class ImageCellRenderer extends JPanel implements ListCellRenderer<User> { private ImageIcon icon; private String name; // 定义绘制单元格时的背景色 private Color background; // 定义绘制单元格时的前景色 private Color foreground; @Override public Component getListCellRendererComponent(JList list , User user , int index , boolean isSelected , boolean cellHasFocus) { // 设置图标 icon = new ImageIcon("icon/" + user.getIcon()); name = user.getName(); // 设置背景色、前景色 background = isSelected ? list.getSelectionBackground() : list.getBackground(); foreground = isSelected ? list.getSelectionForeground() : list.getForeground(); // 返回该JPanel对象作为单元格绘制器 return this; } // 重写paintComponent方法,改变JPanel的外观 public void paintComponent(Graphics g) { int imageWidth = icon.getImage().getWidth(null); int imageHeight = icon.getImage().getHeight(null); g.setColor(background); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(foreground); // 绘制好友图标 g.drawImage(icon.getImage() , getWidth() / 6 - imageWidth / 2 , 10 , null); g.setFont(new Font("SansSerif" , Font.BOLD , 18)); // 绘制好友用户名 g.drawString(name, getWidth() / 6 + imageWidth , 10 + imageHeight/2 ); } // 通过该方法来设置该ImageCellRenderer的最佳大小 public Dimension getPreferredSize() { return new Dimension(60, 80); } }
四、聊天窗口
聊天窗口类也很简单,现在只放了发送消息的相应控件。代码如下:
package com.myipmsg.frame; import java.awt.BorderLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.KeyStroke; import com.myipmsg.bean.User; /** * 聊天窗口 * @author ThinkPad * */ public class ChatFrame extends JDialog { // 聊天信息区 JTextArea msgArea = new JTextArea(12 , 45); // 聊天输入区 JTextField chatField = new JTextField(30); // 发送聊天信息的按钮 JButton msgSendBtn = new JButton("发送信息"); public ChatFrame(User user){ super(); setTitle("和"+user.getName()+"聊天中"); setIconImage(new ImageIcon("icon/"+user.getIcon()).getImage()); msgArea.setEditable(false); add(new JScrollPane(msgArea)); JPanel buttom = new JPanel(); buttom.add(new JLabel("输入信息:")); buttom.add(chatField); buttom.add(msgSendBtn); add(buttom , BorderLayout.SOUTH); // 将Ctrl+Enter键和"send"关联 chatField.getInputMap().put(KeyStroke.getKeyStroke('\n' , java.awt.event.InputEvent.CTRL_MASK) , "send"); // 将"send"与sendAction关联 //chatField.getActionMap().put("send", sendAction); setVisible(true); setLocationRelativeTo(null); pack(); } public static void main(String[] args) { // TODO Auto-generated method stub new ChatFrame(new User("sss", "")); } }