我有2个JInternalFrame,每个都包含一个JPanel。一个JPanel(源)更新其GUI和一些数据以响应鼠标事件。另一个JPanel(目标)接收指示数据已更改的事件并相应地更新其外观。
如果源面板与目标面板重叠,则目标面板中的重绘会在源面板中触发重新绘制。此外,即使源面板遮挡了对目标面板所需的更改,目标面板仍会重新绘制,并仍然在源面板中触发重新绘制。
在我的真实应用程序中,这会产生性能问题,因为多个面板在鼠标拖动时触发重新绘制,并且源面板具有要显示的复杂图像。
如何阻止目标面板更新在源面板中触发重绘?
我尝试的事情:
基于现有的InternalFrameDemo创建了一个最小示例:同样的问题,请参阅下面的代码。该示例有2个面板,如我所述,单击源面板(标记为文档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.
*/
答案 0 :(得分: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);
之后重新粉刷。 (因为我的感觉,我已经选择了高五分之一的值。)