How to keep SWT menu open after user clicks menu item?

偶尔善良 提交于 2019-12-05 16:03:40
Favonius

I tried your code on Win7 32bit and with eclipse 4.2. Unfortunately it was giving problem and was flickering. Anyway, here is another variation. In my opinion you have to use at least two listeners, one for your menu item(s), which in any case are needed, and the other to get the co-ordinates of the menu:

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MenuDetectEvent;
import org.eclipse.swt.events.MenuDetectListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;

public class TestMenu 
{
    private static Point point;

    public static void main(String[] args) 
    {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setLayout(new GridLayout(1, false));

        final Menu menu = new Menu(shell);
        MenuItem item = new MenuItem(menu, SWT.CHECK);
        item.setText("Check 1");
        item.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) 
            {
                if(point == null) 
                    return;
                menu.setLocation(point);
                menu.setVisible(true);
            }
        });

        shell.addMenuDetectListener(new MenuDetectListener() {
            public void menuDetected(MenuDetectEvent e) {
                point = new Point(e.x, e.y);
            }
        });

        shell.setMenu(menu);

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


Update

Thanks to @Baz, please see the comment below.

Tried this on Linux 32bit with eclipse 3.6.2 and unfortunately it doesn't seem to work.

Update 2 (by ulmangt)

Below is a modification of your solution which works for me on both 64-bit Windows 7 and 64-bit Ubuntu Linux.

The org.eclipse.swt.widgets.Menu class has a package protected field which determines whether the menu location has been set. If not, on Linux at least, the menu appears under the mouse click.

So getting the right behavior requires using reflection to reset this boolean field to false. Alternatively, the menu could probably be disposed and recreated.

Finally, Linux appears to like menu.setLocation( point ) and menu.setVisible( true ) to be made from an asyncExec block.

import java.lang.reflect.Field;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MenuDetectEvent;
import org.eclipse.swt.events.MenuDetectListener;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.MenuListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;

public class MenuTest
{
    private static Point point;

    public static void main( String[] args )
    {
        Display display = new Display( );
        final Shell shell = new Shell( display );
        shell.setLayout( new GridLayout( 1, false ) );

        final Menu menu = new Menu( shell );
        MenuItem item = new MenuItem( menu, SWT.CHECK );
        item.setText( "Check 1" );
        item.addSelectionListener( new SelectionAdapter( )
        {
            public void widgetSelected( final SelectionEvent e )
            {
                if ( point == null ) return;

                Display.getDefault( ).asyncExec( new Runnable( )
                {
                    @Override
                    public void run( )
                    {
                        menu.setLocation( point );
                        menu.setVisible( true );
                    }
                } );
            }
        } );

        shell.addMenuDetectListener( new MenuDetectListener( )
        {
            public void menuDetected( MenuDetectEvent e )
            {
                point = new Point( e.x, e.y );
            }
        } );

        menu.addMenuListener( new MenuListener( )
        {
            @Override
            public void menuHidden( MenuEvent event )
            {
                try
                {
                    Field field = Menu.class.getDeclaredField( "hasLocation" );
                    field.setAccessible( true );
                    field.set( menu, false );
                }
                catch ( Exception e )
                {
                    e.printStackTrace();
                }
            }

            @Override
            public void menuShown( MenuEvent event )
            {
            }
        });

        shell.setMenu( menu );

        shell.open( );
        while ( !shell.isDisposed( ) )
        {
            if ( !display.readAndDispatch( ) ) display.sleep( );
        }
        display.dispose( );
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!