being new to programming, i'm having a slight issue resizing the text fields I've added to the JPanel. While I could go the route of creating individual panels with their own text field, I though it would be better to add all the components into one panel. Part of my overall idea is to have my add button reference the panel, containing the text fields, to add more text fields on the tracker for users to fill out, and while I can get the fields to display when I implement the setBounds method on my panel object, i'm having tough time figuring out how resize them in the panel itself. And if you have any other advice on my overall structure, I welcome it.
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class UI {
JFrame frame;
JLabel Title,Name, CheckOut, CheckIn, Email;
JTextField NameField,CheckOutField, CheckInField, EmailField;
JButton Add, Delete;
JPanel buttons, textfields, primary;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UI window = new UI();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public UI(){
design();
}
private void design(){
frame = new JFrame("Form 48 Tracker");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(100, 100, 750, 400);
frame.getContentPane().setLayout(null);
Title = new JLabel();
Title.setText("Form 48 Tracker");
Title.setFont(new Font("Calibri", Font.PLAIN, 28));
Title.setBounds(233, 11, 200, 75);
frame.getContentPane().add(Title);
Title.setForeground(Color.BLACK);
Name = new JLabel();
Name.setText("Name");
Name.setFont(new Font("Calibri", Font.PLAIN, 15));
Name.setBounds(50, 80, 128, 20);
frame.getContentPane().add(Name);
Name.setForeground(Color.BLACK);
CheckOut = new JLabel();
CheckOut.setText("Check Out Date");
CheckOut.setFont(new Font("Calibri", Font.PLAIN, 15));
CheckOut.setBounds(200, 80, 128, 20);
frame.getContentPane().add(CheckOut);
CheckOut.setForeground(Color.BLACK);
CheckIn = new JLabel();
CheckIn.setText("Check In Date");
CheckIn.setFont(new Font("Calibri", Font.PLAIN, 15));
CheckIn.setBounds(350, 80, 128, 20);
frame.getContentPane().add(CheckIn);
CheckIn.setForeground(Color.BLACK);
Email = new JLabel();
Email.setText("Email");
Email.setFont(new Font("Calibri", Font.PLAIN, 15));
Email.setBounds(500, 80, 128, 20);
frame.getContentPane().add(Email);
Email.setForeground(Color.BLACK);
Add = new JButton("Add");
buttons = new JPanel();
buttons.add(Add);
buttons.setBounds(200, 270, 157, 50); //x , y , width , height//
frame.getContentPane().add(buttons);
Add.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
}
});
Delete = new JButton("Delete");
buttons = new JPanel();
buttons.add(Delete);
buttons.setBounds(605, 101, 128, 50);
frame.getContentPane().add(buttons);
primary = new JPanel();
NameField = new JTextField();
CheckOutField = new JTextField();
CheckInField = new JTextField();
EmailField = new JTextField();
primary.add(NameField);
primary.add(CheckOutField);
primary.add(CheckInField);
primary.add(EmailField);
primary.setBounds(50, 110, 128, 20);
frame.getContentPane().add(primary);
}
}
Let's concentrate on the code that's causing the problem, and only that code. I've created a minimal example program, one that has enough code to compile and run, and that demonstrates the problem, but that has no unnecessary code:
import javax.swing.*;
public class UiFoo {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null); // **** no!! ****
JPanel primary = new JPanel();
JTextField NameField = new JTextField();
JTextField CheckOutField = new JTextField();
JTextField CheckInField = new JTextField();
JTextField EmailField = new JTextField();
primary.add(NameField);
primary.add(CheckOutField);
primary.add(CheckInField);
primary.add(EmailField);
primary.setBounds(50, 110, 128, 20);
frame.getContentPane().add(primary);
frame.setSize(600, 250);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
So, if you run this code, you'll see 4 very small JTextFields. Why are they so small? Because you've not set the columns property for the JTextFields, and so they default to columns size 0 and show up like so:
So it's better if you can give the JTextField a columns property so that they have some width, e.g., make this change:
JPanel primary = new JPanel();
int columns = 8;
JTextField NameField = new JTextField(columns);
JTextField CheckOutField = new JTextField(columns);
JTextField CheckInField = new JTextField(columns);
JTextField EmailField = new JTextField();
But this just shows one JTextField, and cuts off the bottom as well:
Why? Because you're artificially constraining the size of the containing JPanel, primary via:
primary.setBounds(50, 110, 128, 20);
This containing JPanel is only 128 pixels wide by 20 pixels high, meaning that it won't even display one JTextField well.
One solution is to use a mix of layout managers and JPanels as well as a JScrollPane to allow for a grid of JPanels to be added, something like so (try it out!):
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.*;
#SuppressWarnings("serial")
public class UiFoo2 extends JPanel {
JPanel singleColumnPanel = new JPanel(new GridLayout(0, 1, 2, 2));
public UiFoo2() {
JButton addButton = new JButton("Add");
addButton.addActionListener(e -> {
JPanel rowPanel = new JPanel(new GridLayout(1, 4, 2, 2));
for (int i = 0; i < 4; i++) {
rowPanel.add(new JTextField(8));
}
singleColumnPanel.add(rowPanel);
singleColumnPanel.revalidate();
singleColumnPanel.repaint();
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(addButton);
JPanel labelPanel = new JPanel(new GridLayout(1, 4, 2, 2));
labelPanel.add(new JLabel("Name", SwingConstants.CENTER));
labelPanel.add(new JLabel("Check Out Date", SwingConstants.CENTER));
labelPanel.add(new JLabel("Check In Date", SwingConstants.CENTER));
labelPanel.add(new JLabel("Email", SwingConstants.CENTER));
singleColumnPanel.add(labelPanel);
JPanel containerPanel = new JPanel(new BorderLayout(5, 5));
containerPanel.add(singleColumnPanel, BorderLayout.PAGE_START);
JScrollPane scrollPane = new JScrollPane(containerPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setPreferredSize(new Dimension(650, 400));
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
UiFoo2 mainPanel = new UiFoo2();
JFrame frame = new JFrame("UiFoo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
This will create a row JPanel that holds four JTextFields that get added to the JScrollPane when the add JButton is pressed, and looks like so:
but we still can do better. Why not instead create a class to hold a row of data, something like so:
import java.util.Date;
public class Form48Customer {
private String name;
private Date checkIn;
private Date checkOut;
private String Email;
public Form48Customer(String name, Date checkIn, Date checkOut, String email) {
this.name = name;
this.checkIn = checkIn;
this.checkOut = checkOut;
Email = email;
}
public Date getCheckIn() {
return checkIn;
}
public void setCheckIn(Date checkIn) {
this.checkIn = checkIn;
}
public Date getCheckOut() {
return checkOut;
}
public void setCheckOut(Date checkOut) {
this.checkOut = checkOut;
}
public String getName() {
return name;
}
public String getEmail() {
return Email;
}
// should override hashCode and equals here
}
and then create a JTable complete with custom model to display objects of this type, and then display them in the GUI. This is much cleaner, more flexible, and extendable. Something like so:
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.*;
import java.util.Date;
import javax.swing.*;
import javax.swing.JFormattedTextField.AbstractFormatter;
import javax.swing.table.*;
#SuppressWarnings("serial")
public class Form48TrackerPanel extends JPanel {
public static final String TITLE = "Form 48 Tracker";
private static final String DATE_FORMAT_TXT = "MM/dd/yyyy";
private Form48TableModel model = new Form48TableModel();
private JTable table = new JTable(model);
private JButton addButton = new JButton("Add");
private JButton deleteButton = new JButton("Delete");
private JButton exitButton = new JButton("Exit");
public Form48TrackerPanel() {
final SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_TXT);
TableCellRenderer dateRenderer = new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if( value instanceof Date) {
value = dateFormat.format(value);
}
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}
};
table.getColumnModel().getColumn(1).setCellRenderer(dateRenderer);
table.getColumnModel().getColumn(2).setCellRenderer(dateRenderer);
JLabel titleLabel = new JLabel(TITLE, SwingConstants.CENTER);
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 28f));
addButton.addActionListener(new AddListener());
addButton.setMnemonic(KeyEvent.VK_A);
deleteButton.addActionListener(new DeleteListener());
deleteButton.setMnemonic(KeyEvent.VK_D);
exitButton.addActionListener(new ExitListener());
exitButton.setMnemonic(KeyEvent.VK_X);
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
buttonPanel.add(addButton);
buttonPanel.add(deleteButton);
buttonPanel.add(exitButton);
setPreferredSize(new Dimension(800, 500));
int ebGap = 8;
setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap, ebGap, ebGap));
setLayout(new BorderLayout(ebGap, ebGap));
add(titleLabel, BorderLayout.PAGE_START);
add(new JScrollPane(table), BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
model.addRow(new Form48Customer("John Smith", new Date(), new Date(), "JSmith#Yahoo.com"));
model.addRow(new Form48Customer("Fred Flinstone", new Date(), new Date(), "FFlinstone#GMail.com"));
}
private class AddListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
AddForm48Panel addFormPanel = new AddForm48Panel();
int result = JOptionPane.showConfirmDialog(Form48TrackerPanel.this,
addFormPanel, "Add Customer", JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE);
if (result == JOptionPane.OK_OPTION) {
Form48Customer customer = addFormPanel.getForm48Customer();
model.addRow(customer);
}
}
}
private class DeleteListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// TODO *** finish this code ***
}
}
private class ExitListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
Window win = SwingUtilities.getWindowAncestor(Form48TrackerPanel.this);
win.dispose();
}
}
private static void createAndShowGui() {
Form48TrackerPanel mainPanel = new Form48TrackerPanel();
JFrame frame = new JFrame(TITLE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class AddForm48Panel extends JPanel {
private static final int TFIELD_COLS = 10;
private static final String DATE_FORMAT_TXT = "MM/dd/yyyy";
private static final Format DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT_TXT);
private static final Insets INSETS = new Insets(5, 5, 5, 5);
private JTextField nameField = new JTextField(TFIELD_COLS);
private JFormattedTextField checkOutDateField = new JFormattedTextField(DATE_FORMAT);
private JFormattedTextField checkInDateField = new JFormattedTextField(DATE_FORMAT);
private JTextField emailField = new JTextField(TFIELD_COLS);
private JComponent[] fields = {nameField, checkOutDateField, checkInDateField, emailField};
private String[] labels = {"Name", "Check Out Date", "Check In Date", "Email"};
public AddForm48Panel() {
InputVerifier verifier = new DateFieldVerifier();
checkInDateField.setInputVerifier(verifier);
checkOutDateField.setInputVerifier(verifier);
setLayout(new GridBagLayout());
for (int i = 0; i < fields.length; i++) {
add(new JLabel(labels[i] + ":"), createGbc(0, i));
add(fields[i], createGbc(1, i));
}
}
public String getName() {
return nameField.getText();
}
public String getEmail() {
return emailField.getText();
}
public Date getCheckOut() {
return (Date) checkOutDateField.getValue();
}
public Date getCheckIn() {
return (Date) checkInDateField.getValue();
}
public Form48Customer getForm48Customer() {
String name = getName();
Date checkOut = getCheckOut();
Date checkIn = getCheckIn();
String email = getEmail();
return new Form48Customer(name, checkIn, checkOut, email);
}
private GridBagConstraints createGbc(int x, int y) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = x;
gbc.gridy = y;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.insets = INSETS;
gbc.anchor = x == 0 ? GridBagConstraints.WEST :GridBagConstraints.EAST;
gbc.fill = GridBagConstraints.HORIZONTAL;
return gbc;
}
private class DateFieldVerifier extends InputVerifier {
#Override
public boolean verify(JComponent input) {
if (input instanceof JFormattedTextField) {
JFormattedTextField ftf = (JFormattedTextField)input;
AbstractFormatter formatter = ftf.getFormatter();
if (formatter != null) {
String text = ftf.getText();
try {
formatter.stringToValue(text);
return true;
} catch (ParseException pe) {
return false;
}
}
}
return true;
}
#Override
public boolean shouldYieldFocus(JComponent input) {
boolean verify = verify(input);
if (!verify) {
String message = "Enter a valid date, e.g.: 01/05/2017";
String title = "Invalid Date Format";
int type = JOptionPane.ERROR_MESSAGE;
JOptionPane.showMessageDialog(input, message, title, type);
}
return verify;
}
}
}
#SuppressWarnings("serial")
class Form48TableModel extends DefaultTableModel {
private static final String[] COL_NAMES = {"Name", "Check Out Date", "Check In Date", "Email"};
public Form48TableModel() {
super(COL_NAMES, 0);
}
public void addRow(Form48Customer customer) {
Object[] rowData = {
customer.getName(),
customer.getCheckOut(),
customer.getCheckIn(),
customer.getEmail()
};
addRow(rowData);
}
public Form48Customer getRow(int row) {
String name = (String) getValueAt(row, 0);
Date checkIn = (Date) getValueAt(row, 1);
Date checkOut = (Date) getValueAt(row, 2);
String email = (String) getValueAt(row, 3);
return new Form48Customer(name, checkIn, checkOut, email);
}
#Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 1:
return Date.class;
case 2:
return Date.class;
default:
break;
}
return super.getColumnClass(columnIndex);
}
}
Which would look like:
I'm trying to create a simple program to manage Employees. When trying to add a new employee I can't seem to get the employee to be displayed on the Jlist.
The main frame...
public class EmployeeFrame extends JFrame implements ActionListener {
// The buttons to display
private JButton addButton;
private JButton editButton;
private JButton deleteButton;
private JButton saveButton;
// The underlying list of employees, and the GUI object to display them
private DefaultListModel<Employee> listModel;
private JList<Employee> employeeList;
public static final String SAVE_FILE = "employees.txt";
/**
* Creates and displays a new EmployeeFrame. The program exits when the
* window is closed.
*/
public EmployeeFrame() {
// Basic window features
super("Employee Manager");
setLocationByPlatform(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
// Try to make it look like a native application -- using try/multi-catch
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
// Initialise an empty list model, a JList to display it, and a scroll
// pane to contain the list
listModel = new DefaultListModel<>();
employeeList = new JList<>(listModel);
JScrollPane employeeScroll = new JScrollPane(employeeList);
employeeScroll.setBorder(new TitledBorder("Employee List"));
// Initialise all buttons and add the current class as an action
// listener to all
addButton = new JButton("Add Employee");
addButton.addActionListener(this);
editButton = new JButton("Edit Employee");
editButton.addActionListener(this);
deleteButton = new JButton("Delete Employee");
deleteButton.addActionListener(this);
saveButton = new JButton("Save Employee List");
saveButton.addActionListener(this);
// Lay out the buttons in a line
Box topBox = Box.createHorizontalBox();
topBox.add(addButton);
topBox.add(Box.createHorizontalStrut(10));
topBox.add(editButton);
topBox.add(Box.createHorizontalStrut(10));
topBox.add(deleteButton);
topBox.add(Box.createHorizontalStrut(10));
topBox.add(saveButton);
// Lay out the window
getContentPane().setLayout(new BorderLayout());
getContentPane().add(topBox, BorderLayout.NORTH);
getContentPane().add(employeeScroll, BorderLayout.CENTER);
pack();
}
public DefaultListModel<Employee> getListModel() {
return this.listModel;
}
#Override
public void actionPerformed(ActionEvent event) {
// Determine which button was pushed
Object source = event.getSource();
// Here's what to do with the delete button
if (source == deleteButton) {
Employee selection = employeeList.getSelectedValue();
if (selection != null) {
listModel.removeElement(selection);
}
}
if (source == addButton) {
AddEmployeeDialog frame = new AddEmployeeDialog(new EmployeeFrame());
frame.setVisible(true);
}
}
public static void main(String[] args) {
new EmployeeFrame().setVisible(true);
}
}
The dialogue that adds the employee...
public class AddEmployeeDialog extends JDialog implements ActionListener {
// Common fields
private JComboBox<String> workerType;
private JTextField givenNameField;
private JTextField familyNameField;
private JDatePicker startDatePicker;
// Fields that depend on the employee type
private JTextField rateField;
private JTextField hoursField;
private JTextField salaryField;
// Buttons
private JButton okButton;
private JButton cancelButton;
// The employee frame -- used to position the dialog and to access the
// employee list
private EmployeeFrame employeeFrame;
public AddEmployeeDialog(final EmployeeFrame frame) {
// Basic initialisation
super(frame, "Add Employee", true);
setLocationRelativeTo(employeeFrame);
this.employeeFrame = frame;
// Common fields
workerType = new JComboBox<String>(Employee.getEmployeeTypes());
givenNameField = new JTextField(20);
familyNameField = new JTextField(20);
startDatePicker = new JDateComponentFactory().createJDatePicker();
// Fields only for hourly workers
rateField = new JTextField(10);
hoursField = new JTextField(5);
// Field only for salaried worker
salaryField = new JTextField(10);
// Top line
Box workerBox = Box.createHorizontalBox();
workerBox.add(new JLabel("Worker type"));
workerBox.add(workerType);
workerBox.add(new JLabel("Start date"));
workerBox.add((JPanel) startDatePicker);
// Next lines (names)
Box givenNameBox = Box.createHorizontalBox();
givenNameBox.add(new JLabel("Given name "));
givenNameBox.add(givenNameField);
Box familyNameBox = Box.createHorizontalBox();
familyNameBox.add(new JLabel("Family name"));
familyNameBox.add(familyNameField);
// Hourly-worker fields
Box hourlyBox = Box.createHorizontalBox();
hourlyBox.setBorder(new TitledBorder("Hourly worker information"));
hourlyBox.add(new JLabel("Rate"));
hourlyBox.add(rateField);
hourlyBox.add(Box.createHorizontalStrut(10));
hourlyBox.add(new JLabel("Hours"));
hourlyBox.add(hoursField);
// Salaried-worker fields
Box salariedBox = Box.createHorizontalBox();
salariedBox.setBorder(new TitledBorder("Salaried worker information"));
salariedBox.add(new JLabel("Salary"));
salariedBox.add(salaryField);
// Ensure that only the appropriate fields are enabled, depending on the
// worker type chosen
workerType.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent arg0) {
String type = (String) workerType.getSelectedItem();
salaryField.setEnabled("Salaried".equals(type));
rateField.setEnabled("Hourly".equals(type));
hoursField.setEnabled("Hourly".equals(type));
}
});
workerType.setSelectedItem(null);
// Create buttons and add the current class as an ActionListener
okButton = new JButton("OK");
okButton.addActionListener(this);
cancelButton = new JButton("Cancel");
cancelButton.addActionListener(this);
// Bottom row of GUI: buttons
Box bottomBox = Box.createHorizontalBox();
bottomBox.add(Box.createHorizontalGlue());
bottomBox.add(okButton);
bottomBox.add(Box.createHorizontalGlue());
bottomBox.add(cancelButton);
bottomBox.add(Box.createHorizontalGlue());
// Lay out the GUI
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
getContentPane().add(workerBox);
getContentPane().add(givenNameBox);
getContentPane().add(familyNameBox);
getContentPane().add(hourlyBox);
getContentPane().add(salariedBox);
getContentPane().add(Box.createVerticalStrut(10));
getContentPane().add(bottomBox);
pack();
}
#Override
public void actionPerformed(ActionEvent event) {
// Convert the value from the date picker into a LocalDate
GregorianCalendar startDateValue = (GregorianCalendar) startDatePicker.getModel().getValue();
LocalDate startDate = startDateValue.toZonedDateTime().toLocalDate();
// Work out which button was pressed
Object source = event.getSource();
if (source == cancelButton) {
// Just close the window
dispose();
}
if (source == okButton) {
// Determine if the employee is hourly or salaried
if (workerType.getSelectedItem().toString() == "Salaried") {
// Create new salaried employee
if (salaryField.getText().matches("[0-9]+")) {
Employee employee = new SalariedEmployee(givenNameField.getText(),
familyNameField.getText(),
startDate,
Double.parseDouble(salaryField.getText()));
employeeFrame.getListModel().addElement(employee);
}
}
else {
// Create new hourly employee
if (rateField.getText().matches("[0-9]+") && hoursField.getText().matches("[0-9]+")) {
Employee employee = new HourlyEmployee(givenNameField.getText(),
familyNameField.getText(),
startDate,
Double.parseDouble(rateField.getText()),
Integer.parseInt(hoursField.getText()));
employeeFrame.getListModel().addElement(employee);
}
}
dispose();
}
}
}
This is what I'm using to add the employee
employeeFrame.getListModel().addElement(employee);
I think this is the right method but it doesn't seem to work. Any help will really be appreciated.
Two problems,
The first:
bad: if (workerType.getSelectedItem().toString() == "Salaried") {. Use equals(...) or equalsIgnoreCase(...). Understand that == checks for reference equality which is most definitely not what you're interested in. You want functional equality which is what the methods test for.
So: if ("Salaried".equalsIgnoreCase(workerType.getSelectedItem().toString())) {
The second:
AddEmployeeDialog frame = new AddEmployeeDialog(new EmployeeFrame());
You're passing in a new EmployeeFrame object meaning you're updating the list model for the wrong EmployeeFrame. Instead pass in the visualized EmployeeFrame.
Change it to:
AddEmployeeDialog frame = new AddEmployeeDialog(EmployeeFrame.this);
My program that I created to shrink your code but still allow it to be runnable and to demonstrate your problem:
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
#SuppressWarnings("serial")
public class EmployeeFrame extends JFrame implements ActionListener {
private JButton addButton;
private DefaultListModel<Employee> listModel;
private JList<Employee> employeeList;
public EmployeeFrame() {
super("Employee Manager");
setLocationByPlatform(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
listModel = new DefaultListModel<>();
employeeList = new JList<>(listModel);
JScrollPane employeeScroll = new JScrollPane(employeeList);
employeeScroll.setBorder(new TitledBorder("Employee List"));
addButton = new JButton("Add Employee");
addButton.addActionListener(this);
Box topBox = Box.createHorizontalBox();
topBox.add(addButton);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(topBox, BorderLayout.NORTH);
getContentPane().add(employeeScroll, BorderLayout.CENTER);
pack();
}
public DefaultListModel<Employee> getListModel() {
return this.listModel;
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == addButton) {
// !! AddEmployeeDialog frame = new AddEmployeeDialog(new EmployeeFrame());
AddEmployeeDialog frame = new AddEmployeeDialog(EmployeeFrame.this);
frame.setVisible(true);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new EmployeeFrame().setVisible(true);
}
});
}
}
#SuppressWarnings("serial")
class AddEmployeeDialog extends JDialog implements ActionListener {
private JComboBox<String> workerType;
private JTextField givenNameField;
private JTextField familyNameField;
private JButton okButton;
private JButton cancelButton;
private EmployeeFrame employeeFrame;
public AddEmployeeDialog(final EmployeeFrame frame) {
super(frame, "Add Employee", true);
setLocationRelativeTo(employeeFrame);
this.employeeFrame = frame;
workerType = new JComboBox<String>(Employee.getEmployeeTypes());
givenNameField = new JTextField(20);
familyNameField = new JTextField(20);
Box workerBox = Box.createHorizontalBox();
workerBox.add(new JLabel("Worker type"));
workerBox.add(workerType);
workerBox.add(new JLabel("Start date"));
Box givenNameBox = Box.createHorizontalBox();
givenNameBox.add(new JLabel("Given name "));
givenNameBox.add(givenNameField);
Box familyNameBox = Box.createHorizontalBox();
familyNameBox.add(new JLabel("Family name"));
familyNameBox.add(familyNameField);
workerType.setSelectedItem(null);
// Create buttons and add the current class as an ActionListener
okButton = new JButton("OK");
okButton.addActionListener(this);
cancelButton = new JButton("Cancel");
cancelButton.addActionListener(this);
Box bottomBox = Box.createHorizontalBox();
bottomBox.add(Box.createHorizontalGlue());
bottomBox.add(okButton);
bottomBox.add(Box.createHorizontalGlue());
bottomBox.add(cancelButton);
bottomBox.add(Box.createHorizontalGlue());
// Lay out the GUI
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
getContentPane().add(workerBox);
getContentPane().add(givenNameBox);
getContentPane().add(familyNameBox);
getContentPane().add(Box.createVerticalStrut(10));
getContentPane().add(bottomBox);
pack();
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == okButton) {
System.out.println("here");
System.out.println(workerType.getSelectedItem());
if ("Salaried".equalsIgnoreCase(workerType.getSelectedItem().toString())) {
Employee employee = new Employee("Salaried", givenNameField.getText(), familyNameField.getText());
employeeFrame.getListModel().addElement(employee);
} else {
Employee employee = new Employee("Hourly", givenNameField.getText(), familyNameField.getText());
employeeFrame.getListModel().addElement(employee);
}
}
dispose();
}
}
class Employee {
private static final String[] EMPLOYEE_TYPES = { "Salaried", "Hourly" };
private String givenName;
private String familyName;
private String type;
public Employee(String type, String givenName, String familyName) {
this.type = type;
this.givenName = givenName;
this.familyName = familyName;
}
public static String[] getEmployeeTypes() {
return EMPLOYEE_TYPES;
}
public String getGivenName() {
return givenName;
}
public String getFamilyName() {
return familyName;
}
public String getType() {
return type;
}
#Override
public String toString() {
return String.format("Employee: %s, %s %s", type, givenName, familyName);
}
}
I'm wondering how I would add a unique(changing one does't change all of them) row to a JTable with a JButton
final DefaultTableModel mod = new DefaultTableModel();
JTable t = new JTable(mod);
mod.addColumn{" "};
mod.addColumn{" "};
JButton b = new JButton
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//How would I make tf unique by producing a different variable every row if changed
final JTextField tf = new JTextField();
final Object[] ro = {"UNIQUE ROW", tf};
mode.addRow(ro);
}):
tf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//s change to an other variable every row added
String s = tf.getText();
}):
You seem close, but you don't want to add JTextField's to a table row. Instead add the data it holds. For example:
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class UniqueRow extends JPanel {
public static final String[] COLS = {"Col 1", "Col 2"};
private DefaultTableModel model = new DefaultTableModel(COLS, 0);
private JTable table = new JTable(model);
private JTextField textField1 = new JTextField(10);
private JTextField textField2 = new JTextField(10);
public UniqueRow() {
add(new JScrollPane(table));
add(textField1);
add(textField2);
ButtonAction action = new ButtonAction("Add Data");
textField1.addActionListener(action);
textField2.addActionListener(action);
add(new JButton(action));
}
private class ButtonAction extends AbstractAction {
public ButtonAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
// get text from JTextField
String text1 = textField1.getText();
String text2 = textField2.getText();
// create a data row with it. Can use Vector if desired
Object[] row = {text1, text2};
// and add row to JTable
model.addRow(row);
}
}
private static void createAndShowGui() {
UniqueRow mainPanel = new UniqueRow();
JFrame frame = new JFrame("UniqueRow");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I need to take all the textField, comboBox, jlst, and jslider input from the first frame and make it into a summary in the second frame after the Submit button is picked. I can't figure out the best way to do this. My assignment requires a popup second frame with a textArea and exit button that brings you back to the first frame.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Hashtable;
public class Ch10Asg extends JFrame
{
private String[] flightNames = {"342", "4324", "939", "104", "222"};
private String[] cardTypes ={"Mastercard", "Visa", "American Express", "Discover"};
private String[] Dates ={"8/1/2013", "8/2/2013", "8/3/2013", "8/4/2013", "8/5/2013"};
private JTextField jtfFirst = new JTextField(10);
private JTextField jtfLast = new JTextField(10);
private JTextField jtfAddress = new JTextField(15);
private JTextField jtfCity = new JTextField(15);
private JTextField jtfState = new JTextField(2);
private JTextField jtfZip = new JTextField(5);
private JTextField jtfCard = new JTextField(16);
private JComboBox jcbo = new JComboBox(flightNames);
private JComboBox jcbcctype = new JComboBox(cardTypes);
private JList jlst = new JList(Dates);
private JSlider jsldHort = new JSlider(JSlider.HORIZONTAL,0,4,0);
private JButton jbtExit = new JButton ("EXIT");
private JButton jbtClear = new JButton ("CLEAR");
private JButton jbtSubmit = new JButton ("SUBMIT");
private JTextField jtfStart = new JTextField();
private JTextField jtfEnd = new JTextField();
public Ch10Asg()
{
JPanel p1 = new JPanel(new GridLayout(3,1));
p1.add(new JLabel("First Name"));
p1.add(jtfFirst);
p1.add(new JLabel("Last Name"));
p1.add(jtfLast);
p1.add(new JLabel("Address"));
p1.add(jtfAddress);
p1.add(new JLabel("City"));
p1.add(jtfCity);
p1.add(new JLabel("State"));
p1.add(jtfState);
p1.add(new JLabel("ZIP"));
p1.add(jtfZip);
JPanel p2 = new JPanel(new GridLayout(3,1));
p2.add(new JLabel("Select Flight Number"));
p2.add(jcbo);
p2.add(new JLabel("Select Date"));
p2.add(jlst);
p2.add(new JLabel("Select Time"));
jsldHort.setMajorTickSpacing(1);
jsldHort.setPaintTicks(true);
Hashtable<Integer, JLabel> labels = new Hashtable<Integer, JLabel>();
labels.put(0, new JLabel("4:00am"));
labels.put(1, new JLabel("5:00am"));
labels.put(2, new JLabel("8:00am"));
labels.put(3, new JLabel("11:00am"));
labels.put(4, new JLabel("5:00pm"));
jsldHort.setLabelTable(labels);
jsldHort.setPaintLabels(true);
p2.add(jsldHort);
JPanel p4 = new JPanel(new GridLayout(3,1));
p4.add(new JLabel("Starting City"));
p4.add(jtfStart);
p4.add(new JLabel("Ending City"));
p4.add(jtfEnd);
p4.add(new JLabel("Select Card Type"));
p4.add(jcbcctype);
p4.add(new JLabel("Enter Number"));
p4.add(jtfCard);
p4.add(jbtExit);
p4.add(jbtClear);
p4.add(jbtSubmit);
add(p1, BorderLayout.NORTH);
add(p2, BorderLayout.CENTER);
add(p4, BorderLayout.SOUTH);
jbtExit.addActionListener(new ActionListener()
{#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
System.exit(0);
}});
jbtClear.addActionListener(new ActionListener()
{#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
jtfFirst.setText("");
jtfLast.setText("");
jtfAddress.setText("");
jtfCity.setText("");
jtfState.setText("");
jtfZip.setText("");
jtfCard.setText("");
}});
jbtSubmit.addActionListener(new ActionListener()
{#Override
public void actionPerformed(ActionEvent arg0) {
new Infopane(jtfFirst.getText());
//dispose();
}});
}//ENDOFCONSTRUCTOR
public static void main(String[] args)
{
Ch10Asg frame = new Ch10Asg();
frame.pack();
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Flights");
frame.setVisible(true);
frame.setSize(700,450);
}//ENDOFMAIN
}//ENDOFCLASS
class Infopane extends JFrame
{
private JTextArea Info = new JTextArea();
private JButton jbtExit1 = new JButton ("EXIT");
public Infopane(String jtfFirst)
{
JPanel s1 = new JPanel();
add(Info, BorderLayout.NORTH);
//Info.setFont(new Font("Serif", Font.PLAIN, 14));
Info.setEditable(false);
JScrollPane scrollPane = new JScrollPane(Info);
//setLayout(new BorderLayout(5,5));
add(scrollPane);
add(jbtExit1, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null); // Center the frame
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Flight Summary");
setVisible(true);
setSize(700,450);
jbtExit1.addActionListener(new ActionListener()
{#Override
public void actionPerformed(ActionEvent arg0) {
System.exit(0);
}});
}
}
Suggestions:
The second window shouldn't be a second JFrame but rather a modal JDialog since it truly is a dialog of the first window. This way, you don't have to fret about the second window closing the entire application when it is closed.
You already have an idea of what you should be doing -- passing information from one object to another -- since you're passing the String held by the first window's first name's JTextField into the second class: jtfFirst.getText()
Instead of passing just one JTextField's text, consider creating a third data class that holds all the information that you want to pass from one class to the other, create an object of this in the submit's ActionListener, and pass it into the new class.
Alternatively, you could give your first class getter methods, and just pass an instance of the first object into the second object, allowing the second object to extract info from the first by calling its getter methods.
Edit
For example here are snippets of a code example that works. The main JPanel is called MainPanel:
class MainPanel extends JPanel {
// my JTextFields
private JTextField fooField = new JTextField(10);
private JTextField barField = new JTextField(10);
public MainPanel() {
add(new JLabel("Foo:"));
add(fooField);
add(new JLabel("Bar:"));
add(barField);
add(new JButton(new AbstractAction("Submit") {
{
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
}
#Override
public void actionPerformed(ActionEvent evt) {
DialogPanel dialogPanel = new DialogPanel(MainPanel.this);
// code deleted....
// create and show a JDialog here
}
}));
add(new JButton(new AbstractAction("Exit") {
{
putValue(MNEMONIC_KEY, KeyEvent.VK_X);
}
#Override
public void actionPerformed(ActionEvent e) {
Window win = SwingUtilities.getWindowAncestor((JButton)e.getSource());
win.dispose();
}
}));
}
// getter methods to get information held in the fields.
public String getFooText() {
return fooField.getText();
}
public String getBarText() {
return barField.getText();
}
}
And in the dialog panel:
class DialogPanel extends JPanel {
private JTextArea textarea = new JTextArea(10, 15);
private MainPanel mainPanel;
public DialogPanel(MainPanel mainPanel) {
this.mainPanel = mainPanel; // actually don't even need this in your case
// extract the information from the origianl class
textarea.append("Foo: " + mainPanel.getFooText() + "\n");
textarea.append("Bar: " + mainPanel.getBarText() + "\n");
add(new JScrollPane(textarea));
add(new JButton(new AbstractAction("Exit") {
{
putValue(MNEMONIC_KEY, KeyEvent.VK_X);
}
#Override
public void actionPerformed(ActionEvent e) {
Window win = SwingUtilities.getWindowAncestor((JButton)e.getSource());
win.dispose();
}
}));
}
}