Java ScrollPane 交互式滚动

Java ScrollPane interactive scrolling

我正在构建一个聊天应用程序,我将聊天添加到附加到 JScrollPaneJPanel。可以在我的 JPanel 中添加和删除聊天,碰巧我希望我的 JScrollPane 执行 3 个功能

  1. 如果垂直 scrollBar 不可见(即由于屏幕上的聊天很少而无需滚动)并且当新聊天进入面板时导致 scrollBar第一次可见然后 scrollBar 必须滚动到它的最大值以使新添加的聊天可见

  2. 如果用户已尽可能滚动到 scrollPane 的最大 value/very 底部,并且当新聊天进入面板时导致 scrollBar' s 最大值上升然后执行与操作 1 相同的操作

  3. 如果用户向上滚动聊天以查看以前的消息(即滚动到某个随机点,该点小于 scrollBar 的最大值)然后出现一些新聊天滚动按钮必须出现在聊天中,如果用户单击它,scrollBar 将滚动到新的最大值以使新添加的聊天可见

基本上我的算法如下

//The user is currently at the bottom of the chat or scrollBar is not visible therefore making current & maximum value = 0
if (scrollBar.currentValue() == scrollBar.maxValue()) {
    scrollButton.setVisible(false);
    guiUpdate();  //Then Add,Remove The Chat
    scrollToVeryButton();
}
else {
    //The user is somewhere top of the chat looking at previous messages
    guiUpdate();   //Then Add,Remove The Chat
    scrollButton.setVisible(true); //Upon clicking scrollToVeryButton(); Is Called
}

不幸的是,该算法不起作用,无论如何,scrollButton 总是最终可见。这是完整的代码:

聊天显示class 用于显示聊天


import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;

class ChatDisplay extends JLayeredPane {

    private JScrollPane scrollPane;
    private JPanel chatDisplay;
    private Scroll notify;

    ChatDisplay() {
        setLayout(null);
        addChatDisplay();
        addNotifyButton();
    }

    private void addChatDisplay() {
        chatDisplay = new JPanel();
        chatDisplay.setLayout(new BoxLayout(chatDisplay, BoxLayout.Y_AXIS));
        scrollPane = new JScrollPane(chatDisplay);
        scrollPane.setBounds(0, 0, 300, 300);
        add(scrollPane, new Integer(0));
    }

    private void addNotifyButton() {
        notify = new Scroll();
        notify.setBounds(150, 150, 80, 50);
        add(notify, new Integer(1));
        notify.setVisible(false);
    }

    //Called To Add An New Chat
    void addButton(String text) {
        guiUpdate(() -> {
            chatDisplay.add(new Chat(text));
            chatDisplay.revalidate();
            chatDisplay.repaint();
        });
    }

    //The general update when gui is changed in anyway
    private void guiUpdate(Runnable update) {
        JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
        if (scrollBar.getValue() == scrollBar.getMaximum()) {
            notify.setVisible(false);
            update.run();
            scrollBar.setValue(scrollBar.getMaximum());
        } else {
            update.run();
            notify.setVisible(true);
        }
    }

    //Called To Remove An Chat
    private void removeButton(JButton button) {
        guiUpdate(() -> {
            chatDisplay.remove(button);
            chatDisplay.revalidate();
            chatDisplay.repaint();
        });
    }

    //The Chat Button
    private final class Chat extends JButton implements ActionListener {

        private Chat(String text) {
            setText(text);
            Dimension dim = new Dimension(300, 100);
            setPreferredSize(dim);
            setMinimumSize(dim);
            setMaximumSize(dim);
            addActionListener(Chat.this);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            removeButton(Chat.this); //Upon Clicking Remove Itself From Chat
        }
    }

    // The ScrollBar
    private final class Scroll extends JButton implements ActionListener {

        private Scroll() {
            setText("Scroll");
            setBackground(Color.green);
            addActionListener(Scroll.this);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
            scrollBar.setValue(scrollBar.getMaximum());  //Scroll To The Bottom Upon Clicking
            setVisible(false);  //Its Job Is Done Wait For Next Event
        }
    }
}

ChatPanel 设置为内容面板

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;

class ChatPanel extends JPanel implements ActionListener {
    private ChatDisplay display;
    private int chat;

    ChatPanel() {
        super(null);
        addDisplay();
        addButton();
    }

    private void addDisplay() {
        display = new ChatDisplay();
        display.setBounds(0, 0, 300, 300);
        add(display);
    }

    private void addButton() {
        JButton add = new JButton("ADD CHAT");
        add.addActionListener(this);
        add.setBounds(0, 310, 300, 30);
        add(add);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        display.addButton("Chat " + (++chat));
    }
}

主要Class

import javax.swing.JFrame;

public class Main {
    public static void main(String args[]) throws Exception {
        JFrame frame = new JFrame("Design Frame");
        frame.setContentPane(new ChatPanel());
        frame.setSize(320, 380);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setVisible(true);
    }
}

我找到了答案

解决方案

关键是只要有任何“调整”[add/remove 聊天] 滚动条总是滚动到底部,并且只有当用户之前滚动到它时它才必须执行此行为最大值

 scrollBar.addAdjustmentListener((event)->
 {
   if(autoScroll)//an boolean flag which is set to true whenever an chat is added/removed 
   {
    scrollBar.setValue(scrollBar.getMaximum());
    
    autoScroll=false; //set to false so the user can scroll freely upwards otherwise it will always reset it to the amaximum value
   }
 });

修复

current=scrollBar.getValue() 

永远不会等于最大值,除非它被添加到它在屏幕上显示的可见量,即

currentValue=scrollBar.getValue()+scrollBar.getVisibleAmount()

解决方案和修复已在 guiUpdate() 方法中实施

完整代码

 private boolean autoScroll;
 private void guiUpdate(Runnable update)
 {
  JScrollBar scrollBar=scrollPane.getVerticalScrollBar();
  
  scrollBar.addAdjustmentListener((event)->
  {
   if(autoScroll)
   {
    scrollBar.setValue(scrollBar.getMaximum());
    
    autoScroll=false;
   }
  });
  
 
  if(scrollBar.getValue()+scrollBar.getVisibleAmount()==scrollBar.getMaximum())
  {
   notify.setVisible(false);
     
   autoScroll=true;  //The user is at the bottom of the screen hence autoScroll to the new maximum
   
   update.run();
  }
  else
  {
   autoScroll=false;  //the user is looking at previous chat messages hence don't scroll to the bottom
   
   update.run();
   
   notify.setVisible(true);
  }
 }

相关帖子

  1. JScrollPane scrollToBottom