Как реализовать ActionListener внутри класса JPanel, который находится внутри другого класса?

1

У меня есть класс под названием "Панель", который расширяет JPanel, и он находится внутри другого класса "Main". Конструктор создает экземпляр JFrame и всех компонентов графического интерфейса пользователя и задает его все, например размер.

Класс "Panel", который расширяет JPanel, имеет метод public void paintComponent (Graphics g) {}, и внутри него я добавил несколько JButtons и использовал g.drawString.

Затем в классе "Основной" я добавил "Панель" в JFrame.

Мой вопрос: я пытаюсь реализовать actionListener для кнопки, добавленной внутри класса Panel. Функция actionListener добавила бы больше кнопок и также использовала g.drawString. Теперь, где бы я поместил ActionListener для этого? Как использовать g.drawString для конкретной панели, а строка g.drawString находится внутри другого класса, который является классом ActionListener? Мне нужно будет использовать Graphics g paintComponent внутри actionPerformed.

Спасибо!

EDIT - ПРИМЕР КОДА:

public class Main{

private JFrame jf;
private JTextField jtf1;
private JTextField jtf2;    
private Panel p;    
private JComboBox jcb1;
private JComboBox jcb2;     
private JButton button;     
private Object options[];

//ActionListener Variables
private int string1 = 150;
private int string2 = 150;      
private int yJtf1 = 150;
private int yJtf2 = 160;        
private int cb1 = 140;
private int cb2 = 165;      
private int count = 0;

    public Main(){

        jf= new JFrame();
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setSize(700, 700);

        p = new Panel();

        jtf1 = new JTextField("", 20);
        jtf2= new JTextField("", 20);

        Object options[] = {""};

        jcb1 = new JComboBox(tools);
        jcb2 = new JComboBox(tools);

        button = new JButton("+");

        jf.add(p);
        jf.setVisible(true);'
    }

    public class Panel extends JPanel{

        public Panel(){
            this.setLayout(null);
        }

        public void paintComponent(Graphics g){

            super.paintComponent(g);

            /*button.addActionListener(new ActionListener(){  //Would this work or should the ActionListener be a class as shown below?
                public void actionPerformed(ActionEvent e){

                    if(count < 3){ //Won't be allowed to add anymore after 3 times
                        string1 += 50;
                        string2 += 50;

                        jtf1 += 50;
                        jtf2 += 50;

                        cb1 += 50;
                        cb2 += 45;

                        //Would like to add the following components to the 'Panel' (which is a JPanel) whenever the JButton 'button' already added to 'Panel' is clicked.
                        p.add(jtf1); //Would doing p.add really add to the panel when the ActionListener is called?
                        jtf1.setBounds(60, yJtf1, 50, 40);
                        p.add(jtf2);
                        jtf2.setBounds(60, yJtf2, 50, 40);

                        add(jcb1);
                        jcb1.setBounds(250, cb1, 50, 40);
                        add(left2);
                        jcb2.setBounds(250, cb2, 50, 40);

                        Font font = new Font("TimesRoman", Font.BOLD, 18);
                        g.setFont(font);  //Getting error on 'g' regardless

                        g.drawString("Hi", 15, string1); //This is the main problem, how would I be able to add this strings to the 'Panel' (which is a JPanel)
                        g.drawString("There", 330, string1);
                    }
                    count++;
                }
            });*/

            add(jtf1);
            jtf1.setBounds(100, 30, 120, 30);
            add(jtf2);
            ljtf2.setBounds(100, 60, 120, 30);

            add(button);
            plusButton.setBounds(200,150, 50, 50);
            //button.addActionListener(new ButtonClicked()); if doing ActionListener via class like below

            add(jcb1);
            jcb1.setBounds(300, 350, 100, 50);
            add(ljcb2);
            jcb2.setBounds(300, 350, 100, 25);

            Font font = new Font("Arial", Font.BOLD, 12);
            g.setFont(font);
            g.drawString("Item:", 40, 45);
            g.drawString("Cost:", 40, 75);
        }
    }


    public static void main(String [] args){
        new Main();
    }

    class ButtonClicked implements ActionListener{ //Action Listener: The follow is what I am trying to implement
        public void actionPerformed(ActionEvent ae){
            if(count < 3){ //Won't be allowed to add anymore after 3 times
                string1 += 50;
                string2 += 50;

                jtf1 += 50;
                jtf2 += 50;

                cb1 += 50;
                cb2 += 45;

                //Would like to add the following components to the 'Panel' (which is a JPanel) whenever the JButton 'button' already added to 'Panel' is clicked.
                p.add(jtf1); //Would doing p.add really add to the panel when the ActionListener is called?
                jtf1.setBounds(60, yJtf1, 50, 40);
                p.add(jtf2);
                jtf2.setBounds(60, yJtf2, 50, 40);

                mp.add(jcb1);
                jcb1.setBounds(250, cb1, 50, 40);
                mp.add(left2);
                jcb2.setBounds(250, cb2, 50, 40);

                Font font = new Font("TimesRoman", Font.BOLD, 18);
                g.setFont(font); 

                g.drawString("Hi", 15, string1); //This is the main problem, how would I be able to add this strings to the 'Panel' (which is a JPanel)
                g.drawString("There", 330, string1);
            }
            count++;
        }
    }
}
  • 0
    Извините, но я не могу заставить ваш код компилироваться. В нем слишком много вопросов. Но если коротко ответить на ваш вопрос внутри вашего кода, нет, это не сработает. Ваш код не имеет смысла. paintComponent предназначен только для рисования (без добавления ActionListener или изменения состояния компонента). Кстати, прекратите использовать абсолютное позиционирование и начните использовать LayoutManager: это облегчит вашу жизнь.
  • 0
    @GuillaumePolet Это просто фрагмент полного кода. Тогда как мне поступить так, например, сделать g.drawString как ActionListener для конкретного JPanel при каждом нажатии кнопки, добавленной в класс Panel?
Показать ещё 2 комментария
Теги:
user-interface
graphics
swing
actionlistener

1 ответ

4

Мне нужно будет использовать Graphics g paintComponent внутри actionPerformed. "'

Нет, вы не будете с тех пор, как графика Swing не активна. Объект Graphics будет находиться в методе JPanel paintComponent и будет передан ему из JVM, когда он и только вызывает метод paintComponent. Метод actionPerformed затем изменит значение переменной String или, возможно, ArrayList<String>, call repaint(), а затем метод JPanel paintComponent будет использовать измененную строку для рисования соответствующего текста.

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


редактировать
При просмотре кода у меня есть несколько предложений:

  • Попробуйте немного исправить свой код, чтобы он был либо компилируемым, либо как можно более компилируемым.
  • Никогда не добавляйте компоненты или ничего не делайте, кроме как рисовать внутри вашего метода paintComopnent(...). У вас нет полного контроля над тем, когда или даже если этот метод будет вызван, а помещение чего-то внутри этого метода приведет к нежелательным побочным эффектам, например, комбинированным полям, которые просто не будут работать.
  • Если вам когда-либо понадобился текст, показанный в вашей программе, вы всегда можете добавить JLabel.
  • Ваша программа использует нулевой макет и setBounds(...) что-то, что приводит к жесткому графическому интерфейсу, который может выглядеть хорошо в одной системе, но обычно будет выглядеть неудовлетворительным при любой другой системе или разрешении экрана. Также создаваемые таким образом программы очень сложно отлаживать, поддерживать и обновлять. Вместо этого используйте менеджеров компоновки, так как это то, чем они превосходят: при создании сложного гибкого графического интерфейса, который может быть легко улучшен и изменен.

редактировать
Я предполагаю, что вы действительно хотите сделать, и, возможно, это добавить дополнительные компоненты, чтобы позволить пользователю вводить больше данных в графический интерфейс. Вы также хотите добавить текст, возможно, для того, чтобы направлять пользователя в том, что может быть для целей компонентов. Если это так, лучшим решением является не добавление Strings в GUI в paintComponent, а скорее добавление Strings/Components организованным способом с использованием строк, отображаемых в JLabels, а также компонентов и ярлыков, хранящихся в JPanel или JPanels и добавлен в графический интерфейс с использованием менеджеров компоновки.

Например, если вы хотите, чтобы пользователь добавлял данные в два поля JText и имел два JComboBoxes, а затем разрешил пользователю добавлять еще 3 из этих парней, если это необходимо, графический интерфейс мог бы выглядеть примерно так:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;

@SuppressWarnings("serial")
public class Main2 extends JPanel {
   private List<DataPanel> dataPanelList = new ArrayList<>();
   private JPanel dataPanelHolder = new JPanel();

   public Main2() {
      DataPanel dataPanel = new DataPanel();
      dataPanelList.add(dataPanel);
      setLayout(new BorderLayout());      
      dataPanelHolder.setLayout(new BoxLayout(dataPanelHolder, BoxLayout.PAGE_AXIS));
      dataPanelHolder.add(dataPanel);
      JPanel innerBorderLayoutPanel = new JPanel(new BorderLayout());
      innerBorderLayoutPanel.add(dataPanelHolder, BorderLayout.PAGE_START);

      JScrollPane scrollPane = new JScrollPane(innerBorderLayoutPanel);
      scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      int w = dataPanel.getPreferredSize().width;
      int h = dataPanel.getPreferredSize().height * 4;
      Dimension viewPortSize = new Dimension(w, h);
      scrollPane.getViewport().setPreferredSize(viewPortSize);

      JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
      buttonPanel.add(new JButton(new AddDatatAction("Add")));
      buttonPanel.add(new JButton(new ExitAction("Exit", KeyEvent.VK_X)));

      add(scrollPane, BorderLayout.CENTER);
      add(buttonPanel, BorderLayout.PAGE_END);
   }

   private class AddDatatAction extends AbstractAction {
      private int maxCount = 4;
      public AddDatatAction(String name) {
         super(name);
         int mnemonic = (int)name.charAt(0);
         putValue(MNEMONIC_KEY, mnemonic);
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         if (dataPanelList.size() < maxCount) {
            DataPanel dataPanel = new DataPanel();
            dataPanelList.add(dataPanel);
            dataPanelHolder.add(dataPanel);
            dataPanelHolder.revalidate();
            dataPanelHolder.repaint();
         }
      }
   }

   private class ExitAction extends AbstractAction {
      public ExitAction(String name, int mnemonic) {
         super(name);
         putValue(MNEMONIC_KEY, mnemonic);
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         Window win = SwingUtilities.getWindowAncestor(Main2.this);
         win.dispose();
      }
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("Main2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new Main2());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

@SuppressWarnings("serial")
class DataPanel extends JPanel {
   private static final String[] TOOLS = {"Tool 1", "Tool 2", "Tool 3", "Tool 4"};
   private static final String[] FIELD_LABELS = {"Item", "Cost"};
   private static final String[] COMBO_LABELS = {"Foo", "Bar"};
   private JTextField[] fields = new JTextField[FIELD_LABELS.length];
   private List<JComboBox<String>> comboList = new ArrayList<>();

   public DataPanel() {
      setBorder(BorderFactory.createTitledBorder("Data"));
      setLayout(new GridBagLayout());
      for (int i = 0; i < FIELD_LABELS.length; i++) {
         add(new JLabel(FIELD_LABELS[i]), createGbc(0, i));
         fields[i] = new JTextField(10);
         add(fields[i], createGbc(1, i));

         JComboBox<String> combo = new JComboBox<>(TOOLS);
         comboList.add(combo);
         add(combo, createGbc(2, i));
         add(new JLabel(COMBO_LABELS[i]), createGbc(3, i));         
      }
   }

   public static GridBagConstraints createGbc(int x, int y) {
      GridBagConstraints gbc = new GridBagConstraints();
      gbc.gridx = x;
      gbc.gridy = y;
      gbc.gridwidth = 1;
      gbc.gridheight = 1;
      gbc.weightx = 1.0;
      gbc.weighty = 1.0;
      int ins = 4;
      gbc.insets = new Insets(ins, ins, ins, ins);
      return gbc;
   }
}

И может выглядеть так:

добавлен один datapanel
Изображение 174551

четыре добавлены:
Изображение 174551

  • 0
    Код добавлен. Спасибо
  • 0
    @OM: Спасибо за публикацию этого, и я пытаюсь просмотреть ваш код, но есть много типографских ошибок и подобных проблем, делающих невозможным приблизить его к стадии компиляции. Пожалуйста, попробуйте исправить это, если вам все еще нужна помощь.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню