我是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;
}
}
答案 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的最大高度(在达到最大高度后滚动),我建议将其包装在滚动窗格中,并在文本区域更改时更新其首选大小