如何将GraphicsContext从客户端发送到服务器,然后发送到所有其他客户端?
我现在遇到输入和输出流的问题。它不会将套接字输入流转换为byte []或将套接字输出流转换为int。如何让程序实际发送byte []数组到服务器?下面是更新后的代码:如何将GraphicsContext从客户端发送到服务器,然后发送到所有其他客户端?
import java.io.*;
import java.net.*;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.awt.image.BufferedImage;
import java.io.File;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.*;
import javax.imageio.ImageIO;
public class PaintClient extends Application {
//GUI components
private TextField tfRed = new TextField("");
private TextField tfGreen = new TextField("");
private TextField tfBlue = new TextField("");
private Button btSetColor = new Button("Set Color");
private Button btReset = new Button("Reset");
private Button btSend = new Button("Send");
//Networking components
private Socket socket;
private ByteArrayOutputStream byteOut;
private ByteArrayInputStream byteIn;
@Override
public void start(Stage primaryStage) {
tfRed.setPrefWidth(80);
tfGreen.setPrefWidth(80);
tfBlue.setPrefWidth(80);
GridPane gridPane = new GridPane();
gridPane.add(new Label("Color"), 0, 0);
gridPane.add(tfRed, 1, 0);
gridPane.add(tfGreen, 2, 0);
gridPane.add(tfBlue, 3, 0);
gridPane.add(btSetColor, 4, 0);
gridPane.add(btReset, 2, 1);
gridPane.add(btSend, 3, 1);
Canvas canvas = new Canvas(365,375);
final GraphicsContext gc = canvas.getGraphicsContext2D();
initDraw(gc);
BorderPane bPane = new BorderPane();
bPane.setTop(gridPane);
bPane.setCenter(canvas);
Scene scene = new Scene(bPane, 375, 450);
primaryStage.setTitle("Drawing Canvas");
primaryStage.setScene(scene);
primaryStage.show();
canvas.addEventHandler(MouseEvent.MOUSE_PRESSED,
new EventHandler<MouseEvent>(){
@Override
public void handle(MouseEvent event) {
gc.beginPath();
gc.moveTo(event.getX(), event.getY());
gc.stroke();
}
});
canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED,
new EventHandler<MouseEvent>(){
@Override
public void handle(MouseEvent event) {
gc.lineTo(event.getX(), event.getY());
gc.stroke();
}
});
//Networking
try {
socket = new Socket("localhost", 8000);
byteIn = new ByteArrayInputStream(socket.getInputStream());
byteOut = new ByteArrayOutputStream(socket.getOutputStream());
new Thread(() -> run()).start();
}
catch (IOException ex) {
ex.printStackTrace();
}
}
public void run(){
while(true) {
/*try {
} catch (IOException ex) {
ex.printStackTrace();
}*/
}
}
public void process (Canvas canvas) {
try {
WritableImage image = canvas.snapshot(null, null);
BufferedImage bImage = SwingFXUtils.fromFXImage(image, null);
ImageIO.write(bImage, "jpg", byteOut);
byteOut.flush();
byte[] byteImage = byteOut.toByteArray();
byteOut.close();
byteOut.write(byteImage);
} catch (IOException ex) {
System.err.println(ex);
}
}
public static void main(String[] args) {
Application.launch(args);
}
private void initDraw(GraphicsContext gc) {
double canvasWidth = gc.getCanvas().getWidth();
double canvasHeight = gc.getCanvas().getHeight();
//Event handler when set color button is clicked
btSetColor.setOnAction(e -> {
if(!(tfRed.getText().trim().isEmpty()) && !(tfGreen.getText().trim().isEmpty()) &&
!(tfBlue.getText().trim().isEmpty())) {
int red = Integer.parseInt(tfRed.getText());
int green = Integer.parseInt(tfGreen.getText());
int blue = Integer.parseInt(tfBlue.getText());
gc.setStroke(Color.rgb(red, green, blue));
}
});
gc.setLineWidth(5);
gc.fill();
gc.strokeRect(
0, //x of the upper left corner of the drawing area
0, //y of the upper left corner of the drawing area
canvasWidth, //width of the drawing area
canvasHeight); //height of the drawing area
gc.setLineWidth(1);
//Event handler when reset button is clicked
btReset.setOnAction(e -> {
gc.clearRect(5, 5, 355, 365);
});
}
}
直接发送GraphicsContext
是不可能的,因为GraphicsContext
是没有明确Serializable
。下面给出了实现你打算的典型方法。答:请记住用户操作为“命令”并将它们发送给服务器/其他客户端。这些命令将在客户端执行,并且您将拥有相同的呈现视图。作为实现的例子,您可以用您自己的API封装GraphicsContext
API,以创建这些命令。
public void fillOvalX(double x, double y, double w, double h) {
// a possible approach
commands.put(new DrawCommand(Type.FILL_OVAL, x, y, w, h));
g.fillOval(x, y, w, h);
}
B.通过调用snapshot()执行GraphicsContext
的快照到一个JavaFX Image
。然后使用SwingFXUtils将其转换为BufferedImage
,最后使用ImageIO和ByteArrayOutputStream
将其转换为byte[]
。然后可以通过网络将数组byte[]
序列化。在连接的另一端,您需要按相反的顺序执行相同的操作。这些链接提供了足够的信息来做到这一点。
非常感谢您的反馈。在我最初在这里发布后,我正在研究snapshot()和ByteArrayStreams。我会很快尝试。 – seeuuaye08
我编辑了代码以显示现在卡在哪里。编辑中说明了我的问题。 – seeuuaye08
*编辑* ---我不需要将GraphicsContext添加到任何其他客户端的GraphicsContexts中,只需要将GraphicsContext替换为其他类型。 – seeuuaye08