Making JButtons overlap

假如想象 提交于 2019-12-03 15:15:04

I would write a custom PianoLayoutManager and position the black keys with a higher z-order than the white buttons. Create your own "constraint" class that allows you to add components like this:

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);

From Using Swing Components tutorial trail

Note: The z-order determines the order that components are painted. The component with the highest z-order paints first and the component with the lowest z-order paints last. Where components overlap, the component with the lower z-order paints over the component with the higher z-order.

Here is an ugly hack that uses null-layout to get you started.

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);
    }
}

This is an example of layeredpane (it works as you expect):

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);
}

However, you need to lay out the piano keys in the correct order (:)) :

Apart from writing your own layout manager, you could just use a null LayoutManager (that is, no automatic layout management) and position the keys manually. Then use setComponentZOrder on the container to make sure the black keys appear above the white ones.

GridBag layout does allow widget overlapping; You could use overlapping spans to construct the layout You want. But yes, writing own layout manager wold be nicer.

I've done a couple games in Swing, and I find it's easier just not to use a layout manager or make your own. For example I have a card game and a custom layout manager that looks at where the card has been played and positions it based on that and the current panel size.

Check out Darryl's solution (the last reply) in this posting. It gets tricky and uses a "Button" as the black button so it paints on top of the white "JButton". This probably won't work in new versions of the JDK that allow AWT and Swing components to be mixed.

However, the neat part is that the keys actually produce a sound when clicked.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!