Home > Back-end >  JButton not linked to ActionLister
JButton not linked to ActionLister

Time:03-20

public class OpenFrame extends JFrame implements ActionListener {

private static final int WIDTH = 500;
private static final int HEIGHT = 500;
private BudgetPlanner budgetPlanner;

private JFrame openFrame;

private JLabel welcomeMessage;
private JPanel openPanel = new JPanel();
private JPanel inputSpace;

private JButton loadButton = new JButton();
private JButton resetButton = new JButton();
private JButton addIncomeButton;
private JButton addExpenseButton;
private JButton viewExpenseButton;
private JButton viewIncomeButton;

private JTextField inputIncome;

public BudgetPlanner callBudgetPlanner() {
    try {
        budgetPlanner = new BudgetPlanner();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    return budgetPlanner;
}

public OpenFrame() {
    openFrame = new JFrame();
    openFrame.setTitle("BudgetPlanner");
    openFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    openFrame.setResizable(false);
    openFrame.setLayout(null);
    openFrame.setLocationRelativeTo(null);
    openFrame.setSize(new Dimension(WIDTH, HEIGHT));
    openFrame.getContentPane().setBackground(Color.GRAY);
    openPanel();
    openFrame.setContentPane(openPanel);

    openFrame.setVisible(true);
}

public void openPanel() {
    openPanel.setLayout(null);

    welcomeMessage = new JLabel("Hello there! Welcome back. Choose an option below:");
    welcomeMessage.setVerticalTextPosition(TOP);
    welcomeMessage.setHorizontalTextPosition(SwingConstants.CENTER);
    welcomeMessage.setBounds(50, 20, 500, 200);
    welcomeMessage.setFont(new Font("Arial", Font.PLAIN, 17));

    openPanel.setBounds(0, 0, 500, 500);
    openPanel.add(welcomeMessage);

    loadButton.setBounds(200, 170, 100, 50);
    loadButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
    loadButton.setText("Load Data");
    loadButton.addActionListener(this);
    loadButton.setFocusable(false);

    resetButton.setBounds(200, 230, 100, 50);
    resetButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
    resetButton.setText("Reset Data");
    resetButton.addActionListener(this);
    resetButton.setFocusable(false);

    openPanel.add(loadButton);
    openPanel.add(resetButton);
}

public void plannerScreen() {
    JPanel loadPanel = new JPanel();
    openFrame.setContentPane(loadPanel);
    loadPanel.setBounds(0, 0, 500, 500);
    JLabel loadCompleteMessage = new JLabel("Welcome to Budget Planner App.");
    loadCompleteMessage.setBounds(138, TOP, 500, 50);
    loadCompleteMessage.setFont(new Font("Arial", Font.BOLD, 14));
    loadPanel.add(loadCompleteMessage);
    JLabel optionMessage = new JLabel("What would you like to do?");
    optionMessage.setBounds(175, TOP   40, 500, 10);
    optionMessage.setFont(new Font("Arial", Font.ITALIC, 13));
    loadPanel.add(optionMessage);
    openButton();
    loadPanel.add(addIncomeButton);
    loadPanel.add(addExpenseButton);
    loadPanel.add(viewIncomeButton);
    loadPanel.add(viewExpenseButton);
}

public void openButton() {
    addIncomeButton = new JButton("Add Income");
    addIncomeButton.setBounds(180, 110, 140, 45);
    addIncomeButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
    addExpenseButton = new JButton("Add Expense");
    addExpenseButton.setBounds(180, 160, 140, 45);
    addExpenseButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
    viewIncomeButton = new JButton("View Income");
    viewIncomeButton.setBounds(180, 210, 140, 45);
    viewIncomeButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
    viewExpenseButton = new JButton("View Expense");
    viewExpenseButton.setBounds(180, 260, 140, 45);
    viewExpenseButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));

    addIncomeButton.addActionListener(new InputData());

}

@Override
public void actionPerformed(ActionEvent e) {
    if (e.getSource() == loadButton) {
        JOptionPane.showMessageDialog(null, "Loading Complete!");
        plannerScreen();
    }

    if (e.getSource() == resetButton) {
        JOptionPane.showMessageDialog(null, "Saved data erased.");
        plannerScreen();
    }
}

public class InputData implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {
        inputSpace = new JPanel();
        inputSpace.setBounds(0, 300, 500, 200);
        inputIncome = new JTextField("How much is your income?", 20);
        openPanel.add(inputSpace);
        inputSpace.add(inputIncome);
    }
}

My code is as shown above. The issue is that when I click on addIncomeButton, it doesn't get linked to InputData actionlister that I created. Once addIncomeButton is clicked, it doesn't do anything. How do I fix this problem? ;-;

My goal is that once the button is clicked, a JTextField would appear will be added onto the same panel.

Any helps will be appreciated! Thanks so much!

CodePudding user response:

Basic recommendations:

  1. Avoid use of null layout and use of setBounds(...) for component placement as this makes for very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain.
  2. The best way to swap or show/hide components with Swing is to use a CardLayout. Please check out the enter image description here

    in the example code below, I've model and some control code in a SwapModel class:

    import java.beans.*;
    import java.util.*;
    import javax.swing.event.*;
    
    public class SwapModel {
        public static String INCOME = "income";
        private PropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
        private SwapGuiMainPanel mainGui;
        private Deque<String> cardStack = new LinkedList<>();
        private double income = 0;
    
        public SwapModel(SwapGuiMainPanel mainGui) {
            this.mainGui = mainGui;
        }
    
        // when income is changed, update it and notify listeners.
        public void addIncome(double value) {
            double oldValue = this.income;
            double newValue = this.income   value;
            this.income = newValue;
            pcSupport.firePropertyChange(INCOME, oldValue, newValue);
        }
        
        public double getIncome() {
            return income;
        }
    
        // go to the next CardLayout view by calling show and pushing the view's constraint String onto the cardStack
        public void swap(String name) {
            mainGui.getCardLayout().show(mainGui.getHolderPanel(), name);
            cardStack.push(name);
        }
        
        // go to the previous CardLayout view by popping the cardStack.
        public String popCardStack() {
            String name = null;
            if (cardStack.size() > 1) {
                cardStack.pop();
                name = cardStack.peek();
                mainGui.getCardLayout().show(mainGui.getHolderPanel(), name);           
            }
            return name;
        }
        
        public void addPropertyChangeListener(String propName, PropertyChangeListener propListener) {
            pcSupport.addPropertyChangeListener(propName, propListener);
        }
    }
    

    This holds an income value, and notifies any classes that want to register listeners about changes in the income value, by use of JavaBeans property change support. It also helps control which view is shown at what time, by controlling a CardLayout object.

    The view portion of this example program codes for several JPanels, including:

    • A WelcomePanel that displays welcome text and has buttons that helps the user load other JPanels. It currently only allows display of one JPanel, the LoadPanel.
    • A LoadPanel that is a menut to allow the user to add or view expenses or income. The JPanel nests several layout managers, including a BoxLayout, GridLayout, and GridBagLayout, to allow for a flexible GUI. A buttonFactory method allows for creation of larger JButtons with a uniform appearance.
    • An AddIncomePanel that allows the user to add additional income to the program's model.
    • A ViewIncomePanel that shows the current income to the user. This class will listen for changes to the model's income property using a PropertyChangeListener.
    • Finally a SwapGuiMainPanel to hold the CardLayout and the holderPanel that uses this layout, and to put everything together:
    import java.awt.BorderLayout;
    import java.awt.CardLayout;
    import java.awt.Font;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.GridLayout;
    import java.awt.Insets;
    import java.awt.event.*;
    import java.beans.*;
    import java.text.NumberFormat;
    import javax.swing.*;
    import javax.swing.border.Border;
    
    @SuppressWarnings("serial")
    public class SwapGuiMainPanel extends JPanel {
        private CardLayout cardLayout = new CardLayout();
        private JPanel holderPanel = new JPanel(cardLayout);
        private SwapModel swapModel = new SwapModel(this);
        private WelcomePanel welcomePanel = new WelcomePanel(swapModel);
        private LoadPanel loadPanel = new LoadPanel(swapModel);
        private AddIncomePanel addIncomePanel = new AddIncomePanel(swapModel);
        private ViewIncomePanel viewIncomePanel = new ViewIncomePanel(swapModel);
        
        public SwapGuiMainPanel() {
            holderPanel.add(welcomePanel, WelcomePanel.NAME);
            holderPanel.add(loadPanel, LoadPanel.NAME);
            holderPanel.add(addIncomePanel, AddIncomePanel.NAME);
            holderPanel.add(viewIncomePanel, ViewIncomePanel.NAME);
            
            swapModel.addPropertyChangeListener(SwapModel.INCOME, new IncomeListener());
            
            int gap = 10;
            setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
            setLayout(new BorderLayout());
            add(holderPanel);
        }
        
        private class IncomeListener implements PropertyChangeListener {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                Double income = (Double) evt.getNewValue();
                if (income != null) {
                    viewIncomePanel.setIncomeValue(income);
                }
            }
        }
        
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                SwapGuiMainPanel mainPanel = new SwapGuiMainPanel();
    
                JFrame frame = new JFrame("GUI");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(mainPanel);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            });
        }
    
        public void swap(String constraint) {
            cardLayout.show(holderPanel, constraint);
        }
        
        public CardLayout getCardLayout() {
            return cardLayout;
        }
        
        public JPanel getHolderPanel() {
            return holderPanel;
        }
        
    }
    
    @SuppressWarnings("serial")
    class WelcomePanel extends JPanel {
        public static final String NAME = "welcome panel";
        private static final String WELCOME_TEXT = "Hello and Welcome! Choose an Option Below:";
        private SwapModel model;
    
        public WelcomePanel(SwapModel model) {
            this.model = model;
            
            int gap = 20;
            JPanel buttonPanel = new JPanel(new GridLayout(0, 1, gap, gap));
            JButton loadButton = new JButton("Load Data");
            loadButton.addActionListener(e -> loadData());
            JButton resetButton = new JButton("Reset Data");
            Font btnFont = loadButton.getFont().deriveFont(Font.BOLD, 16f);
            loadButton.setFont(btnFont);
            resetButton.setFont(btnFont);       
            buttonPanel.add(loadButton);
            buttonPanel.add(resetButton);
            
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.insets = new Insets(gap, gap, gap, gap);
            add(new JLabel(WELCOME_TEXT), gbc);     
            gbc.gridy  ;
            add(buttonPanel, gbc);
        }
        
        private void loadData() {
            model.swap(LoadPanel.NAME);
        }
        
    }
    
    @SuppressWarnings("serial")
    class LoadPanel extends JPanel {
        public static final String NAME = "load panel";
        private SwapModel model;
    
        public LoadPanel(SwapModel model) {
            this.model = model;
            
            JLabel title = new JLabel("Welcome to Budget Planner App");
            title.setHorizontalAlignment(SwingConstants.CENTER);
            title.setAlignmentX(JLabel.CENTER_ALIGNMENT);
            title.setFont(title.getFont().deriveFont(Font.BOLD, 16f));
            
            JLabel subTitle = new JLabel("What would you like to do?");
            subTitle.setHorizontalAlignment(SwingConstants.CENTER);
            subTitle.setAlignmentX(JLabel.CENTER_ALIGNMENT);
            subTitle.setFont(subTitle.getFont().deriveFont(Font.ITALIC));
            
            JPanel titlePanel = new JPanel();
            titlePanel.setLayout(new BoxLayout(titlePanel, BoxLayout.PAGE_AXIS));
            titlePanel.add(title);
            titlePanel.add(subTitle);
            titlePanel.add(Box.createVerticalStrut(30));
            
            JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 10, 10));
            buttonPanel.add(buttonFactory("Add Income", e -> addIncome()));
            buttonPanel.add(buttonFactory("Add Expense", null));
            buttonPanel.add(buttonFactory("View Income", e -> viewIncome()));
            buttonPanel.add(buttonFactory("View Expense", null));
            
            JPanel wrapperPanel = new JPanel(new GridBagLayout());
            wrapperPanel.add(buttonPanel);
                    
            int gap = 10;
            setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
            setLayout(new BorderLayout());
            add(titlePanel, BorderLayout.PAGE_START);
            add(wrapperPanel);
        }
        
        private void addIncome() {
            model.swap(AddIncomePanel.NAME);
        }
        
        private void viewIncome() {
            model.swap(ViewIncomePanel.NAME);
        }
        
        private JButton buttonFactory(String text, ActionListener listener) {
            JButton button = new JButton(text);
            button.addActionListener(listener);
            button.setFont(button.getFont().deriveFont(Font.BOLD, 16f));
            Border originalBorder = button.getBorder();
            int gap = 10;
            Border innerBorder = BorderFactory.createEmptyBorder(gap, gap, gap, gap);
            button.setBorder(BorderFactory.createCompoundBorder(originalBorder, innerBorder));
            return button;
        }
        
    }
    
    @SuppressWarnings("serial")
    class AddIncomePanel extends JPanel {
        public static final String NAME = "add income panel";
        private SwapModel swapModel;
        private JTextField incomeField = new JTextField(20);
        private JButton submitButton = new JButton("Submit");
        private JButton cancelButton = new JButton("Cancel");
    
        public AddIncomePanel(SwapModel swapModel) {
            this.swapModel = swapModel;
            JPanel topPanel = new JPanel();
            topPanel.add(new JLabel("Enter Income:"));
            topPanel.add(incomeField);
            
            submitButton.addActionListener(e -> submitData());
            cancelButton.addActionListener(e -> cancel());
            JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 5));
            buttonPanel.add(submitButton);
            buttonPanel.add(cancelButton);
            
            JPanel innerPanel = new JPanel();
            innerPanel.setLayout(new GridLayout(0, 1, 5, 5));
            innerPanel.add(topPanel);
            innerPanel.add(buttonPanel);
            
            JButton backButton = new JButton("Back");
            backButton.addActionListener(e -> back());
            JPanel bottomButtonPanel = new JPanel();
            bottomButtonPanel.add(backButton);
            
            setLayout(new BorderLayout());
            add(innerPanel, BorderLayout.PAGE_START);
            add(bottomButtonPanel, BorderLayout.PAGE_END);
        }
    
        private void back() {
            swapModel.popCardStack();
        }
    
        private void submitData() {
            String text = incomeField.getText();
            try {
                double value = Double.parseDouble(text);
                swapModel.addIncome(value);
                back();
            } catch (NumberFormatException e) {
                // TODO: show error message
            }
        }
        
        private void cancel() {
            back();
        }
        
    }
    
    @SuppressWarnings("serial")
    class ViewIncomePanel extends JPanel {
        public static final String NAME = "view income panel";
        private SwapModel swapModel;
        private JLabel incomeValue = new JLabel();
        private NumberFormat format = NumberFormat.getCurrencyInstance();
    
        public ViewIncomePanel(SwapModel swapModel) {
            this.swapModel = swapModel;
            
            JPanel topPanel = new JPanel();
            topPanel.add(new JLabel("Income: "));
            topPanel.add(incomeValue);
    
            JButton backButton = new JButton("Back");
            backButton.addActionListener(e -> back());
            JPanel buttonPanel = new JPanel();
            buttonPanel.add(backButton);
            
            setLayout(new BorderLayout());
            add(topPanel, BorderLayout.PAGE_START);
            add(buttonPanel, BorderLayout.PAGE_END);
        }
        
        public void setIncomeValue(double income) {
            incomeValue.setText(format.format(income));
        }
        
        private void back() {
            swapModel.popCardStack();
        }
    }
    

    CodePudding user response:

    The solution is not perfect you can improve the code as per your need. It seems like button is responding to clicks to verify that I have added System.out.println("Clicked") statement inside actionPerformed method.

    package swingButton;
    
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.FileNotFoundException;
    
    import static javax.swing.SwingConstants.TOP;
    
    public class OpenFrame extends JFrame implements ActionListener {
    
        private static final int WIDTH = 500;
        private static final int HEIGHT = 500;
    //    private BudgetPlanner budgetPlanner;
    
        private JFrame openFrame;
    
        private JLabel welcomeMessage;
        private JPanel openPanel = new JPanel();
        private JPanel inputSpace;
    
        private JButton loadButton = new JButton();
        private JButton resetButton = new JButton();
        private JButton addIncomeButton;
        private JButton addExpenseButton;
        private JButton viewExpenseButton;
        private JButton viewIncomeButton;
    
        private JTextField inputIncome;
    
    //    public BudgetPlanner callBudgetPlanner() {
    //        try {
    //            budgetPlanner = new BudgetPlanner();
    //        } catch (FileNotFoundException e) {
    //            e.printStackTrace();
    //        }
    //        return budgetPlanner;
    //    }
    
        public OpenFrame() {
            openFrame = new JFrame();
            openFrame.setTitle("BudgetPlanner");
            openFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            openFrame.setResizable(false);
            openFrame.setLayout(null);
            openFrame.setLocationRelativeTo(null);
            openFrame.setSize(new Dimension(WIDTH, HEIGHT));
            openFrame.getContentPane().setBackground(Color.GRAY);
            openPanel();
            openFrame.setContentPane(openPanel);
    
            openFrame.setVisible(true);
        }
    
        public void openPanel() {
            openPanel.setLayout(null);
    
            welcomeMessage = new JLabel("Hello there! Welcome back. Choose an option below:");
            welcomeMessage.setVerticalTextPosition(TOP);
            welcomeMessage.setHorizontalTextPosition(SwingConstants.CENTER);
            welcomeMessage.setBounds(50, 20, 500, 200);
            welcomeMessage.setFont(new Font("Arial", Font.PLAIN, 17));
    
            openPanel.setBounds(0, 0, 500, 500);
            openPanel.add(welcomeMessage);
    
            loadButton.setBounds(200, 170, 100, 50);
            loadButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
            loadButton.setText("Load Data");
            loadButton.addActionListener(this);
            loadButton.setFocusable(false);
    
            resetButton.setBounds(200, 230, 100, 50);
            resetButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
            resetButton.setText("Reset Data");
            resetButton.addActionListener(this);
            resetButton.setFocusable(false);
    
            openPanel.add(loadButton);
            openPanel.add(resetButton);
        }
    
        public void plannerScreen() {
            JPanel loadPanel = new JPanel();
            openFrame.setContentPane(loadPanel);
            loadPanel.setBounds(0, 0, 500, 500);
            JLabel loadCompleteMessage = new JLabel("Welcome to Budget Planner App.");
            loadCompleteMessage.setBounds(138, TOP, 500, 50);
            loadCompleteMessage.setFont(new Font("Arial", Font.BOLD, 14));
            loadPanel.add(loadCompleteMessage);
            JLabel optionMessage = new JLabel("What would you like to do?");
            optionMessage.setBounds(175, TOP   40, 500, 10);
            optionMessage.setFont(new Font("Arial", Font.ITALIC, 13));
            loadPanel.add(optionMessage);
            openButton();
            loadPanel.add(addIncomeButton);
            loadPanel.add(addExpenseButton);
            loadPanel.add(viewIncomeButton);
            loadPanel.add(viewExpenseButton);
        }
    
        public void openButton() {
            addIncomeButton = new JButton("Add Income");
            addIncomeButton.setBounds(180, 110, 140, 45);
            addIncomeButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
            addExpenseButton = new JButton("Add Expense");
            addExpenseButton.setBounds(180, 160, 140, 45);
            addExpenseButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
            viewIncomeButton = new JButton("View Income");
            viewIncomeButton.setBounds(180, 210, 140, 45);
            viewIncomeButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
            viewExpenseButton = new JButton("View Expense");
            viewExpenseButton.setBounds(180, 260, 140, 45);
            viewExpenseButton.setFont(new Font("Arial", Font.CENTER_BASELINE, 15));
    
            addIncomeButton.addActionListener(new InputData(this));
    
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == loadButton) {
                JOptionPane.showMessageDialog(null, "Loading Complete!");
                plannerScreen();
            }
    
            if (e.getSource() == resetButton) {
                JOptionPane.showMessageDialog(null, "Saved data erased.");
                plannerScreen();
            }
        }
    
        public class InputData implements ActionListener {
            JFrame parent;
    
            public InputData(JFrame parent) {
                this.parent = parent;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Clicked");
                JDialog dialog = new JDialog(parent);
                JPanel inputSpace = new JPanel();
                inputSpace.setLayout(new FlowLayout());
    //            inputSpace.setBounds(0, 300, 500, 200);
                var incomeLabel = new JLabel("How much is your income?");
                inputIncome = new JTextField("How much is your income?", 20);
                inputSpace.add(incomeLabel);
                inputSpace.add(inputIncome);
                inputSpace.add(new JButton("OK"));
                inputSpace.add(new JButton("Cancel"));
    //            openPanel.add(inputSpace);
    //            openFrame.removeAll();
    //            openFrame.setContentPane(inputSpace);
    //            openFrame.add(inputSpace);
    //            parent.setContentPane(inputSpace);
                dialog.add(inputSpace);
                System.out.println("Removing all");
                dialog.setSize(500, 300);
                dialog.setVisible(true);
            }
        }
    
        public static void main(String... $) {
            var of = new OpenFrame();
        }
    }
    

    Budget Planner

  • Related