我在尝试将动画添加到聊天程序时遇到了一些麻烦。它工作正常,直到JScrollPane需要开始滚动,此时ScrollPane不会更新,直到“runnable”通过它的下一个循环(动画工作,并且不,Thread.sleep不是这里的问题)。有人有什么建议吗?我尝试过调用revalidate之类的东西,但没有区别。行~188注释“//需要jsp(JScrollPane)立即更新”是我需要JScrollPane更新它的视图的地方。谢谢! 包com.AI;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.sql.Date;
import java.util.Calendar;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.LineBorder;
import javax.swing.text.DefaultCaret;
public class MainGUI {
public String appName = "Chat Assistant v1.3.3";
public MainGUI mainGUI;
public JPanel mainPanel;
public JScrollPane jsp;
public JFrame newFrame = new JFrame(appName);
public JButton sendMessage;
public JTextField messageBox = new JTextField(30);
public JTextArea chatBox;
String username = "Evan";
public Random rand = new Random();
public Calendar cal= Calendar.getInstance();
//public MainEngine me = new MainEngine();
public String temp = "";
public String tempL = "";
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
MainGUI mainGUI = new MainGUI();
mainGUI.display();
}
});
}
public void display() {
mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
JPanel southPanel = new JPanel();
southPanel.setBackground(Color.BLUE);
southPanel.setLayout(new GridBagLayout());
messageBox.requestFocusInWindow();
sendMessage = new JButton("Send Message");
sendMessage.addActionListener(new sendMessageButtonListener());
chatBox = new JTextArea();
chatBox.setEditable(false);
chatBox.setFont(new Font("Arial", Font.PLAIN, 18));
chatBox.setLineWrap(true);
jsp = new JScrollPane(chatBox);
jsp.setBorder(new LineBorder(Color.white, 7));
mainPanel.add(jsp, BorderLayout.CENTER);
GridBagConstraints left = new GridBagConstraints();
left.anchor = GridBagConstraints.LINE_START;
left.fill = GridBagConstraints.HORIZONTAL;
left.weightx = 512.0D;
left.weighty = 1.0D;
GridBagConstraints right = new GridBagConstraints();
right.insets = new Insets(0, 10, 0, 0);
right.anchor = GridBagConstraints.LINE_END;
right.fill = GridBagConstraints.NONE;
right.weightx = 1.0D;
right.weighty = 1.0D;
southPanel.add(messageBox, left);
southPanel.add(sendMessage, right);
mainPanel.add(BorderLayout.SOUTH, southPanel);
newFrame.add(mainPanel);
newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
newFrame.setSize(720, 480);
newFrame.setVisible(true);
newFrame.setResizable(false);
newFrame.setLocationRelativeTo(null);
messageBox.requestFocusInWindow();
messageBox.addKeyListener(new KeyListener());
startup();
}
public void startup() {
int h = cal.get(Calendar.HOUR_OF_DAY);
int n = rand.nextInt(2) + 1;
String message = "";
chatBox.append("AIBot: ");
if (n == 1)
message = "Welcome back sir!";
else if ( n == 2) {
if ((h > 4) && (h < 11))
message = "Good Morning sir, I hope you have a great day.";
else if ((h >= 11) && (h < 17))
message = "Good Afternoon sir";
else if ((h >= 17) && (h < 25))
message = "Good Evening sir, how was your day?";
else
message = "It's quite late, you should get some rest sir";
}
try {
Runtime.getRuntime().exec( new String[] { "say" , "" + message }) ;
} catch (IOException e) {
e.printStackTrace();
}
messageBox.paintImmediately(messageBox.getBounds());
sendMessage.paintImmediately(sendMessage.getBounds());
messageBox.requestFocusInWindow();
for (int i = 0; i < message.length(); i++) { //Appends 1 letter at a time, "animation", voice is already executed
try {Thread.sleep(35);} catch (InterruptedException e) {e.printStackTrace();}
chatBox.append(message.substring(i, i+1));
chatBox.setCaretPosition(chatBox.getDocument().getLength());
chatBox.paintImmediately(chatBox.getBounds ());
}
chatBox.append("\n\n");
messageBox.setText("");
}
public class KeyListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
sendMessage.doClick();
}
}
}
public class sendMessageButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
if (messageBox.getText().length() < 1) {
// do nothing
} else if (messageBox.getText().equals(".clear")) {
chatBox.setText("Cleared all messages\n");
messageBox.setText("");
} else {
chatBox.append("" + username + ": ");
chatBox.append(messageBox.getText() + "\n\n");
temp = messageBox.getText();
tempL = temp.toLowerCase();
messageBox.setText("");
chatBox.setCaretPosition(chatBox.getDocument().getLength());
chatBox.paintImmediately(chatBox.getBounds ());
}
messageBox.requestFocusInWindow();
chatBox.append("AIBot: ");
//String message = me.disperse(tempL) + " ";
String message = "TEST................";
if (message.contains("username")) {
String[] t = message.split("username");
message = t[0] + username + t[1];
}
chatBox.setCaretPosition(chatBox.getDocument().getLength());
chatBox.paintImmediately(chatBox.getBounds());
//Need jsp (JScrollPane) to instantly update
message += "";
try {
Runtime.getRuntime().exec( new String[] { "say" , "" + message }) ;
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < message.length(); i++) { //Appends 1 letter at a time, "animation", voice is already executed
try {Thread.sleep(35);} catch (InterruptedException e) {e.printStackTrace();}
chatBox.append(message.substring(i, i+1));
chatBox.paintImmediately(chatBox.getBounds());
chatBox.setCaretPosition(chatBox.getDocument().getLength());
}
chatBox.append("\n\n");
chatBox.setCaretPosition(chatBox.getDocument().getLength());
}
}
}
答案 0 :(得分:0)
气垫船,这不是问题。延迟工作正常,动画工作。我唯一需要帮助的是立即更新JScrollPane所需的代码,无论任何Timer / Sleep
是的,您使用Thread.sleep(...)
是的问题。例如,如果您使用上面推荐的Swing Timer进行延迟打印,则滚动窗格会立即更新:
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
@SuppressWarnings("serial")
public class MainGui2 extends JPanel {
private static final Font TEXT_AREA_FONT = new Font("Arial", Font.PLAIN, 18);
private static final String TEST_MESSAGE = "TEST................";
private static final String TIMER = "Timer";
private static final String THREAD_SLEEP = "Thread.sleep";
private static final String[] RADIOS = { TIMER, THREAD_SLEEP };
public static final int TIMER_DELAY = 80;
private JTextArea textArea = new JTextArea(20, 40);
private JTextField textField = new JTextField(10);
private Action sendMsgAxn = new SendMessageAction("Send Message");
private JButton sendMsgButton = new JButton(sendMsgAxn);
private ButtonGroup buttonGroup = new ButtonGroup();
public MainGui2() {
textArea.setFont(TEXT_AREA_FONT);
textArea.setWrapStyleWord(true);
textArea.setLineWrap(true);
textArea.setFocusable(false);
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane
.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
textField.setAction(sendMsgAxn);
JPanel radioPanel = new JPanel(new GridLayout(1, 0));
for (String radioText : RADIOS) {
JRadioButton rBtn = new JRadioButton(radioText);
rBtn.setActionCommand(radioText);
buttonGroup.add(rBtn);
radioPanel.add(rBtn);
}
JPanel southPanel = new JPanel();
southPanel.setLayout(new BoxLayout(southPanel, BoxLayout.LINE_AXIS));
southPanel.add(textField);
southPanel.add(radioPanel);
southPanel.add(sendMsgButton);
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(southPanel, BorderLayout.PAGE_END);
}
class SendMessageAction extends AbstractAction {
private Timer timer;
public SendMessageAction(String name) {
super(name);
int mnemnoic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemnoic);
}
@Override
public void actionPerformed(ActionEvent e) {
if (timer != null && timer.isRunning()) {
return;
}
ButtonModel model = buttonGroup.getSelection();
if (model == null) {
return;
}
String text = textField.getText();
textField.selectAll(); // so text can easily be changed
textArea.append("\nUser > " + text + "\n");
// TODO: in a background thread -- send text to outside process
String command = model.getActionCommand();
if (command.equals(TIMER)) {
timerAction(TEST_MESSAGE);
} else if (command.equals(THREAD_SLEEP)) {
threadSleepAction(TEST_MESSAGE);
}
}
private void threadSleepAction(String text) {
for (int i = 0; i < text.length(); i++) {
textArea.append("" + text.charAt(i));
textArea.setCaretPosition(textArea.getDocument().getLength());
textArea.paintImmediately(textArea.getBounds());
try {
Thread.sleep(TIMER_DELAY);
} catch (InterruptedException e) {
}
}
}
private void timerAction(String text) {
timer = new Timer(TIMER_DELAY, new TimerListener(text));
timer.start();
}
}
private class TimerListener implements ActionListener {
private String message;
private int index = 0;
public TimerListener(String message) {
this.message = message;
}
@Override
public void actionPerformed(ActionEvent e) {
if (message.length() == index) {
((Timer) e.getSource()).stop(); // stop the timer
} else {
textArea.append("" + message.charAt(index));
index++;
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MainGui2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainGui2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
并且永远不要将KeyListener与JTextField一起使用。相反,你想要使用ActionListener或Action,实际上可以对你的JButton使用与JTextField相同的Action。