我正在嘗試基於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