简体   繁体   中英

Repaint() is not called from inside a running thread java

I have a JFrame on to which i have a JPanel, and i am trying to do some free hand drawing on to it using paintComponent(). Now, i change the xPOS and yPOS variable from inside the mouseDragged method, and then calls the repaint(), so it works fine

//**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();}
    }

}

i have a thread, which accepts some new co-ordinates from some other java program thru socket, i am able to accept them, my

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

works fine, but the repaint() method just after that, doesn't seem to work, no error, nothing happens.

FYI, the other java program i mentioned, has the same kind of structure, and i send the co-ordinates from this java program to that one,

//   s.SendData(xpos,ypos);

and that one is able to call the repaint() method from inside the thread. but just can;t seem to understand, why it is not happening in this one. Any help would be appreciated, thanks.

SSCCE PaintBrushServer

 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());


 }
}
}
  1. You never start a thread to read the data (oh you do in the server. Why post duplicate code four times, except for some commented out lines ><)
  2. xpos/ypos updates in one thread might not be seen by another. At least they should be volatile, but I would prefer a setXYPosition() method:

     public synchronized void setXYPosition(int x, int y) { this.xpos = x; this.ypos = y; repaint(); }
  3. Why are you writing bytes and reading (character) lines?
  4. revalidate() like suggested by others is not needed since you are painting directly, not change the layout/component hierarchy.

OK, I eventually got it to work on my computer so I guess this might interest you:

Two things here:

  1. When you override paintComponent , you should still call super: super.paintComponents(g); before drawing on top of the rest.

  2. Make your xpos ypos volatile since you access them from separate threads.

Also there is a missing overriden method in of your code. Eventually, I fixed it all up and I could draw in one frame while seeing it painted in both (having launched the 2 different program).

I am not going to rant about the design and others stuffs. There are other posts with nice suggestions.

One only thing, which i think has not been mentionned, but if you have classes shared between two programs.Put them in another file and use it several times instead of copy/pasting them. This is the case for several of your classes. And if there is only a slight difference between the two, just add a parameter that you can change to indicate which case you are in.

OK, I am ranting, but it is actually when you draw in your server frame, that the clients reacts and draws the same thing. Personnally, I would have called the Client a Server and the Server a Client in your case. Usually, the Server "listens" for clients, and in this case where you draw is your client and where you see it replicated is your server, but that's just semantics.

1) use JTextArea for displaying incoming String or Object from ServerSocked , in the case that you planing to use Stylled Text , then look at JTextPane

2) use SwingWorker for open, read and close (in the finally block ) of Socket , there are two options:

  • use publish() or process() for distribute incoming Chars , String or Object from Socket , since is declared that output will be on EDT, I'd to suggest wrap method JTextCompoent#append into invokeLater

  • easier could be waiting for Socked if is ended and in the done() put String or Object to the desired JComponent

4) sure is possible use Runnable#Thread for distributing String or Object from Socket to the Swing GUI, but I'd suggestint output must be wrapped into invokeLater ,

3) a few very good code about Socket + SwingWorker + JTextArea on this forum

The Answer to above problem of repaint() method not called from inside the thread on PaintBrushServer, while it is being called on PaintBrushClient is....

Just remove the DrawPanel dr = new DrawPanel(); from myFrame(JFrame) class, as i already did that in the beginning.

Thanks all for their comments and suggestions, also @andrewThompson i now know how to provide a good SSCCE..lol

You say you have a thread that accepts coordinates, is this the Event Dispatch Thread? If so then it may be blocking any updates to the UI.

You can use SwingUtilities.invokelater(... ) to make updates to your UI while you are making some other calculations. In your case

repaint() 

or even better

revalidate();
repaint();

should be called inside the invokeLater runnable implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM