首先,我们来看看QQ发送表情包的方法(发表情包不简单吗?不就是点击一下?)
当我们在待输入框里输入 " / " 的时候,我们发送有提示信息。
结果发现,当我们输入 "/xk"的时候,会直接定位到笑哭的这个表情。
因此我的想法是,当我输入 "//" 含有两个反斜杠的文本消息时,线程那边将会判断它是一个表情包。然后通过"//00","//01","//02"这类字符串,去提取字符串后两位的字符,然后去本地路径去调用图片表情包。因此:"00" , "01" , "02" 就要成为图片的名字。否则匹配不方便。
图片名和路径如下:
线程判断和匹配如下:
Stage牛逼,模拟一切弹窗(主要是我太菜了)。
1 if(str.contains("//")){ 2 Platform.runLater(new Runnable(){ 3 public void run(){ 4 Stage stage = new Stage(); 5 BorderPane bp = new BorderPane(); 6 String[] strs=str.split("//"); 7 String img_name = strs[1]; 8 Image image = new Image("file:表情包/"+img_name+".jpg"); 9 ImageView iv = new ImageView(image); 10 bp.setCenter(iv); 11 Scene scene = new Scene(bp); 12 stage.setTitle("表情"); 13 stage.setScene(scene); 14 stage.centerOnScreen(); 15 stage.show(); 16 } 17 }); 18 }
完整代码如下:
1 package 测试; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.io.InputStream; 8 import java.io.OutputStream; 9 import java.net.DatagramPacket; 10 import java.net.InetAddress; 11 import java.net.MulticastSocket; 12 import java.text.SimpleDateFormat; 13 import java.util.Date; 14 import java.util.Optional; 15 16 import javafx.application.Application; 17 import javafx.application.Platform; 18 import javafx.event.ActionEvent; 19 import javafx.scene.Scene; 20 import javafx.scene.control.Alert; 21 import javafx.scene.control.Button; 22 import javafx.scene.control.ButtonType; 23 import javafx.scene.control.Label; 24 import javafx.scene.control.ScrollPane; 25 import javafx.scene.control.TextArea; 26 import javafx.scene.control.TextField; 27 import javafx.scene.control.TitledPane; 28 import javafx.scene.image.Image; 29 import javafx.scene.image.ImageView; 30 import javafx.scene.layout.AnchorPane; 31 import javafx.scene.layout.BorderPane; 32 import javafx.scene.layout.VBox; 33 import javafx.scene.text.Font; 34 import javafx.stage.FileChooser; 35 import javafx.stage.Stage; 36 import sun.misc.BASE64Decoder; 37 import sun.misc.BASE64Encoder; 38 39 public class FX_UDP extends Application { 40 static InetAddress ia; 41 static MulticastSocket socket, socket2, socket1;// socket(6760) 42 // 聊天,socket1(6770) 43 // 窗口颤抖,socket2(6880) 图片流 44 static TextArea ta_1, ta_2; 45 static TextField tf_name; 46 static Stage s1; 47 48 public static void main(String[] args) { 49 try { 50 ia = InetAddress.getByName("228.9.6.7"); 51 socket = new MulticastSocket(6760); 52 socket.joinGroup(ia); 53 new Private_recive().start(); 54 new Image_recive().start(); 55 } catch (IOException e1) { 56 System.out.println("组播地址绑定失败"); 57 } 58 Application.launch(); 59 } 60 61 @Override 62 public void start(Stage s) throws Exception { 63 s1 = s; 64 Label lb_net = new Label("网名:"); 65 lb_net.setFont(Font.font(17));// 设置字体大小 66 tf_name = new TextField("JDR"); 67 68 /* 消息记录 */ 69 ta_1 = new TextArea(); 70 ta_1.setPrefSize(400, 200); 71 ScrollPane pane_info = new ScrollPane(ta_1); 72 TitledPane pane_01 = new TitledPane("消息记录", pane_info); 73 /* 发送窗口 */ 74 ta_2 = new TextArea(); 75 ta_2.setPrefSize(400, 100); 76 ScrollPane pane_send = new ScrollPane(ta_2); 77 TitledPane pane_02 = new TitledPane("发送窗口", pane_send); 78 /* 发送和按钮事件 */ 79 Button btn_send = new Button("发送"); 80 btn_send.setOnAction(this::btnSend); 81 /* 关闭和按钮事件 */ 82 Button btn_close = new Button("关闭"); 83 btn_close.setOnAction(this::btnClose); 84 /* 发送图片和按钮事件 */ 85 Button btn_img = new Button("选择图片"); 86 btn_img.setOnAction(this::btnImg); 87 Button btn_preview = new Button("预览图片"); 88 btn_preview.setOnAction(this::btnPreview); 89 /* 窗口抖动 */ 90 Button btn_shake = new Button("窗口抖动"); 91 btn_shake.setOnAction(this::btnShake); 92 /* 按钮大小 */ 93 btn_send.setPrefSize(70, 30); 94 btn_close.setPrefSize(70, 30); 95 /* 按钮的位置 */ 96 AnchorPane.setTopAnchor(btn_close, 350.0); 97 AnchorPane.setLeftAnchor(btn_close, 0.0); 98 AnchorPane.setTopAnchor(btn_send, 350.0); 99 AnchorPane.setLeftAnchor(btn_send, 330.0); 100 AnchorPane.setTopAnchor(btn_img, 224.0); 101 AnchorPane.setLeftAnchor(btn_img, 100.0); 102 AnchorPane.setTopAnchor(btn_preview, 224.0); 103 AnchorPane.setLeftAnchor(btn_preview, 160.0); 104 AnchorPane.setTopAnchor(btn_shake, 224.0); 105 AnchorPane.setLeftAnchor(btn_shake, 220.0); 106 107 AnchorPane.setTopAnchor(lb_net, 20.0); 108 AnchorPane.setLeftAnchor(lb_net, 420.0); 109 AnchorPane.setTopAnchor(tf_name, 20.0); 110 AnchorPane.setLeftAnchor(tf_name, 470.0); 111 112 VBox vb = new VBox(pane_01, pane_02); 113 114 AnchorPane apane = new AnchorPane(vb, btn_send, btn_close, btn_img, btn_preview, btn_shake, lb_net, tf_name); 115 apane.setStyle("-fx-background-color:#FFE4C4");// 设置背景色 116 Scene scene = new Scene(apane); 117 118 s.setOnCloseRequest(event -> { 119 Alert alert = new Alert(Alert.AlertType.CONFIRMATION); 120 alert.setTitle("退出"); 121 alert.setHeaderText("你是否要退出?"); 122 Optional<ButtonType> result = alert.showAndWait(); 123 if (result.get() == ButtonType.OK) { 124 try { 125 socket.leaveGroup(ia); 126 System.exit(0); 127 } catch (IOException e) { 128 e.printStackTrace(); 129 } 130 } else { 131 event.consume(); 132 } 133 }); 134 s.setTitle("JDR的午夜群聊"); 135 s.setScene(scene); 136 s.setHeight(450); 137 s.setWidth(650); 138 s.show(); 139 } 140 141 /* 窗口抖动 */ 142 public void btnShake(ActionEvent enent) { 143 144 try { 145 String msg = "shake"; 146 DatagramPacket p = new DatagramPacket(msg.getBytes(), msg.getBytes().length, ia, 6760); 147 socket.send(p); 148 } catch (IOException e) { 149 // TODO 自动生成的 catch 块 150 e.printStackTrace(); 151 } 152 } 153 154 /* 发送按钮事件 */ 155 public void btnSend(ActionEvent enent) { 156 try { 157 String msg = ta_2.getText(); 158 DatagramPacket p = new DatagramPacket(msg.getBytes(), msg.getBytes().length, ia, 6760); 159 socket.send(p); 160 } catch (IOException e) { 161 // TODO 自动生成的 catch 块 162 e.printStackTrace(); 163 } 164 } 165 166 /* 关闭按钮事件 */ 167 public void btnClose(ActionEvent event) { 168 Alert alert = new Alert(Alert.AlertType.CONFIRMATION); 169 alert.setTitle("退出"); 170 alert.setHeaderText("你是否要退出"); 171 Optional<ButtonType> result = alert.showAndWait(); 172 if (result.get() == ButtonType.OK) { 173 System.exit(0); 174 } else { 175 event.consume(); 176 } 177 } 178 179 /* 发送图片按钮事件 */ 180 public void btnImg(ActionEvent event) { 181 FileChooser fileChooser = new FileChooser(); 182 fileChooser.setTitle("选择你要查看的文件"); 183 File file = fileChooser.showOpenDialog(null); 184 if (file != null) { 185 InputStream in = null; 186 byte data[] = new byte[5]; 187 // 读取图片字节数组 188 try { 189 in = new FileInputStream(file); 190 data = new byte[in.available()]; 191 in.read(data); 192 in.close(); 193 } catch (IOException e) { 194 e.printStackTrace(); 195 } 196 197 try { 198 /* 发送消息,告诉别人你发了图片 */ 199 String str = tf_name.getText() + "说:我给你发了张图片"; 200 DatagramPacket p1 = new DatagramPacket(str.getBytes(), str.getBytes().length, ia, 6760); 201 socket.send(p1); 202 // 对字节数组Base64编码 203 BASE64Encoder encoder = new BASE64Encoder(); 204 socket2 = new MulticastSocket(6770); 205 DatagramPacket p2 = new DatagramPacket(encoder.encode(data).getBytes(), 206 encoder.encode(data).getBytes().length, ia, 6770); 207 socket2.joinGroup(ia); 208 socket2.send(p2); 209 } catch (IOException e) { 210 e.printStackTrace(); 211 } 212 } 213 } 214 215 public void btnPreview(ActionEvent event) { 216 FileChooser fileChooser = new FileChooser(); 217 fileChooser.setTitle("选择你要查看的文件"); 218 File file = fileChooser.showOpenDialog(null); 219 220 if (file != null) { 221 Stage stage = new Stage(); 222 BorderPane root = new BorderPane(); 223 String path = file.getPath().toString(); 224 String str = path.replaceAll("\\\\", "\\\\\\\\"); 225 Image image = new Image("file:" + str); 226 ImageView iv = new ImageView(); 227 iv.setImage(image); 228 root.setCenter(iv); 229 Scene scene = new Scene(root); 230 stage.setScene(scene); 231 stage.setWidth(400); 232 stage.setHeight(400); 233 stage.show(); 234 } 235 } 236 } 237 238 class Image_recive extends Thread { 239 public void run() { 240 byte[] buf = new byte[5]; 241 DatagramPacket recv = new DatagramPacket(buf, buf.length); 242 while (true) { 243 BASE64Decoder decoder = new BASE64Decoder(); 244 try { 245 FX_UDP.socket2.receive(recv); 246 String str = new String(recv.getData(), 0, recv.getLength()); 247 // Base64解码 248 byte[] b = decoder.decodeBuffer(str); 249 for (int i = 0; i < b.length; ++i) { 250 if (b[i] < 0) {// 调整异常数据 251 b[i] += 256; 252 } 253 } 254 // 生成png图片 255 Date day = new Date(); 256 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); 257 String name = df.format(day); 258 OutputStream out = new FileOutputStream("D:/(" + name + ").jpg"); 259 out.write(b); 260 out.flush(); 261 out.close(); 262 } catch (Exception e) { 263 } 264 } 265 } 266 } 267 268 class Private_recive extends Thread { 269 public void run() { 270 byte[] buf = new byte[100]; 271 DatagramPacket recv = new DatagramPacket(buf, buf.length); 272 Date day = new Date(); 273 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 274 try { 275 while (true) { 276 FX_UDP.socket.receive(recv); 277 String str = new String(recv.getData(), 0, recv.getLength()); 278 /*窗口颤抖*/ 279 if (str.contains("shake")) { 280 try { 281 FX_UDP.s1.setX(50); 282 Thread.sleep(50); 283 // FX_UDP.s1.centerOnScreen(); 284 FX_UDP.s1.setX(450); 285 } catch (InterruptedException e) { 286 // TODO 自动生成的 catch 块 287 e.printStackTrace(); 288 } 289 /*接收表情字符串*/ 290 } else if(str.contains("//")){ 291 Platform.runLater(new Runnable(){ 292 public void run(){ 293 Stage stage = new Stage(); 294 BorderPane bp = new BorderPane(); 295 String[] strs=str.split("//"); 296 String img_name = strs[1]; 297 Image image = new Image("file:表情包/"+img_name+".jpg"); 298 ImageView iv = new ImageView(image); 299 bp.setCenter(iv); 300 Scene scene = new Scene(bp); 301 stage.setTitle("表情"); 302 stage.setScene(scene); 303 stage.centerOnScreen(); 304 stage.show(); 305 } 306 }); 307 /*正常聊天*/ 308 }else { 309 FX_UDP.ta_1.appendText(df.format(day) + "\n"); 310 FX_UDP.ta_1.appendText(str + "\n"); 311 } 312 } 313 } catch (IOException e1) { 314 System.out.println("接受失败"); 315 } 316 } 317 }
验证结果
输入://00 到 //08 中的任何一个字符串