Java Swing:当组件“完成”调整大小时执行某些操作

发布于 2024-08-23 05:40:19 字数 1327 浏览 5 评论 0原文

对于这个有点不清楚的问题表示歉意 - 想不出更好的表达方式。

我使用 JXTaskPane(来自 Swing 实验室扩展 API)以显示一些信息。

用户可以“单击”标题来展开面板。 JXTaskPane 位于容器 JPanel 中,然后将其添加到 JFrame(我的主应用程序窗口)中。

我希望我的应用程序窗口大小调整为展开的任务窗格的大小。为了实现这一点,我向容器 JPanel 添加了一个组件侦听器,它将设置现在展开的面板的大小。

panel.addComponentListener(new ComponentListener()
{   
    public void componentResized(ComponentEvent e)
    {
        Dimension newSize = ((JXTaskPane)e.getSource()).getSize();
        reSizeFrame(newSize);
    }
}

private void reSizeFrame(Dimension newSize)
{   
    if ((newSize.height < maxSize.height) && (newSize.width < maxSize.width))
    {
        containerPanel.setSize(newSize);
        appFrame.setSize(containerPanel.getSize());
        appFrame.pack();
    }
}

问题是 componentResized 方法在任务窗格展开时被调用,因此 resizeFrame 方法被调用很多次,并且在屏幕上看起来非常糟糕。

如何检测 JXTaskpane 何时完成调整大小?我想到了两种方法:

  • 将 resizeFrame() 方法放在 SwingUtilities.invokeLate(..) 调用中。

  • 放入计时器 resizeFrame 调用,以便任何后续调用在计时器触发之前不会执行任何操作。这应该为面板调整大小提供足够的时间。

最好的前进方向是什么?

另外 - 这是我在多年的服务器端程序之后的第一个认真 Java GUI 应用程序。 StackOverflow 非常有帮助。所以谢谢!

Apologies for the somewhat unclear question - couldn't think of a better way of putting it.

I use a JXTaskPane (from the Swing labs extension API) to display some information.

The user can "click" the title to expand the panel. The JXTaskPane is in a container JPanel, which is then added to a JFrame, my main application window.

I want my application window to resize to the size of the expanded task pane. To achieve this, I added a component listener to my container JPanel which would set size to the now expanded panel.

panel.addComponentListener(new ComponentListener()
{   
    public void componentResized(ComponentEvent e)
    {
        Dimension newSize = ((JXTaskPane)e.getSource()).getSize();
        reSizeFrame(newSize);
    }
}

private void reSizeFrame(Dimension newSize)
{   
    if ((newSize.height < maxSize.height) && (newSize.width < maxSize.width))
    {
        containerPanel.setSize(newSize);
        appFrame.setSize(containerPanel.getSize());
        appFrame.pack();
    }
}

The problem is that the componentResized method is called as the task pane expands, as a result the resizeFrame method is called lots of times, and looks really awful on the screen.

How can I detect when the JXTaskpane has finished resizing? I thought of two approaches:

  • Put the resizeFrame() method in a SwingUtilities.invokeLate(..) call.

  • Put in a timer resizeFrame call, so any subsequent calls do not do anything until the timer fires. This should give enough time for the panel to resize.

What is the best way forward?

Also - This is my first serious Java GUI app after years of server side program. StackOverflow has been very helpful. So thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

热风软妹 2024-08-30 05:40:19

我知道您已经选择了一个答案,但是覆盖绘画方法绝对是不正确的,虽然您可能能够在适当的位置破解某些内容,但这并不理想。

查看 JXTaskPane 特别是在 setExpanded() (第 387 行)中,您可以看到它调用 JXCollapsiblePane.setCollapsed(...),然后触发展开的属性更改事件。该属性上的侦听器将不正确,因为它会在动画完成之前触发。因此,如果您进入 JXCollapsiblePane 并查看 setCollapsed(...) (第 470 行),您会发现如果它是动画的,它会设置参数并启动计时器。我们想知道动画何时结束,因此在该文件中查看动画制作器(第 620 行,特别是第 652-667 行),它显示当动画结束时,它会触发 ANIMATION_STATE_KEY 的属性更改,其值为“collapsed” ”或“扩展”。这是您真正想要的活动。但是,您无权访问 JXCollapsiblePane,因此返回 JXTaskPane 并搜索 ANIMATION_STATE_KEY,您会找到第 208 行,其中显示 JXTaskPane 在 JXCollapsiblePane.ANIMATION_STATE_KEY 上创建一个侦听器,并将其作为其自己的事件重新触发。

由于您确实有权访问 JXTaskPane,因此您可以侦听该事件,因此这样做...

taskPane.addPropertyChangeListener(JXCollapsiblePane.ANIMATION_STATE_KEY, new PropertyChangeListener() {
  public void propertyChange(PropertyChangeEvent e) {
    if(e.getNewValue().equals("expanded") {
      ...
    }
    else if(e.getNewValue().equals("collapsed") {
      ...
    }
  }
}

应该可以在您需要时准确地获取您的事件。

在 Swing 中侦听事件的正确方法是通过属性侦听器。不幸的是,找出正确属性和值的唯一方法是挖掘源代码。

I know you've already selected an answer, but overriding the paint method is definitely not correct, and while you may be able to hack something in place, it won't be ideal.

Looking at the source for JXTaskPane and specifically looking in setExpanded() (line 387), you can see it calls JXCollapsiblePane.setCollapsed(...) and then fires a property change event for expanded. A listener on that property won't be correct, because it'll fire before the animation is complete. So, if you go into JXCollapsiblePane and look at setCollapsed(...) (line 470) you'll see that if it's animated, it sets the paramaters and starts a timer. We want to know when the animation ends, so in that file, look at the animator (line 620, and specifically 652-667), which shows that when the animation ends, it fires a property change for ANIMATION_STATE_KEY with a value of "collapsed" or "expanded". This is the event you actually want. However, you don't have access to JXCollapsiblePane, so go back to JXTaskPane and search for ANIMATION_STATE_KEY, and you find line 208, which shows that JXTaskPane creates a listener on JXCollapsiblePane.ANIMATION_STATE_KEY and refires it as it's own event.

Since you do have access to JXTaskPane, you can listen for that event, so doing ...

taskPane.addPropertyChangeListener(JXCollapsiblePane.ANIMATION_STATE_KEY, new PropertyChangeListener() {
  public void propertyChange(PropertyChangeEvent e) {
    if(e.getNewValue().equals("expanded") {
      ...
    }
    else if(e.getNewValue().equals("collapsed") {
      ...
    }
  }
}

should get your event exactly when you want it.

The correct way to listen for events in Swing is through property listeners. Unfortunately, the only way to find out what the correct properties and values are is by digging through source code.

半暖夏伤 2024-08-30 05:40:19

作为建议,您是否尝试过重写 Paint 方法,首先调用 super ,然后在(且仅当)大小发生显着变化时将调整大小代码放在该方法的末尾。

As a suggestion, have you tried overriding the paint method, first calling super and then putting your resize code at the end of that if (and only if) the size has changed significantly.

凑诗 2024-08-30 05:40:19

我不熟悉 JXTaskPane,但我的第一反应是也许您正在处理错误的事件。您希望当用户单击标题时调整框架大小 - 那么为什么不处理该事件(也许使用 EventQueue.invokeLater() 在调整任务窗格大小后调整框架大小)?

但如果这不起作用并且您需要使用上面概述的方法,那么使用 javax.swing.Timer 可能是最好的。将其设置为 200 毫秒左右,然后每次 componentResized() 触发时重新启动()它。

I'm not familiar with JXTaskPane, but my first reaction is that maybe you're handling the wrong event. You want the frame to resize when the user clicks on the header - so why not handle that event (perhaps using EventQueue.invokeLater() to resize the frame after the task pane has been resized)?

But if that doesn't work and you need to use the approach you've outlined above, using a javax.swing.Timer is probably best. Set it for 200 milliseconds or so and just restart() it every time componentResized() fires.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文