This article explains how to adjust a node's width and height according to the node's label, and contains a working demo example.
The easiest way to adjust a node's size according to its label is to get noticed whenever the label is being changed. Afterwards one can manually set the node size so that the label will fit.
A NodeLabel can be edited by using
Graph2DView.openLabelEditor(y.view.YLabel, double, double)
or
Graph2DView.openLabelEditor(y.view.YLabel, double, double, java.beans.PropertyChangeListener)
.
Calling one of these methods will show a TextField where the label can be edited with the difference, that when we use the latter method, we can hand over our own PropertyChangeListener and can adjust the node size whenever the property changed event is fired.
So we can register the following Action to whatever we use to trigger our "edit label" action (PopupMenu, Button, Key Binding).
/**
* Action that opens a text editor for the label of a node
*/
class EditNodeLabel extends AbstractAction {
private NodeLabel label;
EditNodeLabel(NodeLabel label) {
super( "Edit Label" );
this.label = label;
}
public void actionPerformed( ActionEvent e ) {
view.openLabelEditor( label,
label.getLocation().getX(),
label.getLocation().getY(),
getLabelChangeListener()
);
}
}
|
The set LabelChangeListener will then be informed when the label editing ends and can adjust the node size as follows:
class LabelChangeListener implements PropertyChangeListener{
private static final int INDENTATION = 5;
public void propertyChange(PropertyChangeEvent evt) {
NodeLabel label = (NodeLabel) evt.getSource();
adjustNodeSize(label.getRealizer());
}
void adjustNodeSize(NodeRealizer realizer) {
NodeLabel label = realizer.getLabel();
FontMetrics fm = view.getGraphics().getFontMetrics(label.getFont());
String labelText = label.getText();
Pattern pat = Pattern.compile("(.*)", Pattern.MULTILINE);
Matcher matcher = pat.matcher(labelText);
int maxWidth = 0;
while (matcher.find()) {
String currentLine = matcher.group();
int currentWidth = fm.stringWidth(currentLine);
if (currentWidth > maxWidth) {
maxWidth = currentWidth;
}
}
if (maxWidth > 0) {
realizer.setWidth(maxWidth + 2 * INDENTATION);
} else { realizer.setWidth(view.getGraph2D().getDefaultNodeRealizer().getWidth());
}
int lineCount = 1;
for (Matcher m = Pattern.compile("\n").matcher(labelText); m.find();) {
lineCount++;
}
int lineHeight = fm.getHeight();
if (labelText.length() > 0) {
realizer.setHeight(lineHeight * lineCount + 2 * INDENTATION);
} else { realizer.setHeight(view.getGraph2D().getDefaultNodeRealizer().getHeight());
}
}
}
|
Another possibility would be to register a
Graph2DListener
on the Graph2D using
Graph2D.addGraph2DListener(y.view.Graph2DListener)
. A Graph2DListener will get Graph2DEvents and can handle them accordingly. To react on node label changes the listener will look as follows:
class LabelChangedListener implements Graph2DListener{
private static final int INDENTATION = 5;
public void onGraph2DEvent(Graph2DEvent e) {
Node v = null;
String p = e.getPropertyName();
if(e.getSubject() instanceof NodeLabel && "text".equals(p)){
v = ((NodeLabel)e.getSubject()).getNode();
} else if(e.getSubject() instanceof Node && "realizer".equals(p)){
v = (Node)e.getSubject();
}
if(v != null){
adjustNodeSize(view.getGraph2D().getRealizer(v));
}
}
private void adjustNodeSize(NodeRealizer realizer) {
/**
do adjustment here
*/
}
}
|
| Warning |
When registering a Graph2DListener to the graph, the node size changes will happen everytime the label text is set or the NodeRealizer changes. This does for example also happen when loading the graph and will result in other node sizes than the loaded file really had.
Thus it is recommended to use the first solution for adjusting node labels after they have been edited. |
| Note |
|
You can download and execute the attached demos. Please save them to <yfilesDir>/src/demo/view/layout/labeling |