程序不重新绘制JFrame高度最大化

时间:2013-09-10 16:14:24

标签: java swing jframe

您可以通过以下几种方式拖动鼠标来调整JFrame的大小:

  1. 您可以调整其高度(上/下边缘)
  2. 您可以调整其宽度(左/右边缘)
  3. 你可以调整两个角落(在角落里)
  4. 您可以通过将整个窗口拖动到显示器顶部边缘来最大化它
  5. 您可以通过将其顶部/底部边缘拖动到显示器的顶部/底部边缘来最大化其高度
  6. 除了数字5之外,我的程序正在重新绘制每个动作。

    为什么?

    这可能是我程序中的错误吗?它似乎并非如此。我不知道我会在哪里为那个特殊情况添加重绘请求......似乎JFrame本身应该在每次调整大小后调用它的contentPane上重绘,对吧?

    在JFrame类中,它闻起来像Java本身的一个bug。

    SSCCE:

    import javax.swing.JFrame;
    import javax.swing.SwingUtilities;
    
    class Gui
    {
        Gui()
        {
            JFrame masterWindow = new JFrame("My very own SSCCE");
    
            masterWindow.setSize(1100, 100);
            masterWindow.setLocationRelativeTo(null);
            masterWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            masterWindow.setVisible(true);
        }
    }
    
    class Main
    {
        public static void main(String[] args)
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                @Override
                public void run()
                {
                    new Gui();
                }
            });
        }
    }
    

    抓住JFrame的上边缘并将其拖动到屏幕的上边缘并释放。底部延伸部分应为黑色。如果你然后最大化它,它将是灰色的,应该是。

    我仍然说这是Java或Windows bug。

2 个答案:

答案 0 :(得分:2)

它似乎是Windows的Windows实现中的一个错误。 (我也在使用Windows 7和JDK7。)

当Windows决定更改窗口高度时,Window会收到COMPONENT_MOVED事件,但不会收到COMPONENT_RESIZED事件。

在Windows类中,非公开方法dispatchEventImpl()会通过调用COMPONENT_RESIZEDinvalidate()来回复validate()个事件,但会忽略COMPONENT_MOVED事件

这是一种强制方法,可以在此类事件发生后重新验证窗口。这可能偶尔会使窗口在其他情况下重新验证​​,但不常见,因为Window类本身在每次COMPONENT_RESIZED事件后都进行了重新验证,并且报告的错误仅在窗口被主动调整大小时发生。用户。

    masterWindow.addComponentListener(new ComponentAdapter() {
      private int oldWidth = 0;
      private int oldHeight = 0;

      @Override
      public void componentResized(ComponentEvent e) {
        oldWidth = masterWindow.getWidth();
        oldHeight = masterWindow.getHeight();
      }

      @Override
      public void componentMoved(ComponentEvent e) {
          if (masterWindow.getWidth() != oldWidth || masterWindow.getHeight() != oldHeight) {
            masterWindow.invalidate();
            masterWindow.validate();
          }
          oldWidth = masterWindow.getWidth();
          oldHeight = masterWindow.getHeight();
      }
    });

答案 1 :(得分:2)

顺便说一句:也可以通过双击窗口的顶部/底部角落(至少在Windows 8中)调用操作5。

@Enwired:只有在最大化期间实际移动窗口时,您的解决方案才有效。 但是当窗口已经在y = 0时,当调用垂直最大化时,它不起作用。 (我使用一个名为AltDrag的小工具将窗口按到屏幕的边框,这使得这种情况更有可能。但是最初没有移动或重新定位的新窗口可能会遇到同样的问题。)

我注意到,当窗口垂直最大化时,paint()会在窗口上调用一次。

因此,最大化操作的解决方案是覆盖paint()并执行此操作:

@Override
public void paint(Graphics g)
{
    checkResizeWindow(this);
    super.paint(g);
}

public static void checkResizeWindow(Window window)
{
    if (!window.isShowing())
    {
        return;
    }
    Component[] components = window.getComponents();
    if (components.length == 0)
    {
        return;
    }
    Component comp = components[0];
    Insets insets = window.getInsets();
    Dimension innerSize = window.getSize();
    innerSize.width -= insets.left + insets.right;
    innerSize.height -= insets.top + insets.bottom;
    if (!innerSize.equals(comp.getSize()))
    {
        window.invalidate();
        window.validate();
    }
}

我使用的计算是通过检查innerSize与第一个子组件的大小(通常是单个Panel填写整个{{1}来确定窗口是否确实需要重新验证。 }})。

但是,恢复操作仍然存在同样的原始问题。 我们必须找到一个在这种情况下调用的事件,并在那时调用innerSize

我也在考虑......

  • 使用其他事件,如MouseMotion或Focus,但它们只会在以后发生,有些甚至可能经常发生,这可能会导致我们的checkResizeWindow()方法在重复调用过快时出现问题。
  • 使用在每个窗口上调用checkResizeWindow()的定期轮询检查,但轮询通常是一个坏概念,并且有它自己的缺点。