2

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

  1. 您可以调整它的高度(顶部/底部边缘)
  2. 您可以调整它的宽度(左/右边缘)
  3. 您可以调整两者的大小(在角落)
  4. 您可以通过将整个窗口拖动到显示器顶部边缘来最大化它
  5. 您可以通过将其顶部/底部边缘拖动到显示器的顶部/底部边缘来最大化其高度

除了数字 5 之外,我的程序正在对每一个动作进行重新绘制。

这是为什么?

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

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

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 错误。

4

2 回答 2

2

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

当 Windows 决定改变窗口的高度时,COMPONENT_MOVEDWindow 会收到一个事件,但没有COMPONENT_RESIZED收到任何事件。

在 Windows 类中,非公共方法将通过调用anddispatchEventImpl()来响应事件,但它会忽略事件。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();
      }
    });
于 2013-09-10T18:03:41.657 回答
2

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

@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填充整个)来确定窗口是否真的需要重新验证innerSize

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

我也在考虑...

  • 使用其他事件,如 MouseMotion 或 Focus,但它们仅在稍后发生,有些甚至可能经常发生,checkResizeWindow()当重复调用太快时可能会导致我们的方法出现问题。
  • 在每个窗口上使用循环轮询检查checkResizeWindow(),但轮询通常是一个糟糕的概念,并且有其自身的缺点。
于 2013-10-14T14:05:33.890 回答