该工程是仿照QQ微信这种及时聊天软件,能够实现给好友栏里的好友进行一对一及一对多聊天功能,该工程命名为IQer(Instant message for neuQer),而本节这一部分,是先搭建起应用界面,其中主要界面有服务器窗口、登录界面、同学导师栏(好友栏)以及聊天界面。
IM(Instant Messenger)即时通讯的工作基础是由客户端和服务器两个部分共同组成,客户端实施的大部分操作都要经由服务器,这个类似于生物的反射机制,而服务器就类似神经中枢,对客户端进行支配调节。例如,当用户需求登录账号时,客户端会将其输入的账号密码传输到服务器,然后由服务器导出数据库中存储的数据进行账号密码的匹配验证,然后返回相关信息。在客户端和服务器传递信息时,服务器就会返回相应的信息,比如,登录成功、登录失败或者是传输其他客户端的聊天信息。大家可以去对QQ进行一下抓包,看看QQ有几个信息包。
首先我们先要建立一个登录界面,我们可以先来观看几个主流即时通讯软件的登录界面
我们可以发现登录界面最为主要的两大元素:登录账号,登录密码,然后我们可以在根据需求增添功能
另外,我们需要注意,整个IM(instant messenger)工程的结构,这个登陆界面是客户端的类
登陆界面我们就采取下图这种布局
导包这一步对于使用idea这类解释器的倒不是很需要在意
import com.Iqer.client.model.IqerClientUser;
import com.Iqer.client.model.MyIqerClient;
import com.Iqer.server.common.User;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
这里要使用Swing就先把JFrame给继承了,然后在之后有需要为控件添加响应,所以这里要连上ActionListener接口
public class IqerClientLogin extends JFrame implements ActionListener{
因为顶部是一个JLable,并且中部采用的网格布局中,我准备做一个选项卡窗口,就是使用者可以使用账号密码登录,手机账号登录以及邮箱登录三中登录方式进入列表。中部的组件就需要四个JPanel作为四个选项卡,其中也需要一些按钮,以及输入账号框、密码框,也要几个JLable;在定义底部,底部也是几个按钮的流布局,所以就只用定义一个JPanel和三个按钮。
//定义顶部所需要的组件
JLabel jbl1;
//定义中间所需要的组件
//中部有四个JPanel,选项卡窗口管理
JTabbedPane jtp;
JPanel jp2, jp3, jp4,jp5;
JLabel jp2_jbl1,jp2_jbl2,jp2_jbl3,jp2_jbl4;
JButton jp2_jb1;
JTextField jp2_jtf;
JPasswordField jp2_jpf
JCheckBox jp2_jcb1, jp2_jcb2;
//定义底部所需要的组件
JPanel jp1;
JButton jp1_jb1;
JButton jp1_jb2;
JButton jp1_jb3;
定义完组件,我们就要把组件的功能放置到构造函数中去设计。
顶部的JLable用来放置图片
public IqerClientLogin(){
//处理顶部
jbl1 = new JLabel(new ImageIcon("image/upper.jpg"));
中部panel比较多,先放置到后面来设计,底部(南部)是流布局排列的三个按钮
//处理底部(流布局)
jp1 = new JPanel();
jp1_jb1 = new JButton("登录");
jp1_jb2 = new JButton("清除");
jp1_jb3 = new JButton("注册");
在将这些组件按钮加入到流布局的面板JPanel中
//将三个按钮加入到jp1
jp1.add(jp1_jb1);
jp1.add(jp1_jb2);
jp1.add(jp1_jb3);
中部我们需要账号、密码、忘记密码、申请账号保护这四个标签,在账号和密码后面分别是一个文本栏和一个密码栏,这些要放置到网格布局的中部,并且也需要隐形登录和记住密码这两个选择项,而组件的风格就需要视自己设计而定。
//处理中部
jp2 = new JPanel(new GridLayout(3,3));
jp2_jbl1 = new JLabel("IQer账号",JLabel.CENTER);
jp2_jbl2 = new JLabel("IQer密码",JLabel.CENTER);
jp2_jbl3 = new JLabel("忘记密码",JLabel.CENTER);
jp2_jbl3.setForeground(Color.blue);
jp2_jbl4 = new JLabel("申请账号保护",JLabel.CENTER);
jp2_jb1 = new JButton("清除号码");
jp2_jtf = new JTextField();
jp2_jpf = new JPasswordField();
jp2_jcb1 = new JCheckBox("隐身登录");
jp2_jcb2 = new JCheckBox("记住密码");
同样,也要把这些组件按顺序加入到JPanel中,
注意:一定注意这些组件要按顺序,按顺序加入到中部的面板中
//把控件按照顺序加入到jp2中
jp2.add(jp2_jbl1);
jp2.add(jp2_jtf);
jp2.add(jp2_jb1);
jp2.add(jp2_jbl2);
jp2.add(jp2_jpf);
jp2.add(jp2_jbl3);
jp2.add(jp2_jcb1);
jp2.add(jp2_jcb2);
jp2.add(jp2_jbl4);
我在中部设置的是选项卡式的窗口,设置了账号登录,手机号码登录,电子邮件以及产品说明四个选项卡
//创建选项卡窗口
jtp = new JTabbedPane();
jtp.add("IQer号码",jp2);
jp3 = new JPanel();
jtp.add("手机号码",jp3);
jp4 = new JPanel();
jtp.add("电子邮件",jp4);
jp5 = new JPanel();
jtp.add("产品说明",jp5);
这上中下三个面板的构造就写好了,现在就要将这三个板块的panel加入到整个类边框中,并且,我们还要对边框的大小、图标以及宽口可视化、关闭窗口终止程序等功能进行个性化设计。
//设置大小
this.setSize(550, 340);
//设置图标
this.setIconImage((new ImageIcon("image/icon.png")).getImage());
//设置关闭窗口终止
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口可见
this.setVisible(true);
//将jbl1加入到顶部框架(North)中
this.add(jbl1,"North");
//将jp1加入到底部框架(South)中
this.add(jp1,"South");
//将jp2、jp3、jp4共同组建的选项卡jtp加入到中部(Center)
this.add(jtp,"Center");
}
}
当我们从登录界面,进行完账号密码的验证,我们就要进入到好友栏的界面,所以我们这里就要把好友界面给做出来
同样还是要先把该引包的包给引了
我们可以看看其他即时聊天软件的好友栏设计
好友栏中就包括几个好友分类这一元素。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
接口和继承情况也要加上去
/**
* 好友列表(包括:同学名单、导师名单、黑名单)
*/
public class IqerFriendList extends JFrame implements ActionListener, MouseListener {
先说一下这个界面的设计计划
这个好友栏中的好友是被分为:同学、导师和黑名单三个面板名单,打开的好友分类中间panel要加入滚动名单组件(JScrollPanel)。下面两个未打开的好友分类作为按钮以网格布局(GridLayout)方式加入到底部的JPanel中。好友分类中的好友分布及滚动组件以边缘分布(BorderLayout)的方式进行布局。并且,因为有三个不同的好友分类栏,所以我们要把这三个好友种类设置为卡片布局(CardLayout)。
首先,我们要把需要的组件给定义一下
//把整个JFrame设置成CardLayout布局
CardLayout cl;
//处理第一张卡片
JPanel jpfriend1, jpfriend2, jpfriend3;
//卡片布局
//三个按钮
JButton jpfriend_jb1, jpfriend_jb2, jpfriend_jb3;
//滚动条
JScrollPane jsp1;
//处理第二张卡片
JPanel jptutor1, jptutor2, jptutor3;
//卡片布局
//三个按钮
JButton jptutor_jb1, jptutor_jb2, jptutor_jb3;
//滚动条
JScrollPane jsp2;
然后,我们要设计构造方法,由于后面当我们要获得这使用者的账号ID,所以,这里是有一个传值
public IqerFriendList(String ownerId) {
接下来我们就要先来处理第一张好友列表,这里我们先new出这三个需要我们进行卡片布局的按钮
//三张卡片
jpfriend_jb1 = new JButton("我的同学");
jpfriend_jb2 = new JButton("我的导师");
jpfriend_jb3 = new JButton("黑名单");
上面我们分析过了,上面一块的JPanel面板中我们是采用边界布局,中间的Panel中我们先预设50个同学,所以这里的网格布局设置为50行,下面的面板Panel另两个充当好友分类栏的按钮是按照网格布局的2排1列(两个按钮,南北放置)
jpfriend1 = new JPanel(new BorderLayout());
//有50个好友
jpfriend2 = new JPanel(new GridLayout(50, 1, 4, 4));
//陌导师和黑名单
jpfriend3 = new JPanel(new GridLayout(2, 1));
在这里我们已经把50个好友的存放空间给new出来了,然后我们就要把这50个好友给初始化(加上序号以及图标)
注意:好友是被放置在标签内,由一组for循环来进行初始化,并且要把这些标签分别加入到定义的第二个面板中(jpfriend2)
//初始化50个好友
JLabel[] jbls = new JLabel[50];
for (int i = 0; i < jbls.length; i++) {
jbls[i] = new JLabel("同学"+(i + 1) + " ", new ImageIcon("image/profile.png"), JLabel.LEFT);
jpfriend2.add(jbls[i]);
}
把导师和黑名单两个按钮加入到下部的网格布局中,并且把滚动轮加入到中部Panel(jpfriend2)中
//将“我的导师”和“黑名单”加入到jpfriend3中
jpfriend3.add(jpfriend_jb2);
jpfriend3.add(jpfriend_jb3);
jsp1 = new JScrollPane(jpfriend2);
卡片一,同学列表已经做好了,现在我们来制作卡片二,导师列表。
注意:当制作卡片二时,卡片一是在北部处于关闭的状态,卡片三仍然在南部处于关闭状态
我们同样要把这个卡片中所需要的三个按钮以及面板布局给new一下,并且,在初始化25个导师,在把这些组件加入到Panel中,在把Panel加入到卡片布局中,和第一张卡片一样
需要注意的是,在这里卡片一所布置的面板与此时的面板格局是有细微的变化的
/**
* 处理第二张卡片(导师)
*/
//三张卡片
jptutor_jb1 = new JButton("我的同学");
jptutor_jb2 = new JButton("我的导师");
jptutor_jb3 = new JButton("黑名单");
jptutor1 = new JPanel(new BorderLayout());
//有25个导师
jptutor2 = new JPanel(new GridLayout(25, 1, 4, 4));
//初始化25个导师
JLabel[] jbls2 = new JLabel[25];
for (int i = 0; i < jbls2.length; i++) {
jbls2[i] = new JLabel("导师"+(i + 1) + " ", new ImageIcon("image/icon.png"), JLabel.LEFT);
jbls2[i].addMouseListener(this);
jptutor2.add(jbls2[i]);
}
//好友和黑名单
jptutor3 = new JPanel(new GridLayout(2, 1));
//将“我的导师”和“黑名单”加入到jptutor3中
jptutor3.add(jptutor_jb1);
jptutor3.add(jptutor_jb2);
jsp2 = new JScrollPane(jptutor2);
//北边jptutor1进行初始化
jptutor1.add(jptutor3, "North");
jptutor1.add(jsp2, "Center");
jptutor1.add(jptutor_jb3, "South");
第二个窗口设计完成,我们现在要对整个好友栏窗口进行编辑,这里为了可以进行不同种类好友的切换,我们先为这两个标签编一个号,便于后续按钮响应。并且,我们在把该窗口进行个性化设计。
cl = new CardLayout();
this.setLayout(cl);
this.add(jpfriend1, "1");
this.add(jptutor1, "2");
//再窗口显示自己的编号
this.setTitle(ownerId);
this.setSize(250, 550);
this.setIconImage((new ImageIcon("image/icon.png")).getImage());
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
我们刚刚已经定义了两个卡片,并将其加入到了卡片布局中,现在需要完成的就是如何实现这两个卡片之间的切换。之前定义的这两个卡片的抬头是一个按钮组件,我们可以在给这个按钮添加响应,点击按钮便切换卡片。
对于第一张卡片,因为好友的同学分类卡片是被打开的,导师的卡片是被关闭的,所以我们就要在导师按钮下添加响应,用以打开第二行导师卡片
这里我们要在之前制作第一张卡片定义组件的时候,加入对于组件的行为的监听
jpfriend_jb1 = new JButton("我的同学");
jpfriend_jb2 = new JButton("我的导师");
jpfriend_jb2.addActionListener(this);
同样的,当我们打开第二张卡片导师栏时,我们要切换回同学栏,就需要在卡片二中的同学按钮下加入行为监听
jptutor_jb1 = new JButton("我的同学");
jptutor_jb1.addActionListener(this);
jptutor_jb2 = new JButton("我的导师");
添加完了按钮的事件监听,我们开始写一下响应方法,我们要在打开同学好友栏时,点击导师按钮切换到导师好友栏;在打开导师好友栏时,点击同学按钮切换到同学好友栏。这里切换界面,就是直接切换卡片的编号。
@Override
public void actionPerformed(ActionEvent e) {
//如果点击了导师按钮,显示第二张卡片
if (e.getSource() == jpfriend_jb2) {
cl.show(this.getContentPane(), "2");
} else if (e.getSource() == jptutor_jb1) {
cl.show(this.getContentPane(), "1");
}
}
这里我们还要设置一下,鼠标触碰到好友栏中的头像时,至使被触碰的头像变成红色
@Override
public void mouseEntered(MouseEvent e) {
JLabel jl = (JLabel) e.getSource();
jl.setForeground(Color.RED);
}
但是,这里需要注意这里设置了鼠标进入触碰头像后变为红色,但是当鼠标离开时,这个头像并不会变回来,我们必须还要设置一下鼠标退出的行为响应。
@Override
public void mouseExited(MouseEvent e) {
JLabel jl = (JLabel) e.getSource();
jl.setForeground(Color.BLACK);
}
另外,我们在选中待聊天对象时,双击待聊天对象的头像,方可以进入与其的聊天窗口,并且传入待聊天好友的编号。这里,我们还没有写聊天窗口类(IqerChat)这里我们在这里就事先new一下。
@Override
public void mouseClicked(MouseEvent e) {
//响应用户双击的事件,并得到好友的编号
if(e.getClickCount() == 2){
//得到好友的编号
String friendNo = ((JLabel)e.getSource()).getText();
System.out.println("你要和"+friendNo+"聊天");
new IqerChat(this.owner,friendNo);
}
}
}
这里就打开用户1的聊天界面
我们可以先查看一下鼠标触碰头像的响应
我们在打开导师栏,切换到第二张卡片
刚刚我们事先new了一个聊天窗口界面在好友栏的双击头像事件的响应里,现在就把这个聊天窗口给写一下。
我们可以先看看QQ的聊天界面,这里的构造也比较简单
这个聊天窗口的实现其实十分简单,就是上部一个Panel,下面一个文本域和一个发送按钮。
这里没有什么值得注意的,就可以直接写代码了
我们先导包,这里因为我们后面在这里是要做输入输出流的,并且,这里也要加入到工具包
import com.Iqer.client.model.MyIqerClient;
import com.Iqer.server.common.Message;
import com.Iqer.server.model.IqerServer;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Date;
这里因为有发送按钮需要连入监听,所以也需要ActionListener接口
public class IqerChat extends JFrame implements ActionListener {
这个窗口十分简单,不需要多少按钮组件
JTextArea jta;
JTextField jtf;
JButton jb;
JPanel jp;
String ownerID;
String personID;//聊天对象ID
这里也就是把几个组件给加入到JPanel中,并且,再进行一些个性化设置
public IqerChat(String ownerId,String person){
//将自己的ID和聊天对象的ID传值到该类变量中
this.ownerID = ownerId;
this.personID = person;
jta = new JTextArea();
jtf = new JTextField(25);
jb = new JButton("发送");
jb.addActionListener(this);
jp = new JPanel();
jp.add(jtf);
jp.add(jb);
this.add(jta,"Center");
this.add(jp, "South");
this.setTitle(ownerId+"正在和"+person+"对话");
this.setIconImage((new ImageIcon("image/icon.png")).getImage());
this.setSize(750,450);
this.setVisible(true);
}
}
这里这个窗口的展示,我们就从好友栏这里打开展示
我们就打开和同学50的聊天界面
这个界面就成功了。
我们要做的这个即时聊天软件的服务器窗口,这个服务器可以管理我们的账号连接,聊天信息传递以及登录账号管理等功能。在服务器的构造前期,我们就做出连接服务器的按钮就行了,其他的功能我们就可以到后期慢慢实现。
import com.Iqer.server.model.IqerServer;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class IqerServerFrame extends JFrame implements ActionListener {
JPanel jp1;
JButton jb1,jb2;
在构造方法中我们要先导几个组件,并且,因为我们要给按钮加入事件监听,然后要把这些组件加入到面板中
public IqerServerFrame(){
jp1 = new JPanel();
jb1 = new JButton("启动服务器");
jb1.addActionListener(this);
jb2 = new JButton("关闭服务器");
jp1.add(jb1);
jp1.add(jb2);
this.add(jp1);
this.setSize(500,400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
在点击启动服务器按钮后,new出服务器类,启动服务器
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == jb1){
new IqerServer();
}
}
}
好了,这个比较简单的服务器界面就做好了
这一章聊天软件的界面设计的所有界面已经完成,我们下一章将会进行服务端的搭建以及服务器与客户端的连接进行编写。