//简单QQ聊天工具 基于之前发布日记基础
package Chat;
import Q1_Window.Q1_Window;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Q1 {
public static Socket socket;
public static BufferedReader in;
public static PrintWriter os;
public static Q1_in_Listener in_l;
public static Q1_Window window = new Q1_Window() ;//实例化Q1_Window
public static void main(String args[]) throws UnknownHostException, IOException {
//监听连接
Q1_keylistener1 kl1 = new Q1_keylistener1() ;
window.tf1.addKeyListener(kl1);
}
//监听连接
static class Q1_keylistener1 implements KeyListener {
String IP;
public void keyPressed(KeyEvent e) { //默认是一个char一个char响应的
if ( e.getKeyCode() == 10 ) { //10是回车的code号
IP = window.tf1.getText();
try {
//连接
socket = new Socket(IP,5656);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
os = new PrintWriter(socket.getOutputStream());
} catch(IOException e1){
System.out.println("连接问题");
}
//监听输入
in_l = new Q1_in_Listener();
in_l.start();
//监听发送数据
Q1_keylistener2 kl2 = new Q1_keylistener2();
window.tf2.addKeyListener(kl2);
} else{
/*...*/
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
//监听输入
static class Q1_in_Listener extends Thread { //注意:同一个包下面不能用同样的类名 之前Q2用了同样的类名报错(之前分多个类时)
String text;
@SuppressWarnings("unchecked")
public void run() {
while(true) {
try {
text = in.readLine();
} catch (IOException e) {
System.out.println("输入问题");
break;
}
window.l.add(window.l.getSize(), "Q2: " + text);//在此列表的指定位置处插入指定元素。 指定位置 ,元素
}
}
}
//监听数据送出
static class Q1_keylistener2 implements KeyListener {
String text;
@SuppressWarnings("unchecked")
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == 10){
text = window.tf2.getText();
//自己窗口显示要送出信息
window.l.add(window.l.getSize(), "Q1: " + text);
os.println(text);
os.flush();
} else {
/*...*/
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
}
package Chat;
import Q2_Window.Q2_Window;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class Q2 {
static ServerSocket server;
static Socket socket;
static BufferedReader in;
static PrintWriter os;
static Q2_in_Listener in_l;
static Q2_Window window = new Q2_Window();//实例化Q2_Window
public static void main(String args[]) throws UnknownHostException, IOException {
//缺陷连接 只能Q1主动来连接 Q2不具有主动连接功能
//改进:每个端都是Client也是Server
server = new ServerSocket(5656);
socket = server.accept();
window.l.add(0, "Q1: 连接成功!现在你们可以对话啦!");
//套接字送出 送进
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
os = new PrintWriter(socket.getOutputStream());
//通知Q1连接成功
os.println("连接成功!现在你们可以对话啦!");
os.flush();
//监听输入
in_l = new Q2_in_Listener();
in_l.start();
//监听数据发送
Q2_keylistener kl1 = new Q2_keylistener();
window.tf2.addKeyListener(kl1);
}
//监听输入
static class Q2_in_Listener extends Thread { //注意:同一个包下面不能用同样的类名 之前Q2用了同样的类名报错
String text;
public void run() {
while(true) {
try {
text = in.readLine();
} catch (IOException e) {
System.out.println("输入问题");
break;
}
window.l.add(window.l.getSize(), "Q1: " + text);
System.out.println("Q1: " + text);
}
}
}
//监听数据发送
static class Q2_keylistener implements KeyListener {
String text;
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == 10){
text = window.tf2.getText();
window.l.add(window.l.getSize(), "Q2: " + text);
os.println(text);
os.flush();
} else {
/*...*/
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
}
package Q1_Window;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import java.awt.Font;
import javax.swing.JTextField;
import javax.swing.JList;
import java.util.Vector;
public class Q1_Window {
public JFrame frame;
public JTextField tf1;
public JTextField tf2;
public JScrollPane sp;
public Vector<String> v;
public JList<String> list;
@SuppressWarnings("rawtypes")
public DefaultListModel l;
public Q1_Window() {
initialize();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void initialize() {
frame = new JFrame();
JLabel label1 = new JLabel("IP");
label1.setFont(new Font("微软雅黑", Font.PLAIN, 16));
label1.setBounds(25, 226, 29, 15);
frame.getContentPane().add(label1);
JLabel label2 = new JLabel("Text");
label2.setFont(new Font("微软雅黑", Font.PLAIN, 16));
label2.setBounds(210, 226, 42, 15);
frame.getContentPane().add(label2);
tf1 = new JTextField();
tf1.setBounds(50, 224, 144, 21);
frame.getContentPane().add(tf1);
tf1.setColumns(10);
tf2 = new JTextField();
tf2.setBounds(253, 224, 144, 21);
frame.getContentPane().add(tf2);
tf2.setColumns(10);
//DefaultListModel listModel = new DefaultListModel();
//JList list = new JList(listModel);
//v = new Vector();//实现自动增加对象数组
l = new DefaultListModel();
list = new JList(l);
//list.setFont(new Font("微软雅黑", Font.PLAIN, 12));
list.setBorder(BorderFactory.createTitledBorder("Create from liuzebin"));//有意思的边界线
list.setBounds(10, 10, 414, 198);
sp = new JScrollPane(list); //添加滚动条
sp.setBounds(10, 10, 414, 198);//注意一定要设置大小!!!!
//自动生成滚动条
sp.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
sp.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
frame.getContentPane().add(sp);
frame.setTitle("Q1_Chat_Window");
frame.setBounds(100, 100, 450, 300);//前面两个参数是frame在屏幕中的显示位子,后面两个参数是大小
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.setResizable(false); //不允许改变大小
frame.setVisible(true);
}
} package Q2_Window;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import java.awt.Font;
import javax.swing.JTextField;
import javax.swing.JList;
import java.util.Vector;
public class Q2_Window {
public JFrame frame;
public JTextField tf1;
public JTextField tf2;
public JScrollPane sp;
public Vector<String> v;
public JList<String> list;
public DefaultListModel<String> l;
public Q2_Window() {
initialize();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void initialize() {
frame = new JFrame();
JLabel label1 = new JLabel("IP");
label1.setFont(new Font("微软雅黑", Font.PLAIN, 16));
label1.setBounds(25, 226, 29, 15);
frame.getContentPane().add(label1);
JLabel label2 = new JLabel("Text");
label2.setFont(new Font("微软雅黑", Font.PLAIN, 16));
label2.setBounds(210, 226, 42, 15);
frame.getContentPane().add(label2);
tf1 = new JTextField();
tf1.setBounds(50, 224, 144, 21);
frame.getContentPane().add(tf1);
tf1.setColumns(10);
tf2 = new JTextField();
tf2.setBounds(253, 224, 144, 21);
frame.getContentPane().add(tf2);
tf2.setColumns(10);
//v = new Vector();//实现自动增加对象数组
l = new DefaultListModel();
list = new JList(l);
//list.setFont(new Font("微软雅黑", Font.PLAIN, 12));
list.setBorder(BorderFactory.createTitledBorder("Create from liuzebin"));
list.setBounds(10, 10, 414, 198);
sp = new JScrollPane(list); //添加滚动条
sp.setBounds(10, 10, 414, 198);
//自动生成滚动条
sp.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
sp.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
frame.getContentPane().add(sp);
frame.setTitle("Q2_Chat_Window");
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.setResizable(false); //锁定窗口大小
frame.setVisible(true); //之前自己一个类 ,没有此语句,也可执行 出现界面???到Q2引时无法显示
}
}
/*界面:
*/
/*笔记:
1、实现全局引用变量:
一个主类(其他类在主类里面):
static变量,只要实例化一次,可以在主类下面其他类引用变量,无需传递参数。
如:static BufferedReader in;
In = new BufferedReader();
In可以在其他类中直接引用
多个类:
方法一:
如果不在一个主类下面,那么需要传递参数来实现全局引用变量
如:class A{
BufferedReader in = new BufferedReader();
B b = new B(in);
}
Class B{
BufferedReader in;
B(BufferedReader in){
This.in = in
}
//下面引用in
}
方法二:
class A{
BufferedReader in = new BufferedReader();
}
Class B{
A a = new A();
//下面引用in
a.in = …
}
2、全局变量问题
如:
class A{
C c = new C();
}
Class B{
C c = new C();
}
Class C {
//…
}
注意,这样在类A、B中实例的c不是同一个,是全局变量。
3、类的问题
如果类是一个一个分开,那么Q1端和Q2端的类是不能重名的
4、键盘监听器问题
详见日记java keylistener,主要注意如果没有加if语句,默认是一个char输入一个char响应。就不能是每句话的响应了。
要掌握e.getKeyCode(); e.getKeyChar();使用方法
5、list的显示问题
之前用的是
Class Window(){
//主函数 界面省略
Public Vector v = newVector();
Jlist list = new Jlist(v);
v.add(“啦啦啦”);
}
这样就实现添加了。
当没有主函数的只是界面类的时候,在另一个类中实例化这个类,调用v.add(“啦啦啦”);不能实现添加问题。
如:
Class Q1{
Window window = new Window();
window.v.add(“啦啦啦”);
}
理论可以,事实证明失败,主要原因是:list无法动态更新,和tf.setText(“啦啦啦”);有很大差距。
public DefaultListModel l;使用,实现动态更新;
l = new DefaultListModel();
list = new JList(l);
添加:
window.l.add(window.l.getSize(), "Q2: " + text);
6、滚动条实现
JList list = new List();
JScrolPane sp = new JScrolPane(list);
sp.setBound(…);//一定一定要设置大小 和list一样大 不然无法显示
具体情况以及,下拉选项参考使用JAVA SWING 实现列表以及列表的滚动条
*/ /*改进:
1.每个端各自都是Client和Server
2.滚动条实现自动下拉
3.每次输入Text后回车输出清除tf2中的内容 */