首页 文章

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

提问于
浏览
1

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

扩展JPanel的类'Panel'有一个方法public void paintComponent(Graphics g){},在里面我添加了一些JButtons并使用了g.drawString .

然后在'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 回答

  • 4

    我需要在actionPerformed里面使用paintg of paintComponent . “`

    不,你不会_St5599_的paintComponent方法,并且当它只调用paintComponent方法时,它将从JVM传递给它 . 然后actionPerformed方法将更改String变量的值或者更改 ArrayList<String> ,调用 repaint() ,然后JPanel的paintComponent方法将使用更改的String来绘制相应的文本 .

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


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

    • 请尝试稍微修改您的代码,以使其可编译或尽可能接近可编译 .

    • 除了在 paintComopnent(...) 方法内部绘画外,切勿添加组件或执行任何操作 . 你没有't have full control over when or even if that method will be called, and placing something in inside of this method will result in unwanted side effects, like combo boxes that simply won'工作 .

    • 如果您希望程序中显示文本,则始终可以添加JLabel .

    • 您的程序使用空布局和 setBounds(...) 导致严格的GUI,在一个系统上可能看起来不错,但在任何其他系统或屏幕分辨率上通常看起来很差 . 此外,以这种方式创建的程序非常难以调试,维护和升级 . 而是使用布局管理器,因为这是他们擅长的:创建可以轻松增强和更改的复杂灵活的GUI .


    Edit
    我猜你真正想做什么,可能是添加更多组件以允许用户在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

相关问题