Programmatically perform mouse button press /release on RoundRectButton


#1

Hello Beni,

Is there a way to programmatically perform a mouse button press and release on a bibliothek.extension.gui.dock.theme.eclipse.RoundRectButton to minimize, externalize, maximize, and ‘X’ buttons on a dockable. This would be similar to Swing’s ButtonModel setArmed() and setPressed() methods? The RoundRectButton objects are generated by their dockables via DF. From DF API, I was hopping to use trigger() on BasicButtonModel (after getModel() on RoundRectButton), but trigger() is protected. Is there another way? Thank you.

Regards,
/Adi


#2

You can use “CDockable.setExtendedMode” (or “setLocation” if you need more control) to change the position:

dockable.setExtendedMode( ExtendedMode.MINIMIZED );```

To "X" a Dockable, just call "CDockable.setVisible( false )".


These buttons may not always exist, your application should not assume they do, or even try to access them.

#3

Thanks, Beni

This works great for triggering the buttons /actions – now I just need a way to distinguish between the type of buttons (e.g. using instanceof) in order to set the correct parameter within setExtendedMode(ExtendedMode.XXX). So for example, if I discover I have a minimize button I would like to call dockable.setExtendedMode(ExtendedMode.MINIMIZED); for a normalize button I would like to call dockable.setExtendedMode(ExtendedMode.NORMALIZED), etc.

Type of buttons of interest:
minimize,
maximize,
externalize,
normalize,
drop-down menu arrow (when dockable is squeezed)
‘X’ button

How would I be able to tell which type of button /action I have? All my dockables have the same set of buttons generated by DF so I would assume each set maintains the same naming conventions across the dockables. Thank you.

Regards,
/Adi

P.S. In debug mode, I can see that roundRectButton.getAction() returns a DockAction object which has a field, e.g. ‘action= CMaximizeAction (id=175)’, that identifies the type of action – but I have no way of accessing that field.


#4

By the way: If you have access to a DockAction, then you could call its public trigger method to execute the action.

Are you still working on your Glass-Pane? If so: you should really consider to use the method “Component.dispatch” to send MouseEvents to Components below your Glass-Pane. Let the Components decide for their own how to react to MouseEvents, or you will never finish with handling all the different cases.

And if you are not working on your Glass-Pane: why do you want to trigger buttons programmatically? They were intended for the user, not for the application…


#5

Hi Beni,

I do have access to a DockAction, but its trigger() method requires a parameter of type Dockable element, which unfortunately I don’t have – how do I get a Dockable element?

Yes, I am still working on the design of my glass pane and I am open to options for implementing this feature. Also, this feature needs to be user configurable to enable the application to run with or without the glass pane (e.g. when running without the glass pane components such as buttons interact with a rollover, and tree nodes interact with highlights when a mouse hovers over them regardless if a popup menu is displayed. With the glass pane enabled, these components do not interact with mouse events when a popup menu is showing). The glass pane dispatches the mouse event to the component under the glass pane but uses Swing’s component.dispatchEvent() method (same approach to Oracle example). It’s a bit trickier than I anticipated but achievable.

But the glass pane is not the culprit for my question (although the solution may be related to glass panes); I noticed that when I right click on a DF dockable title bar to trigger a popup menu, (1) the buttons rollover, and (2) the same buttons do not react to a left click (while the popup menu is still showing). At first I thought that I have missed something when coding my dockables. But then I noticed three of DF’s demos (Notes, Size & Color, and Common Layouts) also demonstrate similar behavior.

From observation of Windows Look and Feel, when a popup menu is showing, most if not all, buttons, menus, tabs, tree nodes, fields, etc, are inactive when a mouse hovers over them. Clicking on one of these Windows components (either a press or release, depending on the component), triggers that component to react to the event, and simultaneously closes the popup menu that is showing. Eclipse, too, displays this same Windows behavior for Windows L&F.

I understand that such buttons are intended for the user, and I have used them in this way to define my dockables, but for situations when it is desirable to maintain Window L&F for user experience, is there a way to programmatically control these buttons?

I have a faint hunch that it may be simpler to implement a glass pane when triggering a popup menu from a DF dockable title bar to achieve Windows L&F. If this is the case, would it be possible for you to share a code example of DF GlassedPane implementation to achieve this L&F? Either approaches would be a big help.

Thank you.
/Adi


#6

RoundRectButton has a model, which has a Dockable. [inline]button.getModel().getDockable()[/inline].

I just started the demo applications on my Windows machine, and even if a popup was open I could still see rollover effects on the buttons and click them (I was using Java 7 and Windows 7).

Btw.: DockingFrames GlassPane:


#7

Hello Beni,

Thank you. Your tips pointed me to most of the solution I was looking for. For interested readers, here is one way I found to programmatically control the buttons /actions (with the exception of the drop-down arrow) on a dockable title bar:

1- BasicButtonModel roundRectButton = ((RoundRectButton) yourComponent).getModel(); //ensure yourComponent is of type RoundRectButton and get its model.
2- Dockable dockable = roundRectButton.getDockable(); //using the model, get its dockable.
3- roundRectButton.getAction().trigger(dockable); //using the same model, get its action, and trigger using its dockable as the parameter.

The only missing button that I cannot control using the above approach is the drop-down arrow (i.e. when the dockable is squeezed).

Regarding the DF demos: what you are seeing on Windows 7 matches my point (1) in my last posting – which is inconsistent with Windows LAF. In other words, when a popup is open, rollover effects should be blocked on buttons (try it on Explorer or Eclipse). On the second point, since your Windows 7 machine allows you to click on the buttons when a popup is open (my point 2), is a great improvement over my Vista machine, since what you observed is the correct Wondows LAF behavior.

Also, thank you for your GlassedPane class; it is an excellent option and I will explore it further.
Again, thank you for your help.

/Adi


#8

Some magic to show the popup menu (as you see, it really was never meant to be shown programatically).


import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;

import javax.swing.Action;
import javax.swing.JFrame;

import bibliothek.extension.gui.dock.theme.eclipse.RoundRectDropDownButton;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.action.CButton;
import bibliothek.gui.dock.common.action.CDropDownButton;
import bibliothek.gui.dock.common.theme.ThemeMap;

public class PopupTest {
	public static void main( String[] args ) {
		JFrame frame = new JFrame();
		CControl control = new CControl( frame );
		control.setTheme( ThemeMap.KEY_ECLIPSE_THEME );

		frame.add( control.getContentArea() );
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		frame.setBounds( 50, 50, 500, 500 );

		DefaultSingleCDockable dockable = new DefaultSingleCDockable( "a", "Aaaa" );
		CDropDownButton dropDown = new CDropDownButton();
		dropDown.add( new CButton( "button1", null ) );
		dropDown.add( new CButton( "button2", null ) );
		dropDown.add( new CButton( "button3", null ) );
		dockable.addAction( dropDown );

		control.addDockable( dockable );
		dockable.setVisible( true );

		frame.setVisible( true );
		
		while(true){
			try {
				Thread.sleep( 2000 );
			} catch( InterruptedException e ) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			new ShowPopup( frame ).run();
		}
	}

	private static class ShowPopup implements Runnable {
		private Component root;

		public ShowPopup( Component root ) {
			this.root = root;
		}

		private RoundRectDropDownButton findButton( Component item ) {
			if( item instanceof RoundRectDropDownButton ) {
				return (RoundRectDropDownButton) item;
			}
			if( item instanceof Container ) {
				Container parent = (Container) item;
				for( int i = 0, n = parent.getComponentCount(); i < n; i++ ) {
					RoundRectDropDownButton result = findButton( parent.getComponent( i ) );
					if( result != null ) {
						return result;
					}
				}
			}
			return null;
		}

		@Override
		public void run() {
			RoundRectDropDownButton button = findButton( root );
			Action action = button.getActionMap().get( "basic_drop_down_model_popup" );
			action.actionPerformed( new ActionEvent( button, ActionEvent.ACTION_PERFORMED, "nothing" ) );
		}
	}
}