2017-10-19 3 views
0

Ich habe 2 JInternalFrames mit je einem JPanel. Ein JPanel (die Quelle) aktualisiert seine GUI und einige Daten als Reaktion auf ein Mausereignis. Das andere JPanel (das Ziel) empfängt ein Ereignis, das anzeigt, dass sich die Daten geändert haben, und aktualisiert sein Aussehen entsprechend.So verhindern Sie, dass ein JInternalFrame einen überlappenden JInternalFrame neu erstellt

Wenn das Quellfenster das Zielfenster überlappt, löst das Repaint im Zielfenster ein Repaint im Quellfenster aus. Auch wenn die erforderliche Änderung des Zielfensters durch das Quellfenster verdeckt wird, wird das Zielfenster immer noch neu angezeigt und löst weiterhin ein Repaint im Quellfenster aus.

In meiner realen Anwendung erzeugt dies ein Leistungsproblem, da mehrere Panels beim Ziehen mit der Maus Repaints auslösen und das Quellfenster ein komplexes Bild anzeigt.

Wie kann ich verhindern, dass das Update des Zielfensters ein Repaint im Quellfenster auslöst?

Dinge, die ich versucht habe:

  • Parameter geben nur einen nicht überlappten Bit der Zieltafel neu gezeichnet wird stoppt das Problem neu zu zeichnen, die bedeuten, aber in meinem Fall ich weiß nicht, was Bit des Zielfensters ist sichtbar (ich habe getVisibleRect und getClipBounds versucht, aber sie geben nur die gesamte Panelgröße zurück). In meiner realen Anwendung wird das gesamte Zielfenster aktualisiert, nicht nur ein Teil davon, also kann ich das Repaint auch nicht auf diese Weise beschränken.
  • erstellt ein minimales Beispiel basierend auf einem vorhandenen InternalFrameDemo: das gleiche Problem, siehe Code unten. Das Beispiel hat zwei Felder, wie ich beschrieben habe. Durch Klicken auf das Quellfeld (mit der Bezeichnung Dokument 1) wird an dieser Stelle ein rotes Feld gezeichnet und das DataModel-Objekt aktualisiert, das ein Ereignis auslöst, das vom Zielfenster (Dokument 2) aufgenommen wird. , die eine rote Box an der gleichen Stelle in sich zieht. Wenn Sie in der paintComponent-Quellmethode einen Haltepunkt festlegen, können Sie sehen, dass es zwei Aktualisierungen gibt, eine aus dem Repaint von SourcePanel und eine aus dem Repaint von 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); 
    } 

} 

(Copyright-Hinweis für den ursprünglichen JInternalFrame Beispielcode :)

/* 
* 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

Jede 'paintComponent'-Methode muss 'super.paintComponent (g);' aufrufen, bevor Sie etwas anderes tun. Siehe https://docs.oracle.com/javase/tutorial/uiswing/painting/. – VGR

+0

@VGR ok, habe das hinzugefügt - aber es macht keinen Unterschied zu meinem Problem – smiley

Antwort

1

Sie könnten die Maus Änderungen zwischenspeichern und sie in Abständen tun, oder an der Maus-Tracking-Ende.

Am einfachsten ist es wahrscheinlich, ein verschobenes Repaint zu versuchen.

@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); 
} 

Eigentlich nach mehreren callss zu repaint(200L); Neulackierung. (Für mein Gefühl habe ich einen hohen Wert von einer fünften Sekunde gewählt.)

+0

Danke für den interessanten Vorschlag, ich wusste nicht, das war eine Option mit Repaint. Ich habe es in meinem echten Code mit verschiedenen Werten ausprobiert, aber es hilft der Performance nicht wirklich. – smiley

+0

@smiley Ich hatte davor Angst. Alles andere ist Arbeit. Ich hoffe (ich bin sogar davon überzeugt), dass Sie Zyklen in Änderungsereignissen überprüft haben: Maus-Listener im Zielfenster, eine Änderung, die mehrere Änderungen verursacht, die alle auf eine sich wiederholende Änderung des Zielfensters oder was auch immer gerichtet sind. Komplexer Farbcode –

Verwandte Themen