How to Draw Lines on the Screen
- by Geertjan
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:
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.