我正在Java Swing中创建虚拟钢琴类型程序。我现在的钢琴键区域是一个JPanel,其水平BoxLayout包含白色JButtons作为白键。我也想添加黑键,让它们与白键重叠。
我尝试过两种不同的方法。一个是使用OverlayLayout。遗憾的是,OverlayLayout管理器在线没有太多文档,并且在NetBeans GUI构建器中不可用。我不知道如何让它发挥作用。我尝试过的第二件事是使用JLayeredPanes。即使在Netbeans中弄乱它之后,我似乎无法想出那个。
所以我认为我的问题非常简单。如果有的话,在其他JButton之上添加JButton的最佳方法是什么?或者也许可以使用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);
}
}
谢谢你们!现在我需要以某种方式将监听器和文本附加到这些按钮上。
答案 0 :(得分:5)
我会编写一个自定义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顺序的组件上绘制。
这是一个丑陋的黑客,它使用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);
}
}
答案 1 :(得分:3)
这是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);
}
但是,您需要按照正确的顺序布置钢琴键(:)):
答案 2 :(得分:1)
除了编写自己的布局管理器之外,您可以使用null
LayoutManager(即没有自动布局管理)并手动定位键。然后在容器上使用setComponentZOrder
以确保黑键出现在白色上方。
答案 3 :(得分:0)
GridBag布局确实允许窗口小部件重叠;您可以使用重叠跨度来构建所需的布局。但是,是的,编写自己的布局管理器会更好。
答案 4 :(得分:0)
我在Swing中做了几个游戏,我发现不使用布局管理器或制作自己的游戏更容易。例如,我有一个纸牌游戏和一个自定义布局管理器,可以查看卡片的播放位置,并根据该卡片和当前面板大小对其进行定位。
答案 5 :(得分:0)
查看此posting中的Darryl解决方案(最后一个回复)。它变得棘手并使用“按钮”作为黑色按钮,因此它绘制在白色“JButton”之上。这可能不适用于允许混合AWT和Swing组件的JDK的新版本。
然而,整洁的部分是按键在点击时实际产生声音。