【问题标题】:Why is my JPanel inside a JScrollPane not scrolling?为什么我在 JScrollPane 中的 JPanel 不滚动?
【发布时间】:2012-02-07 21:45:57
【问题描述】:

我在JScrollPane 中有一个JPanel(黄色)。

当我在JTextPane 中输入一些文本时,它会调整大小,但垂直滚动条仍然不活动。 yelowPanel.getSize() 返回与之前相同的值。`(您可以在 redPanel 上看到它)。

那么如何刷新yellowPanel?我想垂直滚动面板。 我试图:

panelCreating.revalidate();
panelCreating.invalidate();
panelCreating.repaint();

仅适用于panelCreating.setPreferredSize(new Dimension(333, 777));,但我不知道要设置什么尺寸。这取决于内容。

有个小例子:

package swingtest;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;

public class SwingTest extends JFrame {

    public SwingTest() {
        initComponents();
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new SwingTest().setVisible(true);
            }
        });
    }
    private JPanel panelCenter, panelCreating;
    private JScrollPane scrollPaneCreating, scrollPaneCenter;
    private JTextPane textPane1, textPane2;
    private JButton button1;

    private void initComponents() {
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setMinimumSize(new Dimension(300, 300));

        panelCreating = new JPanel();
        panelCreating.setMinimumSize(new Dimension(160, 200));
        panelCreating.setPreferredSize(new Dimension(160, 200));
        scrollPaneCreating = new JScrollPane(panelCreating,
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

        textPane1 = new JTextPane();
        textPane1.setText("a\na");
        textPane2 = new JTextPane();
        textPane2.setText("b\nb");
        button1 = new JButton("+++");

        panelCenter = new JPanel();
        panelCenter.setBackground(Color.blue);
        scrollPaneCenter = new JScrollPane(panelCenter);



        // ----------------- Left Panel Init -----------------------

        panelCreating.setLayout(new GridBagLayout());
        panelCreating.setBackground(Color.ORANGE);
        panelCreating.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));

        GridBagConstraints c = new GridBagConstraints();
        c.insets = new Insets(0, 0, 4, 4);
        c.anchor = GridBagConstraints.FIRST_LINE_START;
        c.weightx = c.weighty = 0;

        c.gridx = 0;
        c.gridy = GridBagConstraints.RELATIVE;
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.gridheight = 1;
        c.fill = GridBagConstraints.BOTH;
        panelCreating.add(textPane1, c);

        button1.addActionListener(new ActionListener() {

            int height = 50;

            @Override
            public void actionPerformed(ActionEvent e) {
                textPane1.setText(textPane1.getText() + "\na");
                textPane1.setPreferredSize(new Dimension(150, height));
                textPane2.setText(textPane2.getText() + "\nb");
                textPane2.setPreferredSize(new Dimension(150, height));
                height += 30;

                panelCreating.revalidate();
                panelCreating.repaint();
                scrollPaneCreating.revalidate();
            }
        });
        panelCreating.add(button1, c);

        panelCreating.add(textPane2, c);

        // -------------------------------------------------------

        getContentPane().setLayout(new GridBagLayout());
        c = new GridBagConstraints();

        c.ipadx = c.ipady = 0;
        c.insets = new Insets(0, 0, 0, 0);
        c.weighty = 0;
        c.gridheight = 1;
        c.gridx = 0;
        c.gridy = 1;
        c.gridwidth = 1;
        c.weightx = 0;
        c.fill = GridBagConstraints.BOTH;
        getContentPane().add(scrollPaneCreating, c);


        c.gridx = 1;
        c.gridy = 1;
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 1;
        c.weighty = 1;
        getContentPane().add(scrollPaneCenter, c);

    }
}

黄色面板也使用 GridBagLayout。 对不起我的英语

【问题讨论】:

  • 当组件只在垂直方向增长时,为什么水平滚动条会自动启用?请附上sscce,因为不清楚您在问什么(至少对我而言)。
  • 对不起,我的意思是垂直滚动条..
  • @alaster 你能用sscce.org 形式的代码编辑你的帖子吗,因为这可能是为什么 JScrollPane 不能使用 AbsoluteLayout 工作的教训,+1 用于记录这个奇怪的问题
  • 完成。我只使用了 GridBagLayout
  • "完成。 抱歉,怎么了?我看到 2 个 SSCCE 请求,但没有 SSCCE。

标签: java swing jscrollpane


【解决方案1】:

不要在panelCreating 上设置首选大小,而是在scrollPaneCreating 上设置它。并且不要在文本组件上设置首选大小,它们会随着您向它们添加新的文本行而增长。这个想法是让滚动窗格内的面板根据需要增长,并且只限制滚动窗格本身的大小。

    // [...]

    panelCreating = new JPanel();
    //panelCreating.setMinimumSize(new Dimension(160, 200));
    //panelCreating.setPreferredSize(new Dimension(160, 200));
    scrollPaneCreating = new JScrollPane(panelCreating,
        JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
        JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    scrollPaneCreating.setMinimumSize(new Dimension(160, 200));
    scrollPaneCreating.setPreferredSize(new Dimension(160, 200));

    // [...]

        @Override
        public void actionPerformed(ActionEvent e) {
            textPane1.setText(textPane1.getText() + "\na");
            //textPane1.setPreferredSize(new Dimension(150, height));
            textPane2.setText(textPane2.getText() + "\nb");
            //textPane2.setPreferredSize(new Dimension(150, height));
            //height += 30;

            // This isn't necessary either
            //panelCreating.revalidate();
            //panelCreating.repaint();
            //scrollPaneCreating.revalidate();
        }

编辑添加:另一种选择是在附加到滚动窗格的JViewport 上设置大小。视口是显示内容的地方。您可以将滚动窗格想象成由视口和滚动条组成。如果滚动窗格设置为固定大小,则视口大小通过减去滚动条大小来确定。但是如果视口设置为固定大小,则滚动窗格大小是通过将滚动条大小添加到视口大小来确定的。如果您想精确控制应在屏幕上显示多少内容,则最好在视口上设置固定大小,因为滚动条的大小可能因操作系统而异。

scrollPaneCreating.getViewport().setMinimumSize(new Dimension(160, 200));
scrollPaneCreating.getViewport().setPreferredSize(new Dimension(160, 200));

【讨论】:

  • 那是我的错误。而且我什至不需要更改布局。谢谢
【解决方案2】:

JPanel 的默认布局是FlowLayout。请改用GridLayout。有一个相关的例子here。例如,

panelCreating = new JPanel(new GridLayout());
scrollPaneCreating = new JScrollPane(panelCreating);

附录:还要考虑嵌套布局。下面的示例使用BoxLayout 作为左侧面板。

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;

/** @see https://stackoverflow.com/questions/9184476 */
public class SwingTest extends JFrame {

    private static final int N = 8;

    public SwingTest() {
        initComponents();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new SwingTest().setVisible(true);
            }
        });
    }
    private JPanel panelCenter, panelCreating;
    private JScrollPane scrollPaneCreating, scrollPaneCenter;

    private void initComponents() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        panelCreating = new JPanel();
        scrollPaneCreating = new JScrollPane(panelCreating,
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

        panelCenter = new JPanel();
        panelCenter.setBackground(Color.blue);
        scrollPaneCenter = new JScrollPane(panelCenter);

        // ----------------- Left Panel Init -----------------------
        panelCreating.setLayout(new BoxLayout(panelCreating, BoxLayout.Y_AXIS));
        panelCreating.setBackground(Color.orange);
        panelCreating.setBorder(BorderFactory.createEmptyBorder(N, N, N, N));

        panelCreating.add(createTextPane());
        panelCreating.add(Box.createVerticalStrut(N));
        panelCreating.add(createTextPane());
        panelCreating.add(Box.createVerticalStrut(N));
        panelCreating.add(createTextPane());

        // -------------------------------------------------------
        setLayout(new GridLayout(1, 0));
        add(scrollPaneCreating);
        add(scrollPaneCenter);
        pack();
    }

    private JTextPane createTextPane() {
        JTextPane pane = new JTextPane();
        pane.setText(""
            + "Twas brillig and the slithy toves\n"
            + "Did gyre and gimble in the wabe;\n"
            + "All mimsy were the borogoves,\n"
            + "And the mome raths outgrabe.");

        pane.setBorder(BorderFactory.createEmptyBorder(N, N, N, N));
        return pane;
    }
}

【讨论】:

  • 我只使用了 GridBagLayout。内面板和外面板。但是当我在附加的 SSCCE 中使用GridLayout 时,我遇到了同样的问题..
【解决方案3】:

我解决了您添加 1 行的问题。

panelCreating.setPreferredSize(new Dimension((int) panelCreating.getPreferredSize().getWidth(),
                    (int)(panelCreating.getPreferredSize().getHeight()+30)));

该行必须插入以下行之后;

@Override
        public void actionPerformed(ActionEvent e) {
            textPane1.setText(textPane1.getText() + "\na");
            textPane1.setPreferredSize(new Dimension(150, height));
            textPane2.setText(textPane2.getText() + "\nb");
            textPane2.setPreferredSize(new Dimension(150, height));
            height += 30;

说明: 当您在其中设置 textPanes 的首选大小时,网格包布局不会设置它的窗格首选大小,但 scrollPane 仅根据其中窗格的首选大小滚动。因此,每次更改其中组件的大小时,都必须设置窗格的新首选大小,然后 scrollPane 将确切地知道他必须做什么。这就是我所做的,添加一行来增加createPanel 的首选大小,这就是scrollPanel 内的那个

【讨论】:

    猜你喜欢
    • 2014-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多