不从运行的java线程内部调用Repaint()
我有一个JFrame,上面有一个JPanel,我正在尝试使用paintComponent()对其进行一些徒手绘制。 现在,我在mouseDragged方法中更改xPOS和yPOS变量,然后调用repaint(),这样它就可以正常工作了不从运行的java线程内部调用Repaint(),java,swing,Java,Swing,我有一个JFrame,上面有一个JPanel,我正在尝试使用paintComponent()对其进行一些徒手绘制。 现在,我在mouseDragged方法中更改xPOS和yPOS变量,然后调用repaint(),这样它就可以正常工作了 //**PROGRAM 1**-My DrawPanel Class public class DrawPanel extends JPanel implements Runnable, MouseMotionListener{ int xpos =
//**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程序发送到那个java程序
// s.SendData(xpos,ypos);
并且可以从线程内部调用repaint()方法。
但是我可以;我似乎不明白,为什么这件事没有发生。
任何帮助都将不胜感激,谢谢
SSCCEpaintbrush服务器
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客户机
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());
}
}
}
您可以使用
SwingUtilities.invokelater(…)
在进行其他计算时对UI进行更新。就你而言
repaint()
甚至更好
revalidate();
repaint();
应该在
invokeLater
runnable实现中调用。您说您有一个接受坐标的线程,这是事件调度线程吗?如果是这样的话,它可能会阻止对UI的任何更新。1)使用JTextArea
显示从serversocketd
传入的字符串或对象,如果您计划使用styled Text
,请查看JTextPane
2) 使用SwingWorker
打开、读取和关闭Socket
的finally块中的,有两个选项:
- 使用
publish()
或process()
从Socket
分发传入的char
、String
或Object
,由于声明输出将在EDT上,我建议使用wrap方法jTextComponent\35append
到调用器中
- 如果结束,则等待
socketed
,并在done()
putString
或Object
中放入所需的JComponent
4) 当然可以使用Runnable#Thread
将String
或Object
从Socket
分发到Swing GUI,但我建议输出必须打包到invokeLater
3) 在这个论坛上有一些关于Socket+SwingWorker+JTextArea
的非常好的代码
你从不启动线程来读取数据(哦,你在服务器上是这样做的。为什么要发布重复代码四次,除了一些注释掉的行>好的,我最终让它在我的计算机上工作,所以我想这可能会引起你的兴趣:
这里有两件事:
重写paintComponents
时,在绘制其他组件之前,仍应调用super:super.paintComponents(g);
使您的XPOSYPO易失性
,因为您可以从不同的线程访问它们
在你的代码中还有一个缺少的重写方法。最终,我修复了它,我可以在一个框架中绘制,同时看到它在两个框架中绘制(启动了两个不同的程序)
我不打算对设计和其他东西大喊大叫。还有其他一些帖子有很好的建议
只有一件事我想没有提到,但是如果你有两个程序之间共享的类。将它们放在另一个文件中并多次使用,而不是复制/粘贴它们。你的几个类就是这样。如果两者之间只有一点区别,只需添加一个参数,你可以更改它以指示w如果你是这样的话
好的,我在咆哮,但实际上,当你在服务器框架中绘制时,客户端会做出反应并绘制相同的东西。就个人而言,在你的情况下,我会将客户端称为服务器,将服务器称为客户端。通常,服务器“侦听”对于客户端,在本例中,您绘制的是您的客户端,您看到它被复制的是您的服务器,但这只是语义。上述问题的答案是,在PaintBrushServer上调用repaint()方法时,它不是从PaintBrushServer上的线程内部调用的
只需从myFrame(JFrame)类中删除DrawPanel dr=new DrawPanel();
,因为我在开始时已经这样做了
谢谢大家的评论和建议,还有@andrewThompson我现在知道如何提供一个好的SSCE..lol你确定你没有阻止EDT吗?如果是这样,那么任何对repaint()的调用都将是无用的,因为repaint()只是AWT EventQueue上的另一个事件。这可能是可见性问题吗?换句话说:您在不同的线程中修改xpos
和ypos
,但没有正确的同步和paintComponent()
method没有看到更新的值?您能提供一个SSCCE吗?因为我看不到您提供的代码部分有任何问题-它对我来说很好。似乎问题出在面板之外的某个地方…“这是相同的…”别对我们大喊大叫了!发布一个SSCE。@AndrewThompson一如既往,你是对的,一个SSCE帮助解决了这个问题。我只能崇拜你在这个问题上的好斗。不,这只是一个普通的线程。但正如我所说的,这个东西在其他java程序中工作得很好。这里是吗?实际上是重新绘制()可以从任何线程调用,因为它是线程安全的。如果组件的层次结构没有更改,则使用revalidate()没有意义实际上这两个方法都是线程安全的,因此您可以在任何地方使用它们,有关详细信息,请参阅:-)注意到了同步的事情。。第三个是的,是愚蠢的,我知道,但我更想实现我的想法,我计划在未来改变这一点,这只是一个实验,我采取了更清楚地了解事情。谢谢纪尧姆
public synchronized void setXYPosition(int x, int y) {
this.xpos = x;
this.ypos = y;
repaint();
}