Java 始终保持在x轴上相同位置的组件的建议布局?

Java 始终保持在x轴上相同位置的组件的建议布局?,java,swing,jscrollpane,Java,Swing,Jscrollpane,我的情况有点复杂,所以我不想解释,我只想展示一下我目前拥有的东西: 我的想法是,我想把乐器选择器(每个棍子上都有“长笛”的组合框)移到棍子的上方。然而,我总是想把它放在同一个地方,在左边的工作人员正上方,即使是水平滚动。当垂直滚动时,它应该移动,以便始终位于其标尺的正上方。有点像工具栏。问题是它已经在一个JScrollPane中(因为可能有多个横杆,您需要滚动两个轴,每个员工都有一个“仪表板”(尽管最终会有其他UI元素在这个虚拟工具栏中与它连接的员工本地交互))。是否需要使用绝对定位+监听滚动

我的情况有点复杂,所以我不想解释,我只想展示一下我目前拥有的东西:

我的想法是,我想把乐器选择器(每个棍子上都有“长笛”的组合框)移到棍子的上方。然而,我总是想把它放在同一个地方,在左边的工作人员正上方,即使是水平滚动。当垂直滚动时,它应该移动,以便始终位于其标尺的正上方。有点像工具栏。问题是它已经在一个JScrollPane中(因为可能有多个横杆,您需要滚动两个轴,每个员工都有一个“仪表板”(尽管最终会有其他UI元素在这个虚拟工具栏中与它连接的员工本地交互))。是否需要使用绝对定位+监听滚动/调整大小/窗口移动事件?或者有没有一个我不知道的布局可以做这种事情


谢谢你的关注

我通过以下方法在一定程度上实现了这一点:

  • 将一个布局为空的JPanel放在staff上
  • 将组合框添加到此面板
  • 使面板高度与组合框相同,宽度与标尺相同(可以滚动的宽度)
  • AdjustmentListener
    添加到水平条以更新组合框的坐标X
换句话说,组合框在其空布局面板内滑动,以匹配您正在查看的位置。这并不完美,因为当您移动滚动条时,这会导致组合框稍微晃动

我制作的模拟界面与您的类似,如下所示:

注意在屏幕截图中水平条是如何移动的,但带有“长笛”的组合框仍然可见

因此,最重要的代码是:

  • 将组合框放在空布局面板中:

    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和红色面板,工作人员将在其中

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

    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;
    }
}
导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.Component;
导入java.awt.Dimension;
导入java.awt.event.AdjustmentEvent;
导入java.awt.event.AdjustmentListener;
导入java.util.ArrayList;
导入javax.swing.BorderFactory;
导入javax.swing.BoxLayout;
导入javax.swing.JButton;
导入javax.swing.JComboBox;
导入javax.swing.JFrame;
导入javax.swing.JMenu;
导入javax.swing.JMenuBar;
导入javax.swing.JPanel;
导入javax.swing.JScrollPane;
导入javax.swing.SwingUtilities;
公共类ScrollIndependentTest
{
私有ArrayList_ComboBox=新ArrayList();
公共静态最终void main(字符串[]args)
{
SwingUtilities.invokeLater(新的Runnable(){
公开募捐
{
新建ScrollIndependentTest().createAndShowGUI();
}
});
}
public void createAndShowGUI()
{
JFrame=新JFrame();
frame.setTitle(“傅里叶合成”);
JPanel listPanel=newjpanel();
setLayout(新的BoxLayout(listPanel,BoxLayout.Y_轴));
对于(int i=0;i<10;++i)
{
添加(createStaffPanel());
}
JScrollPane scrollPane=新的JScrollPane(列表面板);
scrollPane.getHorizontalScrollBar().addAdjustmentListener(新的AdjustmentListener())
{
@凌驾
公共无效调整值已更改(调整事件e)
{
for(JComboBox组合框:_组合框)
{
//if(comboBox.isVisible())//可能吗?
setLocation(例如getValue(),0);
}
}
});
frame.add(滚动窗格);
/*
*化妆元素,让它看起来更像你的情况
*/
JMenuBar menuBar=新的JMenuBar();
添加(新JMenu(“文件”);
菜单栏添加(新JMenu(“合成”));
添加(新JMenu(“帮助”);
frame.setJMenuBar(菜单栏);
JPanel toolBar=新的JPanel();
setLayout(新的BoxLayout(工具栏,BoxLayout.Y_轴));
对于(int i=0;i<10;++i)
{
添加(新的JButton(“Note”+i));
}
frame.add(工具栏,BorderLayout.WEST);
/*
*结束
*/
框架设置尺寸(新尺寸(500400));
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
私有JPanel createStaffPanel()
{
JPanel staffPanel=新的JPanel();
staffPanel.setLayout(新的BoxLayout(staffPanel,BoxLayout.Y_轴));
staffPanel.setboorder(BorderFactory.createLineBorder(Color.black));
JComboBox组合框=新的JComboBox(新弦[]{“长笛”、“钢琴”、“大提琴”});
comboBox.setBounds(0,0,comboBox.getPreferredSize().width,comboBox.getPreferredSize().height);
_comboBox.add(comboBox);
JPanel comboxpanel=新的JPanel();
comboBoxPanel.setLayout(空);
comboBoxPanel.add(组合框);
comboBoxPanel.setPreferredSize(新维度(600,comboBox.getPreferredSize().height));
添加(comboBoxPanel);
JPanel面板=新的JPanel();
面板.立根背景(颜色.红色);
面板。设置首选尺寸(新尺寸(600100));
面板.setAlignmentX(组件左对齐);
staffPanel.add(面板);
返回工作人员面板;
}
}

我通过以下方法在一定程度上实现了这一点:

  • 将一个布局为空的JPanel放在staff上
  • 添加
    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 );