This patch should help a little with the performance of JLabel by
caching the Insets and don't worrying about storing/restoring the color
from the Graphics. It also slightly improves the initialization where we
could run into an NPE when the font metrics is fetched but the label
doesn't yet have a heavyweight parent. Now we fetch the font metrics
from the toolkit as a fallback.
2006-11-14 Roman Kennke <[EMAIL PROTECTED]>
* javax/swing/plaf/basic/BasicLabelUI.java
(cachedInsets): New field.
(getFontMetrics): New helper method. Fetches the font metrics
from the component or the toolkit.
(getPreferredSize): Use getFontMetrics() helper method for
fetching the font metrics.
(paint): Use getFontMetrics() helper method for
fetching the font metrics. Only paint if icon or text
are != null. Use cached insets.
(paintDisabledText): Don't store/restore color object. The
JComponent painting mechanism takes care of this by calling
create().
(paintEnabledText): Don't store/restore color object. The
JComponent painting mechanism takes care of this by calling
create().
/Roman
Index: javax/swing/plaf/basic/BasicLabelUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicLabelUI.java,v
retrieving revision 1.25
diff -u -1 -5 -r1.25 BasicLabelUI.java
--- javax/swing/plaf/basic/BasicLabelUI.java 17 Aug 2006 14:45:46 -0000 1.25
+++ javax/swing/plaf/basic/BasicLabelUI.java 14 Nov 2006 10:30:19 -0000
@@ -25,37 +25,38 @@
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package javax.swing.plaf.basic;
-import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
+import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
+import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.Icon;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI;
@@ -68,30 +69,35 @@
*/
public class BasicLabelUI extends LabelUI implements PropertyChangeListener
{
/** The labelUI that is shared by all labels. */
protected static BasicLabelUI labelUI;
/**
* These fields hold the rectangles for the whole label,
* the icon and the text.
*/
private Rectangle vr;
private Rectangle ir;
private Rectangle tr;
/**
+ * A cached Insets object for reuse in the label layout methods.
+ */
+ private Insets cachedInsets;
+
+ /**
* Creates a new BasicLabelUI object.
*/
public BasicLabelUI()
{
super();
vr = new Rectangle();
ir = new Rectangle();
tr = new Rectangle();
}
/**
* Creates and returns a UI for the label. Since one UI is shared by all
* labels, this means creating only if necessary and returning the shared
* UI.
*
@@ -119,48 +125,50 @@
{
JLabel lab = (JLabel) c;
Insets insets = lab.getInsets();
int insetsX = insets.left + insets.right;
int insetsY = insets.top + insets.bottom;
Icon icon = lab.getIcon();
String text = lab.getText();
Dimension ret;
if (icon == null && text == null)
ret = new Dimension(insetsX, insetsY);
else if (icon != null && text == null)
ret = new Dimension(icon.getIconWidth() + insetsX,
icon.getIconHeight() + insetsY);
else
{
- FontMetrics fm = lab.getFontMetrics(lab.getFont());
+ FontMetrics fm = getFontMetrics(lab);
ir.x = 0;
ir.y = 0;
ir.width = 0;
ir.height = 0;
tr.x = 0;
tr.y = 0;
tr.width = 0;
tr.height = 0;
vr.x = 0;
vr.y = 0;
vr.width = Short.MAX_VALUE;
vr.height = Short.MAX_VALUE;
layoutCL(lab, fm, text, icon, vr, ir, tr);
+ //System.err.println("font height: " + fm.getHeight());
Rectangle cr = SwingUtilities.computeUnion(tr.x, tr.y, tr.width,
tr.height, ir);
ret = new Dimension(cr.width + insetsX, cr.height + insetsY);
}
+ //System.err.println("preferred label size. "+ ret);
return ret;
}
/**
* This method returns the minimum size of the [EMAIL PROTECTED] JComponent} given. If
* this method returns null, then it is up to the Layout Manager to give
* this component a minimum size.
*
* @param c The [EMAIL PROTECTED] JComponent} to get a minimum size for.
*
* @return The minimum size.
*/
public Dimension getMinimumSize(JComponent c)
{
return getPreferredSize(c);
@@ -177,67 +185,70 @@
*/
public Dimension getMaximumSize(JComponent c)
{
return getPreferredSize(c);
}
/**
* The method that paints the label according to its current state.
*
* @param g The [EMAIL PROTECTED] Graphics} object to paint with.
* @param c The [EMAIL PROTECTED] JComponent} to paint.
*/
public void paint(Graphics g, JComponent c)
{
JLabel b = (JLabel) c;
- FontMetrics fm = g.getFontMetrics();
-
- Insets i = c.getInsets();
- vr.x = i.left;
- vr.y = i.right;
- vr.width = c.getWidth() - i.left + i.right;
- vr.height = c.getHeight() - i.top + i.bottom;
- ir.x = 0;
- ir.y = 0;
- ir.width = 0;
- ir.height = 0;
- tr.x = 0;
- tr.y = 0;
- tr.width = 0;
- tr.height = 0;
Icon icon = (b.isEnabled()) ? b.getIcon() : b.getDisabledIcon();
+ String text = b.getText();
+ if (icon != null || (text != null && ! text.equals("")))
+ {
+ FontMetrics fm = getFontMetrics(b);
+ Insets i = c.getInsets(cachedInsets);
+ vr.x = i.left;
+ vr.y = i.right;
+ vr.width = c.getWidth() - i.left - i.right;
+ vr.height = c.getHeight() - i.top - i.bottom;
+ ir.x = 0;
+ ir.y = 0;
+ ir.width = 0;
+ ir.height = 0;
+ tr.x = 0;
+ tr.y = 0;
+ tr.width = 0;
+ tr.height = 0;
- String text = layoutCL(b, fm, b.getText(), icon, vr, ir, tr);
+ text = layoutCL(b, fm, text, icon, vr, ir, tr);
- if (icon != null)
- icon.paintIcon(b, g, ir.x, ir.y);
+ if (icon != null)
+ icon.paintIcon(b, g, ir.x, ir.y);
- Object htmlRenderer = b.getClientProperty(BasicHTML.propertyKey);
- if (htmlRenderer == null)
- {
- if (text != null && !text.equals(""))
+ if (text != null && ! text.equals(""))
{
- if (b.isEnabled())
- paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent());
+ Object htmlRenderer = b.getClientProperty(BasicHTML.propertyKey);
+ if (htmlRenderer == null)
+ {
+ if (b.isEnabled())
+ paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent());
+ else
+ paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent());
+ }
else
- paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent());
+ {
+ ((View) htmlRenderer).paint(g, tr);
+ }
}
}
- else
- {
- ((View) htmlRenderer).paint(g, tr);
- }
}
/**
* This method is simply calls SwingUtilities's layoutCompoundLabel.
*
* @param label The label to lay out.
* @param fontMetrics The FontMetrics for the font used.
* @param text The text to paint.
* @param icon The icon to draw.
* @param viewR The entire viewable rectangle.
* @param iconR The icon bounds rectangle.
* @param textR The text bounds rectangle.
*
* @return A possibly clipped version of the text.
*/
@@ -253,77 +264,70 @@
/**
* Paints the text if the label is disabled. By default, this paints the
* clipped text returned by layoutCompoundLabel using the
* background.brighter() color. It also paints the same text using the
* background.darker() color one pixel to the right and one pixel down.
*
* @param l The [EMAIL PROTECTED] JLabel} being painted.
* @param g The [EMAIL PROTECTED] Graphics} object to paint with.
* @param s The String to paint.
* @param textX The x coordinate of the start of the baseline.
* @param textY The y coordinate of the start of the baseline.
*/
protected void paintDisabledText(JLabel l, Graphics g, String s, int textX,
int textY)
{
- Color saved_color = g.getColor();
-
g.setColor(l.getBackground().brighter());
int mnemIndex = l.getDisplayedMnemonicIndex();
if (mnemIndex != -1)
BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX,
textY);
else
g.drawString(s, textX, textY);
g.setColor(l.getBackground().darker());
if (mnemIndex != -1)
BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX + 1,
textY + 1);
else
g.drawString(s, textX + 1, textY + 1);
-
- g.setColor(saved_color);
}
/**
* Paints the text if the label is enabled. The text is painted using the
* foreground color.
*
* @param l The [EMAIL PROTECTED] JLabel} being painted.
* @param g The [EMAIL PROTECTED] Graphics} object to paint with.
* @param s The String to paint.
* @param textX The x coordinate of the start of the baseline.
* @param textY The y coordinate of the start of the baseline.
*/
protected void paintEnabledText(JLabel l, Graphics g, String s, int textX,
- int textY)
+ int textY)
{
- Color saved_color = g.getColor();
g.setColor(l.getForeground());
int mnemIndex = l.getDisplayedMnemonicIndex();
if (mnemIndex != -1)
BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX,
textY);
else
g.drawString(s, textX, textY);
-
- g.setColor(saved_color);
}
/**
* This method installs the UI for the given [EMAIL PROTECTED] JComponent}. This
* method will install the component, defaults, listeners, and keyboard
* actions.
*
* @param c The [EMAIL PROTECTED] JComponent} that this UI is being installed on.
*/
public void installUI(JComponent c)
{
super.installUI(c);
if (c instanceof JLabel)
{
JLabel l = (JLabel) c;
@@ -502,16 +506,39 @@
KeyEvent.ALT_DOWN_MASK), null);
keyMap.put(KeyStroke.getKeyStroke(newMnemonic,
KeyEvent.ALT_DOWN_MASK), "press");
}
}
else if (e.getPropertyName().equals("labelFor"))
{
JLabel label = (JLabel) e.getSource();
InputMap keyMap = label.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
int mnemonic = label.getDisplayedMnemonic();
if (mnemonic > 0)
keyMap.put(KeyStroke.getKeyStroke(mnemonic, KeyEvent.ALT_DOWN_MASK),
"press");
}
}
+
+ /**
+ * Fetches a font metrics object for the specified label. This first
+ * tries to get it from the label object itself by calling
+ * [EMAIL PROTECTED] Component#getFontMetrics(Font)}, and if that does not work
+ * (for instance, when we are in the initialization and have no parent yet),
+ * it asks the Toolkit for a font metrics object.
+ *
+ * @param l the label
+ *
+ * @return a suitable font metrics object
+ */
+ private FontMetrics getFontMetrics(JLabel l)
+ {
+ Font font = l.getFont();
+ FontMetrics fm = l.getFontMetrics(font);
+ if (fm == null)
+ {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ fm = tk.getFontMetrics(font);
+ }
+ return fm;
+ }
}