【问题标题】:Refreshing Eclipse RCP part containing an AWT-SWT bridge when contents of the bridge change当桥的内容更改时刷新包含 AWT-SWT 桥的 Eclipse RCP 部件
【发布时间】:2017-10-25 14:41:51
【问题描述】:

我正在开发一个从 Swing 版本过渡的 RCP 应用程序。所以我们有很多 UI 组件在这个过渡期间仍然需要存在于 Swing 世界中。我能够将现有的 Swing 组件正确放置在 AWT-SWT 桥框架中。

在将这些 Swing 组件添加到桥接之前,我已将它们包装在 JScrollable 窗格中,这样当 Swing UI 元素的大小发生变化时,我就不必调整包含部分的大小。我在零件中放置旧 Swing 组件的代码如下所示:

@PostConstruct
public void postConstruct(final Composite parent) {

    /* Create embedding composite */
    final Frame bridgeFrame;
    final Composite embed;
    embed = new Composite(parent, SWT.EMBEDDED);
    embed.setLayout(new FillLayout());
    bridgeFrame = SWT_AWT.new_Frame(embed);
    bridgeFrame.setLayout(new BorderLayout());
    bridgeFrame.add(
            new JScrollPane(getTestPanel()),
            BorderLayout.CENTER);
}

我的 Swing 组件具有这样一种行为:当用户单击按钮时,隐藏在组件中的内容会变得可见,或者新的 UI 元素会添加到 Swing 组件中。例如:

private JPanel getTestPanel() {
    final JPanel output;
    final JButton eastBttn, westBttn;
    output = new JPanel();
    eastBttn = new JButton("East Button");
    westBttn = new JButton("West Button");
    output.setLayout(new BorderLayout());
    output.add(eastBttn, BorderLayout.EAST);
    output.add(westBttn, BorderLayout.WEST);

    eastBttn.addActionListener(evt -> {
        System.out.println("East Button Clicked");
        output.add(new JLabel("East Button Clicked"), BorderLayout.CENTER);
    });

    return output;
}

我的问题是,当 Swing 组件中的元素发生变化时,父桥架无法正确呈现。

首次创建零件时,我的应用程序如下所示:

点击EastButton 后,它应该在该桥框架的中心添加一个文本标签。但是,应用程序视图中没有任何变化。

但是,当我开始稍微调整包含部分窗扇的大小时,包含桥架的部分会正确更新:

如何使包含部分的桥架更新自动更新?

为了测试这是否是桥架上的重绘问题,我有一个菜单项会触发桥架的 repaint / revalidate / pack,但这并没有解决问题。我怀疑它与包含部分的渲染器有关,但不知道如何解决它。

【问题讨论】:

  • 猜测一下(因为我不使用网桥)试试embed.layout(true, true)
  • @greg-449 谢谢!不幸的是,这并不太奏效(或layoutredraw 等的任何变体。

标签: java eclipse rcp e4 swt-awt


【解决方案1】:

我最终通过将自定义 ControlListener / ComponentListener 附加到包含桥的部分来解决此问题。如果桥架工作中的任何更改导致其调整大小超出父级,我会让侦听器调整其大小以适应父级,从而强制滚动窗格接管。

这是我的听众:

public class BridgeComponetAdapter
        extends ComponentAdapter
        implements ControlListener {

    private final Composite parent;
    private final Frame bridgeFrame;
    private Point parentSize;

    public BridgeComponetAdapter(
            final Composite parent,
            final Frame bridgeFrame) {
        this.parent = parent;
        this.bridgeFrame = bridgeFrame;
        bridgeFrame.addComponentListener(this);
        parent.addControlListener(this);
    }

    @Override
    public void componentResized(final ComponentEvent e) {
        System.out.println(e);
        if (e.getSource() != bridgeFrame)
            return;

        final Dimension currentBridgeSize;
        currentBridgeSize = bridgeFrame.getSize();
        if (currentBridgeSize.getWidth() > parentSize.x
                || currentBridgeSize.getHeight() > parentSize.y) {
            bridgeFrame.setSize(parentSize.x, parentSize.y);
        }
    }

    @Override
    public void controlMoved(final ControlEvent e) {}

    @Override
    public void controlResized(final ControlEvent e) {
        System.out.println(e);
        if (e.getSource() == parent)
            parentSize = parent.getSize();
    }
}

这不是一个优雅的解决方案;我仍然对解决问题的其他想法持开放态度。

【讨论】:

    【解决方案2】:

    在纯 Swing 解决方案中也存在同样的问题:

    public static void main(String[] args) {
        JFrame bridgeFrame = new JFrame("Test");
        bridgeFrame.setSize(400, 400);
        bridgeFrame.setLayout(new BorderLayout());
        bridgeFrame.add(new JScrollPane(getTestPanel()), BorderLayout.CENTER);
    
        bridgeFrame.setVisible(true);
    }
    

    您需要在事件处理程序中添加output.doLayout()

    【讨论】:

    • 我在 Swing 元素和 SWT 元素上尝试了许多布局/重绘/重新验证方法的变体,但无济于事...
    • 关于这个具体的例子你是对的。道歉;我正在回复我的原始申请。在我的实际应用程序中,我无法控制嵌入式框架内发生的事情。所以我无法根据需要拨打doLayout。此外,它可能与LayoutManager 有关。在我在这里的简化示例中,BorderLayout 表现得非常好。但是,我的实际应用程序经常将MigLayout 用于嵌入式组件,当内部添加组件时,其行为可能会有所不同。
    猜你喜欢
    • 2012-11-07
    • 1970-01-01
    • 2020-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多