By the way, I only included on constructor but it's trivial to add all
the other matching ones from JTextField.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;
/**
* A custom JTextField with rounded corners.
*/
public class RoundTextField extends JTextField {
public RoundTextField(String text, int columns) {
super(text, columns);
setOpaque(false);
setBorder(new RoundBorder());
}
public void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1,
20, 20);
super.paintComponent(g);
}
public static void main(String[] args) {
JFrame frame = new JFrame("RoundTextField");
frame.setSize(400, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(new RoundTextField("One", 20));
contentPane.add(new RoundTextField("Two", 20));
contentPane.add(new RoundTextField("Three", 20));
frame.setVisible(true);
}
}
class RoundBorder extends AbstractBorder
{
public void paintBorder(Component c, Graphics g,
int x, int y,
int width, int height) {
Color oldColor = g.getColor();
g.setColor(Color.black);
g.drawRoundRect(x, y, width - 1, height - 1,
20, 20);
g.setColor(oldColor);
}
public Insets getBorderInsets(Component c) {
return new Insets(4, 4, 4, 4);
}
public Insets getBorderInsets(Component c, Insets insets) {
insets.left = insets.top = insets.right = insets.bottom = 4;
return insets;
}
}
Thanks!
Shannon
--
Shannon Hickey
shan...@swingteam.com
Swing Team http://TheSwingConnection.com http://TheJavaTutorial.com
Java Software, a division of Sun Microsystems, Inc.
<snip code sample>
Here's another way to do it by writing your own custom UI class. This
can be set on each JTextField with field.setUI(new RoundTextUI()) or
on all newly created JTextFields by using UIManger.put("TextFieldUI",
"RoundTextUI"). Note that the second option will cause it to be used
wherever JTextFields are used (ie. editable JComboBoxes, editable
JTables, etc...) and may not look appropriate. I suggest using the
second option only when you've written custom UI's for the other
components as well that look better with a round JTextField.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalTextFieldUI;
/**
* A custom TextField UI based on Metal that paints
* text fields with a round border.
*/
public class RoundTextUI extends MetalTextFieldUI {
public static ComponentUI createUI(JComponent c) {
return new RoundTextUI();
}
public void installUI(JComponent c) {
super.installUI(c);
c.setBorder(new RoundBorder());
c.setOpaque(false);
}
protected void paintSafely(Graphics g) {
JComponent c = getComponent();
if (!c.isOpaque()) {
g.setColor(c.getBackground());
g.fillRoundRect(0, 0,
c.getWidth() - 1, c.getHeight() - 1,
20, 20);
}
super.paintSafely(g);
}
private static class RoundBorder extends AbstractBorder {
public void paintBorder(Component c, Graphics g,
int x, int y,
int width, int height) {
Color oldColor = g.getColor();
g.setColor(Color.black);
g.drawRoundRect(x, y, width - 1, height - 1, 20, 20);
g.setColor(oldColor);
}
public Insets getBorderInsets(Component c) {
return new Insets(4, 4, 4, 4);
}
public Insets getBorderInsets(Component c, Insets insets) {
insets.left = insets.top =
insets.right = insets.bottom = 4;
return insets;
}
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* A test that shows the usage of a custom TextField UI.
*/
public class Text extends JFrame {
public Text() {
super("Text");
setSize(400, 300);
setLocation(300, 200);
getContentPane().setLayout(new FlowLayout());
JTextField fone = new JTextField("One", 20);
JTextField ftwo = new JTextField("Two", 20);
JTextField fthree = new JTextField("Three", 20);
getContentPane().add(fone);
getContentPane().add(ftwo);
getContentPane().add(fthree);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
// This line makes all text fields use the custom UI.
// Alternatively, the UI could be applied on a case
// by case basis with field.setUI(new RoundTextUI())
UIManager.put("TextFieldUI", "RoundTextUI");
Text t = new Text();
t.setVisible(true);
Shannon Hickey - Swing Team wrote:
> I received a message the other day asking if I knew how to create a
> custom JTextField with rounded corners. After coding one up, I thought
> maybe others might be interested. Here's what I came up with. A main
> has been included so you can see an example of it in use.
> By the way, I only included on constructor but it's trivial to add all
> the other matching ones from JTextField.
Thank you, Shannon, for your examples. May I add that the corners
of the JTextFields, since they are rounded look even nicer using
RenderingHints with AntiAlias turned on in the paintComponent-method
> public void paintComponent(Graphics g) {
> g.setColor(getBackground());
> g.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1,
> 20, 20);
> super.paintComponent(g);
> }
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
As a suggestion in addition.
Linda
--
li...@jalice.ch -> http://www.jalice.net
l.ra...@hswzfh.ch -> http://www.hswzfh.ch
It may be a bad idea to place the anti-aliasing code in the
paintComponent() method, as it will cause the font to also be drawn in
that manner. For some reason, SWING doesn't respond well to that
because it calculates the widths incorrectly. (You'll see this when you
go to place your cursor at an insertion point and the new text appears
before the appropriate character(s). Also, try selecting a full line of
text and you'll notice the highlight represents the incorrectly
calculated width, not the true visible width of the text.
To still use the antialiased border, but not the text, rewrite the
paintBorder() method of the non-public RoundBorder class to look like
this:
public void paintBorder(Component c, Graphics g,
int x, int y,
int width, int height)
{
Color oldColor = g.getColor();
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.black);
g.drawRoundRect(x, y, width - 1, height - 1, 20, 20);
g.setColor(oldColor);
} // ends paintBorder(Component, Graphics, int, int, int, int)
--
Greg Faron
Integre Technical Publishing Co.
Greg Faron wrote:
> It may be a bad idea to place the anti-aliasing code in the
> paintComponent() method, as it will cause the font to also be drawn in
> that manner. For some reason, SWING doesn't respond well to that
> because it calculates the widths incorrectly. (You'll see this when you
> go to place your cursor at an insertion point and the new text appears
> before the appropriate character(s). Also, try selecting a full line of
> text and you'll notice the highlight represents the incorrectly
> calculated width, not the true visible width of the text.
> To still use the antialiased border, but not the text, rewrite the
> paintBorder() method of the non-public RoundBorder class to look like
> this:
I remember, we have once discussed wrong font sizing and we could solve
a problem related to that turning on the FractionalMetrics, too, with
it's RenderingHints, but actually I just have meant the border here - yes.
Linda
--
Oh just one more and I'll walk away all the / everything you win
turns to nothing today, so just one more just one more go inspire
in me the desire in me to never go home
The Cure, Disintegration, Homesick
I'll try that on an issue I'm having with another project. Thanks!