2017-10-19 92 views
0

我有2个JInternalFrame每个都包含一个JPanel。一个JPanel(源代码)更新其GUI和一些响应鼠标事件的数据。另一个JPanel(目标)接收一个事件,指示数据已更改并相应地更新其外观。如何防止JInternalFrame重新绘制重叠JInternalFrame

如果源面板与目标面板重叠,则目标面板中的重新绘制会在源面板中触发重新绘制。同样,即使源面板遮挡了目标面板所需的更改,目标面板仍会重新绘制,并且仍会在源面板中触发重新绘制。

在我的现实生活应用程序中,这会产生性能问题,因为多个面板在鼠标拖动时会触发重新绘制,并且源面板会显示复杂的图像。

如何防止目标面板更新触发源面板中的重绘?

事情我已经尝试:

  • 给参数重新粉刷这意味着只有目标面板的非重叠位重新刷新的问题,但对我来说,我不知道是哪个位的目标面板是可见的(我试过getVisibleRect和getClipBounds,但他们只是返回整个面板的大小)。在我的真实应用程序中,整个目标面板都会更新,而不仅仅是其中的一部分,所以我也不能以这种方式限制重新绘制。
  • 基于现有的InternalFrameDemo创建了一个最小示例:同样的问题,请参阅下面的代码。该示例具有2个面板,如前所述,单击源面板(标记为Document 1)在该位置绘制红色框,并更新DataModel对象,该对象触发目标面板拾取的事件(标记为Document 2) ,它在本身的相同位置绘制一个红色框。在源paintComponent方法中设置断点,可以看到有2个更新,一个来自SourcePanel重绘,另一个来自TargetPanel重绘。

    public class InternalFrameDemo extends JFrame 
             implements ActionListener { 
    JDesktopPane desktop; 
    DataModel model = new DataModel(); 
    
    public InternalFrameDemo() { 
    super("InternalFrameDemo"); 
    
    //Make the big window be indented 50 pixels from each edge 
    //of the screen. 
    int inset = 50; 
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
    setBounds(inset, inset, 
          screenSize.width - inset*2, 
          screenSize.height - inset*2); 
    
    //Set up the GUI. 
    desktop = new JDesktopPane(); //a specialized layered pane 
    MyInternalFrame frame1 = createFrame(); //create first "window" 
    MyInternalFrame frame2 = createFrame(); 
    setContentPane(desktop); 
    
    SourcePanel sp = new SourcePanel(model); 
    frame1.add(sp); 
    TargetPanel tp = new TargetPanel(model); 
    frame2.add(tp); 
    
    //Make dragging a little faster but perhaps uglier. 
    desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); 
    } 
    
    public void actionPerformed(ActionEvent e) { 
    } 
    
    //Create a new internal frame. 
    protected MyInternalFrame createFrame() { 
        MyInternalFrame frame = new MyInternalFrame(); 
        frame.setVisible(true); //necessary as of 1.3 
        frame.setOpaque(true); 
    
    
    desktop.add(frame); 
        try { 
         frame.setSelected(true); 
        } catch (java.beans.PropertyVetoException e) {} 
        return frame; 
    } 
    
    //Quit the application. 
    protected void quit() { 
        System.exit(0); 
    } 
    
    /** 
    * Create the GUI and show it. For thread safety, 
    * this method should be invoked from the 
    * event-dispatching thread. 
    */ 
    private static void createAndShowGUI() { 
        //Create and set up the window. 
        InternalFrameDemo frame = new InternalFrameDemo(); 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    
        //Display the window. 
        frame.setVisible(true); 
    } 
    
    public static void main(String[] args) { 
        //Schedule a job for the event-dispatching thread: 
        //creating and showing this application's GUI. 
        javax.swing.SwingUtilities.invokeLater(new Runnable() { 
         public void run() { 
          createAndShowGUI(); 
         } 
        }); 
    } 
    } 
    

package components; 

    import javax.swing.JInternalFrame; 

    /* Used by InternalFrameDemo.java. */ 
    public class MyInternalFrame extends JInternalFrame { 
    static int openFrameCount = 0; 
    static final int xOffset = 30, yOffset = 30; 

    public MyInternalFrame() { 
     super("Document #" + (++openFrameCount), 
       true, //resizable 
       true, //closable 
       true, //maximizable 
       true);//iconifiable 

     setSize(300,300); 
     setLocation(xOffset*openFrameCount, yOffset*openFrameCount); 
    } 
} 

package components; 

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 

import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class SourcePanel extends JPanel { 

    int boxX, boxY; 
    int boxWidth = 10; 
    int boxHeight = 10; 

    public SourcePanel(DataModel data) { 

     addMouseListener(new MouseAdapter() 
     { 
      @Override 
      public void mousePressed(MouseEvent evt) 
      { 
      if (!SwingUtilities.isRightMouseButton(evt)) 
      { 
       boxX = evt.getX(); 
       boxY = evt.getY(); 
       data.update(boxX,boxY); 
       repaint(); 
      } 
      } 
     }); 
    } 

    @Override 
    public void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 
     g.setColor(Color.RED); 
     int x = Math.min(boxX, this.getWidth()-boxWidth); 
     int y = Math.min(boxY, this.getHeight()-boxHeight); 
     g.drawRect(x, y, boxWidth, boxHeight); 
     g.drawRect(x + 1, y + 1, boxWidth - 2, boxHeight - 2); 
    } 
} 

package components; 

import java.awt.Color; 
import java.awt.Graphics; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 

import javax.swing.JPanel; 

public class TargetPanel extends JPanel implements PropertyChangeListener { 

    int boxX, boxY; 
    int boxWidth = 10; 
    int boxHeight = 10; 

    public TargetPanel(DataModel data) { 
     data.addPropertyChangeListener(this); 
    } 

    @Override 
    public void propertyChange(PropertyChangeEvent evt) 
    { 
     //draw something in response to the data change 
     boxX = ((int[])evt.getNewValue())[0]; 
     boxY = ((int[])evt.getNewValue())[1]; 
     repaint(); 
    } 

    @Override 
    public void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 
     g.setColor(Color.BLUE); 
     g.fillRect(0, 0, getWidth(), getHeight()); 
     g.setColor(Color.RED); 
     int x = Math.min(boxX, this.getWidth()-boxWidth); 
     int y = Math.min(boxY, this.getHeight()-boxHeight); 
     g.fillRect(x, y, boxWidth, boxHeight); 
    } 
} 

package components; 

import java.beans.PropertyChangeListener; 
import java.beans.PropertyChangeSupport; 

public class DataModel { 

    int datax = 10; 
    int datay = 10; 

    public DataModel() 
    { 
    } 

    public void update(int x, int y) 
    { 
     int[] olddata = new int[]{datax,datay}; 
     datax = x; 
     datay = y; 
     int[] newdata = new int[]{datax,datay}; 
     changeSupport.firePropertyChange("DataChange", olddata, newdata); 
    } 

    protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
       this); 

    public void addPropertyChangeListener(PropertyChangeListener listener) 
    { 
     changeSupport.addPropertyChangeListener(listener); 
    } 

    public void removePropertyChangeListener(PropertyChangeListener listener) 
    { 
     changeSupport.removePropertyChangeListener(listener); 
    } 

} 

(版权声明原始JInternalFrame的示例代码:)

/* 
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. 
* 
* Redistribution and use in source and binary forms, with or without 
* modification, are permitted provided that the following conditions 
* are met: 
* 
* - Redistributions of source code must retain the above copyright 
*  notice, this list of conditions and the following disclaimer. 
* 
* - Redistributions in binary form must reproduce the above copyright 
*  notice, this list of conditions and the following disclaimer in the 
*  documentation and/or other materials provided with the distribution. 
* 
* - Neither the name of Oracle or the names of its 
*  contributors may be used to endorse or promote products derived 
*  from this software without specific prior written permission. 
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/ 
+1

每个'paintComponent'方法都必须在执行任何其他操作之前调用'super.paintComponent(g);'。请参阅https://docs.oracle.com/javase/tutorial/uiswing/painting/。 – VGR

+0

@VGR好的,添加了 - 但它对我的问题没有任何影响 – smiley

回答

1

您可以缓存鼠标变化,做他们的时间间隔,或在鼠标跟踪结束。

最容易的可能是尝试推迟重画。

@Override 
public void propertyChange(PropertyChangeEvent evt) 
{ 
    //draw something in response to the data change 
    boxX = ((int[])evt.getNewValue())[0]; 
    boxY = ((int[])evt.getNewValue())[1]; 
    repaint(200L); 
} 

实际上重绘几次后,呼吁repaint(200L);。 (对于我的感觉,我选择了第五秒的高值)。

+0

感谢您提出了一个有趣的建议,我不知道这是重新绘制的选项。我在我的真实代码中尝试了各种值,但它并不能真正帮助性能。 – smiley

+0

@smiley我很害怕这个。其他一切都是工作。我希望(实际上确信)你在变化事件中检查了周期:在目标面板上的鼠标监听器,一个变化导致几个变化,所有这些变化都是目标面板上的重复变化或任何其他变化。复杂的涂料代码。 –