How to Draw Lines on the Screen (Part 1)

I've seen occasional questions on mailing lists about how to use the NetBeans Visual Library to draw lines, e.g., to make graphs or diagrams of various kinds by drawing on the screen. So, rather than drag/drop causing widgets to be added, you'd want widgets to be added on mouse clicks, and you'd want to be able to connect those widgets together somehow.

Via the code below, you'll be able to click on the screen, which causes a dot to appear. When you have multiple dots, you can hold down the Ctrl key and connect them together. A guiding line appears to help you position the dots exactly in line with each other. When you go to File | Print, you'll be able to preview and print the diagram you've created.

A picture that speaks 1000 words:

Here's the code (first create a NetBeans module, then use the New Window wizard to create a new TopComponent, then integrate the code below into the TopComponent):

public final class PlotterTopComponent extends TopComponent {

    private final Scene scene;
    private final LayerWidget baseLayer;
    private final LayerWidget connectionLayer;
    private final LayerWidget interactionLayer;

    public PlotterTopComponent() {

        initComponents();
        
        setName(Bundle.CTL_PlotterTopComponent());
        setToolTipText(Bundle.HINT_PlotterTopComponent());
        
        setLayout(new BorderLayout());

        this.scene = new Scene();
        this.baseLayer = new LayerWidget(scene);
        this.interactionLayer = new LayerWidget(scene);
        this.connectionLayer = new LayerWidget(scene);

        scene.getActions().addAction(new SceneCreateAction());
        
        scene.addChild(baseLayer);
        scene.addChild(interactionLayer);
        scene.addChild(connectionLayer);
    
        add(scene.createView(), BorderLayout.CENTER);
        
        putClientProperty("print.printable", true);
    
    }

    private class SceneCreateAction extends WidgetAction.Adapter {
        @Override
        public WidgetAction.State mousePressed(Widget widget, 
        WidgetAction.WidgetMouseEvent event) {
            if (event.getClickCount() == 1) {
                if (event.getButton() == MouseEvent.BUTTON1 || 
                        event.getButton() == MouseEvent.BUTTON2) {
                    baseLayer.addChild(new BlackDotWidget(scene, widget, event));
                    repaint();
                    return WidgetAction.State.CONSUMED;
                }
            }
            return WidgetAction.State.REJECTED;
        }
    }

    private class BlackDotWidget extends ImageWidget {
        public BlackDotWidget(Scene scene, Widget widget, 
                WidgetAction.WidgetMouseEvent event) {
            super(scene);
            setImage(ImageUtilities.loadImage("org/netbeans/plotter/blackdot.gif"));
            setPreferredLocation(widget.convertLocalToScene(event.getPoint()));
            getActions().addAction(
                    ActionFactory.createExtendedConnectAction(
                       connectionLayer, new BlackDotConnectProvider()));
            getActions().addAction(
                    ActionFactory.createAlignWithMoveAction(
                       baseLayer, interactionLayer,
                       ActionFactory.createDefaultAlignWithMoveDecorator()));
        }
        
    }

    private class BlackDotConnectProvider implements ConnectProvider {

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

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

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

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

        @Override
        public void createConnection(Widget source, Widget target) {
            ConnectionWidget conn = new ConnectionWidget(scene);
            conn.setTargetAnchor(AnchorFactory.createCircularAnchor(target, 10));
            conn.setSourceAnchor(AnchorFactory.createCircularAnchor(source, 10));
            connectionLayer.addChild(conn);
        }

    }

    ...
    ...
    ...

Note: The code above was written based on the Visual Library tutorials on the NetBeans Platform Learning Trail, in particular via the "ConnectScene" sample in the "test.connect" package, which is part of the very long list of Visual Library samples referred to in the Visual Library tutorials on the NetBeans Platform Learning Trail.

The next steps are to add a reconnect action and an action to delete a dot by double-clicking on it. Would be interesting to change the connecting line so that the length of the line were to be shown, i.e., as you draw a line from one dot to another, you'd see a constantly changing number representing the current distance of the connecting line. Also, once lines are connected to form a rectangle, would be cool to be able to write something within that rectangle. Then one could really create diagrams, which would be pretty cool.

Comments:

Nice. Thanks for all your articles.

Posted by guest on September 08, 2012 at 09:00 AM PDT #

is circle next?

Posted by guest on September 10, 2012 at 02:04 AM 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 technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today