Java 以前显示的图像在鼠标单击后消失
我正在为网络战舰类游戏(是的,我也是)编写gui。 如果我用鼠标右键单击设置一个航路点,所有地图标签都会消失,我无法得到它,因为右键单击应该做的是向服务器发送一些字符串,而不会以任何方式影响显示本身。 如果我调用panel.repaint();pane.validate();设置一个航路点后,所有内容都会再次显示,但性能将接近如此之慢 我意识到,这是很多代码,但我无法想象问题会出现在FieldListener中,尽管它一定是。因此我不知道该发布什么。如果你想看别的东西,你可以要它 下面是我们的代码中最有可能导致问题的部分:Java 以前显示的图像在鼠标单击后消失,java,swing,jpanel,paint,jlabel,Java,Swing,Jpanel,Paint,Jlabel,我正在为网络战舰类游戏(是的,我也是)编写gui。 如果我用鼠标右键单击设置一个航路点,所有地图标签都会消失,我无法得到它,因为右键单击应该做的是向服务器发送一些字符串,而不会以任何方式影响显示本身。 如果我调用panel.repaint();pane.validate();设置一个航路点后,所有内容都会再次显示,但性能将接近如此之慢 我意识到,这是很多代码,但我无法想象问题会出现在FieldListener中,尽管它一定是。因此我不知道该发布什么。如果你想看别的东西,你可以要它 下面是我们的代
/**
* The listener for a field.
* @author Andris
*
*/
private class FieldListener implements MouseListener {
private int[] xy;
private int[] pressedPos = new int[] {-1,-1};
@Override
public void mousePressed(MouseEvent evt) {
Field field = map.getField(xy[0],xy[1]);
pressedPos = xy.clone();
switch(evt.getButton()){
case MouseEvent.BUTTON1://-------well, BUTTON1......
break;
case MouseEvent.BUTTON3:
switch(selBtn){
case 2://---------------this is the case
client.Out("some string");// this sends to the server, nothing else...
break;
}
break;
}
}
服务器应答后,将执行此操作(在来自不同包的完全不同的类中,所有消失的字段都是私有的):
以下是自定义绘制方法(可能这是因为ImageObserver错误):
以下是其余部分:
...lots of imports...
/**
* This is the frame in which the GameMap is displayed.
* @author Andris
*
*/
@SuppressWarnings("serial")
public class MapFrame extends JPanel {
...lots of variables...
/**
* Creates the frame, but doesn't make it visible yet.
* @param window the GameWindow in which this frame will be embedded.
* @param client the client who runs this.
*/
public MapFrame(GameWindow window, Client client){
...lots of variables initialized...
panel = new JPanel();
pane = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
buttons = new JButton[nButtons];
buttonListener = new ButtonListener();
for(int i=0; i<nButtons; i++){
buttons[i] = new JButton(buttonTexts[i]);
buttons[i].setName(buttonTexts[i].replace(' ', '_'));
buttons[i].addActionListener(buttonListener);
buttonPanel.add(buttons[i]);
}
…大量导入。。。
/**
*这是游戏地图显示的框架。
*@作者安德里斯
*
*/
@抑制警告(“串行”)
公共类MapFrame扩展了JPanel{
…很多变量。。。
/**
*创建框架,但尚未使其可见。
*@param window将嵌入此框架的游戏窗口。
*@param client运行此操作的客户端。
*/
公共地图框(游戏窗口、客户端){
…初始化了很多变量。。。
panel=新的JPanel();
窗格=新的JScrollPane(面板,
JScrollPane.VERTICAL\u滚动条\u根据需要,
JScrollPane.水平滚动条(根据需要);
按钮=新的JButton[nButtons];
buttonListener=新建buttonListener();
对于(inti=0;i,绘制代码有问题
public void paint(Graphics g){
Image image = getImageNsetToolTip();
Graphics2D g2D=(Graphics2D)g;
g2D.drawImage(image, 0, 0, actImgSize, actImgSize, this);
g2D.setClip(0, 0, actImgSize, actImgSize);
super.paint(g2D);
}
在super之前进行绘制。绘制
可能会擦除您之前绘制的内容。发生这种情况的原因是paint
调用paintComponent
、paintBorder
和paintComponents
paintComponent
的工作之一是为绘制准备图形上下文(清理)
您还应该避免弄乱片段。由于Swing中的绘制方式,您可能会允许组件绘制超出其物理边界。在调用绘制之前,重新绘制管理器会将片段设置为等于组件的大小
相反,您应该使用paintComponent
执行自定义绘制
请查看以了解更多详细信息
现在,我想到了一个问题,为什么要在JLabel
上绘制自定义图像,而JLabel
的一个功能是显示图标?我终于明白了:
有相当多的线程正在运行,因为服务器、客户端、每个连接以及其他连接都在各自的线程中运行。
这可能会导致swing事件队列出现问题,从而导致事情不会在应该执行的时候执行。
这通常仅在有许多其他线程的情况下发生(因此无法进行SSCCE)。
为了防止这种情况,像validate()或repaint()这样的每个方法都应该作为invokeLater调用(因此由事件队列正确处理),特别是当它们是从不同的线程调用时。
这就是我在所有地方写的:
SwingUtilities.invokeLater(new Runnable(){
@override
public void run(){
panel.validate();
panel.repaint();
pane.validate();
}
});
或:
嗨!欢迎这么做。不幸的是,不可能有人回答这个问题,因为它包含太多的代码,而且不完整,所以它很难帮助你。显示一些努力并发布一个,这将在不久的将来得到你宝贵的帮助。因为我不知道问题在哪里,我们的代码是大约3000行,我不认为它包含太多。uch代码和我无法在一个较小的程序中重新创建问题…因为我不知道问题所在,我们的代码大约有3000多行,这就是我们的想法。如果您遵循链接中描述的方法,它将极大地提高发现问题的机会,并获得一个复制问题的较小程序。我正在尝试M提高性能。有人告诉我与其使用图像图标(据称更有效的重新缩放),不如重写绘画或绘画组件方法,尽管我没有发现它(明显)更有效。我尝试了你的建议,但它们没有解决主要问题(虽然省略setClip似乎没有负面影响,因此肯定是一种改进)。既然您提到了它,我意识到,我可能应该坚持使用ImageIcons的(自己的)旧计划,放弃提高性能。谢谢您的最后一句话;)
public void paint(Graphics g){
Image image = getImageNsetToolTip();
Graphics2D g2D=(Graphics2D)g;
g2D.drawImage(image, 0, 0, actImgSize, actImgSize, this);
g2D.setClip(0, 0, actImgSize, actImgSize);
super.paint(g2D);
}
SwingUtilities.invokeLater(new Runnable(){
@override
public void run(){
panel.validate();
panel.repaint();
pane.validate();
}
});
SwingUtilities.invokeLater(new Runnable(){
@override
public void run(){
mapLabels[x][y].repaint();
}
});