使用FlowLayout的面板不能包含JScrollPanes?

时间:2014-07-11 12:47:47

标签: java swing jpanel jscrollpane layout-manager

这就是我最初做的。

public class MyFrame extends JFrame {

    public MyFrame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setPreferredSize(new Dimension(500 ,300));
        setResizable(false);
        pack();
        setLocationRelativeTo(null);

        initComponents();
    }

    private void initComponents() {

        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        for (int i=0; i < 100; i++)
            panel.add(new JLabel("some text"));

        JScrollPane scrollPane = new JScrollPane(panel, 
                ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        // Here I create a JPanel to replace the contentPane of JFrame
        JPanel contentPane = new JPanel();
        contentPane.add(scrollPane);
        setContentPane(contentPane);
    }

如果我用这个代替最后3行:

getContentPane().add(scrollPane);   
一切都好。但正如我之前所做的那样,垂直滚动条没有显示出来。是什么造成的?将JPanel设置为contentPane是错误的吗?

更新:  如果contentPane更改为BorderLayout,一切正常。

// Here I create a JPanel to replace the contentPane of JFrame
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(scrollPane);
setContentPane(contentPane);

所以问题是默认的FlowLayout?

解决:  问题是FlowLayout。它包装了JScrollPane并隐藏了工具栏。使用

scrollPane.setPreferredSize(new Dimension(500, 400)); // longer space in x-axis

解决它。

答案: 不应在使用FlowLayout的Container内使用JSrollPane。

4 个答案:

答案 0 :(得分:2)

首先,将自己的组件用作内容窗格并没有什么不妥。但是默认内容窗格也是一个JPanel实例,因此实际上没有必要用您自己的面板替换它,除非您想使用非面板内容窗格或自定义面板组件。

这是默认内容窗格的样子:

/**
 * Called by the constructor methods to create the default 
 * <code>contentPane</code>. 
 * By default this method creates a new <code>JComponent</code> add sets a 
 * <code>BorderLayout</code> as its <code>LayoutManager</code>.
 * @return the default <code>contentPane</code>
 */
protected Container createContentPane() {
    JComponent c = new JPanel();
    c.setName(this.getName()+".contentPane");
    c.setLayout(new BorderLayout() {
        /* This BorderLayout subclass maps a null constraint to CENTER.
         * Although the reference BorderLayout also does this, some VMs
         * throw an IllegalArgumentException.
         */
        public void addLayoutComponent(Component comp, Object constraints) {
            if (constraints == null) {
                constraints = BorderLayout.CENTER;
            }
            super.addLayoutComponent(comp, constraints);
        }
    });
    return c;
}

此方法取自JRootPane。它基本上是一个简单的JPanel,你可以看到自定义的布局管理器。

现在,您的示例中存在一些问题。

首先是调用顺序 - 您在向其中添加内容之前调整框架大小。只需更改订单,您就会看到滚动窗格:

public class MyFrame extends JFrame
{
    public MyFrame ()
    {
        super();

        // Add components first
        initComponents ();

        // Setup frame after so it fits its new content
        setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
        setPreferredSize ( new Dimension ( 500, 300 ) );
        setResizable ( false );
        pack ();
        setLocationRelativeTo ( null );
    }

    private void initComponents ()
    {
        JPanel panel = new JPanel ();
        panel.setLayout ( new BoxLayout ( panel, BoxLayout.Y_AXIS ) );

        for ( int i = 0; i < 100; i++ )
        {
            panel.add ( new JLabel ( "some text" ) );
        }

        JScrollPane scrollPane =
                new JScrollPane ( panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );

        // Here I create a JPanel to replace the contentPane of JFrame
        JPanel contentPane = new JPanel ();
        contentPane.add ( scrollPane );
        setContentPane ( contentPane );
    }

    public static void main ( String[] args )
    {
        SwingUtilities.invokeLater ( new Runnable ()
        {
            public void run ()
            {
                new MyFrame ().setVisible ( true );
            }
        } );
    }
}

它仍然会有所不同,因为您的new JPanel ()默认使用FlowLayout,而不是默认内容窗格组件使用的BorderLayout
With FlowLayout

只需设置BorderLayout即可获得您想要查看的结果:

JPanel contentPane = new JPanel ( new BorderLayout () );

答案 1 :(得分:1)

看看Rob Camick的WrapLayout,这是FlowLayout的扩展

enter image description here enter image description here

import java.awt.*;
import javax.swing.*;

public class TestWrapLayout {
    public TestWrapLayout () {
        ImageIcon icon = new ImageIcon(getClass().getResource("/resources/stackoverflow2.png"));
        JPanel panel = new JPanel(new WrapLayout());
        for (int i = 1; i <= 250; i++) {
            JLabel iconlabel = new JLabel(icon);
            iconlabel.setLayout(new BorderLayout());
            JLabel textlabel = new JLabel(String.valueOf(i));
            textlabel.setHorizontalAlignment(JLabel.CENTER);
            textlabel.setForeground(Color.WHITE);
            textlabel.setFont(new Font("impact", Font.PLAIN,20));
            iconlabel.add(textlabel);
            panel.add(iconlabel);
        }
        JFrame frame = new JFrame();
        frame.add(new JScrollPane(panel));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new TestWrapLayout();
            }
        });
    }
}

答案 2 :(得分:0)

使用pack()功能添加面板后,您必须更新相框。当你这样做

getContentPane().add(scrollPane);

函数add为您执行此操作(ref

答案 3 :(得分:0)

首先,创建第二个面板的原因是什么?那里 已经是第一个以BoxLayout作为布局的面板 经理集。只需设置具有第一个面板的滚动窗格 如父母按预期工作。

你要么打电话

setContentPane(scrollPane);

add(scrollPane);

现在我要解释导致这种意外行为的原因。这个 是一种怪癖,有时会发生在使用嵌套技术的人身上 在构建布局时。使用嵌套时,布局可以 相互影响。

选择另一个布局 - FlowLayout - 作为底层基础布局, 您导致第一个面板以其首选大小显示。代替 一个面板,你现在有两个面板,基板影响了 带标签的面板 - 它控制着它的大小。 FlowLayout 显示所有孩子的首选大小;它不尊重mimimum也不尊重 最大尺寸。因此,(第一个)可见面板的大小可以显示其所有标签; 这是计算首选大小的方式 - 足够大以显示所有大小 儿童。然而,有100个标签,它是非常大的;布局被打破了。它是 垂直那么大,我们实际上无法到达窗户的底部。

因此,通过我们的可见面板显示其所有标签,展示的目的是什么 verticall滚动条?不需要,因为所有标签都是“可见的”(放在上面 窗户区域,虽然设计被打破了。

所以问题不在于滚动条;他们正常工作。如果你 设置(在您的示例中)垂直滚动条策略为VERTICAL_SCROLLBAR_ALWAYS 你会看到滚动条但没有滑块,因为所有标签都是“可见的” 而且没有什么可滚动的。 (滚动条显示隐藏的内容 布局。)问题在于FlowLayout仅以首选大小显示其组件。

以下是一个按预期工作的固定代码示例:

package com.zetcode;

import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

public class MyFrame extends JFrame {

    public MyFrame() {

        initComponents();

        setTitle("Scrollbar");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);                       
        setPreferredSize(new Dimension(300, 200));
        pack();
        setLocationRelativeTo(null);        

    }

    private void initComponents() {

        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        for (int i=0; i < 100; i++)
            panel.add(new JLabel("some text"));

        JScrollPane scrollPane = new JScrollPane(panel, 
                ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

        setContentPane(scrollPane);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MyFrame ex = new MyFrame();
                ex.setVisible(true);
            }
        });
    }    
}

Example shapshot