0

This is an extension of : Make a TitledBorder title editable

To be more specific, I want the TitledBorder to be editable when the title is double clicked. I'm placing the Border around a java Box that uses BoxLayout. The double click would preferably open a JTextField right there, but if that cannot be done, opening another window to edit the title is acceptable.

TitledBorder editableBorder = new TitledBorder(editableString);
editableBorder.setTitleJustification(TitledBorder.CENTER);

Box containerBox = new Box(BoxLayout.PAGE_AXIS);
containerBox.setBorder(new CompoundBorder(editableBorder, new EmptyBorder(10, 0, 10, 0)));

Box insideBox = new Box(BoxLayout.PAGE_AXIS);
insideBox.add(new JLabel(new ImageIcon(new BufferedImage(200,40,BufferedImage.TYPE_INT_RGB))));
containerBox.add(insideBox);
DarkHark
  • 614
  • 1
  • 6
  • 20
  • Unable to investigate further ATM, but maybe a `MouseListener` on the panel, screening for mouse clicks only in the top part, combined with an option pane with text field to change the text. *"The double click would preferably open a JTextField right there"* Could possibly be done, but it would take some jiggery-pokery (the best term I can come up with just before bed). – Andrew Thompson Jul 19 '18 at 15:21
  • @Andrew Thompson I like that idea and as soon as I make some other fixes in my code, I'll look into that. Thank you. – DarkHark Jul 19 '18 at 16:09

1 Answers1

2

Here is an example. The MouseListener uses a JPopupMenu to display the text field. This means you can cancel editing by using the Escape key.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class TitledBorderListener extends MouseAdapter
{
    private JPopupMenu editPopup;
    private JTextField editTextField;
    private TitledBorder titledBorder;

    @Override
    public void mouseClicked(MouseEvent e)
    {
        if (e.getClickCount != 2)
            return;

        //  Edit the border on a double click

        JComponent component = (JComponent)e.getSource();
        Border border = component.getBorder();

        if (border instanceof TitledBorder)
        {
            titledBorder = (TitledBorder)border;
            FontMetrics fm = component.getFontMetrics( titledBorder.getTitleFont() );
            int titleWidth = fm.stringWidth(titledBorder.getTitle()) + 20;
            Rectangle bounds = new Rectangle(0, 0, titleWidth, fm.getHeight());

            if (bounds.contains(e.getPoint()))
            {
                if (editPopup == null)
                    createEditPopup();

                //  Position the popup editor over top of the title

                editTextField.setText( titledBorder.getTitle() );
                Dimension d = editTextField.getPreferredSize();
                d.width = titleWidth;
                editPopup.setPreferredSize(d);
                editPopup.show(component, 0, 0);

                editTextField.selectAll();
                editTextField.requestFocusInWindow();
            }
        }
    }

    private void createEditPopup()
    {
        editTextField = new JTextField();

        //  Add an Action to the text field to save the new title text

        editTextField.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                String value = editTextField.getText();
                titledBorder.setTitle( value );
                editPopup.setVisible(false);
                editPopup.getInvoker().revalidate();
                editPopup.getInvoker().repaint();
            }
        });

        //  Add the editor to the popup

        editPopup = new JPopupMenu();
        editPopup.setBorder( new EmptyBorder(0, 0, 0, 0) );
        editPopup.add(editTextField);
    }

    private static void createAndShowUI()
    {

        JPanel panel = new JPanel();
        panel.setBorder( new TitledBorder("Double Click to Edit") );
        panel.addMouseListener( new TitledBorderListener() );

        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( panel );
        frame.setSize(200, 200);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}
camickr
  • 321,443
  • 19
  • 166
  • 288
  • Exactly what I was looking for. I see you commented where the Popup is set to be above the previous title, but how does that work? I'm going to have many Boxes with TitledBorders on top of each other and want to make sure this works for each of them. The box sizes can vary too. I just don't see how it knows where to be. Is it the Rectangle bounds? – DarkHark Jul 19 '18 at 17:57
  • @DarkHark, `and want to make sure this works for each of them.` - well try it. Its a single line of code for each panel. If it doesn't work, then you can do some debugging. We are not here to write 100% perfect code for you, just point you in the right direction. – camickr Jul 19 '18 at 18:43
  • A `JPopupMenu`! Of course. I completely forgot about them. – Andrew Thompson Jul 19 '18 at 22:06