Написание небольшого приложения для головоломки DnD и проблемы с массивом JButton

#java #arrays #swing #jframe #jbutton

Вопрос:

После добавления объекта класса Puzzle в Main все отображается в основном так, как должно. когда я нажимаю на любую из кнопок, некоторые индексы состояния должны меняться на противоположные, так что от true к false или от false к true.

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

мой код:

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

}```
 

Ответ №1:

нажатие кнопки не хочет регистрироваться ни для одной кнопки из массива, но все же регистрируется для одной кнопки

 System.out.println( levers[0] );

if(e.getSource() == levers[0])
{
    display.setText("A works");
}
 

Добавьте некоторый отладочный код в свой список действий, и вы увидите, что значение 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». Используйте правильное имя переменной, например «кнопка». Однако в этом случае вы не хотите использовать цикл «для каждого».

Вместо этого вам нужен обычный цикл for, чтобы вы могли индексировать свой массив, добавляя каждую кнопку по мере ее создания:

 //for(JButton i : levers)
for (int i = 0; i < doors; i  )
{
    JButton button = new JButton(String.valueOf(label));
    levers[i] = button;
    ...
 

Другие вопросы:

  1. имена методов не должны начинаться с символа верхнего регистра.
  2. компоненты должны быть добавлены в рамку ДО того, как рамка станет видимой.
  3. компоненты должны быть созданы на Event Dispatch Thread (EDT) .
  4. Не используйте нулевую компоновку и setBounds(). Swing был разработан для использования с менеджерами по компоновке.
  5. Не устанавливайте размеры экрана жестко. Вместо этого вы можете использовать frame.setExtendedState(JFrame.MAXIMIZED_BOTH); , поэтому он будет работать для всех размеров экрана.

Комментарии:

1. Спасибо, я бы сделал обычный цикл for, но Intellij предложил вместо этого использовать для каждого.

Ответ №2:

Введение

Ваш код был слишком сложным, чтобы я мог его понять. Мне нравится простой код. Короткие методы и простые классы.

Вот графический интерфейс, который я придумал.

Странный Рычаг

Вот графический интерфейс после того, как я нажал пару букв JButtons

Странный Рычаг

Объяснение

У Oracle есть отличный учебник по созданию графического интерфейса с помощью JFC/Swing, который покажет вам, как создать графический интерфейс Swing. Пропустите раздел Netbeans.

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

Первое, что я сделал, это создал PuzzleModel класс для хранения логического массива. Это хорошая идея, чтобы отделить вашу модель от вашего представления и классов контроллеров. Этот шаблон является шаблоном модели / представления / контроллера (MVC).

Качели JFrame могут содержать много JPanels . Я создал сегмент JPanel для размещения a JLabel и a JButton , выровненных по вертикали. Я использовал GridBagLayout его для выравнивания JLabel и. JButton Менеджеры по компоновке Swing помогут вам избежать абсолютного позиционирования и проблем, связанных с абсолютным позиционированием.

Я создал основную JPanel для размещения 8 сегментов JPanels . Они JPanels выровнены с a FlowLayout .

Как вы можете видеть, мой JFrame размер меньше вашего. Вы создаете JFrame как можно меньшее число «а». Если пользователь хочет сделать его больше, для этого и предназначен прямоугольник в правом верхнем углу.

Качели предназначены для того, чтобы быть спроектированными изнутри наружу. Вы не указываете JFrame размер и не пытаетесь подгонять компоненты. Вы создаете компоненты и позволяете Swing определять размер JFrame . Если вы хотите JFrame , чтобы созданный мной шрифт был больше, увеличьте размеры шрифта. Подсказка: Доля или кратность 72 баллов выглядит лучше на большинстве дисплеев.

Я создал два ActionListener класса, один для алфавита JButtons , а другой для рычага JButton . Это облегчает фокусировку на алфавите JButtons . Все, что вам нужно сделать ActionListener , — это поменять местами соответствующие 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;
        }
        
    }
    
}