Java 如何防止在swing中调整组件大小时闪烁?
如果我运行下面的示例,我会在JSplitPane的右侧看到闪烁。有没有办法避免这种情况Java 如何防止在swing中调整组件大小时闪烁?,java,swing,Java,Swing,如果我运行下面的示例,我会在JSplitPane的右侧看到闪烁。有没有办法避免这种情况 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; public class FlickerTest { int width = 1; private void create() { fina
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class FlickerTest
{
int width = 1;
private void create()
{
final JFrame f = new JFrame("JSplitPane");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p1 = new JPanel();
p1.setPreferredSize(new Dimension(100, 300));
JPanel p2 = new JPanel();
p2.setPreferredSize(new Dimension(0,0));
p2.setBackground(Color.gray);
JSplitPane jsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, p1, p2);
jsp.setSize(new Dimension(400, 800));
Timer timer = new Timer(1, new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
width++;
if (width == 2)
{
try
{
Thread.sleep(1500);
}
catch (Exception ex)
{
}
}
int frameWidth = f.getWidth() + width;
Dimension d = new Dimension(frameWidth, f.getHeight());
f.setSize(d);
if (width > 20)
{
Timer t = (Timer) e.getSource();
t.stop();
}
}
});
f.add(jsp);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
timer.start();
}
public static void main(String[] args) throws Exception
{
new FlickerTest().create();
}
}
不要在计时器中使用Thread.sleep()。您正在阻止EDT响应事件和进行绘制。这对您有用吗
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class FlickerTest
{
int width = 1;
private void create()
{
final JFrame f = new JFrame("JSplitPane");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p1 = new JPanel();
p1.setPreferredSize(new Dimension(100, 300));
JPanel p2 = new JPanel();
p2.setPreferredSize(new Dimension(0,0));
p2.setBackground(Color.gray);
JSplitPane jsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, p1, p2);
jsp.setSize(new Dimension(400, 800));
Timer timer = new Timer(1, new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
width++;
int frameWidth = f.getWidth() + width;
if (width>1502) {
frameWidth = f.getWidth() + width - 1500;
}
Dimension d = new Dimension(frameWidth, f.getHeight());
f.setSize(d);
if (width > 1520)
{
Timer t = (Timer) e.getSource();
t.stop();
}
}
});
f.add(jsp);
f.pack();
//f.setLocationRelativeTo(null);
f.setVisible(true);
timer.start();
}
public static void main(String[] args) throws Exception
{
new FlickerTest().create();
}
}
- 使用30毫秒而不是1毫秒的延迟。30毫秒每秒可为您提供30帧的平滑效果,这已经足够了
- 使用
代替setBounds
。不确定这是否会产生影响,但会提供对坐标的更多控制setSize
- 不要在
计时器中调用
,而是在计时器上设置初始延迟sleep()
- 调用
setPreferredSize(0,0)
请注意:在Win 7中,Aero的已知问题是在调整大小时闪烁:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6873928这个技巧提高了Win7+Aero中的重绘率:将resizeable设置为null,并提供自己的resize挂钩。它不是完美的,但还是好得多。。请看我的例子:
import java.awt.event.*;
import java.awt.*;
import javax.swing.event.*;
import javax.swing.*;
class ResizeHookDemo extends JDialog {
private final static int width = 580, height = 350;
private final JFileChooser fc;
private java.awt.geom.GeneralPath gp;
public ResizeHookDemo() {
super((JDialog)null, "Choose File", true);
fc = new JFileChooser() {
@Override
public void paint(Graphics g) {
super.paint(g);
int w = getWidth();
int h = getHeight();
g.setColor(new Color(150, 150, 150, 200));
g.drawLine(w-7, h, w, h-7);
g.drawLine(w-11, h, w, h-11);
g.drawLine(w-15, h, w, h-15);
gp = new java.awt.geom.GeneralPath();
gp.moveTo(w-17, h);
gp.lineTo(w, h-17);
gp.lineTo(w, h);
gp.closePath();
}
};
fc.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("CancelSelection")) {
setVisible(false);
// action...
}
else if (e.getActionCommand().equals("ApproveSelection")) {
setVisible(false);
// action...
}
}
});
MouseInputListener resizeHook = new MouseInputAdapter() {
private Point startPos = null;
public void mousePressed(MouseEvent e) {
if (gp.contains(e.getPoint()))
startPos = new Point(getWidth()-e.getX(), getHeight()-e.getY());
}
public void mouseReleased(MouseEvent mouseEvent) {
startPos = null;
}
public void mouseMoved(MouseEvent e) {
if (gp.contains(e.getPoint()))
setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
else
setCursor(Cursor.getDefaultCursor());
}
public void mouseDragged(MouseEvent e) {
if (startPos != null) {
int dx = e.getX() + startPos.x;
int dy = e.getY() + startPos.y;
setSize(dx, dy);
repaint();
}
}
};
fc.addMouseMotionListener(resizeHook);
fc.addMouseListener(resizeHook);
fc.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 20));
add(fc);
setResizable(false);
setMinimumSize(new Dimension(width, height));
setDefaultCloseOperation(HIDE_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String args[]) {
System.out.println("Starting demo...");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ResizeHookDemo().setVisible(true);
}
});
}
}
对于我来说,将NoeraseBack转变为true起到了作用:
System.setProperty("sun.awt.noerasebackground", "true");
sleep调用与闪烁无关,因为它只在事件的第一次触发时被调用,而不是在随后的事件中被调用。也许,也许不是,重点是你不应该在EDT上使用ad.sleep()。在我的机器上,这个代码没有闪烁。顺便说一句,我在Mac OSX上运行这个。嗯,也许这是Mac的问题。当我有访问权限时,我必须在windows框上重试。谢谢。是的,我的是窗户。但是你应该真正尊重Swing线程模型,尽管我不确定这是否是给你带来麻烦的原因。应该补充的是,我也从未见过运行Windows7和Java1.6.0-b105的flicker。代码的两个版本都没有闪烁,但原始版本“跳”到非常宽,而我发布的版本逐像素增加。不,这没有任何区别。@John Thorhauer工作正常,没有冻结调整大小,因为您的示例Andrew Thompson+1I覆盖了更新()调用JPanel和SplitPane,但仍然存在相同的问题。顺便说一句,我在MacOSX上运行这个。不确定这是否有区别。@john,@hover,我原来的答案是错的,所以我改变了它。“30ms给你一个平滑的每秒30帧,…”试试“33&1/3fps”。+1我开始在大约30毫秒或33毫秒时看到平滑的结果⅓ Hz.:-)计时器从1变为30似乎起到了相当大的作用。
System.setProperty("sun.awt.noerasebackground", "true");