Dylan
Dylan

Reputation: 13922

How to stop multiple selections with multiple StyledText widgets

I'm working on an application using SWT in Java, and I've encountered some wierd behavior from multiple StyledText widgets. It's fairly consistent: if there are more than one StyledText widget displayed in the window/view/editor at once, you can select whatever you want from each one individually, at the same time. In the screenshot, there are 4 separate widgets with 4 separate selections.

a clip of what I mean

My expectation is that if I start selecting from one widget, whatever other widget that might already have a selection should then lose it, similarly to the behavior you would expect from a web browser; only one selection at a time.

I'd like to fix this problem, but I hope to avoid needing to make some manager that listens to every widget and turns off selections when a new one is made. Is there a better way to do this? (Also why is this happening in the first place?)

Upvotes: 1

Views: 553

Answers (1)

Favonius
Favonius

Reputation: 13984

Why is it happening?

To best of my knowledge the behavior of a widget depends on its implementation i.e. whether it is a

  1. native widget (like org.eclipse.swt.widgets.Text) or
  2. custom widget (like org.eclipse.swt.custom.StyledText)

The difference lies in the handling of the mouse down or mouse up events.

For example,

In case of org.eclipse.swt.widgets.Text the left mouse down eventually translates to OS.SendMessage (hwnd, OS.WM_LBUTTONUP, wParam, lParam);

Whereas

org.eclipse.swt.custom.StyledText uses a mouse event handler and extra processing in the handleMouseDown(Event event) method. Most of the functionality or UI is done using custom draw/redraw/validate/invalidate/update methods.

To put it in a very crude win32 sdk way:

  1. There are some controls provided by windows/win32 GDI
  2. And, some are custom user drawn controls

See the below SWT code which uses text, styledtext, browser etc for testing. Also Note the browser control is not exactly a win32 control it is a wrapper control around Internet Explorer activex or mozilla's gecko engine, therefore its behavior is same as that of styled text.

Any possible solution ?

Well I can only think of borrowing SWT's styledtext code and then making a version which suits me.

Or

As you have already mentioned, use some listener to reset all the other unfocused widgets (which even in my opinion is not a very clean solution).

Test Code & Output

enter image description here

Code:

import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class StyledTextTest {

    private static Display display;

    public static void main(String[] args) 
    {
        display = new Display();
        Shell shell = new Shell(display);
        shell.setLayout(new GridLayout(2,true));
        shell.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

        createStyledText(shell);
        createStyledText(shell);

        createText(shell);
        createText(shell);

        createCombo(shell);
        createCombo(shell);

        createCustomCombo(shell);
        createCustomCombo(shell);

        createBrowser(shell);
        createBrowser(shell);

        shell.pack();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }

    private static void createCustomCombo(Composite parent) 
    {
        new Label(parent, SWT.NONE).setText("Custom Combo");
        CCombo c = new CCombo(parent, SWT.DROP_DOWN);
        c.setItems(new String[] {"test best", "best rest", "rest test"});
        c.select(0);        
        c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    }

    private static void createCombo(Composite parent) 
    {
        new Label(parent, SWT.NONE).setText("Combo");
        Combo c = new Combo(parent, SWT.DROP_DOWN);
        c.setItems(new String[] {"test best", "best rest", "rest test"});
        c.select(0);        
        c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    }

    static void createBrowser(Composite parent)
    {
        new Label(parent, SWT.NONE).setText("Browser");
        Browser browser = new Browser(parent, SWT.NONE);
        browser.setText("<div>This is a test !!</div>");
        browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    }

    static void createText(Composite parent) {
        new Label(parent, SWT.NONE).setText("Text");
        final Text text = new Text(parent, SWT.BORDER);
        text.setText("0123456789 ABCDEFGHIJKLM NOPQRSTUVWXYZ");

    }

    static void createStyledText(Composite parent)
    {
        new Label(parent, SWT.NONE).setText("Styled Text");

        StyledText text = new StyledText (parent, SWT.BORDER|SWT.SINGLE);
        text.setText("0123456789 ABCDEFGHIJKLM NOPQRSTUVWXYZ");
        // make 0123456789 appear bold
        StyleRange style1 = new StyleRange();
        style1.start = 0;
        style1.length = 10;
        style1.fontStyle = SWT.BOLD;
        text.setStyleRange(style1);
        // make ABCDEFGHIJKLM have a red font
        StyleRange style2 = new StyleRange();
        style2.start = 11;
        style2.length = 13;
        style2.foreground = display.getSystemColor(SWT.COLOR_RED);
        text.setStyleRange(style2);
        // make NOPQRSTUVWXYZ have a blue background
        StyleRange style3 = new StyleRange();
        style3.start = 25;
        style3.length = 13;
        style3.fontStyle = SWT.BOLD | SWT.ITALIC;
        text.setStyleRange(style3);

    }
}

Upvotes: 1

Related Questions