2

我有一个 JFrame,上面有一个 JPanel,我正在尝试使用paintComponent() 对其进行一些自由手绘。现在,我从 mouseDragged 方法内部更改 xPOS 和 yPOS 变量,然后调用 repaint(),所以它工作正常

//**PROGRAM 1**-My DrawPanel Class
  public class DrawPanel extends JPanel implements Runnable, MouseMotionListener{
    int xpos = 0;
    int ypos = 0;
    String message;
    DrawPanel(){
        //constructor ini
        addMouseMotionListener(this);
        setBackground(Color.green);
        setSize(500, 400);
        setBounds(10, 10, 500, 400);
        }

    public void paintComponent(Graphics g) {

      g.setColor(Color.red);
      g.fillOval(xpos, ypos, 5, 5);
      }

    @Override
    public void mouseDragged(MouseEvent arg0) {
     xpos= arg0.getX();
         ypos= arg0.getY();
    //   s.SendData(xpos,ypos);
        repaint();
    }

    public void run() {

        try{
            while((message = reader.readLine())!=null) {
                int in = message.indexOf("#");
                xpos = Integer.parseInt(message.substring(0, in));
                ypos = Integer.parseInt(message.substring(in+1));
                System.out.print(xpos+" "+ypos);

                repaint();
            }}catch(Exception e){e.printStackTrace();}
    }

}

我有一个线程,它通过套接字从其他一些java程序接受一些新坐标,我能够接受它们,我的

System.out.print(xpos+" "+ypos);

工作正常,但之后的 repaint() 方法似乎不起作用,没有错误,没有任何反应。

仅供参考,我提到的另一个 java 程序具有相同的结构,我将坐标从这个 java 程序发送到那个,

//   s.SendData(xpos,ypos);

并且可以从线程内部调用 repaint() 方法。但似乎无法理解,为什么它没有发生在这一点上。任何帮助将不胜感激,谢谢。

SSCCE画笔服务器

 import java.awt.*;
 import java.awt.event.*;
//import java.awt.image.BufferedImage;
import java.io.*;
import java.net.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class PaintBrush {

DrawPanel dr = new DrawPanel();
 myFrame mf;
 Graphics g1;
 boolean flag=false;
 server s;
 BufferedReader reader;
PaintBrush(){
myFrame mf = new myFrame();
s = new server();
}

public static void main(String[] args) {

    new PaintBrush();
   }

public class ButtonPanel extends JPanel{
ButtonPanel(){
    add(new myButton());
}
 }

public class DrawPanel extends JPanel implements Runnable, MouseMotionListener{

int xpos = 0;
 int ypos = 0;
String message;

DrawPanel(){
    //constructor ini
    addMouseMotionListener(this);
    setBackground(Color.green);
    setSize(500, 400);
    setBounds(10, 10, 500, 400);
    //s = new server();

}

public void paintComponent(Graphics g) {

  g.setColor(Color.red);
  g.fillOval(xpos, ypos, 5, 5);

}

@Override
public void mouseDragged(MouseEvent arg0) {
     xpos= arg0.getX();
     ypos= arg0.getY();
     s.SendData(xpos,ypos);
    repaint();
}


@Override
public void run() {
    try{

        while((message = reader.readLine())!=null) {

            int in = message.indexOf("#");
            xpos = Integer.parseInt(message.substring(0, in));
            ypos = Integer.parseInt(message.substring(in+1));
           // System.out.print(xpos+" "+ypos);
           repaint();
        }}catch(Exception e){e.printStackTrace();}
}




}
 public class myFrame extends JFrame{
 myFrame(){
     DrawPanel dr = new DrawPanel();
    //setBackground(Color.black); 
    setResizable(false);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   setVisible(true);
    setSize(665,490);
    getContentPane().add(BorderLayout.CENTER,dr);
    getContentPane().add(BorderLayout.NORTH, new ButtonPanel());
 }
}public class myButton extends JButton{

 myButton(){
     setText("PaintBrushServer");
    // addActionListener(new listen());

 }

 }

public class server {
  ServerSocket ssock;
 Socket clientSocket;
 PrintWriter writer;
 DataOutputStream os = null;
 server(){
     //ini server
      try {
        ssock = new ServerSocket(42422);
        System.out.println("waiting");
        clientSocket = ssock.accept();
        System.out.println(clientSocket.getRemoteSocketAddress()+" connected\n");
        //writer = new PrintWriter(.getOutputStream());
        InputStreamReader streamReader = new InputStreamReader(clientSocket.getInputStream());
        reader = new BufferedReader(streamReader);
        os = new DataOutputStream(clientSocket.getOutputStream());
        new Thread(dr).start();
      } catch (IOException e) {

        e.printStackTrace();
    }
 }
 public void SendData(int x, int y){
    try{ 
        os.writeBytes(x+"#"+y+"\n");
    }catch(Exception e){e.printStackTrace();}
 }

}
}

SSCCE-PaintBrushClient

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.*;
import java.net.*;
import javax.swing.*;
public class Client {
int xpos = 0;
int ypos = 0;
Boolean flag = false;
ClientConnect cc ;
DataOutputStream os = null;

BufferedReader reader;
Client(){
//server connect
ClientConnect cc = new ClientConnect();

}
public static void main(String[] args) {

new Client();
}

public class ClientConnect {
private Socket sock;
String message;
ClientConnect(){
   try {
    sock = new Socket("127.0.0.1", 42422);
    InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());
    reader = new BufferedReader(streamReader);
    os = new DataOutputStream(sock.getOutputStream());
     //sr = new ServerReader();
     //sr.start();
    new myFrame();

} catch (UnknownHostException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
}}

public void SendData(int x, int y){
try{ 
    os.writeBytes(x+"#"+y+"\n");
}catch(Exception e){e.printStackTrace();}
}
public class DrawPanel extends JPanel implements Runnable, MouseMotionListener{

 String message;
DrawPanel(){
    //constructor ini
    addMouseMotionListener(this);
    setBackground(Color.green);
    setSize(500, 400);
    setBounds(10, 10, 500, 400);
}

public void paintComponent(Graphics g) {
  g.setColor(Color.red);
  g.fillOval(xpos, ypos, 5, 5);

}

@Override
public void run() {

    // TODO Auto-generated method stub
       try{

        while((message = reader.readLine())!=null) {
            int in = message.indexOf("#");
            xpos = Integer.parseInt(message.substring(0, in));
            ypos = Integer.parseInt(message.substring(in+1));
            //System.out.println(message);
            System.out.println(xpos+" "+ypos);
            repaint();

        }}catch(Exception e){e.printStackTrace();}
}

@Override
public void mouseDragged(MouseEvent arg0) {
    // TODO Auto-generated method stub
     xpos= arg0.getX();
     ypos= arg0.getY();
     //flag = true;
     //System.out.println(xpos);
     //SendData(xpos,ypos);
    repaint();
}

public void mouseMoved(MouseEvent arg0) {
    }
}
 public class myButton extends JButton{
 myButton(){
 setText("PaintBrushClient");
 //addActionListener(new listen());
 }
 }
public class ButtonPanel extends JPanel{
ButtonPanel(){
    add(new myButton());
}
}

public class myFrame extends JFrame{
 myFrame(){
 DrawPanel dr = new DrawPanel();
 new Thread(dr).start();
setResizable(false);
 setBackground(Color.black); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
    setSize(665,490);
    getContentPane().add(BorderLayout.CENTER,dr);
    getContentPane().add(BorderLayout.NORTH, new ButtonPanel());


 }
}
}
4

6 回答 6

2
  1. 您永远不会启动线程来读取数据(哦,您是在服务器中执行的。为什么要发布四次重复的代码,除了一些注释掉的行><)
  2. 一个线程中的 xpos/ypos 更新可能不会被另一个线程看到。至少它们应该是易变的,但我更喜欢 setXYPosition() 方法:

    public synchronized void setXYPosition(int x, int y) {
      this.xpos = x;
      this.ypos = y;
      repaint();
    }
    
  3. 你为什么要写字节和读(字符)行?
  4. 不需要其他人建议的 revalidate() ,因为您是直接绘画,而不是更改布局/组件层次结构。
于 2012-04-11T10:21:34.227 回答
2

好的,我最终让它在我的电脑上工作,所以我想这可能会让你感兴趣:

这里有两件事:

  1. 当你覆盖时paintComponent,你仍然应该调用 super:super.paintComponents(g);在其余部分之上绘制之前。

  2. 制作您的 xpos ypos volatile,因为您从单独的线程访问它们。

您的代码中还缺少一个覆盖方法。最终,我把它全部修好了,我可以在一帧中绘制,同时看到它在两帧中都被绘制(启动了两个不同的程序)。

我不会抱怨设计和其他东西。还有其他帖子有很好的建议。

唯一的一件事,我认为没有被提及,但是如果您在两个程序之间共享类。将它们放在另一个文件中并多次使用,而不是复制/粘贴它们。您的几个课程就是这种情况。如果两者之间只有细微差别,只需添加一个您可以更改的参数以指示您所处的情况。

好的,我在咆哮,但实际上当您在服务器框架中绘制时,客户端会做出反应并绘制相同的东西。就个人而言,在您的情况下,我会将客户端称为服务器,将服务器称为客户端。通常,服务器“侦听”客户端,在这种情况下,您绘制的是您的客户端,而您看到它复制的是您的服务器,但这只是语义。

于 2012-04-11T23:02:01.387 回答
1

1)JTextArea用于显示传入String或发件人ObjectServerSocked如果您打算使用Stylled Text,则查看JTextPane

2)SwingWorker用于打开、读取和关闭(中finally block)的Socket,有两种选择:

  • 使用publish()orprocess()分发传入或from Chars,因为声明输出将在 EDT 上,我建议将 wrap 方法放入StringObjectSocketJTextCompoent#appendinvokeLater

  • 更容易等待Socked如果结束并在done()看跌期权StringObject期望JComponent

4) 肯定可以Runnable#Thread用于分发StringObjectSocketSwing GUI 分发,但我建议必须将输出包装到invokeLater,

Socket + SwingWorker + JTextArea3)关于这个论坛上的一些非常好的代码

于 2012-04-11T08:50:54.963 回答
1

上述问题的答案是在 PaintBrushServer 上的线程内部没有调用 repaint() 方法,而在 PaintBrushClient 上调用它是......

只需DrawPanel dr = new DrawPanel();从 myFrame(JFrame) 类中删除,就像我一开始就已经这样做了。

谢谢大家的意见和建议,还有@andrewThompson,我现在知道如何提供一个好的SSCCE ..lol

于 2012-04-12T06:21:47.007 回答
0

你说你有一个接受坐标的线程,这是Event Dispatch Thread吗?如果是这样,那么它可能会阻止对 UI 的任何更新。

于 2012-04-11T08:26:27.487 回答
-1

在进行其他一些计算时,您可以使用SwingUtilities.invokelater( ... )它来更新您的 UI。在你的情况下

repaint() 

甚至更好

revalidate();
repaint();

应该在invokeLater可运行的实现中调用。

于 2012-04-11T08:25:39.687 回答