如何在另一个类中的JPanel类中实现ActionListener?

时间:2014-11-25 17:45:41

标签: java swing user-interface graphics actionlistener

我有一个名为' Panel'它扩展了JPanel,它位于另一个名为' Main'的类中。构造函数实例化JFrame和所有GUI组件,并将其全部设置,例如大小。

班级'小组'扩展JPanel有一个方法public void paintComponent(Graphics g){},在里面我添加了一些JButtons并使用了g.drawString' s。

然后在' Main'上课时,我添加了' Panel'到JFrame。

我的问题是,我正在尝试将一个actionListener实现到一个添加到' Panel'类。 actionListener函数会添加更多按钮并使用g.drawString。现在我在哪里放置ActionListener才能这样做?如何将g.drawString用于特定面板,而g.drawString行位于另一个类中,即ActionListener类?我需要在actionPerformed中使用paintg of paintComponent。

谢谢!

编辑 - 代码示例:

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

1 个答案:

答案 0 :(得分:4)

  

我需要在actionPerformed中使用paintG of paintComponent。&#34;`

不,你不会因为Swing图形被动不活跃。 Graphics对象将驻留在JPanel的paintComponent方法中,当它只调用paintComponent方法时,它将从JVM传递给它。然后,actionPerformed方法将更改String变量的值,或者更改ArrayList<String>,调用repaint(),然后JPanel的paintComponent方法将使用更改的String来绘制相应的文本。 / p>

如果您需要更具体的帮助,请考虑告诉我们更多详情并发布minimal example program


修改
在审核您的代码时,我有几点建议:

  • 请尝试稍微修改您的代码,以使其可编辑或尽可能接近可编译。
  • 除了在paintComopnent(...)方法内部绘画外,不要添加组件或做任何事情。您无法完全控制何时或甚至是否会调用该方法,并且在此方法中放置一些内容会导致不必要的副作用,例如仅仅无法工作的组合框。
  • 如果您希望程序中显示文字,则可以随时添加JLabel。
  • 您的程序使用空布局和setBounds(...)导致严格的GUI在某个系统上看起来不错,但在任何其他系统或屏幕分辨率上看起来都很差。此外,以这种方式创建的程序非常难以调试,维护和升级。而是使用布局管理器,因为这是他们擅长的:创建可以轻松增强和更改的复杂灵活的GUI。

修改
我猜你真正想做什么,可能是添加更多组件以允许用户在GUI中输入更多数据。您还希望添加文本,以引导用户了解组件的用途。如果是这样,那么最好的解决方案是不要在paintComponent中将字符串添加到GUI,而是以有组织的方式添加字符串/组件,其中字符串显示在JLabel中,组件和标签都保存在JPanel中或JPanels,并使用布局管理器添加到GUI。

例如,如果您希望用户在两个JTextfields中添加数据并拥有两个JComboBox,然后允许用户在需要时再添加3个这样的人,GUI可能看起来像这样:

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

可能看起来像:

添加了一个数据通道 enter image description here

四,补充说: enter image description here