动态更改文本框JTextArea的大小

时间:2015-01-25 13:20:16

标签: java swing user-interface text resize

我是Java的新手,我一直在尝试构建一个简单的即时消息程序。我希望文本框(在发送消息之前键入消息的地方)动态改变大小(带有最大高度约束),因为一个人输入一条大消息,有点像WhatsApp或iMessage上发生的事情。

我已经尝试计算文本框中的文本行数(考虑文本换行的效果),然后根据文本框的高度增加/减少文本框的高度存在的文本包裹行数。我使用getScrollableUnitIncrement()方法确定了1行文本的高度。

此外,正如我所知,有没有比我上面概述的更好的方法来动态更改文本框的大小?

我使用了嵌入在JScrollPane中的JTextArea,并且我在JTextArea上使用componentListener来根据需要调整文本框的大小。

请查看组件监听器方法中的while循环,因为我不认为这部分程序正常运行...

以下是代码片段:

public class clienterrors extends JFrame {
    private JTextArea userText;
    private JTextPane chatWindow;
    private String userName="testName";
    private Document doc;

    // Automatic resizing of the text box
    private static Dimension textBoxSize = new Dimension(20, 20);
    public static int numRows = 1;
    private static final int rowHeight = 20;
    private final int maxHeight = 80;


    public static void main(String[] args) {
        clienterrors george = new clienterrors();
        george.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    public clienterrors(){
        super("Client instant messaging platform");

        // Chat window initialisation
        chatWindow = new JTextPane();
        chatWindow.setEditable(false);
        doc = chatWindow.getDocument();
        add(new JScrollPane(chatWindow), BorderLayout.CENTER);


        // Text box initialisation
        userText = new JTextArea();
        userText.setLineWrap(true);
        userText.setWrapStyleWord(true);

        JScrollPane jsp = new JScrollPane(userText);
        jsp.setPreferredSize(textBoxSize);
        jsp.setMaximumSize(new Dimension(20, 40));


        // Gets the text box to resize as appropriate
        userText.addComponentListener(
                new ComponentAdapter() {
                    @Override
                    public void componentResized(ComponentEvent e) {

                        // Needs to cater for when removing & pasting large messages into the text box
                        while (countLines(userText) > numRows && textBoxSize.getHeight() < maxHeight) {
                            textBoxSize.setSize(20, (int) textBoxSize.getHeight() + rowHeight);
                            revalidate();
                            numRows++;  // numRows is used as an update to see which
                        }

                        while (countLines(userText) < numRows && textBoxSize.getHeight() > 20){
                            textBoxSize.setSize(20, (int)textBoxSize.getHeight() - rowHeight);
                            revalidate();
                            numRows--;
                        }
                    }
                }
        );

        // Allows u to send text from text box to chat window
        userText.addKeyListener(
                new KeyAdapter() {
                    @Override
                    public void keyTyped(KeyEvent e) {
                        if(e.getKeyChar() == '\n' && enterChecker(userText.getText())){
                            // returns the text (-1 on the substring to remove the \n escape character when pressing enter)
                            showMessage("\n" + userName + ": " + userText.getText().substring(0, userText.getText().length() - 1));
                            userText.setText("");
                        }
                    }
                }
        );
        add(jsp, BorderLayout.SOUTH);


        //JFrame properties
        setSize(300, 400);
        setVisible(true);
    }

    // shows message on the chat window
    private void showMessage(final String text){
        SwingUtilities.invokeLater(
                new Runnable() {
                    @Override
                    public void run() {
                        try{
                            doc.insertString(doc.getLength(), text, null);
                        }catch(BadLocationException badLocationException){
                            badLocationException.printStackTrace();
                        }
                        // place caret at the end (with no selection), so the newest message can be automatically seen by the user
                        chatWindow.setCaretPosition(chatWindow.getDocument().getLength());
                    }
                }
        );
    }

    // Prevents the user from sending empty messages that only contain whitespace or \n
    private static boolean enterChecker(String t){
        for(int i=0; i<t.length(); i++)
            if (t.charAt(i) != '\n' && t.charAt(i) != ' ')
                return true;
        return false;
    }

    // This counts the number of wrapped lines in the text box to compare to numRows - only used to resize the text box
    // (got this off the internet)
    private static int countLines(JTextArea textArea) {
        if(!enterChecker(textArea.getText())) return 0; // this prevents getting an error when you're sending an empty message
        AttributedString text = new AttributedString(textArea.getText());
        FontRenderContext frc = textArea.getFontMetrics(textArea.getFont())
                .getFontRenderContext();
        AttributedCharacterIterator charIt = text.getIterator();
        LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(charIt, frc);
        float formatWidth = (float) textArea.getSize().width;
        lineMeasurer.setPosition(charIt.getBeginIndex());

        int noLines = 0;
        while (lineMeasurer.getPosition() < charIt.getEndIndex()) {
            lineMeasurer.nextLayout(formatWidth);
            noLines++;
        }

        return noLines;
    }

}

1 个答案:

答案 0 :(得分:1)

JTextArea会自动更新其首选大小,以便显示所有文本。如果您不将其包装在ScrollPane中,BorderLayout将自动显示您想要的内容,而无需任何其他逻辑:

public class ClientErrors extends JFrame {
    private JTextArea userText;
    private JTextPane chatWindow;
    private String userName = "testName";

    // Automatic resizing of the text box
    public static int numRows = 1;
    private static final int rowHeight = 20;
    private final int maxHeight = 80;
    private Document doc;

    public static void main(String[] args) {
        ClientErrors george = new ClientErrors();
        george.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public ClientErrors() {
        super("Client instant messaging platform");

        // Chat window initialisation
        chatWindow = new JTextPane();
        chatWindow.setEditable(false);
        doc = chatWindow.getDocument();
        add(new JScrollPane(chatWindow), BorderLayout.CENTER);

        // Text box initialisation
        userText = new JTextArea();
        userText.setLineWrap(true);
        userText.setWrapStyleWord(true);

        // Allows u to send text from text box to chat window
        userText.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                if (e.getKeyChar() == '\n' && enterChecker(userText.getText())) {
                    // returns the text (-1 on the substring to remove the \n
                    // escape character when pressing enter)
                    showMessage("\n"
                            + userName
                            + ": "
                            + userText.getText().substring(0,
                                    userText.getText().length() - 1));
                    userText.setText("");
                }
            }
        });
        add(userText, BorderLayout.SOUTH);

        // JFrame properties
        setSize(300, 400);
        setVisible(true);
    }

    // shows message on the chat window
    private void showMessage(final String text) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    doc.insertString(doc.getLength(), text, null);
                } catch (BadLocationException badLocationException) {
                    badLocationException.printStackTrace();
                }
                // place caret at the end (with no selection), so the newest
                // message can be automatically seen by the user
                chatWindow.setCaretPosition(chatWindow.getDocument()
                        .getLength());
            }
        });
    }

    // Prevents the user from sending empty messages that only contain
    // whitespace or \n
    private static boolean enterChecker(String t) {
        for (int i = 0; i < t.length(); i++)
            if (t.charAt(i) != '\n' && t.charAt(i) != ' ')
                return true;
        return false;
    }
}

编辑:如果您还想要输入JTextArea的最大高度(在达到最大高度后滚动),我建议将其包装在滚动窗格中,并在文本区域更改时更新其首选大小