X

Geertjan's Blog

  • August 31, 2006

Selection and Connection in Visual Library 2.0

Geertjan Wielenga
Product Manager
When you move a widget or when you connect the widget to another widget, you make use of the same mouse gesture—you click the left mousebutton and then you move the mouse in the direction where you want the widget to move or in the direction where the other widget is, the one to which you want to connect. So, how to enable both actions, despite the fact that their mouse gestures are the same? In the IDE, for example, as in many IDEs or other applications, you've got a "Selection mode" and a "Connection mode". Here you can see how I've implemented it in my Simpsons application—right-click anywhere in the JComponent and then you get a popup menu that lets you make the selection:

The key concept here, in relation to the NetBeans Visual Library 2.0, is that of "active tools". So, when you make a selection in the popup menu, you change the active tool from "Selection", which is the default, to "Connection". How to implement this yourself? Well, I learnt about this functionality via the cool test.tool.ToolTest sample, which comes with the Visual Library 2.0. And all of it is standard code, nothing that you need to fiddle with, even, it all just works out of the box.

First, I created an inner class that provides a popup menu, with two items which, when selected, result in a polite information message in the status bar, so that the user knows which tool is currently selected:

private final class MyPopupProvider implements PopupMenuProvider, ActionListener {
private JPopupMenu menu;
public MyPopupProvider() {
menu = new JPopupMenu("Popup menu");
JMenuItem item;
item = new JMenuItem("Connection Mode");
item.setActionCommand(ACTION_CONNECT);
item.addActionListener(this);
menu.add(item);
item = new JMenuItem("Selection Mode");
item.setActionCommand(ACTION_SELECT);
item.addActionListener(this);
menu.add(item);
}
public JPopupMenu getPopupMenu(Widget widget) {
return menu;
}
public void actionPerformed(ActionEvent e) {
setActiveTool(e.getActionCommand());
if (e.getActionCommand().equals(ACTION_SELECT)){
StatusDisplayer.getDefault().setStatusText("Selection mode");
} else {
StatusDisplayer.getDefault().setStatusText("Connection mode");
}
}
}

At the top of the file, I declare my constants:

private static final String ACTION_CONNECT = "connect"; // NOI18N
private static final String ACTION_SELECT = "selection"; // NOI18N

In the Constructor, I set the default active tool, together with the status bar message:

setActiveTool(ACTION_SELECT);
StatusDisplayer.getDefault().setStatusText("Selection mode");

And then, for each widget, within the code that defines the widget, I specify what happens when one or the other tool is active. These, for example, are Barney's active tool settings:

barney.createActions(ACTION_SELECT).addAction(moveAction);
barney.createActions(ACTION_CONNECT).addAction(connectAction);

Then I need to define what "moveAction" and "connectAction" mean.

So, at the top of the file I declared two Widget Actions:

private WidgetAction moveAction = ActionFactory.createAlignWithMoveAction(mainLayer, interactionLayer, null);
private WidgetAction connectAction = ActionFactory.createConnectAction(interactionLayer, new SceneConnectProvider());

And that's it. There's a lot more to be said about the connectAction, because to be able to connect one widget to another (via arrows, as shown above and in previous blog entries), you need to specify quite a bit more. But, here too, everything is just standard code that I copied and pasted from the samples.

Finally, the arrows are pretty cool. As you can see here, you can select an arrow:

And then you can move that arrow so that it connects to a different widget. Or... you can move the arrow back into the widget, or into nowhere, which will make the arrow disappear. Really cool and powerful stuff in this Visual Library 2.0!

Join the discussion

Comments ( 12 )
  • Youmna Saturday, October 6, 2007

    I am implementing something similar to that. The problem is that I cannot handle both the selection and the movement of the widget if i say:

    this.getActions().addAction(Scene.createSelectAction());

    this.createActions(ACTION_SELECT).addAction(moveAction);

    this.createActions(ACTION_CONNECT).addAction(Scene.connectAction);

    I cannot move the widget, and I've to remove the select action to be able to move it.

    Do u know why is that?


  • Geertjan Saturday, October 6, 2007

    Do this instead, because the order is important:

    this.getActions().addAction(Scene.createSelectAction());

    this.createActions(ACTION_CONNECT).addAction(Scene.connectAction);

    this.createActions(ACTION_SELECT).addAction(moveAction);

    Also, look at the Simpsons sample for 6.0:

    http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=3785


  • Youmna Saturday, October 6, 2007

    I downloaded the simpsons plug-in it's really amazing. but, where in the code do u handle the part of pressing CTRL to activate the connections mode? I see from the code that you did not use the above technique, how do u change the mode?

    thanks


  • Geertjan Saturday, October 6, 2007

    Connect action is defined like this:

    private WidgetAction connectAction = ActionFactory.createExtendedConnectAction(interactionLayer, new SceneConnectProvider());

    Then, connect action must be added to the widget BEFORE the move action, otherwise the move action consumes all mouse-pressed, mouse-dragged, and mouse-released events. So this is my widget and notice that the connect action is addded BEFORE the move action:

    private Widget createSimpsonWidget(String label, Image image) {

    IconNodeWidget character = new IconNodeWidget(this);

    character.setImage(image);

    character.setLabel(label);

    mainLayer.addChild(character);

    character.getActions().addAction(createSelectAction());

    character.getActions().addAction(createObjectHoverAction());

    character.getActions().addAction(connectAction);

    character.getActions().addAction(moveAction);

    character.getLabelWidget().getActions().addAction(editorAction);

    return character;

    }


  • Geertjan Saturday, October 6, 2007

    Once you have defined the connect action as described above, and have added it in the correct order, you will notice that when you press the Ctrl button, your drag gesture will cause the connect to work, i.e., an arrow will appear from one widget and you will then be able to connect that arrow to another widget.


  • BynightJava Tuesday, June 10, 2008

    excuse me but how do i move a group of object widget in mainlayer? can you show me an example?

    thanks for Help.


  • Michael Alderton-Smith Thursday, February 25, 2010

    Hi, great article.... again.

    Quick question that nobody seems to be able to answer:

    How do you get the connections to work on VMDGraphScene? Is there a way access the four built in LayerWidgets?

    I have found no documentation anywhere on actually creating an editable and connectable VMD based map.

    All the articles cover building from a database for example, but I can't figure how to apply what I know from the more basic Scenes to this.

    Do I just go ahead and create my own layers for connections? Or is there an easy way to do this. Please excuse the annoyance, but I'm finding VMD documentation very limited.

    Thanks in advance


  • guest Tuesday, June 21, 2011

    I'm picking up your stuff years after you post them, but many of them have proven great time-savers in my work.


  • guest Wednesday, July 13, 2011

    Where can I find test.tool.ToolTest, is this still around? Thanks.


  • Geertjan Thursday, July 14, 2011
  • Rafa Tuesday, March 13, 2012

    Hi Geertjan,

    I find your examples very useful, I've learned a lot, but recently I am having problems with the Connection Widget.

    In runtime, when I create a Connection widget, a dependency is automatically added to the source and target widgets, but it is not deleted when the connection widget is deleted.

    Is this normal operation?

    Thank you


  • guest Monday, July 2, 2012

    My question is similar to the one above...i think...

    Say I connect two widgets - there is an arrow between them.

    When I delete one of those widgets, how can I get the arrow connecting them to disappear as well???


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.