JTextField in which the predefined text in not editable but other text can be appended to it?

后端 未结 5 906
一个人的身影
一个人的身影 2020-12-11 17:58

While going through Java swing I faced this problem. I have a JTextField which has predefined and not editable text. the user should be able to append other text to it but w

相关标签:
5条回答
  • 2020-12-11 18:45

    I have a JTextField which has predefined and not editable text. the user should be able to append other text to it but without editing the predefined text. Is there any method to obtain this solution or any other?

    use

    1. JComboBox (non_editable)

    2. JSpinner with SpinnerListModel

    originally made by @camickr

    enter image description here

    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.text.*;
    
    public class NavigationFilterPrefixWithBackspace extends NavigationFilter {
    
        private int prefixLength;
        private Action deletePrevious;
    
        public NavigationFilterPrefixWithBackspace(int prefixLength, JTextComponent component) {
            this.prefixLength = prefixLength;
            deletePrevious = component.getActionMap().get("delete-previous");
            component.getActionMap().put("delete-previous", new BackspaceAction());
            component.setCaretPosition(prefixLength);
        }
    
        @Override
        public void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) {
            fb.setDot(Math.max(dot, prefixLength), bias);
        }
    
        @Override
        public void moveDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) {
            fb.moveDot(Math.max(dot, prefixLength), bias);
        }
    
        class BackspaceAction extends AbstractAction {
    
            private static final long serialVersionUID = 1L;
    
            @Override
            public void actionPerformed(ActionEvent e) {
                JTextComponent component = (JTextComponent) e.getSource();
                if (component.getCaretPosition() > prefixLength) {
                    deletePrevious.actionPerformed(null);
                }
            }
        }
    
        public static void main(String args[]) throws Exception {
            JTextField textField = new JTextField(" $ ", 20);
            textField.setNavigationFilter(new NavigationFilterPrefixWithBackspace(textField.getDocument().getLength(), textField));
            JFrame frame = new JFrame("Navigation Filter Example");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(textField);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
    
    • I'd suggest to use OverlayLayout (JLabel over JTextField), by changing Insets (input area) in JTextField for JLabels area, otherwise any formatting in JTextField make code and suggestion in this thread quite useless and with strange output to the Swing GUI

    • e.g. JTextField.setHorizontalAlignment(JTextField.RIGHT);


    EDIT

    • put JLabel & JTextField to JPanel, quite simple and without side effects

    • change built in FlowLayout for JPanel

    • required to call revalidate() and repaint() in the case that text in JLabel is changed

    enter image description here

    import java.awt.BorderLayout;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    
    public class NavigationFilterBias {
    
        private JFrame frame = new JFrame("Navigation Filter Example");
        private JPanel panel = new JPanel();
        private JLabel label = new JLabel(" $ ");
        private JTextField textField = new JTextField();
    
        public NavigationFilterBias() {
            panel.setBorder(textField.getBorder());
            panel.setBackground(textField.getBackground());
            panel.setLayout(new BorderLayout());
            panel.add(label,BorderLayout.WEST);
            textField.setBorder(null);
            panel.add(textField,BorderLayout.CENTER);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(panel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String args[]) throws Exception {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    NavigationFilterBias exam = new NavigationFilterBias();
                }
            });
        }
    }
    
    0 讨论(0)
  • 2020-12-11 18:51

    You can simply use a DocumentFilter:

    import java.awt.FlowLayout;
    
    import javax.swing.JFrame;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    import javax.swing.text.AbstractDocument;
    import javax.swing.text.AttributeSet;
    import javax.swing.text.BadLocationException;
    import javax.swing.text.DocumentFilter;
    
    public class TestDocumentFilter {
    
        private static final String TEXT_NOT_TO_TOUCH = "You can't touch this!";
    
        private void initUI() {
            JFrame frame = new JFrame(TestDocumentFilter.class.getSimpleName());
            frame.setLayout(new FlowLayout());
            final JTextField textfield = new JTextField(50);
            textfield.setText(TEXT_NOT_TO_TOUCH);
            ((AbstractDocument) textfield.getDocument()).setDocumentFilter(new DocumentFilter() {
                @Override
                public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
                    if (offset < TEXT_NOT_TO_TOUCH.length()) {
                        return;
                    }
                    super.insertString(fb, offset, string, attr);
                }
    
                @Override
                public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
                    if (offset < TEXT_NOT_TO_TOUCH.length()) {
                        length = Math.max(0, length - TEXT_NOT_TO_TOUCH.length());
                        offset = TEXT_NOT_TO_TOUCH.length();
                    }
                    super.replace(fb, offset, length, text, attrs);
                }
    
                @Override
                public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
                    if (offset < TEXT_NOT_TO_TOUCH.length()) {
                        length = Math.max(0, length + offset - TEXT_NOT_TO_TOUCH.length());
                        offset = TEXT_NOT_TO_TOUCH.length();
                    }
                    if (length > 0) {
                        super.remove(fb, offset, length);
                    }
                }
            });
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(textfield);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    new TestDocumentFilter().initUI();
                }
            });
        }
    
    }
    
    0 讨论(0)
  • 2020-12-11 18:59

    Take a look at DocumentFilter. It should allow you to define a "protected" area of text.

    Examples here and here

    0 讨论(0)
  • 2020-12-11 19:00

    Alternative solution:
    1. Put the $ symbole in the JTextField
    2. Remove the dollar symbole when the JTextField get the focus
    3. Let the user modify the full text
    4. When he's done typing (see here) add the $ symbole back

    But it would be way easier to add a label next to the JTextField

    0 讨论(0)
  • 2020-12-11 19:02

    Though I believe DocumentFilter is the logical and versatile solution, a short solution here. It simply makes an JTextField with an inner left margin in which the fixed text is written.

    public class PrefixTextField extends JTextField {
        private String prefix;
        private JLabel label;
    
        public PrefixTextField(String prefix) {
            this.prefix = prefix;
            label = new JLabel(prefix + '\u00a0');
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            int w = SwingUtilities.computeStringWidth(
                    getFontMetrics(getFont()), prefix);
            setMargin(new Insets(3, 3 + w, 3, 3));
            super.paintComponent(g);
            SwingUtilities.paintComponent(g, label, this.getParent(),
                    2 + 3, 0, getWidth(), getHeight());
        }
    }
    
    0 讨论(0)
提交回复
热议问题