3

我有一个对话框,其中附加控件会导致对话框在出现时调整大小。有一天我可能会找到一种方法来制作动画,但现在我只满足于调整大小。问题是,它闪烁。

我将问题简化为测试:

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

/**
 * Shows flickering when resizing a dialog.
 */
public class FlickerTest extends FakeJDialog
{
    public FlickerTest()
    {
        super((Window) null, "Flicker Test");

        JButton button = new JButton("Bigger!");
        button.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent event)
            {
                Window window = SwingUtilities.getWindowAncestor((Component) event.getSource());
                window.setSize(window.getWidth(), window.getHeight() + 20);
            }
        });

        JPanel contentPane = new JPanel(new BorderLayout());
        contentPane.setOpaque(true);
        contentPane.add(button, BorderLayout.PAGE_START);

        JRootPane rootPane = new JRootPane();
        rootPane.setContentPane(contentPane);

        add(rootPane);

        setResizable(false);
        pack();
        setLocationRelativeTo(null);
    }

    public static void main(String[] args) throws Exception
    {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new FlickerTest().setVisible(true);
            }
        });
    }
}

每次单击按钮时,窗口都会改变大小。在相当长的一段时间内,对话框底部变黑。通过录制我的屏幕,我能够得到一个截图来展示它:

在此处输入图像描述

我怎样才能避免这种情况?

进一步的调查:

Dialog 的以下子类表现出与 JDialog 相同的闪烁:

import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Window;

import javax.swing.JLayeredPane;
import javax.swing.JRootPane;
import javax.swing.RootPaneContainer;

/**
 * Minimal subclass of Dialog required to cause the flickering.
 * If you comment out "implements RootPaneContainer", the flickering goes away.
 */
public class FakeJDialog extends Dialog implements RootPaneContainer
{
    public FakeJDialog(Window owner, String title)
    {
        super(owner, title, Dialog.ModalityType.MODELESS);
    }

    public JRootPane getRootPane()
    {
        throw new UnsupportedOperationException();
    }

    public Container getContentPane()
    {
        throw new UnsupportedOperationException();
    }

    public void setContentPane(Container contentPane)
    {
        throw new UnsupportedOperationException();
    }

    public JLayeredPane getLayeredPane()
    {
        throw new UnsupportedOperationException();
    }

    public void setLayeredPane(JLayeredPane layeredPane)
    {
        throw new UnsupportedOperationException();
    }

    public Component getGlassPane()
    {
        throw new UnsupportedOperationException();
    }

    public void setGlassPane(Component glassPane)
    {
        throw new UnsupportedOperationException();
    }
}

我觉得这很有趣,因为仅仅注释掉就implements RootPaneContainer足以完全改变行为。Swing 或 AWT 中的某些东西显然是在寻找这个接口并专门处理这些组件。所以这表明没有 JDialog 的子类可以避免这个问题。

4

2 回答 2

2

我不相信有办法解决这个问题JDialog。不过,java.awt.Dialog没有这个问题。

于 2012-11-29T04:08:57.640 回答
0

试试这个,我做了一个几乎完全消除闪烁的例子

此外,您将获得标记清晰的调整大小角

在此处输入图像描述

/*
 * resizing swing trick in Win7+Aero demo
 * @author: s1w_
*/
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);
      }
    });
  }
}
于 2014-10-10T12:08:13.997 回答