Java JScrollPane滚动到底部......差不多

时间:2015-02-23 03:50:05

标签: java swing

我的Java程序中有一个带有JPanel的ScrollPane,可以附加很多文本。每次添加后我都需要ScrollPane滚动到最底部。以下代码的问题在于它滚动了几乎"到底但不是一路走来。关于我做错了什么想法?

import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;

public class Sample extends JFrame{
    JTextField input = new JTextField();
    JPanel log = new JPanel();
    JScrollPane scrollPane = new JScrollPane(log);
    JScrollBar scrollBar = scrollPane.getVerticalScrollBar();

    public Sample(){

        input.setBorder(new TitledBorder("Message"));
        input.setToolTipText("Type a message here.");

        log.setBorder(new TitledBorder("Log"));
        log.setLayout(new BoxLayout(log, BoxLayout.Y_AXIS));
        log.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        // Add the panels to the frame
        setLayout(new BorderLayout(10, 10));
        add(input, BorderLayout.NORTH);
        add(scrollPane, BorderLayout.CENTER);

        setTitle("Chat Window");
        setSize(400, 300);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);

        // Register Key listener
        input.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    log.add(new ServerBubble(input.getText()));
                    log.add(Box.createRigidArea(new Dimension(0, 10)));
                    input.setText(null);
                    scrollPane.revalidate();
                    scrollBar.setValue(scrollBar.getMaximum());
                }
            }
        });
    }

    public static void main(String[] args) {
        JFrame frame = new Exercise33_9Server();

    }

    private class ServerBubble extends JLabel{

        private final Color LIGHT_GREEN = new Color(204, 255, 229);
        private final Color DARK_GREEN = new Color(0, 102, 51);
        String message;

        public ServerBubble(String label){
            message = processText(label);
            setOpaque(true);
            setForeground(DARK_GREEN);
            setBackground(LIGHT_GREEN);
            setHorizontalAlignment(LEFT);
            setBorder(new LineBorder(DARK_GREEN, 3, true));
            setText(label);
            setBorder(BorderFactory.createCompoundBorder(getBorder(), BorderFactory.createEmptyBorder(5, 5, 5, 5)));
        }

        private String processText(String message){
            message = "<HTML>" + message;
            return message;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

基本上,您可能在组件层次结构有时间更新之前尝试更新视口。有时候,你只需要等待。

此示例基本上使用SwingUtilities.invokeLater将请求发送到事件队列,以便在不久的将来某些时间执行某些工作&#34;。这允许当前待处理的更新处理时间......

if (e.getKeyCode() == KeyEvent.VK_ENTER) {

    log.add(new ServerBubble(input.getText()));
    log.add(Box.createRigidArea(new Dimension(0, 10)));
    input.setText(null);
    log.revalidate();

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            Dimension vpSize = scrollPane.getViewport().getExtentSize();
            Dimension logSize = log.getSize();

            int height = logSize.height - vpSize.height;
            scrollPane.getViewport().setViewPosition(new Point(0, height));
        }
    });
}

此时,我抓住视图的当前大小并将其与日志面板的当前大小进行比较,然后使用不同来计算面板底部的y偏移量,这将允许最后一个元素可见......