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);
}
}
Мой код показан выше. Проблема в том, что когда я нажимаю кнопку addIncomeButton, она не связывается с созданным мной списком действий InputData. После нажатия addIncomeButton ничего не происходит. Как решить эту проблему? ;-;
Моя цель состоит в том, что после нажатия кнопки появится JTextField, который будет добавлен на ту же панель.
Любая помощь будет оценена! Огромное спасибо!
Вы не видите новые компоненты, потому что openFrame.setContentPane(loadPanel);
заменил видимый openPanel
на loadPanel
.
Канонический способ поменять местами представления — использовать CardLayout. И да, избегайте нулевых макетов, как метко предлагает @Progman.
Решение не идеально, вы можете улучшить код в соответствии с вашими потребностями. Кажется, что кнопка реагирует на клики, чтобы убедиться, что я добавил оператор System.out.println("Clicked")
внутри метода actionPerformed
.
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();
}
}
Основные рекомендации:
setBounds(...)
для размещения компонентов, так как это делает очень негибкие графические интерфейсы, которые, хотя они могут хорошо выглядеть на одной платформе, выглядят ужасно на большинстве других платформ или разрешений экрана, и их очень сложно обновлять и поддерживать.Например:
в приведенном ниже примере кода у меня есть модель и некоторый управляющий код в классе SwapModel:
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);
}
}
Он содержит значение дохода и уведомляет любые классы, которые хотят зарегистрировать слушателей, об изменениях значения дохода, используя поддержку изменения свойств JavaBeans. Это также помогает контролировать, какое представление отображается в какое время, управляя объектом CardLayout.
Часть просмотра этого примера программных кодов для нескольких панелей JPanel, в том числе:
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();
}
}
Обычно рекомендуется не использовать макет
null
и возиться сsetBounds()
. Вместо этого используйте фактический менеджер компоновки, см. docs.oracle.com/javase/tutorial/uiswing/layout/visual.html