package Client;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Date;
import java.util.Set;
import java.sql.Connection;
import java.text.Format;
import java.text.SimpleDateFormat;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import java.util.*;
import org.jvnet.substance.skin.*;
public class ClientChatInterface extends JFrame implements WindowListener,FocusListener{
private static JPanel panel1;
private static JPanel panel2;
private static JPanel panel3;
private static JPanel panel4;
private static JPanel inputPanel;
private static JTextArea input;
private static JTextField status;
private static JLabel label1;
private static JComboBox comboBox;
private static JButton clear;
private static JButton sendButton;
private static JLabel label2;
private static JLabel label3;
private static JTextArea textArea;
private static Container container;
private static CardLayout card;
private static GridLayout grid1;
private static GridLayout grid2;
private static JScrollPane jsp;
private static JScrollPane inputScroll;
private static BufferedReader in;
private static PrintWriter out;
//主要是用来新建不同的对象并存入数组列表
private static JTextArea jt;
private static JScrollPane js;//同上
private static Date date;
private static SimpleDateFormat f;
private static String time;
private static JSplitPane splitPanel;
private static JMenuBar menuBar;
private static JMenu system;
private static JMenuItem exit;
private static JMenu format;
private static JMenu font;
private static JMenu color;
private static JMenu size;
private static final Color[] colorStyle={Color.BLACK,Color.GREEN,Color.BLUE,Color.YELLOW,Color.PINK,Color.RED,Color.ORANGE,
Color.CYAN,Color.GRAY,Color.LIGHT_GRAY,Color.MAGENTA,Color.WHITE};
private static String fontNames[]={"Serif","幼圆","方正舒体","楷书"};
private static String colorNames[]={"Black","Green","Blue","Yellow","Pink","Red","Orange","Cyan","Gray","Light_gray","Magenta","White"};
private static String sizeNames[]={"一号","二号","三号","四号","五号","六号"};
private static JRadioButtonMenuItem fonts[]=new JRadioButtonMenuItem[fontNames.length];
private static JRadioButtonMenuItem colors[]=new JRadioButtonMenuItem[colorNames.length];
private static JRadioButtonMenuItem sizes[]=new JRadioButtonMenuItem[sizeNames.length];
private static JCheckBoxMenuItem bold;
private static JCheckBoxMenuItem italic;
private static ButtonGroup fontGroup,colorGroup,sizeGroup;
private static int style;
private static int fontSize=13;
//jmap主要是用来存放每个在线用户的用户名以及与他对应的聊天面板
private static Map<String,JTextArea>jmap;
private static int count=1;
private static String cName;
private static String myname;
private static Socket socket;
private static int number;
private static String message;
private static boolean flag=false;
private static boolean first=true;
private static String ss=new String();
private static String from=new String();
// private static String message1=new String();
private static String messageTime=new String();
private static String m=new String();
public ClientChatInterface(final BufferedReader in,final PrintWriter out,String serverName,String userName){
super(userName);
myname=userName;
this.out=out;
this.in=in;
jmap=new HashMap<String,JTextArea>();
//菜单栏
menuBar=new JMenuBar();
system=new JMenu("System");
exit=new JMenuItem("Exit");
format=new JMenu("Format");
font=new JMenu("Font");
color=new JMenu("Color");
size=new JMenu("Size");
fontGroup=new ButtonGroup();
colorGroup=new ButtonGroup();
sizeGroup=new ButtonGroup();
class ItemHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
for(int i=0;i<colorNames.length;i++){
if(colors[i].isSelected()){
input.setForeground(colorStyle[i]);
status.setForeground(colorStyle[i]);
textArea.setForeground(colorStyle[i]);
jt.setForeground(colorStyle[i]);
comboBox.setForeground(colorStyle[i]);
label1.setForeground(colorStyle[i]);
label2.setForeground(colorStyle[i]);
label3.setForeground(colorStyle[i]);
sendButton.setForeground(colorStyle[i]);
clear.setForeground(colorStyle[i]);
break;
}
}
//处理字体
for(int i=0;i<fontNames.length;i++){
if(e.getSource()==fonts[i]){
input.setFont(new Font(fontNames[i],style,fontSize));
status.setFont(new Font(fontNames[i],style,fontSize));
textArea.setFont(new Font(fontNames[i],style,fontSize));
jt.setFont(new Font(fontNames[i],style,fontSize));
comboBox.setFont(new Font(fontNames[i],style,fontSize));
label1.setFont(new Font(fontNames[i],style,fontSize));
label2.setFont(new Font(fontNames[i],style,fontSize));
label3.setFont(new Font(fontNames[i],style,fontSize));
sendButton.setFont(new Font(fontNames[i],style,fontSize));
clear.setFont(new Font(fontNames[i],style,fontSize));
break;
}
}
repaint();
}
}
class StyleHandler implements ItemListener{
public void itemStateChanged(ItemEvent e){
style=0;
if(bold.isSelected())
style+=Font.BOLD;
if(italic.isSelected())
style+=Font.ITALIC;
input.setFont(new Font(input.getFont().getName(),style,fontSize));
status.setFont(new Font(status.getFont().getName(),style,fontSize));
textArea.setFont(new Font(textArea.getFont().getName(),style,fontSize));
jt.setFont(new Font(jt.getFont().getName(),style,fontSize));
comboBox.setFont(new Font(comboBox.getFont().getName(),style,fontSize));
label1.setFont(new Font(label1.getFont().getName(),style,fontSize));
label2.setFont(new Font(label2.getFont().getName(),style,fontSize));
label3.setFont(new Font(label3.getFont().getName(),style,fontSize));
sendButton.setFont(new Font(sendButton.getFont().getName(),style,fontSize));
clear.setFont(new Font(clear.getFont().getName(),style,fontSize));
repaint();
}
}
class SizeHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
for(int i=0;i<sizeNames.length;i++){
if(sizes[i].isSelected()){
fontSize=13+i*3;
break;
}
}
input.setFont(new Font(input.getFont().getName(),style,fontSize));
status.setFont(new Font(status.getFont().getName(),style,fontSize));
textArea.setFont(new Font(textArea.getFont().getName(),style,fontSize));
jt.setFont(new Font(jt.getFont().getName(),style,fontSize));
comboBox.setFont(new Font(comboBox.getFont().getName(),style,fontSize));
label1.setFont(new Font(label1.getFont().getName(),style,fontSize));
label2.setFont(new Font(label2.getFont().getName(),style,fontSize));
label3.setFont(new Font(label3.getFont().getName(),style,fontSize));
sendButton.setFont(new Font(sendButton.getFont().getName(),style,fontSize));
clear.setFont(new Font(clear.getFont().getName(),style,fontSize));
repaint();
}
}
ItemHandler ch=new ItemHandler();
StyleHandler sh=new StyleHandler();
SizeHandler ss=new SizeHandler();
for(int i=0;i<fontNames.length;i++){
fonts[i]=new JRadioButtonMenuItem(fontNames[i]);
font.add(fonts[i]);
fontGroup.add(fonts[i]);
fonts[i].addActionListener(ch);
}
for(int i=0;i<colorNames.length;i++){
colors[i]=new JRadioButtonMenuItem(colorNames[i]);
color.add(colors[i]);
colorGroup.add(colors[i]);
colors[i].addActionListener(ch);
}
for(int i=0;i<sizeNames.length;i++){
sizes[i]=new JRadioButtonMenuItem(sizeNames[i]);
size.add(sizes[i]);
sizeGroup.add(sizes[i]);
sizes[i].addActionListener(ss);
}
exit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
sendMessage("exit");
System.exit(0);
}
});
bold=new JCheckBoxMenuItem("Bold");
italic=new JCheckBoxMenuItem("Italic");
bold.addItemListener(sh);
italic.addItemListener(sh);
//设置分隔线
font.addSeparator();
font.add(bold);
font.add(italic);
setJMenuBar(menuBar);
menuBar.add(system);
menuBar.add(format);
system.add(exit);
format.add(font);
format.add(color);
format.add(size);
f=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
clear=new JButton("清空聊天记录(alt+c)");
sendButton=new JButton("发送()alt+s");
sendButton.setMnemonic('s'); //设置发送信息的快捷键alt+s
clear.setMnemonic('c');
panel1=new JPanel();
panel2=new JPanel();
panel3=new JPanel();
panel4=new JPanel(); //放置text;
splitPanel=new JSplitPane(JSplitPane.VERTICAL_SPLIT);
inputPanel=new JPanel();
inputPanel.setLayout(new BorderLayout());
input=new JTextArea(10,1);
inputScroll=new JScrollPane(input,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
inputPanel.add(inputScroll,BorderLayout.CENTER);
status=new JTextField();
comboBox=new JComboBox();
label1=new JLabel();
label2=new JLabel();
textArea=new JTextArea();
jt=textArea;
jsp=new JScrollPane(textArea,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
jsp.setWheelScrollingEnabled(true);//设置鼠标滚轮可以滑动文本框
label3=new JLabel("聊天记录:");
card=new CardLayout();
grid1=new GridLayout(3,1);
grid2=new GridLayout(2,1);
panel1.setLayout(new BorderLayout());
panel2.setLayout(new GridLayout(1,4));
panel3.setLayout(grid2);
panel4.setLayout(card);
panel1.add(label1,BorderLayout.NORTH);
panel1.add(inputPanel,BorderLayout.CENTER);
panel1.add(label3,BorderLayout.SOUTH);
panel2.add(label2);
panel2.add(comboBox);
panel2.add(clear);
panel2.add(sendButton);
panel3.add(panel2);
panel3.add(status);
validate();
splitPanel.setDividerLocation(0.3);
splitPanel.add(panel1,JSplitPane.TOP);
splitPanel.add(panel4,JSplitPane.BOTTOM);
container=getContentPane();
container.add(splitPanel,BorderLayout.CENTER);
container.add(panel3,BorderLayout.SOUTH);
input.addFocusListener(this);
class SendListen implements ActionListener{
public void actionPerformed(ActionEvent e){
if(input.getText().equals("")){
JOptionPane.showMessageDialog(null,"输入的内容不能为空!","提示",JOptionPane.WARNING_MESSAGE);
}else{
sendMessage(input.getText());
input.setText("");
}
label1.setText("输入信息完毕,准备输下一条");
}
}
sendButton.addActionListener(new SendListen());
clear.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
jt.setText("");
}
});
status.setEditable(false);
textArea.setEditable(false);
setSize(400,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//使位于中央
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = getSize();
if (frameSize.height > screenSize.height) {
frameSize.height = screenSize.height;
}
if (frameSize.width > screenSize.width) {
frameSize.width = screenSize.width;
}
setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
//改变下拉框值时的处理事件类
class Listener extends Thread implements ActionListener{
public void run(){
cName=(String)comboBox.getSelectedItem();
if(cName.equals(myname)){
JOptionPane.showMessageDialog(null,"您选择的用户是自己","提示",JOptionPane.INFORMATION_MESSAGE);
}else{
//告诉服务线程要改变用户聊了
out.println("change");
out.flush();
//告诉服务器要和谁聊
out.println(cName);
out.flush();
}
jt=jmap.get(cName);
card.show(panel4,cName);
}
public void actionPerformed(ActionEvent e){
if(count++==1){
this.start();
}else{
if(e.getActionCommand().equals("comboBoxChanged")){
this.interrupt();
new Listener().start();
}else{
this.start();
}
}
}
}
Listener listener=new Listener();
comboBox.addActionListener(listener);
setVisible(true);
}
public void windowClosing(WindowEvent e){
sendMessage("exit");
System.exit(0);
}
public void windowClosed(WindowEvent e){
sendMessage("exit");
System.exit(0);
}
public void windowActivated(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
/**
* @param message:将要发送的信息
*/
public void sendMessage(String message){
try{
date=new Date();
time=f.format(date);
if(!comboBox.getSelectedItem().equals(myname)){
if(!message.equals("exit")){
out.println(myname+" "+time);
out.flush();
}
out.println(message);
out.flush();
}else{
jt=jmap.get(myname);
}
jt.append(myname+" "+time+"\n"+message+"\n");
}catch(Exception e5){
System.out.println(e5.getMessage());
e5.printStackTrace();
jt.append( "\n发送信息出错!");
}
}
/**
* 主要是用来实现下拉框显示的在线用户的更新
* @param name:需要增加的在线用户的名字
*/
public static void addComboItem(String name){
JTextArea jt1=new JTextArea();
if(!name.equals(myname))
jt1.setToolTipText("您正在与"+name+"聊天");
else
jt1.setToolTipText(myname+",您现在没和别人聊天");
jmap.put(name,jt1);
jt1.setEditable(false);
js=new JScrollPane(jt1,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
inputPanel.add(js,BorderLayout.CENTER);
panel4.add(js,name);
comboBox.addItem(name);
number++;
label2.setText("OnLineNum:"+number+" Select:");
}
/**
* 通过服务器获得在线用户,并且为每个在线用户设置一个聊天面板
* @param in:先前与服务器建立连接时创建的输入流
* @param out:先前与服务器建立连接时创建的输出流
*/
public static void initUser()throws IOException{
String userN="";
number=0;
//当读到服务器发来的"The End"命令时,说明已经把在线用户信息发送完毕了
while(!(userN=in.readLine()).equals("theEnd")){
//创建与该用户聊天的面板,即实现下拉框对应的用户
addComboItem(userN);
if(!userN.equals(myname)){
comboBox.setSelectedItem(userN);
}
}
//如果我是第一个上线的用户的话,那我设置一个布尔值,下次一有用户上线(即第二位),我就选中他
if(number==1){
first=true;
}
label2.setText("OnLineNum:"+number+" Select:");
connect(in);
}
/**
*
* @return 标志在线用户数的
*/
public static JLabel getLabel2(){
return label2;
}
public static int getNum(){
return number;
}
/**
* 进行一次通话
*/
public synchronized static void communicate(){
try{
//读取信息,可能是来通知来了新用户,需要加到下拉框,也可能是对方发过来的消息
//flag表示是否来了新用户消息;flag初始值为false
if(!flag){
ss=(String)in.readLine();
}else{
ss=m;
}
if(ss.equals("add")){
//读取新增用户名,并加到下拉框
from=in.readLine();
addComboItem(from);
//如果是第一个登录的客户,所以就要当第二个用户刚登录时就选中默认的
if(first==true){
comboBox.setSelectedItem(from);
first=false;
}
}else{
//如果不是新增的用户的话,那就是普通的聊天
from=ss;
messageTime=in.readLine();
message=in.readLine();
if(message.equals("leave")){
comboBox.removeItem(from);
number--;
getLabel2().setText("OnLineNum:"+number+" Select:");
}else{
do{
try{
//调出相应的面板
jt=jmap.get(from);
jt.append( messageTime+"\n");
jt.append(message+"\n");
//来了消息时就使面板变黄
jt.setBackground(Color.ORANGE);
//使记录框指针始终指向末尾
jt.setCaretPosition(jt.getText().length());
//来了消息时在聊天面板最下方表明消息来源
status.setText(from+"来新的消息了,请注意查收");
status.setBackground(Color.BLUE);
}catch(Exception e4){
System.out.println(e4.getMessage());
e4.printStackTrace();
status.setText("出现故障了");
}
//继续读下一个消息来源的用户名
m=in.readLine();
if(m.equals(from)){
messageTime=(String)in.readLine();
message=(String)in.readLine();
//如果我正和我聊的人下线了时,则删除该用户
if(message.equals("leave")){
comboBox.removeItem(from);
number--;
getLabel2().setText("OnLineNum:"+number+" Select:");
flag=false;
break;
}
}else if(m.equals("add")){
from=in.readLine();
addComboItem(from);
break;
}
else{
flag=true;
}
}while(m.equals(from));
}
}
}catch(EOFException eof){
status.setText("接收信息时出错了!");
}catch(IOException t){
jt.append(t.getMessage());
}
}
public static void connect(BufferedReader in){
while(true){
communicate();
}
}
/**
* 对焦处理
*/
public void focusGained(FocusEvent e){
label1.setText("正在输入信息...");
status.setText("");
status.setBackground(Color.white);
input.setBackground(Color.PINK);
jt.setBackground(Color.WHITE);
}
/**
* 失焦处理
*/
public void focusLost(FocusEvent e){
label1.setText("输入信息:");
input.setBackground(Color.GRAY);
}
}