Connecting Shapes & Showing Properties

Continuation from yesterday's blog entry, with a more relevant sample, based on applications I've seen on the NetBeans Platform. It is very common to want to let the user click in a window causing a dialog to be displayed followed by a widget being created, with properties and the possibility of being connected to each other (via Ctrl plus left mousebutton movement):

To achieve the above, create a new module, use the Window component wizard to create a new window, with "ToolVisualizer" as the class name prefix, set dependencies on the Visual Library, Nodes API, and the Dialogs API, and then paste the code below into the TopComponent:

private final Scene scene;
private final LayerWidget layer;
private final LayerWidget connectionLayer;

//Constructor:
public ToolVisualizerTopComponent() {

    initComponents();

    ...
    ...
    ...

    scene = new Scene();

    layer = new LayerWidget(scene);
    connectionLayer = new LayerWidget(scene);

    scene.addChild(layer);
    scene.addChild(connectionLayer);

    scene.getActions().addAction(ActionFactory.createSelectAction(new SelectProvider() {

        @Override
        public boolean isAimingAllowed(Widget widget, Point point, boolean bln) {
            return true;
        }

        @Override
        public boolean isSelectionAllowed(Widget widget, Point point, boolean bln) {
            return true;
        }

        @Override
        public void select(Widget widget, Point point, boolean bln) {
            NotifyDescriptor.InputLine desc = new NotifyDescriptor.InputLine("Name:", "Set a Name");
            DialogDisplayer.getDefault().notify(desc);
            Shape shape = new Shape(desc.getInputText(), new Date());
            ShapeWidget tw = new ShapeWidget(scene, point, shape);
            layer.addChild(tw);
            scene.repaint();
            scene.validate();
        }

    }));

    jScrollPane1.setViewportView(scene.createView());

}

class Shape {

    String type;
    Date date;

    public Shape(String type, Date date) {
        this.type = type;
        this.date = date;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}

class ShapeWidget extends IconNodeWidget {

    public ShapeWidget(Scene scene, Point loc, final Shape shape) {
        super(scene);
        setPreferredLocation(loc);
        setLabel(shape.getType());
        setImage(ImageUtilities.loadImage("org/vislib/scene/circlered.png", true));
        getActions().addAction(ActionFactory.createExtendedConnectAction(connectionLayer, new MyConnectProvider()));
        getActions().addAction(ActionFactory.createMoveAction());
        getActions().addAction(ActionFactory.createPopupMenuAction(new PopupMenuProvider() {
            @Override
            public JPopupMenu getPopupMenu(final Widget widget, Point localLocation) {
                JPopupMenu popup = new JPopupMenu();
                JMenuItem propsMenu = new JMenuItem("Properties");
                propsMenu.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        AbstractNode node = new AbstractNode(Children.LEAF) {
                            @Override
                            protected Sheet createSheet() {
                                Sheet sheet = super.createSheet();
                                Set set = sheet.createPropertiesSet();
                                set.put(new TypeProperty(shape));
                                set.put(new DateProperty(shape));
                                sheet.put(set);
                                return sheet;
                            }
                        };
                        node.setDisplayName(shape.getType());
                        node.setShortDescription("Description of " + shape.getType());
                        NodeOperation.getDefault().showProperties(node);
                    }
                });
                popup.add(propsMenu);
                return popup;
            }
        }));

    }

}

private static class TypeProperty extends PropertySupport.ReadOnly {

    private final Shape shape;

    public TypeProperty(Shape shape) {
        super("shapeType", String.class, "Type", "Displays shape type");
        this.shape = shape;
    }

    @Override
    public String getValue() throws IllegalAccessException, InvocationTargetException {
        return shape.getType();
    }

}

private static class DateProperty extends PropertySupport.ReadOnly {

    private final Shape shape;

    public DateProperty(Shape shape) {
        super("shapeDate", Date.class, "Date", "Displays shape date");
        this.shape = shape;
    }

    @Override
    public Date getValue() throws IllegalAccessException, InvocationTargetException {
        return shape.getDate();
    }

}

private class MyConnectProvider implements ConnectProvider {

    public boolean isSourceWidget(Widget source) {
        return source instanceof IconNodeWidget && source != null ? true : false;
    }

    public ConnectorState isTargetWidget(Widget src, Widget trg) {
        return src != trg && trg instanceof IconNodeWidget ? ConnectorState.ACCEPT : ConnectorState.REJECT;
    }

    public boolean hasCustomTargetWidgetResolver(Scene arg0) {
        return false;
    }

    public Widget resolveTargetWidget(Scene arg0, Point arg1) {
        return null;
    }

    public void createConnection(Widget source, Widget target) {
        ConnectionWidget conn = new ConnectionWidget(scene);
        conn.setTargetAnchorShape(AnchorShape.TRIANGLE_FILLED);
        conn.setTargetAnchor(AnchorFactory.createRectangularAnchor(target));
        conn.setSourceAnchor(AnchorFactory.createRectangularAnchor(source));
        connectionLayer.addChild(conn);
    }

}

That's all, now you can display the properties of the current widget and you're also able to connect widgets to each other.

Comments:

Hi The theme/coloring on these forms how was it acheived? thx

Posted by Jay Bennie on August 15, 2010 at 09:09 AM PDT #

Hi,

I am a java programer, but when I read thses tutorial I found myself ignorant, I did not understand anything, what java version is this ? is there any tutorial on how to write these things ? can you plz put the whole code so I can run it in netbaens.

thanks, your help is appreciated

Posted by Kamal on August 16, 2010 at 01:25 AM PDT #

Thanks for this very informative tutorial.

Of note, on the Mac, I have to use CTRL + OPTION + LEFT-CLICK to make a connection.

Posted by guest on June 23, 2011 at 09:53 AM PDT #

Hi,

May I know is that possible for me to do the same thing on the connector?
I want to show properties of the line/connector too.
How?

Thanks

Posted by CT on March 01, 2013 at 10:45 AM PST #

Hi Geertjan,

I am newbie in netbeans platform development, but I very interest to create an application on top of it.
Based on this tutorial/example,
Currently I have some issue about how to make the properties sheet automatically show in the properties when I select (one click) on the icon
without need to create some popup properties windows.

What should i do to make this happen?

Thanks
Feriyanto

Posted by Fery on March 12, 2014 at 03:30 AM PDT #

Not sure I understand -- I advise that you purchase https://leanpub.com/nbp4beginners and let the authors know about any scenarios that are missing from the book so they can cover it in the next release of it.

Posted by Geertjan on March 12, 2014 at 03:40 AM PDT #

Hi Geertjan,

Sorry for my unclear question.
I follow this tutorial to create some workflow

https://platform.netbeans.org/tutorials/nbm-visual_library.html

My issue is how to show the properties of IconNodeWidget not in the popup Properties, but in the propertySheetWindow when the icon is selected.
I just follow the tutorial
https://platform.netbeans.org/tutorials/nbm-nodesapi2.html to learn how the properties used and still not success.

I'am implement TopComponent with ExplorerManager.Provider, and extends node with AbstractNode but the behaviour between Node and IconNodeWidget is quite different.
Please show me what i have to use?Did i do the right thing?

Thanks for your help and info.

Feri

Posted by guest on March 18, 2014 at 09:06 PM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java and JavaScript technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily, mainly on topics connected to Oracle JET and NetBeans IDE.

Search


Archives
« April 2017
SunMonTueWedThuFriSat
      
1
2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
23
24
25
26
27
28
29
30
      
Today