JScrollPane不会立即更新

时间:2015-10-07 15:21:02

标签: java swing jscrollpane jtextarea runnable

我在尝试将动画添加到聊天程序时遇到了一些麻烦。它工作正常,直到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());
        }
    }
}

1 个答案:

答案 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。