Search code examples
javaswingjtextfield

JTextField "Bubble" Text


I was wondering if it was possible to make something similar to the tag entering system on StackOverflow in Swing (probably using a JTextField).

enter image description here


Solution

  • You can redefine your own class that extends the JTextField class and make the style you want.

    This link might help and there's another example here.

    EDIT:

    I created a small example of what you want. This is just a draft and can be improved but you have a start point now.

    public class MainPanel extends JPanel{
    
        public MainPanel() {
            super(new BorderLayout());
            final JPanel p = new JPanel(new GridLayout(5,1,5,5));
            final JTextPane tp = new JTextPane();
            final StyledDocument doc = tp.getStyledDocument();
            final SimpleAttributeSet attr =  new SimpleAttributeSet();
            JTextField textField01 = new JTextField(20) {
                //Unleash Your Creativity with Swing and the Java 2D API!
                //http://java.sun.com/products/jfc/tsc/articles/swing2d/index.html
                @Override protected void paintComponent(Graphics g) {
                    if(!isOpaque()) {
                        int w = getWidth();
                        int h = getHeight();
                        Graphics2D g2 = (Graphics2D)g.create();
                        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                        g2.setColor(UIManager.getColor("TextField.background"));
                        g2.fillRoundRect(0, 0, w-1, h-1, h, h);
                        g2.setColor(Color.GRAY);
                        g2.drawRoundRect(0, 0, w-1, h-1, h, h);
                        g2.dispose();
                    }
                    super.paintComponent(g);
                }
            };
            textField01.setOpaque(false);
            textField01.setBackground(new Color(0,0,0,0));
            textField01.setBorder(BorderFactory.createEmptyBorder(4, 8, 4, 8));
            textField01.setText("Test");
            textField01.addKeyListener(new KeyAdapter() {
                public void keyReleased(KeyEvent e) {
                }
    
                public void keyTyped(KeyEvent e) {
                    // TODO: Do something for the keyTyped event
                }
    
                public void keyPressed(KeyEvent e) {
                    // TODO: Do something for the keyPressed event
                    if(e.getKeyCode() == KeyEvent.VK_ENTER){
                        JTextField textField = (JTextField) e.getSource();
                        String text = textField.getText();
                        textField.setText("");
                        JLabel label = new JLabel(text);
                        label.setOpaque(true);
                        label.setBackground(Color.lightGray);
                        label.setBorder(BorderFactory.createLineBorder(Color.black,1));
                        tp.setCaretPosition(tp.getDocument().getLength());
                        tp.insertComponent(label);
                        try {
                            doc.insertString(doc.getLength(), " ", attr);  
                        }
                        catch (BadLocationException ex){
                            ex.printStackTrace();
                        }
                    }
                }
            });
            p.add(textField01);
            p.add(tp);
            add(p);
            setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
            setPreferredSize(new Dimension(320, 200));
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                @Override public void run() {
                    createAndShowGUI();
                }
            });
        }
    
        public static void createAndShowGUI() {
            try{
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            }catch(Exception e) {
                e.printStackTrace();
            }
            JFrame frame = new JFrame("Tags editor");
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            frame.getContentPane().add(new MainPanel());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
    
    class RoundedCornerBorder extends AbstractBorder {
        @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
            Graphics2D g2 = (Graphics2D)g.create();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            int r = height-1;
            RoundRectangle2D round = new RoundRectangle2D.Float(x, y, width-1, height-1, r, r);
            Container parent = c.getParent();
            if(parent!=null) {
                g2.setColor(parent.getBackground());
                Area corner = new Area(new Rectangle2D.Float(x, y, width, height));
                corner.subtract(new Area(round));
                g2.fill(corner);
            }
            g2.setColor(Color.GRAY);
            g2.draw(round);
            g2.dispose();
        }
        @Override public Insets getBorderInsets(Component c) {
            return new Insets(4, 8, 4, 8);
        }
        @Override public Insets getBorderInsets(Component c, Insets insets) {
            insets.left = insets.right = 8;
            insets.top = insets.bottom = 4;
            return insets;
        }
    }