推荐的组件布局始终保持在x轴的相同位置?

时间:2014-05-28 07:28:30

标签: java swing jscrollpane

我的情况有点复杂,所以不要解释我只是展示我目前所拥有的图片:

Screenshot of the UI

我的想法是,我想在工作人员上方移动乐器选择器(在每个工作人员中说"长笛"的组合框)。但是,我总是希望将它保持在工作人员正上方的同一个地方,即使在水平滚动时也是如此。当垂直滚动时,它应该移动,以便它总是直接在其工作人员上方。有点像工具栏。问题是它已经存在于JScrollPane中(因为可能有多个五线谱,你需要滚动两个轴,并且每个工作人员都有一个"仪表板;将是其他UI元素在本地伪工具栏中与其附加的工作人员进行交互))。这是否需要使用绝对定位+监听滚动/调整大小/窗口移动事件?或者是否有一个我不知道可以做这种事情的布局?

感谢您的期待!

2 个答案:

答案 0 :(得分:2)

我通过以下方法进行了一些工作:

  • 在员工
  • 上放置一个带有空布局的JPanel
  • 将comboBox添加到此面板
  • 使面板高度与组合框相同,宽度与工作人员一样(宽度可滚动)
  • 在水平栏中添加AdjusmentListener以更新组合框的坐标X.

换句话说,组合框在其空布局面板中滑动以匹配您正在查看的位置。它并不完美,因为当你移动scrollBar时,这会导致组合框稍微摆动。

我看起来像你的模拟界面如下:

screenshot

请注意屏幕截图中的水平条是如何移动的,但组合框中的"长笛"仍然可见。

所以最重要的代码是:

  • 将comboBox放在空布局面板中:

    JComboBox comboBox = new JComboBox(new String[]{"Flute", "Piano", "Cello"});
    comboBox.setBounds(0, 0, comboBox.getPreferredSize().width, comboBox.getPreferredSize().height);
    _comboBoxes.add(comboBox);
    
    JPanel comboBoxPanel = new JPanel();
    comboBoxPanel.setLayout(null);
    comboBoxPanel.add(comboBox);
    

    然后,您将此面板放在工作人员上,无论您使用何种布局。在我的情况下,我有一个带有垂直Box布局的面板,其中包含comboBoxPanel和工作人员所在的红色面板。

  • 将一个监听器添加到滚动条并更新其面板中的组合框位置:

    scrollPane.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener() {
        @Override
        public void adjustmentValueChanged(AdjustmentEvent e)
        {
            for (JComboBox comboBox : _comboBoxes)
            {
                comboBox.setLocation(e.getValue(), 0);
            }
        }
    });
    

完整代码:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;


public class ScrollIndependentTest
{
    private ArrayList<JComboBox> _comboBoxes = new ArrayList<JComboBox>();

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

    public void createAndShowGUI()
    {
        JFrame frame = new JFrame();

        frame.setTitle("Fourier Synthesis");

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

        for (int i = 0; i < 10; ++i)
        {
            listPanel.add(createStaffPanel());
        }

        JScrollPane scrollPane = new JScrollPane(listPanel);
        scrollPane.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener()
        {
            @Override
            public void adjustmentValueChanged(AdjustmentEvent e)
            {
                for(JComboBox comboBox : _comboBoxes)
                {
                    //if (comboBox.isVisible()) //maybe?
                    comboBox.setLocation(e.getValue(), 0);
                }
            }
        });
        frame.add(scrollPane);

        /*
         * Cosmetic elements to make it look more similar to your case
         */
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(new JMenu("File"));
        menuBar.add(new JMenu("Synthesis"));
        menuBar.add(new JMenu("Help"));
        frame.setJMenuBar(menuBar);
        JPanel toolBar = new JPanel();
        toolBar.setLayout(new BoxLayout(toolBar, BoxLayout.Y_AXIS));
        for (int i = 0; i < 10; ++i)
        {
            toolBar.add(new JButton("Note " + i));
        }
        frame.add(toolBar, BorderLayout.WEST);
        /*
         *  end
         */

        frame.setSize(new Dimension(500, 400));
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private JPanel createStaffPanel()
    {
        JPanel staffPanel = new JPanel();
        staffPanel.setLayout(new BoxLayout(staffPanel, BoxLayout.Y_AXIS));
        staffPanel.setBorder(BorderFactory.createLineBorder(Color.black));

        JComboBox comboBox = new JComboBox(new String[]{"Flute", "Piano", "Cello"});
        comboBox.setBounds(0, 0, comboBox.getPreferredSize().width, comboBox.getPreferredSize().height);
        _comboBoxes.add(comboBox);

        JPanel comboBoxPanel = new JPanel();
        comboBoxPanel.setLayout(null);
        comboBoxPanel.add(comboBox);

        comboBoxPanel.setPreferredSize(new Dimension(600, comboBox.getPreferredSize().height));
        staffPanel.add(comboBoxPanel);

        JPanel panel = new JPanel();
        panel.setBackground(Color.red);
        panel.setPreferredSize(new Dimension(600, 100));
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        staffPanel.add(panel);

        return staffPanel;
    }
}

答案 1 :(得分:2)

  1. 将组件添加到各个滚动窗格,但从不显示水平滚动条
  2. 让所有滚动窗格共享相同的BoundRangeModel。
  3. 创建一个使用此模型的单独JScrollBar组件。每当滚动时,单独的滚动窗格也会滚动:
  4. 类似的东西:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.text.*;
    
    public class ScrollSSCCE extends JPanel
    {
        public ScrollSSCCE()
        {
            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
            BoundedRangeModel model = null;
    
            for (int i = 0; i < 5; i++)
            {
                JLabel label = new JLabel("Flute " + i);
                label.setAlignmentX(JComponent.LEFT_ALIGNMENT);
                add( label );
    
                JTextArea textArea = new JTextArea(3, 20);
                textArea.setText("Just some text to make a horizontal scroll necessary");
                JScrollPane scrollPane = new JScrollPane( textArea );
                scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
                scrollPane.setAlignmentX(JComponent.LEFT_ALIGNMENT);
                add( scrollPane );
    
                //  Share the horizontal scrollbar model
    
                JScrollBar horizontal = scrollPane.getHorizontalScrollBar();
    
                if (i == 0)
                    model = horizontal.getModel();
                else
                    horizontal.setModel( model );
            }
    
            //  Create the scrollbar that uses the shared model
    
            JScrollBar shared = new JScrollBar( JScrollBar.HORIZONTAL );
            shared.setModel( model );
            shared.setAlignmentX(JComponent.LEFT_ALIGNMENT);
            add( shared );
        }
    
        private static void createAndShowUI()
        {
            JFrame frame = new JFrame("Scroll SSCCE");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add( new ScrollSSCCE() );
            frame.setLocationByPlatform( true );
            frame.setSize(200, 400);
            frame.setVisible( true );
        }
    
        public static void main(String[] args)
        {
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    createAndShowUI();
                }
            });
        }
    }
    

    编辑:

    您甚至无需创建“共享”滚动条即可实现此目的。只需使用最后一个滚动窗格的滚动条:

    if (i != 4)
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    
      

    我也需要一个垂直滚动条。

    不要以为你需要创建另一个面板。只需将当前面板直接添加到滚动窗格:

    JScrollPane master = new JScrollPane( new ScrollSSCCE() );
    master.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    
    JFrame frame = new JFrame("Scroll SSCCE");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //frame.add( new ScrollSSCCE() );
    frame.add( master );
    frame.setLocationByPlatform( true );
    frame.setSize(200, 400);
    frame.setVisible( true );
    

    这是我的最后一个提示。我不会在附近呆几天。祝你好运。