【问题标题】:Java ScrollPane interactive scrollingJava ScrollPane 交互式滚动
【发布时间】:2020-07-13 16:37:49
【问题描述】:

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

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

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

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

基本上我的算法如下

//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
}

不幸的是,该算法不起作用,并且无论如何滚动按钮始终可见。这是完整的代码:

用于显示聊天的聊天显示类


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));
    }
}

主类

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);
    }
}

【问题讨论】:

  • 为了更好的帮助,请尽快发布正确的minimal reproducible example,与缩进保持一致,对于 4 个空格的 Java,单个空格几乎不可能跟随程序的流程(并且无需在程序的每一行之间有 1 个空行,它使程序比它应该的更长并且更难阅读)。 .setLayout(null) 某事告诉我那里出了点问题,尤其是JScrollPanes。
  • 我已经在这里发布了整个代码并且我使用空布局管理器只是为了演示目的。布局管理器仍然存在同样的问题,我不能在 JLayeredPane 中使用布局管理器,否则滚动按钮不会出现在聊天的顶部(更高深度)。主要逻辑位于 guiUpdate() 方法中,与布局无关

标签: java swing jscrollpane


【解决方案1】:

我找到了答案

解决方案

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

 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多