当我在其 ViewPort 中绘制 JPanel 时,JScrollPane 不滚动

JScrollPane does not scroll when I paint the JPanel in its ViewPort

我正在尝试在作为 JScrollPane 的客户端(ViewPort 视图)的 JPanel 子类上绘制一些树结构。我可以很好地绘制树,但即使它比视口大,JScrollPane 也不会滚动。客户端是 JTextArea 的相同 JScrollPane 工作正常。

下面的代码创建了一个框架,其中有 2 个并排的滚动窗格——一个有效,另一个无效。 (为了简单起见,我只是绘制文本。)我是 Swing GUI 的新手,所以我无疑在做一些愚蠢的事情,但是几天的搜索和阅读并没有告诉我我的错误。

import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import java.awt.Graphics;

public class ScrollTest extends javax.swing.JFrame {

    public ScrollTest() {
        initComponents();
        prepComponents();
    }

    void prepComponents() {
        leftScrollPaneContent = new JTextArea();
        leftScrollPane.setViewportView(leftScrollPaneContent);
        rightScrollPaneContent = new TestPanel();
        rightScrollPane.setViewportView(rightScrollPaneContent);
        String s = "Test of JTextArea setText()\n\n";
        for (int i = 1; i < 30; i++) {
            s += "Line " + i + ": This is a test.\n";
        }
        leftScrollPaneContent.setText(s);
        rightScrollPaneContent.repaint();
    }

    @SuppressWarnings("unchecked")
    private void initComponents() {
        leftPanel = new javax.swing.JPanel();
        jPanelLabel = new javax.swing.JLabel();
        leftScrollPane = new javax.swing.JScrollPane();
        rightPanel = new javax.swing.JPanel();
        subclassLabel = new javax.swing.JLabel();
        rightScrollPane = new javax.swing.JScrollPane();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jPanelLabel.setText("JTextArea in a ScrollPane");

        leftScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
        leftScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        javax.swing.GroupLayout leftPanelLayout = new javax.swing.GroupLayout(leftPanel);
        leftPanel.setLayout(leftPanelLayout);
        leftPanelLayout.setHorizontalGroup(
                leftPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(leftPanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(leftScrollPane)
                        .addContainerGap())
                .addGroup(leftPanelLayout.createSequentialGroup()
                        .addGap(101, 101, 101)
                        .addComponent(jPanelLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 180, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap(114, Short.MAX_VALUE))
        );
        leftPanelLayout.setVerticalGroup(
                leftPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(leftPanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(jPanelLabel)
                        .addGap(18, 18, 18)
                        .addComponent(leftScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 332, Short.MAX_VALUE)
                        .addContainerGap())
        );

        subclassLabel.setText("JPanel subclass in a ScrollPane");

        rightScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
        rightScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        javax.swing.GroupLayout rightPanelLayout = new javax.swing.GroupLayout(rightPanel);
        rightPanel.setLayout(rightPanelLayout);
        rightPanelLayout.setHorizontalGroup(
                rightPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(rightPanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(rightScrollPane)
                        .addContainerGap())
                .addGroup(rightPanelLayout.createSequentialGroup()
                        .addGap(66, 66, 66)
                        .addComponent(subclassLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 200, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap(77, Short.MAX_VALUE))
        );
        rightPanelLayout.setVerticalGroup(
                rightPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(rightPanelLayout.createSequentialGroup()
                        .addComponent(subclassLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(rightScrollPane)
                        .addContainerGap())
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(leftPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addComponent(rightPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap(14, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addGroup(layout.createSequentialGroup()
                                        .addContainerGap()
                                        .addComponent(leftPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                .addGroup(layout.createSequentialGroup()
                                        .addGap(17, 17, 17)
                                        .addComponent(rightPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                        .addContainerGap())
        );

        pack();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ScrollTest().setVisible(true);
            }
        });
    }

    private javax.swing.JLabel jPanelLabel;
    private javax.swing.JPanel leftPanel;
    private javax.swing.JScrollPane leftScrollPane;
    private javax.swing.JPanel rightPanel;
    private javax.swing.JScrollPane rightScrollPane;
    private javax.swing.JLabel subclassLabel;
    // End of variables declaration                   
    private JTextArea leftScrollPaneContent;
    private JPanel rightScrollPaneContent;

    public class TestPanel extends JPanel {

        public void paint(Graphics g) {
            super.paint(g);
            g.drawString("Test of JPanel g.drawString()\n", 10, 20);
            for (int i = 3; i < 33; i++) {
                g.drawString("Line " + (i-2) + ": This is a test.", 10, 20 * i);
            }
        }
    }
}

您的 JTextArea leftScrollPaneContent 覆盖 getPreferredSize() 哪个 return size 巧妙 源自实际的文本和字体。 周围的JScrollPane用这个大小来决定 如果需要滚动条。
此外,JTextArea(因为从 JTextComponent 延伸) 还实现了 Scrollable 接口。 这为周围的环境提供了一些额外的提示 JScollPane 以获得更好的滚动行为。


您的 TestPanel rightScrollPaneContent 没有做任何事情。 因此它从 JPanel 继承了一个 getPreferredSize() 方法 return只有 10x10 的小尺寸(这对于 空 JPanel,没有子组件)。 因此周围的JScrollPane决定没有 需要为这个所谓的微小内容显示任何滚动条。

因此,最重要的是,在您的 TestPanel 中,您需要覆盖 getPreferredSize() 和 return 那里有一个合理的大尺寸。 作为奖励(为了更好的滚动行为)你也可以实现 Scrollable 界面。 或者您选择从另一个 class 扩展您的 class 它已经实现了 Scrollable 接口。