仿QQ通信(一)绘制客户端界面


这次我们准备做一个仿QQ的通信项目,首先要做的是把一些图形界面先准备好,那么我们开始第一步吧

绘制登录界面

我们不妨先看一眼QQ真实的登录界面长啥样

QQ登录界面

QQ登录失败界面

当然由于能力问题,而且Java的GUI确实很一般,所以我们做个简易版本的就好。把功能大概地抽象一下

  1. 首先画一个窗口,分两个子窗口,上面画成蓝色背景,下面的用于绘制组件

  2. 下面的窗口要有提示文本提醒你输入账户和密码,且设置一个文本框一个密码框用于获取账号和密码

  3. 设置两个按钮,注册和登录,并对它们添加监听器

  4. 如果登录成功,打印登录信息,如果登录失败,在原界面显示失败信息,这里我们设置随机数让登录成功的可能性为50%

    代码如下

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    public class LoginUI extends JFrame {
        private JTextField jtf1;
        private JPasswordField jtf2;
        private JPanel north;
    
        public static void main(String[] args) {
            LoginUI ui = new LoginUI("登录界面");
            ui.draw();
    
        }
    
        public LoginUI(String title) {
            super(title);
        }
    
        public void draw() {
            //窗体设置
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setSize(400, 400);
            setLocation(800, 400);
    
            //Panel设置
            north = new JPanel();
            north.setBackground(new Color(59, 122, 199));//north设置颜色
            north.setPreferredSize(new Dimension(0, 200));
            JPanel south = new JPanel();
            south.setPreferredSize(new Dimension(0, 200));
            add(north, BorderLayout.NORTH);
            add(south, BorderLayout.SOUTH);
    
            //south处理
            JLabel user = new JLabel("用户名");
            JLabel password = new JLabel("密码");
            jtf1 = new JTextField(20);
            jtf2 = new JPasswordField(20);
            JButton jb1 = new JButton("登录");
            JButton jb2 = new JButton("注册");
            jtf1.setEditable(true);
            jtf2.setEditable(true);
    
            //设置绝对位置
            user.setBounds(70, 60, 40, 40);
            password.setBounds(70, 90, 40, 40);
            jtf1.setBounds(150, 70, 150, 20);
            jtf2.setBounds(150, 100, 150, 20);
            jb1.setBounds(240, 130, 60, 20);
            jb2.setBounds(150, 130, 60, 20);
    
            //将组件添加进south
            south.setLayout(null);
            south.add(user);
            south.add(jtf1);
            south.add(password);
            south.add(jtf2);
            south.add(jb1);
            south.add(jb2);
    
            //可视化
            setVisible(true);
    
            //添加监听器
            LoginUIListener ll = new LoginUIListener(this);
            jb1.addActionListener(ll);
            jb2.addActionListener(ll);
    
        }
    
        public void drawfault() {
    
            JLabel label = new JLabel("账号或密码错误,请重新输入!");
            label.setBounds(40, 140, 40, 40);
            north.add(label);
            setVisible(true);
        }
    
        private class LoginUIListener implements ActionListener {
            LoginUI ui;
    
            public LoginUIListener(LoginUI ui) {
                this.ui = ui;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                if (e.getActionCommand().equals("注册")) {
                    String name = jtf1.getText();
                    String password = String.valueOf(jtf2.getPassword());
                    System.out.println("新用户注册成功!\n用户名:\t" + name + "\n密码:\t" + password);
    
                    //todo:UserData.allusers.put(name, password);
                }
    
                if (e.getActionCommand().equals("登录")) {
                    //todo:检查是否能够登录??在UserData里面查询该用户
                    if (Math.random() > 0.5) {
                        String name = jtf1.getText();
                        String password = String.valueOf(jtf2.getPassword());
                        System.out.println("用户登录成功!\n用户名:\t" + name + "\n密码:\t" + password);
                        dispose();
    										Client client = new Client(name);
    										client.start();
    
                    } else {
                        ui.drawfault();
                    }
                }
            }
    
        }
    }
    
    

    来看看我们模拟的效果

模拟QQ登录界面

上面输入123,下面输入456

在这里插入图片描述

或者

在这里插入图片描述

那么我们第一部分完工了,下面第二部分,绘制QQ好友列表界面

绘制好友列表界面

同样的,我们先看看QQ是咋做的

在这里插入图片描述

  1. 一个高瘦的界面,分两个部分上面是个人信息,下面是好友列表
  2. 个人信息有背景,有头像、用户名和个性签名
  3. 每一个好友的信息,包括头像、用户名、个性签名
  4. 好友列表中有若干个好友,由于好友数量较多时屏幕画不下,因此采用要加滚动条
  5. 双击好友可以开启与他的聊天界面

这里我们仍然分两个部分,上面个人信息下面的好友列表各一个panel,下面由于要装滑动条,采用JScrollPane,好友列表中采用JList实现,而由于每一个好友在屏幕中的显示有图片和文字,因此我们重写Jlist的单元渲染器(ListCellRenderer)。

关于检测双击,一般我们用e.getClickCount检测,我们可以在MouseAdapter中的mouseClicked检测这一行为。

关于如何重写单元渲染器,javax.swing.ListCellRenderer中有一个官方示范,截取部分如下

ListCellRenderer的官方示范

照着这个抄就行,至于单元渲染器的介绍,这里三篇博客讲的挺详细的,贴在这里自取

https://blog.csdn.net/yanhanhui1/article/details/104983677

https://blog.csdn.net/weixin_36571185/article/details/71616952

https://www.cnblogs.com/hesi/p/6242699.html

该说的说完了直接上代码吧,这次我们先写一个Client类,用户列表界面作为其子类,并且我们修改在上一部分代码里面增加一点内容,使得登录成功后登录页面关闭,并且启动一个客户端,关于Clinet类的通信有关内容我们下期再讲,本期主要解决GUI相关问题。

接下来开始写登录界面的主要代码

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class Client {
    private final String userID;

    public Client(String userID){
        this.userID=userID;
    }
    
    public void start(){
        ListUI lui = new ListUI("好友列表",this.userID);
        lui.draw();
    }
    
    private class ListUI extends JFrame {
    
        private JPanel lnorth;
        private JScrollPane lsouth;
        private String userID;
    
        public ListUI(String title,String userID) {
            super(title);
            this.userID=userID;
        }
    
        public void draw() {
            //窗体设置
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setSize(400, 700);
            setLocation(200, 100);


            //Panel设置
            lnorth = new JPanel();
            lnorth.setBackground(new Color(59, 122, 199));//north设置颜色
            lnorth.setPreferredSize(new Dimension(0, 150));
            lsouth = new JScrollPane();
            lsouth.setBackground(new Color(7, 11, 14));//north设置颜色
            lsouth.setPreferredSize(new Dimension(0, 515));
            add(lnorth, BorderLayout.NORTH);
            add(lsouth, BorderLayout.SOUTH);
    
            //lnorth的处理:加上个人信息
            JLabel userName = new JLabel(this.userID);
            //todo:从UserData数据库里面取头像
            ImageIcon headimage = (new ImageIcon("img/QQicon.png"));
            headimage.setImage(headimage.getImage().getScaledInstance(100,100,Image.SCALE_DEFAULT));
            JLabel head = new JLabel(headimage);
            //todo:从UserData数据库里面取个人签名
            JLabel signature = new JLabel("I am so vegetable qwq");
    
            //将组件设置位置加入lnorth
            userName.setBounds(150,20,200,20);
            head.setBounds(20,20,100,100);
            signature.setBounds(150,40,200,100);
            lnorth.setLayout(null);
            lnorth.add(userName);
            lnorth.add(head);
            lnorth.add(signature);



            //lsouth处理
            //首先我们重写JList的单元渲染器类
            @SuppressWarnings({ "rawtypes", "serial" })
            class MyCellRenderer  extends JLabel implements ListCellRenderer {
                public MyCellRenderer() {
                     setOpaque(true);
                }
                @Override
                public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
                                                              boolean cellHasFocus) {
                    Color background;
                    Color foreground;
    
                    // check if this cell represents the current DnD drop location
                    JList.DropLocation dropLocation = list.getDropLocation();
                    if (dropLocation != null&& !dropLocation.isInsert()&& dropLocation.getIndex() == index) {
                        background = Color.RED;
                        foreground = Color.WHITE;
                        // check if this cell is selected
                    }else if (isSelected) {
                      background = Color.BLUE;
                      foreground = Color.WHITE;
    
                    // unselected, and not the DnD drop location
                    } else {
                      background = Color.WHITE;
                      foreground = Color.BLACK;
                    };
    
                    /*******设置JLable的文字******/
                    String text="<html>姓名<br/>个性签名 <html/>";
                    setText(text);//设置JLable的文字
                    /*******设置JLable的图片*****/
                    // 得到此图标的 Image,然后创建此图像的缩放版本。
                    ImageIcon headimage = (new ImageIcon("img/QQicon.png"));
                    headimage.setImage(headimage.getImage().getScaledInstance(50,50,Image.SCALE_DEFAULT));
                    setIcon(headimage);
                    setIconTextGap(30);//设置JLable的图片与文字之间的距离


                    setBackground(background);
                    setForeground(foreground);
                    return this;
                }
            }



            //todo:从Userdata中找出用户的每一个好友,并取他们的头像和用户名和个人标签
            JPanel[] jl = new JPanel[50];
            for(int i=0;i<50;i++){
                JPanel jf = new JPanel();
                jf.setLayout(null);
                jf.setPreferredSize(new Dimension(200,200));
                jl[i]=jf;
            }
            ListModel<JPanel> jListModel =  new DefaultComboBoxModel<JPanel>(jl);  //数据模型
            JList<JPanel> myJlist = new JList<JPanel>();
            myJlist.setModel(jListModel);
            myJlist.setCellRenderer(new MyCellRenderer());
            myJlist.setFont(new Font(Font.SERIF, Font.PLAIN, 18));
    
            //加滚动条
            lsouth.setViewportView(myJlist);
    
            //加监听器
            myJlist.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if(e.getClickCount() == 2){
                        System.out.println("双击");
                        JList myList = (JList) e.getSource();
                        int index = myList.getSelectedIndex();    //已选项的下标
                        Object obj = myList.getModel().getElementAt(index);  //取出数据
                        System.out.println(obj.toString());
                        DialogUI du = new DialogUI("111");
                        du.draw();
                        
                    }
                }
            });
            setVisible(true);
        }
    }
}

我们来看看效果咋样

模拟好友列表

效果还是可以的,图中的蓝色是因为该元素被选中了,这个背景色你可以自己调,在JList的单元渲染器里面可以设置,beselected为true时的颜色。我们再看看双击后java控制台的输出

java控制台的输出

也是很符合预期的,那么这部分基本上就完成了。

绘制对话界面

接下来我们完成第三部分,对话界面。

同样的,首先我们来看看QQ正版的对话界面长啥样吧,这部分应该是最简单的

QQ对话窗口

观察一下我们发现屏幕大致分3块,右边是图像,这里我们给个背景色好了,左边分三块,上面是对话界面,下面的发送界面是一个文本框加一个发送按钮,中间界面里面有截屏、表情、文件、发送等按钮。

基本没啥难度,直接放代码吧

package Clinet;

import javax.swing.*;
import java.awt.*;

public class DialogUI extends JFrame {
    private String friendName;

    public DialogUI(String friendName){
        super("与"+friendName+"的对话");
        this.friendName=friendName;
    }
    public void draw(){
        //窗体设置
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(800, 800);
        setLocation(100, 100);

        //Panel设置
        JPanel east = new JPanel();
        JPanel west = new JPanel();
        JPanel north = new JPanel();
        JPanel south = new JPanel();
        JPanel center = new JPanel();
        add(east,BorderLayout.EAST);
        add(west,BorderLayout.WEST);
        west.setLayout(new BorderLayout());
        west.add(north, BorderLayout.NORTH);
        west.add(south, BorderLayout.SOUTH);
        west.add(center,BorderLayout.CENTER);
        east.setBackground(new Color(0x4D62C1));//east设置颜色
        north.setBackground(new Color(0xE07456));//north设置颜色
        north.setVisible(true);
        east.setPreferredSize(new Dimension(200, 0));
        west.setPreferredSize(new Dimension(600, 0));
        north.setPreferredSize(new Dimension(0, 500));
        south.setPreferredSize(new Dimension(0, 200));


        //south处理
        JButton send = new JButton("发送");
        JButton file = new JButton("文件");
        JButton emoji = new JButton("表情");
        JButton catchScreen = new JButton("截屏");
        JTextArea sender = new JTextArea();
        sender.setText("在这里输入文字");


        //设置绝对位置
        send.setBounds(0,0,100,100);
        file.setBounds(150,0,100,100);
        emoji.setBounds(300,0,100,100);
        catchScreen.setBounds(450,0,100,100);
        sender.setBounds(50,50,500,200);
        center.add(send);
        center.add(file);
        center.add(emoji);
        center.add(catchScreen);
        south.add(sender);

        //可视化
        setVisible(true);


    }
}

看看效果咋样

对话界面

不错,完工,我们下一期再介绍服务器的代码,下下期介绍客户端服务器通信的代码。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值