java模拟一个简单的QQ

效果图:

     

  1 package testFour;
  2
  3 import java.awt.Color;
  4 import java.awt.Dimension;
  5 import java.awt.FontMetrics;
  6 import java.awt.Graphics;
  7 import java.io.ByteArrayInputStream;
  8 import java.io.IOException;
  9 import java.io.InputStream;
 10 import java.net.BindException;
 11 import java.net.ServerSocket;
 12 import java.util.Iterator;
 13
 14 import javax.imageio.ImageIO;
 15 import javax.imageio.ImageReader;
 16 import javax.imageio.stream.ImageInputStream;
 17 import javax.swing.ImageIcon;
 18 import javax.swing.JLabel;
 19 import javax.swing.JPanel;
 20 import javax.swing.JTextPane;
 21 import javax.swing.text.BadLocationException;
 22 import javax.swing.text.Document;
 23 import javax.swing.text.SimpleAttributeSet;
 24 import javax.swing.text.StyleConstants;
 25
 26 public class QQ {
 27     public static final int PICUTER = 1;
 28     public static final int FILE = 2;
 29     public static final int PARAGRAPH = 3;
 30     public static final int SEND = 1;
 31     public static final int RECEIVE = 2;
 32     public static final int FILEX = 3;
 33
 34     public static int getUnusedPort() throws BindException{
 35         int port;
 36         for(port = 10000 ; port <= 65535; ++port){
 37             ServerSocket ss = null;
 38             try {
 39                 ss = new ServerSocket(port);
 40             } catch (IOException e) {
 41                 e.printStackTrace();
 42             }
 43             if(ss != null) break;
 44         }
 45         if(port > 65535)
 46             throw new BindException("没有可用的端口!");
 47         return port;
 48     }
 49
 50     public synchronized static void setTextPane(JTextPane tp, byte[] bt, int len, int flag, int tag){
 51          ImageIcon myIcon = null;
 52          if(tag == SEND)
 53              myIcon = new ImageIcon("ff.jpg");
 54          else if(tag == RECEIVE)
 55              myIcon = new ImageIcon("gg.jpg");
 56          else if(tag == FILEX)
 57              myIcon = new ImageIcon("kk.jpg");
 58
 59          SimpleAttributeSet set = new SimpleAttributeSet();
 60          Document doc = tp.getStyledDocument();
 61
 62          if(tag == SEND || tag == RECEIVE){
 63               tp.setCaretPosition(doc.getLength());
 64               JLabel fileLabel = new JLabel("", myIcon, JLabel.CENTER);
 65               tp.insertComponent(fileLabel);
 66          }
 67
 68          if(flag == PARAGRAPH){
 69              FontMetrics fm = tp.getFontMetrics(tp.getFont());
 70              int paneWidth = tp.getWidth();
 71              String text = new String(bt, 0, len);
 72
 73              if( tag/3 == SEND ){
 74                  StyleConstants.setForeground(set, new Color(0,255,0));//设置文字颜色
 75                  StyleConstants.setFontSize(set, 15);//设置字体大小
 76              }
 77              else if( tag/3 == RECEIVE){
 78                  StyleConstants.setForeground(set, new Color(0,0,0));//设置文字颜色
 79                  StyleConstants.setFontSize(set, 15);//设置字体大小
 80              }
 81
 82              try
 83               {
 84                   for(int i = 0, cnt = 0; i < text.length(); ++i){
 85                       if((cnt += fm.charWidth(text.charAt(i))) >= paneWidth){
 86                           cnt = 0;
 87                           doc.insertString(doc.getLength(), "\n", set);
 88                           continue;
 89                       }
 90                       doc.insertString(doc.getLength(), String.valueOf(text.charAt(i)), set);
 91                   }
 92                   doc.insertString(doc.getLength(), "\n", set);
 93
 94                   tp.setCaretPosition(doc.getLength());//最简单的设置滚动条的位置到最后输出文本的地方
 95                                                          //就是将JTextPane中的插入符的位置移动到文本的末端!
 96               }
 97               catch (BadLocationException e)
 98               {
 99               }
100
101          } else if(flag == PICUTER) {
102
103              try{
104                      InputStream is = new ByteArrayInputStream(bt, 0, len);
105                      ImageInputStream iis = ImageIO.createImageInputStream(is);
106                      Iterator<ImageReader> itImage = ImageIO.getImageReaders(iis);
107                      if(itImage.hasNext()){
108                          ImageReader reader = itImage.next();
109                          ImageIcon ii = new ImageIcon( bt, reader.getFormatName() );
110                          tp.setCaretPosition( doc.getLength() );
111                          tp.insertComponent( new PicuterPanel(ii) );
112                          doc.insertString(doc.getLength(), "\n", set);
113                      }
114              }catch(IOException ex){
115                      ex.printStackTrace();
116              }catch(BadLocationException e1){
117
118              }
119
120          } else if(flag == FILE) {
121               try{
122                   tp.setCaretPosition(doc.getLength());
123                   JLabel fileLabel = new JLabel(new String(bt, 0, len), myIcon, JLabel.LEFT);
124                   tp.insertComponent(fileLabel);
125                   doc.insertString(doc.getLength(), "\n", set);
126               }catch (BadLocationException e) {
127                   e.printStackTrace();
128             }
129          }
130     }
131 }
132
133 class PicuterPanel extends JPanel{
134     private ImageIcon ii;
135     public PicuterPanel(ImageIcon ii){
136         this.ii = ii;
137         setPreferredSize(new Dimension(200, 300));
138         setBackground(new Color(255, 255, 255));
139     }
140
141     protected void paintComponent(Graphics g) {
142           super.paintComponent(g);
143           g.drawImage(ii.getImage(), 0, 0, 200, 300, 0, 0, ii.getIconWidth(), ii.getIconHeight(), this);
144     }
145 }

  1 package testFour;
  2
  3 import java.awt.BorderLayout;
  4 import java.awt.Color;
  5 import java.awt.Dialog;
  6 import java.awt.Dimension;
  7 import java.awt.FlowLayout;
  8 import java.awt.Font;
  9 import java.awt.Frame;
 10 import java.awt.Point;
 11 import java.awt.event.ActionEvent;
 12 import java.awt.event.ActionListener;
 13 import java.awt.event.MouseAdapter;
 14 import java.awt.event.MouseEvent;
 15 import java.awt.event.WindowAdapter;
 16 import java.awt.event.WindowEvent;
 17 import java.net.InetAddress;
 18 import java.net.UnknownHostException;
 19 import java.util.Map;
 20 import java.util.Random;
 21 import java.util.Set;
 22 import java.util.TreeMap;
 23 import java.util.TreeSet;
 24
 25 import javax.print.attribute.standard.Severity;
 26 import javax.swing.BoxLayout;
 27 import javax.swing.ImageIcon;
 28 import javax.swing.JButton;
 29 import javax.swing.JLabel;
 30 import javax.swing.JMenuItem;
 31 import javax.swing.JOptionPane;
 32 import javax.swing.JPanel;
 33 import javax.swing.JPopupMenu;
 34 import javax.swing.JScrollBar;
 35 import javax.swing.JScrollPane;
 36 import javax.swing.JTextField;
 37 import javax.swing.ScrollPaneConstants;
 38
 39
 40
 41 public class QQDialog extends Frame{
 42         private JPanel QQP = new JPanel();
 43         private JButton myFriend = new JButton("QQ好友>>");
 44         private JPanel funP = new JPanel();
 45         private JButton add = new JButton("添加好友");
 46         private JButton serach = new JButton("查询好友");
 47         private JPanel pp = new JPanel();
 48         private JPanel tmp = null;
 49         private final int QQPheight = 397;
 50         private JScrollPane jsp = new JScrollPane(QQP);
 51         private static Set<String>QQset;//姓名的集合
 52         private static Map<String, QQFrame>QQmap;//姓名到对通信窗口的映射
 53         private static Map<String, byte[]>nameToIP;//姓名到IP的映射
 54         ImageIcon[] ii = new ImageIcon[3];
 55
 56         public static Map<String, QQFrame> getMap(){
 57             return QQmap;
 58         }
 59
 60         public static Set<String> getSet(){
 61             return QQset;
 62         }
 63
 64         public static Map<String, byte[]> getNameToIP(){
 65             return nameToIP;
 66         }
 67
 68         public QQDialog(){
 69
 70             QQset = new TreeSet<String>();
 71             QQmap = new TreeMap<String, QQFrame>();
 72             nameToIP = new TreeMap<String, byte[]>();
 73
 74             ii[0] = new ImageIcon("ff.jpg");
 75             ii[1] = new ImageIcon("gg.jpg");
 76             ii[2] = new ImageIcon("kk.jpg");
 77             setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
 78             jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
 79             jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
 80             pp.add(jsp);
 81             pp.setLayout(new BoxLayout(pp, BoxLayout.Y_AXIS));
 82             QQP.setLayout(new BoxLayout(QQP, BoxLayout.Y_AXIS));
 83             JPanel pmyFriend = new JPanel();
 84             pmyFriend.setLayout(new BorderLayout());
 85             pmyFriend.add(myFriend, "Center");
 86             pmyFriend.setPreferredSize(new Dimension(300, 20));
 87             add(pmyFriend);
 88             pp.setPreferredSize(new Dimension(300, 400));
 89             add(pp);
 90             add(funP);
 91
 92             JLabel myself = null;
 93             try {
 94                 myself = new JLabel(InetAddress.getLocalHost().getHostName() + ":" + InetAddress.getLocalHost().getHostAddress());
 95             } catch (UnknownHostException e) {
 96                 e.printStackTrace();
 97             }
 98             addLabelListener(myself);
 99             myself.setIcon(new ImageIcon("ff.jpg"));
100
101             tmp = new JPanel();
102             tmp.setLayout(new FlowLayout(FlowLayout.CENTER));
103             tmp.setBackground(new Color(255, 0, 255));
104             tmp.setPreferredSize(new Dimension(250, 60));
105             tmp.add(myself);
106             QQP.add(tmp);
107             funP.setLayout(new FlowLayout(FlowLayout.CENTER));
108             funP.add(add);
109             funP.add(serach);
110
111             myFriend.addMouseListener(new MouseAdapter() {
112
113                     public void mouseClicked(MouseEvent e) {//将好友面板进行收缩的效果!
114                         if("QQ好友>>".equals(myFriend.getText())){
115                             QQP.setVisible(false);
116                             myFriend.setText("QQ好友<<");
117                         }
118                         else{
119                             QQP.setVisible(true);
120                             myFriend.setText("QQ好友>>");
121                         }
122                     }
123
124             });
125
126             add.addMouseListener(new MouseAdapter() {
127                     public void mouseClicked(MouseEvent e) {
128                         InputDialog dlg = new InputDialog();
129                         if(dlg.key == InputDialog.CANCELBTN || dlg.key== 0) return;
130                         Random rd = new Random();
131                         int index = Math.abs(rd.nextInt()) % 3;
132                         JLabel ll = new JLabel(dlg.getNameText() + ":" + dlg.getIPText(), ii[index], JLabel.LEFT);
133                         tmp = new JPanel();
134                         tmp.setLayout(new FlowLayout(FlowLayout.CENTER));
135                         tmp.setBackground(new Color(255, 0, 255));
136
137                         /*
138                          *  BoxLayout布局简直是蛋疼的要命,一个面板X是BoxLayout布局,如果该面板添加一个面板Y的话
139                          *  那么Y就会填充X面板!如果在添加一个面板Z, 那么Y, Z就会一起布满X面板!但是可以设置Y,Z面板
140                          *  的比例! 如果X添加的是一个按钮或者标签时,还不能控制其大小.....无语了!
141                          *
142                          *  下面的我的做法将标签添加到面板tmp中,然后再将tmp添加中QQP面板中!这样就可以控制标签的大小了!
143                          *  再添加新的面板的时候,要设置一下之前面板的PreferredSize!保证每一个标签的距离适中!
144                          *  也就是保证所有的添加的面板的高度之和 == QQP.getHeight();
145                          * */
146                         int cnt = QQP.getComponentCount();//显示QQ好友的个数!
147                         if(cnt >= 1)
148                             QQP.getComponent(cnt-1).setPreferredSize(new Dimension(250, 60));
149                         int h = QQP.getHeight() - cnt*60;
150                         if(h < 0) h=60;
151                         tmp.setPreferredSize(new Dimension(250, h));
152                         tmp.add(ll);
153                         QQP.add(tmp);
154                         QQP.add(tmp);
155                         addLabelListener(ll);//给标签添加监听器
156                         JScrollBar jsb = jsp.getVerticalScrollBar();
157                         QQP.updateUI();//利用当前外观的值重置 UI 属性。 也可以保证滚动条随时的更新
158                         //终于搞好了,将垂直滚动条自动的移动到最低端
159                         jsp.getViewport().setViewPosition(new Point(0, jsp.getVerticalScrollBar().getMaximum()));
160                     }
161             });
162
163             serach.addMouseListener(new MouseAdapter() {
164                     public void mouseClicked(MouseEvent e) {
165                           String name = JOptionPane.showInputDialog(null, "好友姓名", "好友查询", JOptionPane.OK_OPTION);
166                           if(name == null)  return ;
167                           if(!QQset.contains(name))
168                                   JOptionPane.showMessageDialog(null, "好友不存在!", "查询结果", JOptionPane.OK_OPTION);
169                           else{
170                               QQFrame fm = QQmap.get(name);
171                               if(fm == null){
172                                   try{
173                                         fm = new QQFrame(name, nameToIP.get(name));
174                                     }catch(RuntimeException ex){
175                                         JOptionPane.showMessageDialog(null, ex.getMessage(), "Socket错误!", JOptionPane.OK_CANCEL_OPTION);
176                                         return ;
177                                     }
178                                   QQmap.put(name, fm);
179                               }
180                               else fm.requestFocus();
181                           }
182                     }
183             });
184
185             addWindowListener(new WindowAdapter() {
186                     public void windowClosing(WindowEvent e) {
187                         if(qr == null) System.out.println("hehe");
188                         qr.setFlag();//udp服务线程停止
189                         ss.setFlag();//tcp服务线程停止
190                         System.exit(0);
191                     }
192             });
193
194             QQP.setBackground(new Color(255, 0, 255));
195             funP.setBackground(new Color(255, 255, 0));
196             setResizable(false);
197             setSize(300, 500);
198             setLocation(500, 200);
199             setVisible(true);
200         }
201
202
203         public void addLabelListener(final JLabel lab){
204              lab.setOpaque(true);
205              lab.setBackground(new Color(255, 255, 255));
206              lab.setPreferredSize(new Dimension(250, 55));
207
208              String NameAndIP = lab.getText();
209               String name = NameAndIP.substring(0, NameAndIP.indexOf(‘:‘));
210               String ip = NameAndIP.substring(NameAndIP.indexOf(‘:‘) + 1, NameAndIP.length());
211
212               String[] ipStr = ip.split("\\.");//将字符串中的数字分离
213              byte[] ipBuf = new byte[4];//存储IP的byte数组
214              for(int i = 0; i < 4; i++){
215                  ipBuf[i] = (byte)(Integer.parseInt(ipStr[i])&0xff);
216              }
217              nameToIP.put(name, ipBuf);
218              QQset.add(name);
219
220              lab.addMouseListener(new MouseAdapter() {
221                      Color oldC = lab.getBackground();
222                      public void mouseEntered(MouseEvent e) {
223                           lab.setBackground(new Color(0, 255, 0));
224                      }
225
226                      public void mouseExited(MouseEvent e) {
227                           lab.setBackground(oldC);
228                      }
229
230                      public void mouseClicked(MouseEvent e) {
231                           //打开通信窗口
232                           if(e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2){
233                                  String NameAndIP = lab.getText();
234                                  String name = NameAndIP.substring(0, NameAndIP.indexOf(‘:‘));
235                                  if(QQmap.get(name) != null){//这个好友的窗口已经存在!
236                                     QQmap.get(name).requestFocus();
237                                     return ;
238                                  }
239                                  QQFrame fm = null;
240                                 try{
241                                     fm = new QQFrame(name, nameToIP.get(name));
242                                 }catch(RuntimeException ex){
243                                     JOptionPane.showMessageDialog(null, ex.getMessage(), "Socket错误!", JOptionPane.OK_CANCEL_OPTION);
244                                     return ;
245                                 }
246
247                                  QQmap.put(name, fm);//name 和 窗口的映射!
248                           }
249                           else if(e.getButton() == MouseEvent.BUTTON3){
250                                JPopupMenu pm = new JPopupMenu("胡峻峥");
251                                JMenuItem del = new JMenuItem("删除");
252                                del.setFont(new Font("华文行楷", Font.ITALIC, 20));
253                                del.setForeground(new Color(255, 0, 0));
254                                del.addActionListener(new ActionListener() {
255                                     public void actionPerformed(ActionEvent e) {
256                                         int choose = JOptionPane.showConfirmDialog(null, "确定删除!", "删除对话框", JOptionPane.YES_NO_OPTION);
257                                            if(choose == JOptionPane.OK_OPTION){
258                                                QQP.remove(lab.getParent());
259                                                int cnt = QQP.getComponentCount();
260                                                int h = QQP.getHeight() - (cnt-1)*60;
261                                              if(h < 0) h=60;
262                                                if(cnt >= 1)
263                                                  QQP.getComponent(cnt-1).setPreferredSize(new Dimension(250, h));
264
265                                                cnt = QQP.getComponentCount();
266                                                if(cnt*60 <= QQPheight)
267                                                    QQP.setPreferredSize(new Dimension(QQP.getWidth(), QQPheight));
268                                                else
269                                                    QQP.setPreferredSize(new Dimension(QQP.getWidth(), cnt*60));
270                                                QQP.updateUI();
271
272                                                String NameAndIP = lab.getText();
273                                               String name = NameAndIP.substring(0, NameAndIP.indexOf(‘:‘));
274                                                QQset.remove(name);
275                                                QQFrame fm = QQmap.get(name);
276                                                if(fm != null) fm.dispose();
277                                                QQmap.remove(name);
278                                            }
279                                     }
280                               });
281
282                                JMenuItem edit = new JMenuItem("编辑");
283                                edit.addActionListener(new ActionListener() {
284
285                               public void actionPerformed(ActionEvent e) {
286                                     //得到之前的数据!
287                                     String content = lab.getText();
288                                     //从新设置到文本框中
289                                     InputDialog id = new InputDialog(content.substring(content.indexOf(‘:‘)+1), content.substring(0, content.indexOf(‘:‘)));
290                                     if(id.key == InputDialog.CANCELBTN || id.key== 0) return;
291                                     lab.setText(id.NAME + ":" + id.IP);
292                                 }
293                               });
294                                edit.setFont(new Font("华文行楷", Font.ITALIC, 20));
295                                edit.setForeground(new Color(255, 0, 255));
296                                pm.setBorderPainted(true);
297                                pm.setBackground(new Color(125, 0, 125));
298                                pm.add(del);  pm.add(edit);
299                                pm.show(lab, e.getX(), e.getY());
300                           }
301                      }
302
303              });
304         }
305
306         //内部类,用来访问Frame中的数据成员
307         class InputDialog extends Dialog{
308             private JLabel ipLabel = new JLabel("IP地址:");
309             private JLabel nameLabel = new JLabel("姓名:");
310             private JButton okBtn = new JButton("确定");
311             private JButton cleBtn = new JButton("取消");
312             private JTextField ipText = new JTextField(20);
313             private JTextField nameText = new JTextField(20);
314             private static final int OKBTN = 1;
315             private static final int CANCELBTN = 2;
316             private int key = 0;
317             private String IP = null, NAME = null;
318             void initDialog(){
319                 JPanel p = null;
320                 setModal(true);
321                 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
322
323                 add(p = new JPanel());
324                 p.setLayout(new FlowLayout(FlowLayout.CENTER));
325                 ipLabel.setPreferredSize(new Dimension(50, 12));
326                 p.add(ipLabel); p.add(ipText);
327
328
329                 add(p = new JPanel());
330                 p.setLayout(new FlowLayout(FlowLayout.CENTER));
331                 nameLabel.setPreferredSize(new Dimension(50, 12));
332                 p.add(nameLabel); p.add(nameText);
333
334                 add(p = new JPanel());
335                 p.setLayout(new FlowLayout(FlowLayout.CENTER));
336                 p.add(okBtn); p.add(cleBtn);
337
338                 addWindowListener(new WindowAdapter() {
339                         public void windowClosing(WindowEvent e) {
340                              key = 0;
341                              dispose();
342                         }
343                 });
344
345                 addMouseListener(new MouseAdapter() {
346                         public void mouseClicked(MouseEvent e) {
347                              requestFocus();
348                         }
349                 });
350
351                 okBtn.addMouseListener(new MouseAdapter() {
352                         public void mouseClicked(MouseEvent e) {
353                              key = InputDialog.OKBTN;
354                              if("".equals(ipText.getText()) || "".equals(nameText.getText()) || !checkIP(ipText.getText()) )
355                                      JOptionPane.showMessageDialog(null, "信息不全或者IP填写错误!");
356                              else{
357                                  String name = nameText.getText();
358                                  if(QQset.contains(name)){
359                                      JOptionPane.showMessageDialog(null, "好友已存在!", "QQ好友", JOptionPane.OK_OPTION);
360                                      return ;
361                                  }
362                                  QQset.add(name);//将新增加的好友添加到集合中!
363                                  IP = ipText.getText();
364                                  NAME = nameText.getText();
365                                  dispose();
366                              }
367                         }
368                 });
369
370                 cleBtn.addMouseListener(new MouseAdapter() {
371                         public void mouseClicked(MouseEvent e) {
372                             key = InputDialog.CANCELBTN;
373                             dispose();
374                         }
375                 });
376                 setSize(300, 200);
377                 setLocation(200, 200);
378                 setVisible(true);
379             }
380
381             public InputDialog(String ip, String name){
382                 super(new Frame());
383                 ipText.setText(ip);
384                 nameText.setText(name);
385                 initDialog();
386             }
387
388             public InputDialog(){
389                 super(new Frame());
390                 initDialog();
391             }
392
393             public boolean checkIP(String ip){
394                 int i, begin = 0, end;
395                 for(i = 1; i <= 4; ++i){
396                     end = ip.indexOf(‘.‘, begin);
397                     if(end == -1) return false;
398                     int p = Integer.valueOf(ip.substring(begin, end));
399                     if(p < 0 || p > 255)  return false;
400                 }
401                 return true;
402             }
403
404             public String getIPText(){
405                 return IP;
406             }
407
408             public String getNameText(){
409                 return NAME;
410             }
411
412         }
413
414
415         private static ServerSocketQQ ss = null;
416         private static QQReceive qr = null;
417
418         public static void main(String[] args){
419
420              ss = new ServerSocketQQ();
421              new Thread(ss).start();
422              if(ServerSocketQQ.getPort() < 1) return;
423
424              qr = new QQReceive();
425              new Thread(qr).start();
426              if(qr.getPort() < 1)  return ;
427
428             new QQDialog();
429         }
430 }

  1 package testFour;
  2
  3 import java.awt.Color;
  4 import java.awt.Dimension;
  5 import java.awt.FlowLayout;
  6 import java.awt.Font;
  7 import java.awt.Frame;
  8 import java.awt.Label;
  9 import java.awt.TextArea;
 10 import java.awt.event.KeyAdapter;
 11 import java.awt.event.KeyEvent;
 12 import java.awt.event.MouseAdapter;
 13 import java.awt.event.MouseEvent;
 14 import java.awt.event.WindowAdapter;
 15 import java.awt.event.WindowEvent;
 16 import java.io.File;
 17 import java.io.FileInputStream;
 18 import java.io.IOException;
 19 import java.io.InputStream;
 20 import java.io.OutputStream;
 21 import java.net.DatagramPacket;
 22 import java.net.DatagramSocket;
 23 import java.net.InetAddress;
 24 import java.net.InetSocketAddress;
 25 import java.net.Socket;
 26 import java.net.SocketAddress;
 27 import java.net.UnknownHostException;
 28 import java.util.Calendar;
 29 import java.util.Iterator;
 30 import java.util.Map;
 31
 32 import javax.imageio.ImageIO;
 33 import javax.imageio.ImageReader;
 34 import javax.imageio.stream.ImageInputStream;
 35 import javax.swing.BoxLayout;
 36 import javax.swing.JButton;
 37 import javax.swing.JFileChooser;
 38 import javax.swing.JOptionPane;
 39 import javax.swing.JPanel;
 40 import javax.swing.JScrollPane;
 41 import javax.swing.JTextPane;
 42 import javax.swing.filechooser.FileFilter;
 43
 44
 45
 46 public class QQFrame extends Frame{
 47      private TextArea taSend = new TextArea();
 48      private JTextPane taReceive = new JTextPane();
 49      private JScrollPane p = new JScrollPane(taReceive);
 50      private JPanel pSend = new JPanel();
 51      private JPanel pReceive = new JPanel();
 52      private Label laSend = new Label("发送端.....");
 53      private Label laReceive = new Label("接收端.....");
 54      private JButton FileBtn = new JButton("传输文件");
 55      private JButton PicuterBtn = new JButton("发送图片");
 56      private InetAddress sendIAD = null;//当前窗口所对应的好友所在机器的IP对象
 57      private String QQname = null;//该对话框所对应的好友的姓名
 58      private Socket st =null;
 59      private String text;
 60      private DatagramSocket ds = null;
 61
 62      public QQFrame(String name, byte[] ipBuf) throws RuntimeException{
 63          try {
 64             sendIAD = InetAddress.getByAddress(ipBuf);
 65          } catch (UnknownHostException e3) {
 66             JOptionPane.showMessageDialog(null, "IP错误", "错误类型", JOptionPane.OK_CANCEL_OPTION);
 67             return ;
 68          }
 69
 70          ds = QQReceive.getUdpSocket();
 71          if(ds == null)  throw new RuntimeException("udp Socket出错!");
 72
 73          QQname = name;
 74          text = "";
 75          setSize(600, 600);
 76          setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
 77          pSend.setLayout(new FlowLayout(FlowLayout.LEFT));
 78          pSend.add(laSend);
 79          pSend.add(FileBtn);
 80          pSend.add(PicuterBtn);
 81          pReceive.setLayout(new FlowLayout(FlowLayout.LEFT));
 82          pReceive.add(laReceive);
 83
 84          taReceive.setForeground(new Color(255, 0, 255));
 85          add(pReceive);
 86          add(p);
 87          add(pSend);
 88          add(taSend);
 89          setTitle("我的好友 " + QQname);
 90
 91
 92          taSend.setPreferredSize(new Dimension(0, 200));
 93          taReceive.setPreferredSize(new Dimension(0, 400));
 94
 95          taSend.setFont(new Font("仿宋", Font.PLAIN, 20));
 96          taReceive.setFont(new Font("黑体", Font.PLAIN, 25));
 97
 98          taReceive.setEditable(false);//不能进行文本的编辑,但是可以进行访问
 99
100          taSend.addKeyListener(new KeyAdapter() {
101
102              public void keyPressed(KeyEvent e) {
103                 if(e.getKeyCode() == KeyEvent.VK_ENTER){
104                      text = taSend.getText();
105                      if(text == null) return;
106                      text += "\n\n";
107                      byte[] bt = text.getBytes();
108                      DatagramPacket dp = null;
109                      try {
110                          //向指定的ip和端口发送数据~!
111                          //先说明一下数据是谁发送过来的!
112                          dp = new DatagramPacket(QQname.getBytes(), QQname.getBytes().length, sendIAD, QQReceive.getPort());
113                          ds.send(dp);
114
115                          dp = new DatagramPacket("PARAGRAPH".getBytes(), "PARAGRAPH".getBytes().length, sendIAD, QQReceive.getPort());
116                          ds.send(dp);
117                          dp = new DatagramPacket(bt, bt.length, sendIAD, QQReceive.getPort());
118                          ds.send(dp);
119                      } catch (IOException e1) {
120                         e1.printStackTrace();
121                      }
122
123                      synchronized(QQ.class){//发送端向接收窗口添加数据时 要 和 接收端向接收窗口添加数据时同步!
124                          byte[] x = new String(QQname + " : ").getBytes();
125                          QQ.setTextPane(taReceive, x, x.length, QQ.PARAGRAPH, QQ.SEND);
126                          x = text.getBytes();
127                          QQ.setTextPane(taReceive, x, x.length, QQ.PARAGRAPH, QQ.SEND*3);
128                      }
129
130                      taSend.setText("");//发送端清空
131                      e.consume();//不让这个回车字符在输入端显示!
132                      return ;
133                 }
134             }
135
136          });
137
138          addWindowListener(new WindowAdapter() {
139
140             public void windowClosing(WindowEvent e) {
141                 Map<String, QQFrame>mp = QQDialog.getMap();
142                 mp.remove(QQname);
143                 dispose();
144             }
145
146          });
147
148          FileBtn.addMouseListener(new MouseAdapter() {//文件传输
149                 public void mouseClicked(MouseEvent e) {
150                      JFileChooser jfc = new JFileChooser();
151                      jfc.showOpenDialog(null);
152                      File fl = jfc.getSelectedFile();
153                      if(fl == null) return ;
154                      try {
155                         st =  new Socket();//尝试连接对方
156                         st.connect(new InetSocketAddress(sendIAD, ServerSocketQQ.getPort()), 1000);
157                      } catch (IOException e2) {
158                         st = null;
159                         JOptionPane.showMessageDialog(null, "连接错误!", "ServerSocket", JOptionPane.OK_CANCEL_OPTION);
160                      }
161                      if(st != null){
162                         try {
163                             byte[] bt = new byte[1024];
164                             InputStream is = st.getInputStream();
165                             OutputStream os = st.getOutputStream();
166                             //先说明一下是谁发送过来的!
167                             os.write(QQname.getBytes());
168                             os.flush();
169
170                             //向对方首先发送文件名, 然后发送文件内容!
171                             os.write(fl.getName().getBytes());
172                             os.flush();
173
174                             int len;
175                             InputStream fis = new FileInputStream(fl);
176                             while( (len = fis.read(bt)) != -1){
177                                 os.write(bt, 0, len);
178                                 os.flush();
179                             }
180                             bt = new String(Calendar.getInstance().getTime().toString() + ":文件已传输!").getBytes();
181                             QQ.setTextPane(taReceive, bt, bt.length, QQ.FILE, QQ.FILEX);
182                             st.shutdownOutput();//输出流结束,并标记一下,使服务端知道客户端输出已经结束了!
183                             st.close();
184
185                         } catch (IOException e1) {
186                             e1.printStackTrace();
187                         }
188                      }
189                 }
190          });
191
192          PicuterBtn.addMouseListener(new MouseAdapter() {
193                 public void mouseClicked(MouseEvent e) {
194                     JFileChooser jfc = new JFileChooser();
195                     jfc.setFileFilter(new PicuterFilter());//设置当前的文件过滤器!
196                     jfc.setAcceptAllFileFilterUsed(false);//设置所有文件过滤器不使用!
197                     //jfc.addChoosableFileFilter(new Filter());
198                     jfc.showOpenDialog(null);
199
200                    //将输入流按照下面方式处理, 根据Iterator<ImageReader> itImage是否能
201                    //成功的返回一个ImageReader对象确认该流文件是否是一个图片文件!
202                    //并ImageReader类中的getFormatName()得到文件的格式!
203                    //通过最后可以通过ImageIcon的byte[]构造函数建立ImageIcon对象!
204                    //最后将图片显示在面板上!
205                     File fl = jfc.getSelectedFile();
206                     if(fl == null) return ;
207                     try{
208                              InputStream is = new FileInputStream(fl);
209                              ImageInputStream iis = ImageIO.createImageInputStream(is);
210                              Iterator<ImageReader> itImage = ImageIO.getImageReaders(iis);
211                              if(itImage.hasNext()){
212                                   ImageReader reader = itImage.next();
213                                   byte[] imageByte = new byte[1024*64];
214                                   int len = iis.read(imageByte);
215                                   if(len > 64 * 1000){
216                                       JOptionPane.showMessageDialog(new Frame(), "图片过大!请采用文件传输!");
217                                       return ;
218                                   }
219                                   DatagramPacket dp = null;
220                                   //先说明一下数据是谁发送过来的!
221                                   dp = new DatagramPacket(QQname.getBytes(), QQname.getBytes().length, sendIAD, QQReceive.getPort());
222                                   ds.send(dp);
223
224                                   dp = new DatagramPacket("PICUTER".getBytes(), "PICUTER".getBytes().length, InetAddress.getLocalHost(), QQReceive.getPort());
225                                   ds.send(dp);
226                                   dp = new DatagramPacket(imageByte, len, InetAddress.getLocalHost(), QQReceive.getPort());
227                                   ds.send(dp);
228                                   synchronized(QQ.class){
229                                       byte[] name = new String(dp.getAddress().getHostName() + " : ").getBytes();
230                                       QQ.setTextPane(taReceive, name, name.length, QQ.PARAGRAPH, QQ.SEND);
231                                       QQ.setTextPane(taReceive, imageByte, len, QQ.PICUTER, 0);
232                                   }
233                              }
234                              else throw new NoPicuterException("不是一张图片!");
235                     }catch(IOException ex){
236                         ex.printStackTrace();
237                     }
238                 }
239          });
240
241          setVisible(true);
242      }
243
244      public DatagramSocket getDs(){
245          return ds;
246      }
247
248      public JTextPane getReceive(){
249          return taReceive;
250      }
251
252 }
253
254 class PicuterFilter extends FileFilter {
255
256     public boolean accept(File file){
257            return(file.isDirectory() || file.getName().endsWith(".gif")
258                   || file.getName().endsWith(".png") || file.getName().endsWith(".bmp")
259                   || file.getName().endsWith(".jpg") );
260            /* 返回要显示的文件类型 */
261            /*
262             *   File.isDirectory()测试此抽象路径名表示的文件是否是一个目录
263            */
264       }
265
266       public String getDescription() {
267           return("Picuter Files(*.gif, *.png, *.jpg, *.bmp)");                  //返回显示文件类型的描述
268       }
269 }
270
271 class NoPicuterException extends IOException{
272     public NoPicuterException(String x){
273         super(x);
274     }
275 }

 1 package testFour;
 2
 3 import java.io.IOException;
 4 import java.net.DatagramPacket;
 5 import java.net.DatagramSocket;
 6 import java.net.SocketException;
 7 import java.util.Map;
 8 import java.util.Set;
 9
10 import javax.swing.JOptionPane;
11
12 public class QQReceive implements Runnable{
13     private QQFrame fm = null;
14     private static DatagramSocket ds = null;
15     private static int port = 10101;
16     private boolean flag = true;
17
18     public void setFlag(){
19         if(ds != null)
20             ds.close();
21         flag = false;
22     }
23     public QQReceive(){
24         try {
25             //建立udp通信方式
26             ds = new DatagramSocket(port);
27          } catch (SocketException e1) {
28              port = -1;
29              JOptionPane.showMessageDialog(null, "DatagramSocket端口绑定错误!", "绑定错误", JOptionPane.OK_CANCEL_OPTION);
30         }
31     }
32
33     public static DatagramSocket getUdpSocket(){
34         return ds;
35     }
36
37     public static int getPort(){
38         return port;
39     }
40
41     public DatagramSocket getDS(){
42         return ds;
43     }
44
45     public void run(){
46         if(ds == null) return ;
47         while(flag){
48             byte[] bt = new byte[10024*10];
49             int flag = 0;
50             DatagramPacket dp = new DatagramPacket(bt, bt.length);
51             try {
52                     ds.receive(dp);
53
54                     String name = new String(dp.getData(), 0, dp.getLength());
55                     Map<String, QQFrame>mp = QQDialog.getMap();
56                     Set<String>  set = QQDialog.getSet();
57                     fm = mp.get(name);
58                     if(set.contains(name) && fm == null){//如果存在该好友,但是不存在对应的对话窗口
59                          //自动产生对话窗口
60                          Map<String, byte[]> nameToIP = QQDialog.getNameToIP();
61                          fm = new QQFrame(name, nameToIP.get(name));
62                     }
63                     ds.receive(dp);
64                     String tag = new String(dp.getData(), 0, dp.getLength());
65                     if( tag.equals("FILE") )
66                         flag = QQ.FILE;
67                     else if( tag.equals("PICUTER"))
68                         flag = QQ.PICUTER;
69                     else if( tag.equals("PARAGRAPH"))
70                         flag = QQ.PARAGRAPH;
71
72                     ds.receive(dp);
73
74             } catch (IOException e) {
75                 e.printStackTrace();
76             }
77             synchronized(QQ.class){
78                 if(fm == null) continue;
79                 byte[] x = new String(dp.getAddress().getHostName() + " : ").getBytes();
80                 QQ.setTextPane(fm.getReceive(), x, x.length, QQ.PARAGRAPH, QQ.RECEIVE);
81                 QQ.setTextPane(fm.getReceive(), dp.getData(), dp.getLength(), flag, QQ.RECEIVE*3);
82             }
83         }
84     }
85 }

  1 package testFour;
  2
  3 import java.io.File;
  4 import java.io.FileOutputStream;
  5 import java.io.IOException;
  6 import java.io.InputStream;
  7 import java.io.OutputStream;
  8 import java.net.ServerSocket;
  9 import java.net.Socket;
 10 import java.util.Calendar;
 11 import java.util.Map;
 12 import java.util.Set;
 13
 14 import javax.swing.JOptionPane;
 15
 16 public class ServerSocketQQ implements Runnable{
 17     private ServerSocket sst = null;
 18     private Socket st = null;
 19     private static int port = 10100;
 20     private boolean flag = true;
 21
 22     public void setFlag(){
 23         if(sst != null)
 24             try {
 25                 sst.close();
 26             } catch (IOException e) {
 27                 e.printStackTrace();
 28             }
 29         flag = false;
 30     }
 31
 32     public static int getPort(){
 33         return port;
 34     }
 35
 36     public ServerSocketQQ(){
 37         //建立服务端
 38         try {
 39             sst = new ServerSocket(port);
 40         } catch (IOException e) {
 41             port = -1;
 42             JOptionPane.showMessageDialog(null, "ServerSocket端口绑定错误!", "绑定错误", JOptionPane.OK_CANCEL_OPTION);
 43         }
 44
 45     }
 46
 47     public void run(){
 48         byte[] bt = null;
 49         int len = 0;
 50         if(sst == null)  return ;
 51         while(true){
 52             try{
 53                 //侦听并接受到此服务套接字的连接。此方法在进行连接之前一直阻塞。 创建新套接字
 54                 st = sst.accept();
 55                 //得到客户端传输过来的流
 56                 InputStream is = st.getInputStream();
 57                 OutputStream os  = st.getOutputStream();
 58                 bt = new byte[1024];
 59
 60                 len = is.read(bt);
 61                 String name = new String(bt, 0, len);
 62                 QQFrame fm = null;
 63                 Map<String, QQFrame>mp = QQDialog.getMap();
 64                 Set<String>  set = QQDialog.getSet();
 65                 fm = mp.get(name);
 66                 if(set.contains(name) && fm == null){//如果存在该好友,但是不存在对应的对话窗口
 67                      //自动产生对话窗口
 68                      Map<String, byte[]> nameToIP = QQDialog.getNameToIP();
 69                      fm = new QQFrame(name, nameToIP.get(name));
 70                 }
 71                 if(fm == null){//对方不存在该好友!
 72                     st.close();
 73                     continue;
 74                 }
 75
 76                 len = is.read(bt);
 77                 String fileName = new String(bt, 0, len);
 78
 79                 int choose = JOptionPane.showConfirmDialog(null, "接受或不接受", "文件传输提示", JOptionPane.YES_NO_OPTION);
 80                 if(choose == JOptionPane.NO_OPTION){
 81                     bt = new String(Calendar.getInstance().getTime().toString() + ":文件接受失败!").getBytes();
 82                     QQ.setTextPane(fm.getReceive(), bt, bt.length, QQ.FILE, QQ.FILEX);
 83                     st.close();
 84                     continue;
 85                 }
 86                 FileOutputStream fos = new FileOutputStream( new File(fileName) );
 87                 while( (len = is.read(bt)) != -1 ){//先将流文件变成byte[], 然后利用套接字的输出流发送给客户端
 88                      fos.write(bt);
 89                      fos.flush();
 90                 }
 91                 bt = new String(Calendar.getInstance().getTime().toString() + ":文件接受成功!").getBytes();
 92                 QQ.setTextPane(fm.getReceive(), bt, bt.length, QQ.FILE, QQ.FILEX);
 93                 st.close();
 94            }catch(IOException e){
 95                e.printStackTrace();
 96            }
 97         }
 98      }
 99
100 }

时间: 2024-10-24 10:28:25

java模拟一个简单的QQ的相关文章

java-第十三章-类的无参方法(一)-模拟一个简单的购房商贷月供计算器

package 本章总结; public class A02class { double Money = 0; public double showA(double money, int choice) { switch (choice) { case 1: Money = (money + money * 0.0603) / 36; break; case 2: Money = (money + money * 0.0612) / 60; break; case 3: Money = (mon

利用java实现一个简单的远程监控程序

一般的远程监控软件都是用c或者c++等语言开发的,而使用java如何来实现相同的功能呢. 首先我们先介绍一下一个简单的远程监控程序的实现原理. 功能一,远程屏幕监视 (1) 必须要有监控端与被监控端,而且程序保持启动. (2) 被监控端获取本机的屏幕截屏发图给监控端. (3) 监控端在本地窗口中显示被监控端发送过来的图像. (4) (2)(3)步骤重复执行,这时在监控端即可实时监视到被监控端的桌面操作了. 功能二,远程控制 (1) 必须要有监控端与被监控端,而且程序保持启动. (2) 在监控端监

java创建一个简单的小框架frame

import java.awt.*; import javax.swing.*; public class SimpleFrameTest { public static void main(String[] args) { EventQueue.invokeLater(new Runnable(){ // 开一个线程 public void run() { SimpleFrame frame = new SimpleFrame(); frame.setTitle("记事本"); //

java模拟一个抽奖程序

今天用一个程序模拟一个从1-32之间,随机抽取7组号码的抽奖程序 * 需要使用Java的图形界面知识 * 窗口  JFrame * 面板  JPanel * 显示文本信息的标签  JLabel * 文本框 JTextField * 按钮  JButton 还涉及到线程Thread 先看效果图: 但是这里留一个问题?就是去除重复数字(可以自己先实现,后期我会上传的) 下面看看代码,代码中有注释,不懂留言: package thread.test1; import java.awt.BorderLa

Java写一个简单学生管理系统

其实作为一名Java的程序猿,无论你是初学也好,大神也罢,学生管理系统一直都是一个非常好的例子,初学者主要是用数组.List等等来写出一个简易的学生管理系统,二.牛逼一点的大神则用数据库+swing来做一个有界面的学生管理系统.其实都并不会太难. 今天我就先写一个简单的用List来实现学生管理系统: 首先,管理系统是针对学生对象的,所以我们先把学生对象就写出来: package bean; public class Student { String name; String studentId;

java实现一个简单的Web服务器

Web服务器也称为超文本传输协议服务器,使用http与其客户端进行通信,基于java的web服务器会使用两个重要的类, java.net.Socket类和java.net.ServerSocket类,并基于发送http消息进行通信. 这个简单的Web服务器会有以下三个类: *HttpServer *Request *Response 应用程序的入口在HttpServer类中,main()方法创建一个HttpServer实例,然后调用其await()方法,顾名思义,await()方法会在指定端口

如何设计Java框架----一个简单的例子【翻译】

原文:http://www.programcreek.com/2011/09/how-to-design-a-java-framework/ 原文和翻译都只是参考,如有不对,欢迎指正. 你可能会好奇框架是如何工作的,我会创建一个简单的框架来演示一下. 框架的目标首先,为什么我们需要框架而不是库呢?框架的目标是定义一个让开发者实现基于个性化需求的某些功能的过程,换句话说,框架定义了骨架而开发者进行填补. 简单的框架在下面的例子中,前三个类是框架的一部分,第四个类是该框架的客户端代码. Main.j

黑马程序员——java——模拟一个字符串中的trim方法去掉一个字符串两端的空格

模拟一个字符串中的trim方法去掉一个字符串两端的空格 public class StingTrimDemo { //模拟一个trim方法, 去掉一个字符串两边的空格], public static void main(String[] args) { // TODO Auto-generated method stub String s = " my java "; System.out.println("未去空格前的字符串+++:[ "+s+" ]&q

Java实现一个简单的缓存方法

缓存是在web开发中经常用到的,将程序经常使用到或调用到的对象存在内存中,或者是耗时较长但又不具有实时性的查询数据放入内存中,在一定程度上可以提高性能和效率.下面我实现了一个简单的缓存,步骤如下. 创建缓存对象EntityCache.java public class EntityCache {   /**    * 保存的数据    */   private Object datas;   /**    * 设置数据失效时间,为0表示永不失效    */   private long time