如何使JScrollPane(在BorderLayout中,包含JPanel)顺利地自动滚动

我正在尝试在JScrollPanel内部创建一个不同大小的JPanel(可能比标准屏幕宽得多)。 目前它效果很好,我已经配置滚动条手动工作正常,但我希望JPanel不断向左“滚动”,以便随着时间的推移显示整个事物。 我发现的所有答案都是特定于JTextArea并使用Carets,或使用rectToVisible。 这些都不会起作用,因为我试图在内部滚动到单个JPanel。

我已经包含了我认为是以下所有相关代码的内容。

center是JPanel(其中Grid是一个子类,用于专门绘制一些特定单元格的网格),带有我想要自动滚动的BorderLayout。

public GuiViewFrame(Song playMe) { String[][] songArray = playMe.to2DArray(); this.displayPanel = new ConcreteGuiViewPanel(playMe); main = new JPanel(); main.setLayout(new BorderLayout()); displayPanel.setLayout(new BorderLayout()); center = new Grid(playMe); labels = new Labels(playMe); horiz = new Horiz(playMe); center.setPreferredSize(new Dimension(10 * songArray.length, 10 * songArray[0].length)); horiz.setPreferredSize(new Dimension(10 * songArray.length, 10)); horiz.setVisible(true); main.add(center, BorderLayout.CENTER); main.add(horiz, BorderLayout.NORTH); scroll = new JScrollPane(main, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); add(scroll, BorderLayout.CENTER); labels.setPreferredSize(new Dimension(20, 10 * songArray[0].length)); labels.setVisible(true); add(labels, BorderLayout.WEST); JScrollBar horiz = scroll.getHorizontalScrollBar(); InputMap im = horiz.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); im.put(KeyStroke.getKeyStroke("RIGHT"), "positiveUnitIncrement"); im.put(KeyStroke.getKeyStroke("LEFT"), "negativeUnitIncrement"); im.put(KeyStroke.getKeyStroke("HOME"), "minScroll"); im.put(KeyStroke.getKeyStroke("END"), "maxScroll"); this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); this.pack(); } 

整个项目是为播放组合MIDI和GUI的音乐生成一个视图,但是现在一旦MIDI播放了足够的歌曲,相关的音符就会关闭。 我想以一定的速度滚动以跟上MIDI的步伐。

您可以设置水平滚动条的值来控制当前可见的内容:

 JScrollBar horizontal = scroll.getHorizontalScrollBar(); horizontal.setValue( horizontal.getValue() + ??? ); 

您需要使用Swing Timer以适当的间隔安排滚动。

使用Timer滚动文本的简单示例:

 import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; public class TimerTest extends JPanel implements ActionListener { JLabel timeLabel; JLabel scrollLabel; public TimerTest() { setLayout( new BorderLayout() ); timeLabel = new JLabel( new Date().toString() ); add(timeLabel, BorderLayout.NORTH); scrollLabel = new JLabel( "Some continuously scrolling text!! " ); add(scrollLabel, BorderLayout.SOUTH); int time = 1000; javax.swing.Timer timer = new javax.swing.Timer(time, this); timer.setInitialDelay(1); timer.start(); } public void actionPerformed(ActionEvent e) { timeLabel.setText( new Date().toString() ); String oldText = scrollLabel.getText(); // Scroll right to left String newText = oldText.substring(1) + oldText.substring(0, 1); // Scroll left to right // int length = oldText.length(); // String newText = oldText.substring(length-1, length) // + oldText.substring(0, length-1); scrollLabel.setText( newText ); } private static void createAndShowGUI() { JFrame frame = new JFrame("SSCCE"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add( new TimerTest() ); frame.setLocationByPlatform( true ); frame.pack(); frame.setVisible( true ); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } } 

一种可能的解决方案可能是利用JComponent#scrollRectToVisible和Swing Timer

例如…

滑动

 import java.awt.Container; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JViewport; import javax.swing.Scrollable; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class ScrollTest { public static void main(String[] args) { new ScrollTest(); } public ScrollTest() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new JScrollPane(new TestPane())); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel implements Scrollable { public TestPane() { Timer timer = new Timer(40, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JViewport viewport = (JViewport) getParent(); Rectangle viewRect = viewport.getViewRect(); if (viewRect.x + viewRect.width < getWidth()) { viewRect.x += 2; scrollRectToVisible(viewRect); } else { ((Timer)e.getSource()).stop(); } } }); timer.start(); } @Override public Dimension getPreferredSize() { return new Dimension(1000, 200); } protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.drawLine(0, 0, getWidth(), getHeight()); g2d.dispose(); } @Override public Dimension getPreferredScrollableViewportSize() { return new Dimension(200, 200); } @Override public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { return 64; } @Override public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { return 64; } @Override public boolean getScrollableTracksViewportWidth() { return getPreferredSize().width <= getParent().getSize().width; } @Override public boolean getScrollableTracksViewportHeight() { return getPreferredSize().height <= getParent().getSize().height; } } }