Java模擬qq軟件的詳細(xì)過(guò)程
**之前在封裝代碼后出現(xiàn)了問(wèn)題,按照最初的寫法,在登陸完畢后彈出聊天界面后會(huì)卡死,原因是當(dāng)時(shí)登陸界面和聊天界面都是使用的主線程,我的代碼沒(méi)有寫其他線程,無(wú)法多線程運(yùn)行,因此在彈出聊天界面時(shí)線程不夠用了,就卡在了監(jiān)聽(tīng)線程里,因?yàn)樵诒O(jiān)聽(tīng)線程中再有新的監(jiān)聽(tīng)就會(huì)被卡住
在宇哥的指點(diǎn)下,將啟動(dòng)服務(wù)器和客戶端的部分改為線程,就解決了此問(wèn)題。改善后的代碼簡(jiǎn)練和清晰了很多,更方便大家參考,代碼如下:
**
登陸界面的實(shí)現(xiàn)
登陸界面主要使用了JFrame,以及相關(guān)的一些組件,并且在界面中加上監(jiān)聽(tīng)
登陸界面效果圖

登陸界面代碼Login類
package com.lding.net;
import javax.swing.*;
import java.awt.*;
/**
* @program: Chat
* @description:
* @author: 王丁
* @date: 2021-09-26 08:58
**/
public class Login{
JTextField jTextField;
public static void main(String[] args){
Login login = new Login ();
login.showUI ("kk");
}
public void showUI(String str){
JFrame jf = new JFrame ();
jf.setTitle ("❤️DDqq登陸界面❤️");
jf.setSize (500, 400);
jf.setDefaultCloseOperation (3);
jf.setLocationRelativeTo (null);
jf.setResizable (false);
FlowLayout fl = new FlowLayout (FlowLayout.CENTER, 5, 5);
jf.setLayout (fl);
Dimension dim1 = new Dimension (500, 200);//圖片大小
Dimension dim2 = new Dimension (100, 50);//標(biāo)簽大小
Dimension dim3 = new Dimension (300, 30);//輸入框大小
Dimension dim4 = new Dimension (100, 40);//按鈕大小
ImageIcon icon = new ImageIcon ("source/Login1.jpg");
JLabel labimg = new JLabel (icon);
labimg.setPreferredSize (dim1);
jf.add (labimg);
JLabel labuser = new JLabel ();
labuser.setText ("user:");
labuser.setPreferredSize (dim2);
jf.add (labuser);
JTextField textuser = new JTextField ();
textuser.setPreferredSize (dim3);
jf.add (textuser);
JLabel labpassword = new JLabel ();
labpassword.setText ("password:");
labpassword.setPreferredSize (dim2);
jf.add (labpassword);
JPasswordField textPassword = new JPasswordField ();
textPassword.setPreferredSize (dim3);
jf.add (textPassword);
JButton button = new JButton ();
button.setBorder (BorderFactory.createRaisedBevelBorder ());
button.setText ("login");
button.setPreferredSize (dim4);
jf.add (button);
jf.setVisible (true);
LoginListener ll = new LoginListener(textuser,textPassword, jf);
button.addActionListener (ll);
this.jTextField=ll.jTextField;
}
}
login的監(jiān)聽(tīng)類 LoginListener
package com.lding.net;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* @program: Chat
* @description:
* @author: 王丁
* @date: 2021-09-26 08:59
**/
public class LoginListener implements ActionListener {
JTextField jTextField;
JPasswordField jPasswordField;
JFrame jf ;
LoginListener( JTextField jTextField,JPasswordField jPasswordField,JFrame jf){
this.jf=jf;
this.jTextField = jTextField;
this.jPasswordField = jPasswordField;
}
@Override
public void actionPerformed(ActionEvent e){
if(jTextField.getText().equals("Alice")&&String.valueOf(jPasswordField.getPassword()).equals("1234")){
System.out.println ("服務(wù)端登錄??!");
String name =jTextField.getText();
new Server(name).start();
jf.dispose();
}else if(jTextField.getText().equals("Lding")&&String.valueOf(jPasswordField.getPassword()).equals("1234")){
String name =jTextField.getText();
System.out.println ("客戶端登錄!!");
new Client(name).start();
jf.dispose();
}
}
}
在登陸完畢后,需要跳轉(zhuǎn)到聊天界面,這里采用的方法是通過(guò)一個(gè)flag標(biāo)志來(lái)判斷是否登陸完畢,當(dāng)?shù)顷懲戤吅螅瑫?huì)創(chuàng)建新的聊天界面,并且登陸頁(yè)面會(huì)被關(guān)閉
依然是雙端通信,假定一端為客戶端,一端為服務(wù)端,其實(shí)兩端都可為用戶。
聊天界面運(yùn)行圖
先登陸Alice的賬號(hào) 密碼為123456

登陸成功后顯示ok,并等待連接

再登陸冷丁的賬號(hào),密碼為123456

當(dāng)lding賬號(hào)登陸成功后完成連接,這時(shí)候會(huì)彈出兩個(gè)新的JFram窗口,為聊天見(jiàn)面

隨后可以發(fā)送消息,消息可以實(shí)時(shí)顯示時(shí)間,并顯示用戶名
一方發(fā)送的消息會(huì)在另一方的窗口上實(shí)時(shí)顯示出來(lái)

Client類代碼
package com.lding.net;
import com.lding.ui.MsgUI;
import javax.swing.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @program: Chat
* @description: 客戶端
* @author: 王丁
* @date: 2021-09-26 08:58
**/
public class Client extends Thread{
String name;
public Client(String name) {
this.name=name;
}
public static void main(String[] args) {
String port="客戶端";
Login login=new Login();
login.showUI(port);
}
@Override
public void run(){
try {
startClient();
} catch (IOException e) {
e.printStackTrace ();
}
}
void startClient() throws IOException{
Socket socket=new Socket("127.0.0.1",8888);
//輸入 輸出流對(duì)象
InputStream inputStream=socket.getInputStream();
OutputStream outputStream=socket.getOutputStream();
MsgUI msgUI=new MsgUI(outputStream,name);
JTextPane showmsgpane=msgUI.initUI("客戶端");
outputStream.flush();
int count=1;
while(true){
int msglenth=inputStream.read();
System.out.println("消息長(zhǎng)度:"+msglenth);
byte[] msgbytes=new byte[msglenth];
//將接下來(lái)的數(shù)據(jù)讀入字節(jié)數(shù)組中
inputStream.read(msgbytes);
count++;
if(count%2==0){
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設(shè)置日期格式
String date = df.format(new Date());// new Date()為獲取當(dāng)前系統(tǒng)時(shí)間,也可使用當(dāng)前時(shí)間戳
String getmsg=new String(msgbytes);
String msg=showmsgpane.getText();
showmsgpane.setText(msg+date+" ["+getmsg+"]"+"說(shuō):"+"\n");
}else{
String getmsg=new String(msgbytes);
String msg=showmsgpane.getText();
showmsgpane.setText(msg+getmsg+"\n");
}
}
}
}
Server代碼
package com.lding.net;
import com.lding.ui.MsgUI;
import javax.swing.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @program: Chat
* @description:
* @author: 王丁
* @date: 2021-09-26 08:58
**/
public class Server extends Thread{
JTextField jTextField;
String name;
public Server(String name){
this.name=name;
}
public static void main(String[] args) {
String port="服務(wù)端";
Login login=new Login();
login.showUI(port);
}
@Override
public void run(){
try {
startServer();
} catch (IOException e) {
e.printStackTrace ();
}
}
void startServer() throws IOException{
ServerSocket serverSocket=new ServerSocket(8888);
System.out.println("等待連接?。?);
Socket clientsocket=serverSocket.accept();//監(jiān)聽(tīng)連接
System.out.println("連接成功??!");
InputStream inputStream=clientsocket.getInputStream();
OutputStream outputStream=clientsocket.getOutputStream();
MsgUI msgUI=new MsgUI(outputStream,name);
JTextPane showmsgpane=msgUI.initUI("服務(wù)端");
//outputStream.flush();
int count=1;
while(true){
int msglenth=inputStream.read();
System.out.println("消息長(zhǎng)度是:"+msglenth);
byte[] msgbytes=new byte[msglenth];
//將接下來(lái)的數(shù)據(jù)讀入字節(jié)數(shù)組中
inputStream.read(msgbytes);
count++;
if(count%2==0){
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設(shè)置日期格式
String date = df.format(new Date());// new Date()為獲取當(dāng)前系統(tǒng)時(shí)間,也可使用當(dāng)前時(shí)間戳
String getmsg=new String(msgbytes);
String msg=showmsgpane.getText();
showmsgpane.setText(msg+date+" ["+getmsg+"]"+"說(shuō):"+"\n");
}else{
String getmsg=new String(msgbytes);
String msg=showmsgpane.getText();
showmsgpane.setText(msg+getmsg+"\n");
}
}
}
}
登陸界面代碼
MsgUI
package com.lding.ui;
import javax.swing.*;
import java.awt.*;
import java.io.OutputStream;
/**
* @program: Chat
* @description:
* @author: 王丁
* @date: 2021-09-26 08:59
**/
public class MsgUI extends JFrame {
OutputStream outputStream;
String name;
public MsgUI(OutputStream outputStream,String name){
this.outputStream=outputStream;
this.name=name;
}
public JTextPane initUI(String title){
setTitle(title);
setSize(800,800);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new FlowLayout());
//接收顯示框
JTextPane jtp=new JTextPane();
jtp.setPreferredSize(new Dimension(750,400));
JScrollPane jsp=new JScrollPane(jtp);
jtp.getText();
Dimension dim=new Dimension(750,400);//按鈕大小
//發(fā)送框
JTextPane jtp1=new JTextPane();
jtp1.setPreferredSize(new Dimension(750,200));
JScrollPane jsp1=new JScrollPane(jtp1);
JButton btn=new JButton("發(fā)送");
add(jsp);
add(jsp1);
add(btn);
setVisible(true);
MsgListener msgl=new MsgListener(jtp1,this.outputStream,name);
btn.addActionListener(msgl);
return jtp;
}
}
MsgUIListener
package com.lding.ui;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
/**
* @program: Chat
* @description:
* @author: 王丁
* @date: 2021-09-26 09:00
**/
public class MsgListener implements ActionListener {
JTextPane jtp;
OutputStream outputStream;
String name;
public MsgListener(JTextPane jtp,OutputStream outputStream,String name){
this.jtp=jtp;
this.outputStream=outputStream;
this.name=name;
}
@Override
public void actionPerformed(ActionEvent e) {
byte[] names=this.name.getBytes();
try {
outputStream.write(names.length);
outputStream.write(names);
outputStream.flush();
} catch (IOException ex) {
ex.printStackTrace();
}
String msg=jtp.getText();
byte[] msgs=msg.getBytes();
try {
outputStream.write(msgs.length);
outputStream.write(msgs);
outputStream.flush();
} catch (IOException ex) {
ex.printStackTrace();
}
jtp.setText(null);
}
}
之后會(huì)豐富更多功能 敬請(qǐng)期待! 感謝您的觀看!??!
到此這篇關(guān)于Java模擬qq軟件的詳細(xì)過(guò)程的文章就介紹到這了,更多相關(guān)Java 模擬 qq內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot中接收POST參數(shù)的幾種方式詳解
SpringBoot時(shí)間格式化的方法小結(jié)
解決mybatis plus字段為null或空字符串無(wú)法保存到數(shù)據(jù)庫(kù)的問(wèn)題
如何解決@PutMapping或@PostMapping接收String類型參數(shù)多兩個(gè)“引號(hào)問(wèn)題
java 四舍五入保留小數(shù)的實(shí)現(xiàn)方法
簡(jiǎn)單聊聊Java中驗(yàn)證碼功能的實(shí)現(xiàn)
java調(diào)用opencv身份證號(hào)識(shí)別詳解

