为 DnD 拼图编写一个小应用程序并遇到 JButton 数组的问题
Writing a small app for a DnD puzzle and have trouble with a JButton array
将 class Puzzle 的对象添加到 Main 后,一切都会按应有的方式显示。当我点击任何按钮时,一些状态索引应该交换到相反的位置,从真到假或从假到真。
不幸的是,单击按钮并不想注册数组中的任何按钮,但它确实注册了一个由其自身初始化的按钮。我该如何解决这个问题?
我的代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
public class Puzzle extends JFrame implements ActionListener
{
int doors = 8;
boolean [] state = new boolean[doors];
JButton [] levers = new JButton[doors];
JButton weird = new JButton("weird lever");
JLabel display = new JLabel();
Puzzle()
{
reset();
this.setSize(new Dimension(1920, 1080));
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
this.setResizable(false);
this.setLayout(null);
this.add(display);
this.add(weird);
int num = levers.length;
int start = 50;
int size = (1920-(num+1)*start)/num;
char label = 'A';
display.setBounds(size*2, 150, 2000, 300);
display.setFont(new Font("Arial Black", Font.PLAIN, 200));
Display();
for(JButton i : levers)
{
i = new JButton(String.valueOf(label));
label++;
i.setBounds(start, 500, size, size);
start+=(size+50);
i.addActionListener(this);
i.setFont(new Font("Arial black", Font.PLAIN, size/2));
i.setFocusable(false);
this.add(i);
}
weird.setFocusable(false);
weird.setBounds(550, 800, 800, 200);
weird.setFont(new Font("Arial Black", Font.PLAIN, size/2));
weird.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e)
{
/*if(e.getSource() == levers[0])
{
state[2] = Swap(state[2]);
Display();
}
if(e.getSource() == levers[1])
{
state[4] = Swap(state[4]);
state[6] = Swap(state[6]);
Display();
}
if(e.getSource() == levers[2])
{
state[2] = Swap(state[2]);
state[3] = Swap(state[3]);
state[6] = Swap(state[6]);
state[7] = Swap(state[7]);
Display();
}
if(e.getSource() == levers[3])
{
state[0] = Swap(state[0]);
state[2] = Swap(state[2]);
state[7] = Swap(state[7]);
Display();
}
if(e.getSource() == levers[4])
{
state[1] = Swap(state[1]);
state[3] = Swap(state[3]);
state[4] = Swap(state[4]);
state[5] = Swap(state[5]);
Display();
}
if(e.getSource() == levers[5])
{
state[0] = Swap(state[0]);
state[2] = Swap(state[2]);
state[6] = Swap(state[6]);
Display();
}
if(e.getSource() == levers[6])
{
state[1] = Swap(state[1]);
state[5] = Swap(state[5]);
Display();
}
if(e.getSource() == levers[7])
{
state[1] = Swap(state[1]);
state[2] = Swap(state[2]);
state[4] = Swap(state[4]);
state[5] = Swap(state[5]);
Display();
}
*/
if(e.getSource() == levers[0])
{
display.setText("A works");
}
if(e.getSource() == weird)
{
display.setText("test");
}
}
boolean Swap(boolean n)
{
return !n;
}
void Display()
{
StringBuilder toDisplay = new StringBuilder();
for (boolean j : state)
{
if (j)
{
toDisplay.append("| ");
} else
toDisplay.append("_ ");
}
display.setText(toDisplay.toString());
}
void reset ()
{
Arrays.fill(state, true);
}
}```
button clicking doesn't want to register for any of the buttons from the array yet it does register for a single button
System.out.println( levers[0] );
if(e.getSource() == levers[0])
{
display.setText("A works");
}
向您的 ActionListener 添加一些调试代码,您将看到 levers[0]
的值为“null”。
for(JButton i : levers)
{
i = new JButton(String.valueOf(label));
label++;
i.setBounds(start, 500, size, size);
start+=(size+50);
i.addActionListener(this);
i.setFont(new Font("Arial black", Font.PLAIN, size/2));
i.setFocusable(false);
this.add(i);
}
您创建了按钮,但从未将每个按钮的实例添加到数组中。
for(JButton i : levers)
为什么要使用“i”作为变量名。通常“i”用作索引。使用适当的变量名称,例如“按钮”。但是,在这种情况下,您不想使用“for each”循环。
相反,您需要一个普通的 for 循环,这样您就可以在创建数组时为数组编制索引以添加每个按钮:
//for(JButton i : levers)
for (int i = 0; i < doors; i++)
{
JButton button = new JButton(String.valueOf(label));
levers[i] = button;
...
其他问题:
- 方法名称不应以大写字符开头。
- 应在框架可见之前将组件添加到框架。
- 应在
Event Dispatch Thread (EDT)
上创建组件。
- 不要使用空布局和 setBounds()。 Swing 旨在与布局管理器一起使用。
- 不要硬编码屏幕尺寸。相反,您可以使用
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
,因此它适用于所有屏幕尺寸。
简介
你的代码太复杂了,我看不懂。我喜欢简单的代码。简短的方法和简单的 classes.
这是我想出的 GUI。
这是我点击几个字母后的 GUI JButtons
说明
Oracle 有一个漂亮的教程 Creating a GUI With JFC/Swing,它将向您展示如何创建 Swing GUI。跳过 Netbeans 部分。
您的代码缺少一个主要方法,所以我添加了一个。我通过调用 SwingUtilities
invokeLater
方法启动了 Swing 应用程序。此方法确保在 Event Dispatch Thread.
上创建和执行 Swing 组件
我做的第一件事是创建一个 PuzzleModel
class 来保存布尔数组。将模型与视图和控制器分开是个好主意 classes。此模式是 model / view / controller (MVC) 模式。
一个 Swing JFrame
可以包含多个 JPanels
。我创建了一个段 JPanel
来容纳一个 JLabel
和一个 JButton
垂直对齐。我使用 GridBagLayout
来对齐 JLabel
和 JButton
。 Swing layout managers 帮助您避免绝对定位和绝对定位带来的问题。
我创建了一个主 JPanel
来容纳 8 个部分 JPanels
。这些 JPanels
与 FlowLayout
.
对齐
如您所见,我的 JFrame
比您的小。您创建尽可能小的 JFrame
。如果用户想把它变大,那就是右上角的矩形。
Swing 应由内而外进行设计。您没有指定 JFrame
大小并尝试使组件适合。您创建组件并让 Swing 确定 JFrame
的大小。如果您希望我创建的 JFrame
更大,请增大字体大小。提示:72 点的分数或倍数在大多数显示器上看起来更好。
我创建了两个 ActionListener
classes,一个用于字母表 JButtons
,一个用于杠杆 JButton
。这样可以更轻松地专注于字母表 JButtons
。在 ActionListener
中,您所要做的就是在左键单击每个 JButton 时交换适当的 isVertical
布尔值。我只是翻转了相应的布尔值作为演示。
代码
这是完整的可运行代码。
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PuzzleGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new PuzzleGUI());
}
private JLabel[] leverLabel;
private final PuzzleModel model;
public PuzzleGUI() {
this.model = new PuzzleModel();
}
@Override
public void run() {
JFrame frame = new JFrame("Weird Lever");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.AFTER_LAST_LINE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
System.out.println(frame.getSize());
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
char c = 'A';
boolean[] isVertical = model.getIsVertical();
leverLabel = new JLabel[isVertical.length];
for (int i = 0; i < isVertical.length; i++) {
String labelText = (isVertical[i]) ? "|" : "-";
panel.add(createLeverButtonPanel(labelText, Character.toString(c), i));
c = (char) (((int) c) + 1);
}
return panel;
}
public void updateMainPanel() {
boolean[] isVertical = model.getIsVertical();
for (int i = 0; i < isVertical.length; i++) {
String labelText = (isVertical[i]) ? "|" : "-";
leverLabel[i].setText(labelText);
}
}
private JPanel createLeverButtonPanel(String labelText, String buttonText, int index) {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
Font font1 = new Font("Arial Black", Font.PLAIN, 144);
Font font2 = new Font("Arial Black", Font.PLAIN, 72);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
leverLabel[index] = new JLabel(labelText);
leverLabel[index].setFont(font1);
panel.add(leverLabel[index], gbc);
gbc.gridy++;
JButton button = new JButton(buttonText);
button.addActionListener(new AlphabetButtonListener());
button.setFont(font2);
panel.add(button, gbc);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
Font font2 = new Font("Arial Black", Font.PLAIN, 48);
JButton button = new JButton("Weird Lever");
button.addActionListener(new LeverButtonListener());
button.setFont(font2);
panel.add(button);
return panel;
}
public class AlphabetButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
String text = button.getText();
char c = text.charAt(0);
int index = ((int) c - 'A');
model.swap(index);
updateMainPanel();
}
}
public class LeverButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
// TODO Auto-generated method stub
}
}
public class PuzzleModel {
private boolean[] isVertical;
public PuzzleModel() {
int doors = 8;
this.isVertical = new boolean[doors];
reset();
}
private void reset() {
Arrays.fill(isVertical, true);
}
public void swap(int index) {
isVertical[index] = !isVertical[index];
}
public boolean[] getIsVertical() {
return isVertical;
}
}
}
将 class Puzzle 的对象添加到 Main 后,一切都会按应有的方式显示。当我点击任何按钮时,一些状态索引应该交换到相反的位置,从真到假或从假到真。
不幸的是,单击按钮并不想注册数组中的任何按钮,但它确实注册了一个由其自身初始化的按钮。我该如何解决这个问题?
我的代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
public class Puzzle extends JFrame implements ActionListener
{
int doors = 8;
boolean [] state = new boolean[doors];
JButton [] levers = new JButton[doors];
JButton weird = new JButton("weird lever");
JLabel display = new JLabel();
Puzzle()
{
reset();
this.setSize(new Dimension(1920, 1080));
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
this.setResizable(false);
this.setLayout(null);
this.add(display);
this.add(weird);
int num = levers.length;
int start = 50;
int size = (1920-(num+1)*start)/num;
char label = 'A';
display.setBounds(size*2, 150, 2000, 300);
display.setFont(new Font("Arial Black", Font.PLAIN, 200));
Display();
for(JButton i : levers)
{
i = new JButton(String.valueOf(label));
label++;
i.setBounds(start, 500, size, size);
start+=(size+50);
i.addActionListener(this);
i.setFont(new Font("Arial black", Font.PLAIN, size/2));
i.setFocusable(false);
this.add(i);
}
weird.setFocusable(false);
weird.setBounds(550, 800, 800, 200);
weird.setFont(new Font("Arial Black", Font.PLAIN, size/2));
weird.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e)
{
/*if(e.getSource() == levers[0])
{
state[2] = Swap(state[2]);
Display();
}
if(e.getSource() == levers[1])
{
state[4] = Swap(state[4]);
state[6] = Swap(state[6]);
Display();
}
if(e.getSource() == levers[2])
{
state[2] = Swap(state[2]);
state[3] = Swap(state[3]);
state[6] = Swap(state[6]);
state[7] = Swap(state[7]);
Display();
}
if(e.getSource() == levers[3])
{
state[0] = Swap(state[0]);
state[2] = Swap(state[2]);
state[7] = Swap(state[7]);
Display();
}
if(e.getSource() == levers[4])
{
state[1] = Swap(state[1]);
state[3] = Swap(state[3]);
state[4] = Swap(state[4]);
state[5] = Swap(state[5]);
Display();
}
if(e.getSource() == levers[5])
{
state[0] = Swap(state[0]);
state[2] = Swap(state[2]);
state[6] = Swap(state[6]);
Display();
}
if(e.getSource() == levers[6])
{
state[1] = Swap(state[1]);
state[5] = Swap(state[5]);
Display();
}
if(e.getSource() == levers[7])
{
state[1] = Swap(state[1]);
state[2] = Swap(state[2]);
state[4] = Swap(state[4]);
state[5] = Swap(state[5]);
Display();
}
*/
if(e.getSource() == levers[0])
{
display.setText("A works");
}
if(e.getSource() == weird)
{
display.setText("test");
}
}
boolean Swap(boolean n)
{
return !n;
}
void Display()
{
StringBuilder toDisplay = new StringBuilder();
for (boolean j : state)
{
if (j)
{
toDisplay.append("| ");
} else
toDisplay.append("_ ");
}
display.setText(toDisplay.toString());
}
void reset ()
{
Arrays.fill(state, true);
}
}```
button clicking doesn't want to register for any of the buttons from the array yet it does register for a single button
System.out.println( levers[0] );
if(e.getSource() == levers[0])
{
display.setText("A works");
}
向您的 ActionListener 添加一些调试代码,您将看到 levers[0]
的值为“null”。
for(JButton i : levers)
{
i = new JButton(String.valueOf(label));
label++;
i.setBounds(start, 500, size, size);
start+=(size+50);
i.addActionListener(this);
i.setFont(new Font("Arial black", Font.PLAIN, size/2));
i.setFocusable(false);
this.add(i);
}
您创建了按钮,但从未将每个按钮的实例添加到数组中。
for(JButton i : levers)
为什么要使用“i”作为变量名。通常“i”用作索引。使用适当的变量名称,例如“按钮”。但是,在这种情况下,您不想使用“for each”循环。
相反,您需要一个普通的 for 循环,这样您就可以在创建数组时为数组编制索引以添加每个按钮:
//for(JButton i : levers)
for (int i = 0; i < doors; i++)
{
JButton button = new JButton(String.valueOf(label));
levers[i] = button;
...
其他问题:
- 方法名称不应以大写字符开头。
- 应在框架可见之前将组件添加到框架。
- 应在
Event Dispatch Thread (EDT)
上创建组件。 - 不要使用空布局和 setBounds()。 Swing 旨在与布局管理器一起使用。
- 不要硬编码屏幕尺寸。相反,您可以使用
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
,因此它适用于所有屏幕尺寸。
简介
你的代码太复杂了,我看不懂。我喜欢简单的代码。简短的方法和简单的 classes.
这是我想出的 GUI。
这是我点击几个字母后的 GUI JButtons
说明
Oracle 有一个漂亮的教程 Creating a GUI With JFC/Swing,它将向您展示如何创建 Swing GUI。跳过 Netbeans 部分。
您的代码缺少一个主要方法,所以我添加了一个。我通过调用 SwingUtilities
invokeLater
方法启动了 Swing 应用程序。此方法确保在 Event Dispatch Thread.
我做的第一件事是创建一个 PuzzleModel
class 来保存布尔数组。将模型与视图和控制器分开是个好主意 classes。此模式是 model / view / controller (MVC) 模式。
一个 Swing JFrame
可以包含多个 JPanels
。我创建了一个段 JPanel
来容纳一个 JLabel
和一个 JButton
垂直对齐。我使用 GridBagLayout
来对齐 JLabel
和 JButton
。 Swing layout managers 帮助您避免绝对定位和绝对定位带来的问题。
我创建了一个主 JPanel
来容纳 8 个部分 JPanels
。这些 JPanels
与 FlowLayout
.
如您所见,我的 JFrame
比您的小。您创建尽可能小的 JFrame
。如果用户想把它变大,那就是右上角的矩形。
Swing 应由内而外进行设计。您没有指定 JFrame
大小并尝试使组件适合。您创建组件并让 Swing 确定 JFrame
的大小。如果您希望我创建的 JFrame
更大,请增大字体大小。提示:72 点的分数或倍数在大多数显示器上看起来更好。
我创建了两个 ActionListener
classes,一个用于字母表 JButtons
,一个用于杠杆 JButton
。这样可以更轻松地专注于字母表 JButtons
。在 ActionListener
中,您所要做的就是在左键单击每个 JButton 时交换适当的 isVertical
布尔值。我只是翻转了相应的布尔值作为演示。
代码
这是完整的可运行代码。
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PuzzleGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new PuzzleGUI());
}
private JLabel[] leverLabel;
private final PuzzleModel model;
public PuzzleGUI() {
this.model = new PuzzleModel();
}
@Override
public void run() {
JFrame frame = new JFrame("Weird Lever");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.AFTER_LAST_LINE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
System.out.println(frame.getSize());
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
char c = 'A';
boolean[] isVertical = model.getIsVertical();
leverLabel = new JLabel[isVertical.length];
for (int i = 0; i < isVertical.length; i++) {
String labelText = (isVertical[i]) ? "|" : "-";
panel.add(createLeverButtonPanel(labelText, Character.toString(c), i));
c = (char) (((int) c) + 1);
}
return panel;
}
public void updateMainPanel() {
boolean[] isVertical = model.getIsVertical();
for (int i = 0; i < isVertical.length; i++) {
String labelText = (isVertical[i]) ? "|" : "-";
leverLabel[i].setText(labelText);
}
}
private JPanel createLeverButtonPanel(String labelText, String buttonText, int index) {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
Font font1 = new Font("Arial Black", Font.PLAIN, 144);
Font font2 = new Font("Arial Black", Font.PLAIN, 72);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
leverLabel[index] = new JLabel(labelText);
leverLabel[index].setFont(font1);
panel.add(leverLabel[index], gbc);
gbc.gridy++;
JButton button = new JButton(buttonText);
button.addActionListener(new AlphabetButtonListener());
button.setFont(font2);
panel.add(button, gbc);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
Font font2 = new Font("Arial Black", Font.PLAIN, 48);
JButton button = new JButton("Weird Lever");
button.addActionListener(new LeverButtonListener());
button.setFont(font2);
panel.add(button);
return panel;
}
public class AlphabetButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
String text = button.getText();
char c = text.charAt(0);
int index = ((int) c - 'A');
model.swap(index);
updateMainPanel();
}
}
public class LeverButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
// TODO Auto-generated method stub
}
}
public class PuzzleModel {
private boolean[] isVertical;
public PuzzleModel() {
int doors = 8;
this.isVertical = new boolean[doors];
reset();
}
private void reset() {
Arrays.fill(isVertical, true);
}
public void swap(int index) {
isVertical[index] = !isVertical[index];
}
public boolean[] getIsVertical() {
return isVertical;
}
}
}