我正在尝试基于JWindow
制作自定义用户界面,以便选择要共享的屏幕区域。我扩展了JWindow
并添加了代码以使其可调整大小,并使用AWTUtilities.setWindowShape()
“切出”窗口的中心。Swing JWindow如何调整大小而不闪烁?
运行代码时,由于窗口在负x和y方向(即向上和向左)调整大小,因此我正在经历闪烁。看来正在发生的事情是,窗口在更新组件之前被调整大小并绘制。以下是代码的简化版本。运行时,顶部面板可用于向上和向左调整窗口大小。窗口的背景设置为绿色,以清楚说明我不想显示的像素在哪里。
编辑:改进了代码塑造正确使用ComponentListener
窗口和在底部加入哑分量来进一步说明闪烁(也更新截图)。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Area;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.border.LineBorder;
import com.sun.awt.AWTUtilities;
public class FlickerWindow extends JWindow implements MouseListener, MouseMotionListener{
JPanel controlPanel;
JPanel outlinePanel;
int mouseX, mouseY;
Rectangle windowRect;
Rectangle cutoutRect;
Area windowArea;
public static void main(String[] args) {
FlickerWindow fw = new FlickerWindow();
}
public FlickerWindow() {
super();
setLayout(new BorderLayout());
setBounds(500, 500, 200, 200);
setBackground(Color.GREEN);
controlPanel = new JPanel();
controlPanel.setBackground(Color.GRAY);
controlPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
controlPanel.addMouseListener(this);
controlPanel.addMouseMotionListener(this);
outlinePanel = new JPanel();
outlinePanel.setBackground(Color.BLUE);
outlinePanel.setBorder(new CompoundBorder(new EmptyBorder(2,2,2,2), new LineBorder(Color.RED, 1)));
add(outlinePanel, BorderLayout.CENTER);
add(controlPanel, BorderLayout.NORTH);
add(new JButton("Dummy button"), BorderLayout.SOUTH);
setVisible(true);
setShape();
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
setShape();
}});
}
public void paint(Graphics g) {
// un-comment or breakpoint here to see window updates more clearly
//try {Thread.sleep(10);} catch (Exception e) {}
super.paint(g);
}
public void setShape() {
Rectangle bounds = getBounds();
Rectangle outlineBounds = outlinePanel.getBounds();
Area newShape = new Area (new Rectangle(0, 0, bounds.width, bounds.height));
newShape.subtract(new Area(new Rectangle(3, outlineBounds.y + 3, outlineBounds.width - 6, outlineBounds.height - 6)));
setSize(bounds.width, bounds.height);
AWTUtilities.setWindowShape(this, newShape);
}
public void mouseDragged(MouseEvent e) {
int dx = e.getXOnScreen() - mouseX;
int dy = e.getYOnScreen() - mouseY;
Rectangle newBounds = getBounds();
newBounds.translate(dx, dy);
newBounds.width -= dx;
newBounds.height -= dy;
mouseX = e.getXOnScreen();
mouseY = e.getYOnScreen();
setBounds(newBounds);
}
public void mousePressed(MouseEvent e) {
mouseX = e.getXOnScreen();
mouseY = e.getYOnScreen();
}
public void mouseMoved(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
的重写paint()
方法可以被用作一个断点或Thread.sleep()
可以去掉有,因为它发生,以提供更新的更清楚的视图。
我的问题似乎源于setBounds()
方法导致窗口被绘制到屏幕之前被布置。截至重写paint()
方法断点处看到)调整较大(达和左)在
窗口:调整大小,因为它应该是之前
窗口
如在断点见于重写paint()
方法调整大小更小(向下和向右)期间
窗口):
授予这些屏幕截图中侵略性鼠标拖动运动采取但闪烁变得相当即使对于更温和的鼠标拖动也很烦人。
将大小调整为更大的屏幕截图上的绿色区域显示在绘制/布局完成之前绘制的新背景,它似乎发生在底层ComponentPeer
或本机窗口管理器中。 “调整为较小”屏幕截图上的蓝色区域显示JPanel
的背景被推入视图,但现在已过时。这发生在Linux(Ubuntu)和Windows XP下。
有没有人找到一种方法来使Window
或JWindow
调整到后台缓冲区,然后对屏幕进行任何更改,从而避免这种闪烁效果?也许有一个java.awt....
系统属性可以设置,以避免这种情况,我找不到一个。
编辑#2:注释掉调用AWTUtilities.setWindowShape()
(以及可选地取消注释paint()
Thread.sleep(10)
的线)然后拖动顶板周围积极为了清楚地看到闪烁的性质。
编辑#3:是否有人能够在Windows 7或Mac OSX上的Sun Java下测试此行为?
@willjcroz:+1,非常好的问题。对所有人:请做**不** ** **没有**的任何回答**也提出问题。 – SyntaxT3rr0r 2010-12-01 12:30:30
我想知道同样问题的答案 - 我讨厌它多年,但从来没有发现即使是一个hacky的解决方法。在Windows 7上测试过,尽管我没有得到与你相同的效果,但我得到的东西非常相似。每个Java应用程序都会显示调整大小的人工制品,而不仅仅是您的示例。奇怪的是,移动一个窗口工作正常,只调整大小(可能是因为Windows 7本身处理移动窗口,并不会触发Java中的调整大小 - 如果我没有记错的话,不像Windows XP)。 – Domchi 2010-12-02 17:17:12
@Domchi:感谢在Windows 7上确认它发生的事情:-)。在XP上移动窗口看起来很顺利,没有重绘。也许你是指XP上的窗口'修复'很差。合成WM(如Vista/Win7,Linux上的OSX和Compiz等)可以处理以前被遮挡的窗口部分的“修复”,而不需要重新绘制,这是我认为XP可能会崩溃的地方。 – willjcroz 2010-12-02 18:59:10