Some days ago I was trying to find a solution for a multiline label widget for the netbeans visual library, I tried some solutions (out of the box) like QLabel and others found on the web, without any success, after 2 weeks of frustrating research, I decided to continue with other features of my system, and then later on, I returned to this issue again and give it a try.
The problem:I needed a Widget that supported Multiline label, auto-fit on resize, and drag and drop action, the first approach was to include QLabel within a ComponentWidget, It did not work for me, and then, I tried with a JTextArea in this way:
public class MultilineLabelWidget extends ComponentWidget{ public MultilineLabelWidget( Scene scene, String text ) { super( scene, new JTextArea( text ) ); JTextArea jText = (JTextArea) this.getComponent(); jText.setOpaque( false ); jText.setEditable( false ); jText.setLineWrap( true ); jText.setWrapStyleWord( true ); jText.setHighlighter( null ); jText.setBorder( BorderFactory.createEmptyBorder() ); this.getActions().addAction( ActionFactory.createResizeAction() ); this.getActions().addAction( ActionFactory.createMoveAction() ); this.setBorder( org.netbeans.api.visual.border.BorderFactory.createLineBorder( 8 ) ); }}and It partially worked!!, the problem is that JTextArea is painted after the widget, so the MoveAction will not work! out-of-the-box, ummm, I tried another solution, not extending the ComponentWidget but creating an in-line ComponentWidget and trying to catch the Mouse Events and redirect the calls to its Action in the Widget, like this:
JTextArea jText = new JTextArea( hm ); jText.setOpaque( false ); jText.setEditable( false ); jText.setLineWrap( true ); jText.setWrapStyleWord( true ); jText.setBorder( BorderFactory.createEmptyBorder() ); final ComponentWidget widget = new ComponentWidget(scene,jText); widget.getActions().addAction( ActionFactory.createResizeAction() ); widget.getActions().addAction( ActionFactory.createMoveAction() ); jText.addMouseMotionListener( new MouseMotionListener(){ @Override public void mouseDragged( MouseEvent event ) { widget.getActions().mouseDragged( widget, new WidgetAction.WidgetMouseEvent(new Date().getTime(),event) ); } @Override public void mouseMoved( MouseEvent event ) { widget.getActions().mouseMoved( widget, new WidgetAction.WidgetMouseEvent(new Date().getTime(),event) ); }} ); jText.addMouseListener( new MouseListener(){ @Override public void mouseClicked( MouseEvent event ) { widget.getActions().mouseClicked( widget, new WidgetAction.WidgetMouseEvent(new Date().getTime(),event) ); } @Override public void mouseEntered( MouseEvent event ) { widget.getActions().mouseEntered( widget, new WidgetAction.WidgetMouseEvent(new Date().getTime(),event) ); } @Override public void mouseExited( MouseEvent event ) { widget.getActions().mouseExited( widget, new WidgetAction.WidgetMouseEvent(new Date().getTime(),event) ); } @Override public void mousePressed( MouseEvent event ) { widget.getActions().mousePressed( widget, new WidgetAction.WidgetMouseEvent(new Date().getTime(),event) ); } @Override public void mouseReleased( MouseEvent event ) { widget.getActions().mouseReleased( widget, new WidgetAction.WidgetMouseEvent(new Date().getTime(),event) ); }} ); jText.setHighlighter( null ); widget.setBorder( org.netbeans.api.visual.border.BorderFactory.createLineBorder( 8 ) );It worked better than the previous solution!, BUT!!!!!!!!!, It just worked when I moved the mouse pointer slowly (of course, first click and then drag), but every time I moved the mouse pointer as I usually do, the component was not repainted (It did not followed the mouse pointer), and at the moment I released the left button on the mouse, the widget was painted!, frustrating for me because I think It should be easy to do it!
(please developer of Visual Library, include a Multiline Label Widget Out-of-the-box).
The solutionFinally, I found a code on the net (It references to com.exalto.UI) and adapted it to fit within the Visual Library Widget, so the result It is this:
package test.designer.widget;import java.awt.Graphics2D;import java.awt.Insets;import java.awt.Rectangle;import java.awt.font.LineBreakMeasurer;import java.awt.font.TextAttribute;import java.awt.font.TextLayout;import java.text.AttributedCharacterIterator;import java.text.AttributedString;import org.netbeans.api.visual.widget.LabelWidget;import org.netbeans.api.visual.widget.Scene;public class MultilineLabelWidget extends LabelWidget{ private boolean justify; public MultilineLabelWidget( Scene scene, String label ) { super( scene ); this.setLabel( label ); this.setJustified( true ); } @Override protected void paintWidget() { paintOrGetSize( this.getGraphics() ); } private void paintOrGetSize( Graphics2D gr ) { float width = (float) ( this.getBounds() != null ? this.getBounds().getWidth() : this.getPreferredSize() .getWidth() ); Insets insets = this.getBorder().getInsets(); float rwidth = width - ( insets.left + insets.right );// + margin.left + margin.right; Rectangle rec = this.calculateClientArea(); gr.setFont( getFont() );float x = 0.0F;//+ margin.left; float y = (float) rec.getY();//+ margin.top; if ( rwidth > 0 && this.getLabel() != null && this.getLabel().length() > 0 ) { AttributedString as = new AttributedString( this.getLabel() ); as.addAttribute( TextAttribute.FONT, getFont() ); AttributedCharacterIterator aci = as.getIterator(); LineBreakMeasurer lbm = new LineBreakMeasurer( aci, gr.getFontRenderContext() ); while ( lbm.getPosition() < aci.getEndIndex() )
{
TextLayout textLayout = lbm.nextLayout( rwidth );
if ( gr != null && isJustified() && textLayout.getVisibleAdvance() > 0.80 * rwidth )
{
textLayout = textLayout.getJustifiedLayout( rwidth );
}
if ( gr != null )
{
textLayout.draw( gr, x, y + textLayout.getAscent() );
}
y += textLayout.getDescent() + textLayout.getLeading() + textLayout.getAscent();
}
}
}
public boolean isJustified()
{
return justify;
}
public void setJustified( boolean justify )
{
boolean old = this.justify;
this.justify = justify;
if ( old != this.justify )
{
repaint();
}
}
}
It worked for me, It worked for my purposes, I hope It works for you.
Please modify it, improve the code, see if It works for you, and feedback to me.
Thanks a lot.
References:
http://graph.netbeans.org/servlets/ReadMsg?listName=users&msgNo=1295
http://graph.netbeans.org/servlets/ReadMsg?list=users&msgNo=726
http://www.koders.com/java/fid9BE9B31AC9BED01828448BF91A61AFA5AE431E16.aspx