【问题标题】:Disabling JTextArea resizing when user press Enter当用户按 Enter 时禁用 JTextArea 调整大小
【发布时间】:2015-07-01 09:58:14
【问题描述】:

我有一个JTextArea,我希望用户输入一个人的地址。我知道用户输入的有效地址不会超过5 rows10 columns。所以我把它设置为JTextArea (5,10)。这样就可以正常工作了。

问题是当用户持续按enter 5 次以上时,文本区域将开始调整大小。我不想将文本区域放在 JScrollPane 中,因为用户输入的文本不适合滚动。

问题:当用户按下enter 时,我们如何禁止JTextArea 调整大小?

这是我的代码:

public class JTextAreaDemo {

private JFrame frame;

JTextAreaDemo(){
    frame= new JFrame();
    frame.setSize(300, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new net.miginfocom.swing.MigLayout());
    frame.setVisible(true);
    frame.setLocationRelativeTo(null);

    JLabel label=new JLabel("Address :");
    JTextArea address= new JTextArea(5,20);
    frame.add(label,"cell 0 0");
    frame.add(address, "cell 1 0");
}

public static void main(String [] args){
    SwingUtilities.invokeLater(new Runnable(){

        @Override
        public void run() {
            new JTextAreaDemo();

        }});
    }
 }

【问题讨论】:

  • 把它放在JScrollPane,它正在调整大小,因为它的首选大小正在改变
  • 你的意思是说当用户第5次按下回车键时,要么被空格替换,要么被忽略?
  • @MadProgrammer 好吧,这行得通。一件事,当用户按下回车键时,如何避免光标移动到第六行/行?
  • @Blip 是的,当用户第六次按下 Enter 时,它不应该做任何事情。它不应移动到第六行/行。
  • 使用DocumentFilter

标签: java swing layout-manager jtextarea miglayout


【解决方案1】:

您可以尝试使用DocumentFilter,例如:

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

public class TestFrame extends JFrame {

    public static void main(String... s) {
        new TestFrame();
    }

    private JTextArea area;

    public TestFrame() {
        init();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }


    private void init() {
        area = new JTextArea();
        ((AbstractDocument)area.getDocument()).setDocumentFilter(getFilter(5));
        add(new JScrollPane(area));
    }

    private DocumentFilter getFilter(final int lineCount) {
        return new DocumentFilter(){

            @Override
            public void replace(FilterBypass fb, int offset, int length,
                    String text, AttributeSet attrs)
                    throws BadLocationException {
                if(area.getLineCount()<=lineCount && area.getLineOfOffset(area.getCaretPosition())<lineCount)
                        if(text.contains("\n") && area.getLineCount()<lineCount)
                            super.replace(fb, offset, length, text, attrs);
                        else if(!text.contains("\n"))
                            super.replace(fb, offset, length, text, attrs);
            }
        };
    }

}

【讨论】:

  • 嗯,这实际上是我正在寻找的考虑限制行数/行数。非常感谢。
  • 作为一般经验法则,过滤器不应该知道文本组件,这有点违背了目的。
  • @MadProgrammer 是的,但这只是示例。在这种情况下,我们需要计算来自Document 的行号的方法。关于换行也很好。
【解决方案2】:

如前所述,可以使用DocumentFilter。由于它提供了优雅的解决方案,我发布了这个答案。

public class JTextAreaDemo {

    private JFrame frame = new JFrame();
    JTextArea address = new JTextArea(5, 20);

    JTextAreaDemo() {

        JLabel label = new JLabel("Address :");
        frame.getContentPane().add(label, BorderLayout.CENTER);
        frame.getContentPane().add(address, BorderLayout.SOUTH);

        ((PlainDocument) address.getDocument()).setDocumentFilter(new LineFilter());

        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    class LineFilter extends DocumentFilter {

        @Override
        public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {

            if (address.getLineCount() < 5 || !string.contains("\n"))
                super.insertString(fb, offset, string, attr);
        }

        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {

            if (address.getLineCount() < 5 || !text.contains("\n"))
                super.replace(fb, offset, length, text, attrs);
        }
    }

    public static void main(String[] args) {

        new JTextAreaDemo();
    }
}

虽然对于覆盖方法insertString 的用户输入将不相关,但覆盖所有基础通常是个好主意。否则,它可以被删除。

请注意,不需要JScrollBar

编辑:

为了让@MadProgrammer 在晚上安静地入睡,行数是直接从文档中完成的(以一种不太优雅的方式):

@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {

    String content = fb.getDocument().getText(0, fb.getDocument().getLength());
    Matcher matcher = Pattern.compile("\n").matcher(content);
    int lines = 0;
    while (matcher.find()) {
        lines++;
    }
    if (lines < 4 || !text.contains("\n"))
        super.replace(fb, offset, length, text, attrs);
}

insertString 方法可以使用相同的代码。

【讨论】:

  • 一般经验法则,过滤器不应该知道正在使用它的 UI/文本组件。假设文本区域没有启用换行,那么它变得相对容易......如果没有......
  • @MadProgrammer 我完全同意经验法则,尽管当内容(文档方面)影响视觉效果(UI 组件方面)时,我认为这样做是有好处的。我添加了一个经验法则友好的解决方案。
  • 如果换行,它对您没有帮助。检查that
  • @alex2410 OP 证明他们没有使用换行。否则我会考虑的。
【解决方案3】:

使用setPreferredSize(new Dimension(X,Y)) 这样JTextArea 将保持您设置的尺寸,并且根本不会移动! 您仍然需要将您的 JTextArea 放入 JScrollPane 思想中。

【讨论】:

  • 好吧,使用JScrollPane 设置首选大小是可行的。单独设置首选尺寸无法实现,无论如何感谢您的提示。
  • @Giovanrich 不客气,我编辑了我对您的回答的回答,完成后不要忘记关闭您的问题。
  • JTextArea 和 MigLayout 讨厌 setPreferredSize,这是关于 JScrollPane 内 JTextArea 的行/自动换行,否则 .... :-)
  • 好吧,我不会忘记的。我如何避免它移动到第六列?见@Blip第二条评论
  • 我会避免使用这样的东西,因为你无法控制与字体和字体渲染相关的许多特质
【解决方案4】:

我建议您应该使用 InputVerifier 来跟踪已在您的 JTextArea 中输入的输入数,当它达到 4 时,它应该忽略输入。

正如您在 cmets 中指出的那样,DocumentListener 会做同样的事情,KeyListener 也会做同样的事情。

【讨论】:

  • InputVerifer 不是只会在焦点丢失时收到通知吗?当字段设置为换行时,这不会阻止用户用文本溢出字段,例如
  • @MadProgrammer DocumentListener 怎么样? - 不保存跟踪的目的吗?
  • @MadProgrammer 我真的忽略了 是的,这是真的,我正在纠正我的答案以适应这一点。
  • DocumentFilter 可能是首选,然后您只需拒绝不想要的输入而不会导致突变错误
猜你喜欢
  • 1970-01-01
  • 2017-11-18
  • 1970-01-01
  • 2019-07-28
  • 1970-01-01
  • 1970-01-01
  • 2013-08-25
  • 2016-01-14
  • 2013-12-16
相关资源
最近更新 更多