【问题标题】:Making JButtons overlap使 JButton 重叠
【发布时间】:2011-05-15 21:10:41
【问题描述】:

我正在 Java Swing 中创建一个虚拟钢琴类型程序。我现在的钢琴键区域是一个带有水平 BoxLayout 的 JPanel,其中包含白色 JButton 作为白键。我也想添加黑键,并让它们与白键重叠。

我尝试了两种不同的方法。一种是使用 OverlayLayout。不幸的是,没有太多关于 OverlayLayout 管理器的在线文档,而且它在 NetBeans GUI 构建器中不可用。我不知道如何使它工作。我尝试的第二件事是使用 JLayeredPanes。我似乎也无法弄清楚这一点,即使在 Netbeans 中弄乱了它。

所以我认为我的问题很简单。如果有的话,将 JButtons 添加到其他 JButtons 之上的最佳方法是什么?或者也许有替代使用 JButtons 作为钢琴键的替代方法?

编辑

我已经结合 aioobe 和 dacwe 的代码来获得我想要的结果。我基本上使用了 dacwe 的 z-ordering 和 aioobe 的基本尺寸(放大了一点)和 mod 7 部分。我还添加了一些变量以使事情更清楚。这就是我现在所拥有的。

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

public class Test2 {

public static void main(String[] args) {

    JFrame frame = new JFrame("Test");

    JLayeredPane panel = new JLayeredPane();
    frame.add(panel);

    int maxKeys = 8;

    int width = 60;
    int height = 240;

    for (int i = 0; i < maxKeys; i++) {
        JButton b = new JButton();
        b.setBackground(Color.WHITE);
        b.setLocation(i * width, 0);
        b.setSize(width, height);

        panel.add(b, 0, -1);
    }

    int width2 = 48;
    int height2 = 140;
    for (int i = 0; i < maxKeys; i++) {
        int j = i % 7;
        if (j == 2 || j == 6)
            continue;

        JButton b = new JButton();
        b.setBackground(Color.BLACK);
        b.setLocation(i*(width) + (width2*3/4), 0);
        b.setSize(width2, height2);

        panel.add(b, 1, -1);
    }

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(500,280);
    frame.setVisible(true);
    }
}

谢谢各位!现在我需要以某种方式将侦听器和文本附加到这些按钮上。

【问题讨论】:

    标签: java swing jbutton overlap jlayeredpane


    【解决方案1】:

    我会编写一个自定义的PianoLayoutManager 并将黑键定位为比白键更高的 z 顺序。创建您自己的“约束”类,允许您添加这样的组件:

    add(new WhiteKey(), new PianoLayoutConstraint(WHITE, 1);
    add(new WhiteKey(), new PianoLayoutConstraint(WHITE, 2);
    ...
    add(new WhiteKey(), new PianoLayoutConstraint(WHITE, n);
    
    add(new BlackKey(), new PianoLayoutConstraint(BLACK, 1);
    add(new BlackKey(), new PianoLayoutConstraint(BLACK, 2);
    ...
    add(new BlackKey(), new PianoLayoutConstraint(BLACK, m);
    

    来自Using Swing Components tutorial trail

    注意: z 顺序决定了组件的绘制顺序。 z 顺序最高的组件首先绘制,z 顺序最低的组件最后绘制。在组件重叠的地方,具有较低 z 顺序的组件会覆盖具有较高 z 顺序的组件。

    这是一个丑陋的 hack,它使用空布局来帮助您入门。

    import java.awt.Color;
    import javax.swing.*;
    
    class PianoComponent extends JPanel {
    
        PianoComponent() {
    
            setLayout(null);
    
            for (int i = 0; i < 20; i++) {
                JButton key = new JButton();
                key.setBackground(Color.WHITE);
                key.setLocation(i * 20, 0);
                key.setSize(20, 120);
                add(key);
                setComponentZOrder(key, i);
            }
    
            for (int i = 0; i < 20; i++) {
                int j = i % 7;
                if (j == 2 || j == 6)
                    continue;
    
                JButton key = new JButton();
                key.setBackground(Color.BLACK);
                key.setLocation(i * 20 + 12, 0);
                key.setSize(16, 80);
                add(key);
                setComponentZOrder(key, 0);
            }
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            JFrame jf = new JFrame("Piano!");
            jf.setSize(400, 200);
            jf.add(new PianoComponent());
            jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            jf.setVisible(true);
        }
    }
    

    【讨论】:

    • 组件z顺序搞砸了!!
    • Ehhh,编译并运行并将鼠标移到它上面......它会在重新渲染时以错误的顺序呈现按钮。
    • 看起来很棒!但我只是试了一下,当按钮被按下或突出显示时,图层顺序会发生变化。他们可以保持相同的 Z 顺序吗?我还能将动作侦听器绑定到匿名 JButton 吗?反正我的面板上只有一个八度。
    • 啊,是的。我也看到了。看看 dacwes 的答案...使用 JLayeredPane 和需要两个 intsadd 方法应该可以解决问题。
    【解决方案2】:

    这是 layeredpane 的一个示例(它可以按您的预期工作):

    public static void main(String[] args) {
    
        JFrame frame = new JFrame("Test");
    
        JLayeredPane panel = new JLayeredPane();
        frame.add(panel);
    
    
        for (int i = 0; i < 8; i++) {
            JButton b = new JButton();
            b.setBackground(Color.WHITE);
            b.setLocation(i * 20, 0);
            b.setSize(20, 100);
    
            panel.add(b, 0, -1);
        }
    
        for (int i = 0; i < 4; i++) {
            JButton b = new JButton();
            b.setBackground(Color.BLACK);
            b.setLocation(10 + i * 40, 0);
            b.setSize(20, 70);
    
            panel.add(b, 1, -1);
        }
    
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setVisible(true);
    }
    

    但是,您需要按正确的顺序排列钢琴键 (:)):

    【讨论】:

    • 太棒了!这似乎是一个愚蠢的问题,但我可以将 ActionListeners 和 text 分配给那些匿名 JButtons 吗?
    • 发布另一个问题,以便我得到接受! ;) 好吧,只需添加 b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { /*your code*/ } });
    【解决方案3】:

    除了编写自己的布局管理器之外,您还可以使用null LayoutManager(即没有自动布局管理)并手动定位键。然后在容器上使用setComponentZOrder 确保黑键出现在白键上方。

    【讨论】:

    • 你会如何处理aioobe遇到的问题?
    • 嗯,在我运行 1.6.0_22 的 OSX 上,我看不到 z 排序有任何问题。
    【解决方案4】:

    GridBag 布局确实允许小部件重叠;您可以使用重叠跨度来构建您想要的布局。但是,是的,编写自己的布局管理器会更好。

    【讨论】:

      【解决方案5】:

      我在 Swing 中做过几款游戏,我发现不使用布局管理器或自己制作会更容易。例如,我有一个纸牌游戏和一个自定义布局管理器,它查看纸牌的播放位置并根据它和当前面板大小定位它。

      【讨论】:

        【解决方案6】:

        posting 中查看 Darryl 的解决方案(最后的回复)。它变得棘手并使用“按钮”作为黑色按钮,因此它绘制在白色“JButton”之上。这可能不适用于允许混合 AWT 和 Swing 组件的新版本 JDK。

        不过,简洁的部分是按键在点击时实际上会发出声音。

        【讨论】:

          猜你喜欢
          • 2012-12-13
          • 1970-01-01
          • 2016-02-02
          • 1970-01-01
          • 2021-10-17
          • 2014-09-20
          • 2016-08-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多