I'm assuming that the user will be typing in the single character of each text field. There are a couple of possibilities:
1) Create an IconBorder. This would simply paint your supplied Icon on top of the text field. Simple proof of concept:
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.*;
public class IconBorder implements Border
{
private Icon icon;
private Insets borderInsets = new Insets(0, 0, 0, 0);
public IconBorder(Icon icon)
{
this.icon = icon;
}
//
// Implement the Border interface
//
@Override
public Insets getBorderInsets(Component c)
{
return borderInsets;
}
@Override
public boolean isBorderOpaque()
{
return false;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
{
icon.paintIcon(c, g, x+1, y+1);
}
private static void createAndShowUI()
{
JPanel panel = new JPanel();
panel.add( createTextField( new Ellipse2D.Double(0, 0, 30, 30) ) );
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( panel );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
private static JTextField createTextField(Shape shape)
{
JTextField textField = new JTextField(1);
textField.setFont( new Font("Serif", Font.PLAIN, 18) );
OutlineIcon icon = new OutlineIcon(shape, Color.RED, 2);
CompoundBorder inner = new CompoundBorder( textField.getBorder(), new EmptyBorder(5, 10, 5, 10) );
CompoundBorder border = new CompoundBorder(new IconBorder(icon), inner);
textField.setBorder( border );
return textField;
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
The above code uses the OutlineIcon
class found in Playing With Shapes to provide the Icon for the Border. Or you can use any "transparent" Icon that you have lying around.
But as you can see there is a lot of playing around with insets to try to get the text aligned properly. If you want to go with the Border approach, it may be better to create a "CircleBorder" and a "SquareBorder", then you can just paint the shape directly in the paintBorder(...) method and do the painting based on the size of the parent component.
2) Another approach would be to use a JLabel with an Icon. You can set the properties of the JLabel such that the text is both horizontally and vertically centered so that it paints on top of the label. In order to support keyboard input, you would then need to make each label focusable and add a KeyListener to listen for the key pressed and then set the text of the label. (I like this approach as the sizing of the components will be done easily based on the size of the Icon that you use).
3) Or finally you could use a JLabel with an Icon like above. But then you could set the layout manager to a BorderLayout and then add your JTextField to the label. You would need to make the JTextField non-opaque.