2

I'm working on an RCP application that's in a transition from a Swing version. So we have a lot of UI components that still need to live in the Swing world during this transition. I'm able to properly place the existing Swing components in AWT-SWT bridge frames.

I've wrapped these Swing components in a JScrollable pane before adding them to the bridge so that I don't have to resize the containing-part when the size of the Swing UI elements change. The code where I place an old Swing component in a part looks like this:

@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);
}

My Swing component has a behavior where when the user clicks a button, things that were hidden in the component are made visible, or new UI elements are added to the Swing component. For example:

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;
}

My problem is, when the elements in the Swing-component change, the parent bridge-frame doesn't properly get rendered.

When the parts are first created, my application looks like this: before

After I click on the EastButton it's supposed to add a text label in the center of that bridge frame. However, nothing changes in the application view.

But, when I even begin to resize the containing part-sash a little, the part containing the bridge-frame updates correctly:after resizing

What can I do to make the bridge-frame update containing part update automatically?

To test whether this was a repainting issue on the bridge-frame, I had a menu item which would trigger a repaint / revalidate / pack of the bridge-frame, but that didn't solve the issue. I suspect it has something to do with the renderer of the containing part, but have no idea how to go about addressing it.

anishthecoder
  • 940
  • 6
  • 20

2 Answers2

1

The same a problem exists in a pure Swing solution:

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);
}

You need to add an output.doLayout() in your event handler.

Brian de Alwis
  • 2,814
  • 2
  • 18
  • 32
  • I tried many variants of the layout / repaint / revalidate approach on both the Swing element and the SWT element to no avail... – anishthecoder May 27 '17 at 00:36
  • You're right in regard to this specific example. Apologies; I was responding with my original application in view. In my actual application, I don't have much control over what's happening within the embedded frame. So I couldn't call for `doLayout` as I needed. Also, it could have something to do with the `LayoutManager`. In my simplified example here, the BorderLayout behaves quite nicely. However, my actual application often uses `MigLayout` for the embedded components, which may not behave the same way when components are internally added. – anishthecoder May 27 '17 at 06:41
0

I eventually got around the problem by attaching a custom ControlListener / ComponentListener to the part containing the bridge. If any changes within the workings of the bridge-frame caused it to resize to beyond the parent, I'd have the listener resize it to fit within the parent thus forcing the scroll-pane to take over.

Here's my listener:

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();
    }
}

It's not an elegant solution; I'm still open to other ideas to solve the problem.

anishthecoder
  • 940
  • 6
  • 20