Заставить JButtons перекрываться - PullRequest
5 голосов
/ 25 ноября 2010

Я создаю виртуальную программу типа фортепиано на Java Swing. Моя область для клавиш пианино сейчас - это JPanel с горизонтальной BoxLayout, содержащей белые JButton в качестве белых клавиш. Я также хочу добавить черные клавиши, чтобы они перекрывали белые клавиши.

Я пробовал два разных подхода. Один использует OverlayLayout. К сожалению, для менеджера OverlayLayout в Интернете не так много документации, и она недоступна в построителе графического интерфейса пользователя NetBeans. Я понятия не имею, как заставить это работать. Второе, что я попробовал - это использование JLayeredPanes. Я не могу понять это, даже после того, как возиться с этим в Netbeans.

Так что я думаю, что мой вопрос довольно прост. Каков наилучший подход, если он есть, для добавления JButtons поверх других JButton? Или, может быть, есть альтернатива использованию кнопок J для клавиш пианино?

EDIT

Я объединил код aioobe и dacwe, чтобы получить желаемый результат. Я в основном использовал z-упорядочение dacwe с базовыми размерами aioobe (немного увеличенное) и часть 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);
    }
}

Спасибо, ребята! Теперь мне нужно как-то прикрепить слушатель и текст к этим кнопкам.

Ответы [ 6 ]

5 голосов
/ 25 ноября 2010

Я бы написал пользовательский 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);

От Использование учебного курса по компонентам Swing

Примечание: Z-порядок определяет порядок окрашивания компонентов.Компонент с самым высоким z-порядком рисует первым, а компонент с самым низким z-порядком рисует первым.Там, где компоненты перекрываются, компонент с более низким z-порядком закрашивает компонент с более высоким z-порядком.

Вот уродливый хак, который использует null-layout для начала работы.

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

enter image description here

3 голосов
/ 25 ноября 2010

Это пример многоуровневой панели (она работает так, как вы ожидаете):

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

Однако вам необходимо расположить клавиши пианино в правильном порядке (:)):

alt text

1 голос
/ 25 ноября 2010

Помимо написания собственного менеджера макетов, вы можете просто использовать null LayoutManager (то есть без автоматического управления макетом) и расположить клавиши вручную. Затем используйте setComponentZOrder на контейнере, чтобы убедиться, что черные клавиши появляются над белыми.

0 голосов
/ 26 ноября 2010

Проверьте решение Дэррила (последний ответ) в этом сообщении .Он становится хитрым и использует «кнопку» в качестве черной кнопки, поэтому он рисует поверх белого «JButton».Это, вероятно, не будет работать в новых версиях JDK, которые позволяют микшировать компоненты AWT и Swing.

Тем не менее, важная часть заключается в том, что клавиши при нажатии нажимают на звук.

0 голосов
/ 25 ноября 2010

Я сделал пару игр на Swing, и я считаю, что проще не использовать менеджер макетов и не создавать свои собственные. Например, у меня есть карточная игра и собственный менеджер раскладки, который смотрит, где была разыграна карта, и размещает ее в зависимости от этого и текущего размера панели.

0 голосов
/ 25 ноября 2010

Макет GridBag позволяет перекрывать виджеты; Вы можете использовать перекрывающиеся интервалы для создания макета, который вы хотите. Но да, написание собственного менеджера верстки будет приятнее.

...