How do I reference a string in another class? - java

I am making a login applet to install on my wireless hardrive and am currently building the frameworks for it, (Every time I try to declare the Strings as anything BUT final it shows an error saying only final permitted) I am trying to use the String user and the String pass in if statements which are found in my Skeleton class:
package open;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Skeleton extends JFrame implements ActionListener{
private static final long serialVersionUID = 1248L;
public static void addComponentsToPane(Container pane, Container container) {
//Adding in text fields for login
JButton b1 = new JButton("Login");
final JTextField field2 = new JTextField(2);
final JTextField field = new JTextField(1);
//Creating Box Layout - Subject to change
GroupLayout layout = new GroupLayout(pane);
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
//Setting alignments
b1.setAlignmentX(Component.CENTER_ALIGNMENT);
field.setAlignmentY(BOTTOM_ALIGNMENT);
field2.setAlignmentY(BOTTOM_ALIGNMENT);
b1.setAlignmentY(CENTER_ALIGNMENT);
//Dimensions for User
field.setMaximumSize(new Dimension(235, 20));
field.setMinimumSize(new Dimension(235, 20));
//Dimensions for Password
field2.setMaximumSize(new Dimension(235, 20));
field2.setMinimumSize(new Dimension(235, 20));
//Dimensions for Button
b1.setMaximumSize(new Dimension(100, 40));
b1.setMinimumSize(new Dimension(100, 40));
//Adding space between components
container.add(Box.createRigidArea(new Dimension(275,20)));
container.add(field);
container.add(Box.createRigidArea(new Dimension(275,10)));
container.add(field2);
container.add(Box.createRigidArea(new Dimension(275,12)));
container.add(b1);
//Listen to the login button
b1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
String user = field.getText();
String pass = field2.getText();
System.out.println("Value: " + user + " " + pass);
};
});
}
public static void createAndShowGUI() {
JFrame frame = new JFrame("User Login");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
addComponentsToPane(frame.getContentPane(), frame);
//Create a grey label
JLabel greyLabel = new JLabel();
greyLabel.setOpaque(true);
greyLabel.setBackground(new Color(205, 209, 209));
greyLabel.setPreferredSize(new Dimension(300, 400));
//Adding the label to the pane
frame.getContentPane().add(greyLabel, BorderLayout.CENTER);
//Display the window.
frame.setSize(275, 175);
frame.setVisible(true);
}
public static void closer(boolean close, JFrame frame){
System.out.println(close);
if(close == true){
frame.setVisible(false);
frame.dispose();
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public void actionPerformed(ActionEvent arg0) {
}
}
In my other class there is almost nothing because the class itself relies on importing the String variables
package password;
import open.Skeleton;
import refrence.Resources;
public class PasswordCompare
{
public static void main(String[] args)
{
System.out.println(user);
System.out.println(pass);
}
}

Myself, I would display the above GUI as a modal JDialog, not as a JFrame, I would use a JPasswordField instead of a 2nd JTextField, and I'd give my class public getter methods that would allow the calling class to query the state of its fields, something like
public String getUserName() {
return userNameTextField.getText();
}
and
public char[] getPassword() {
return passwordField.getPassword();
}
Note that passwords should almost never be handled as Strings because doing so would introduce significant vulnerability to your application making it much easier for others to extract passwords.
So as a modal dialog, the calling code is stopped when the dialog is visible, and then only restarts when the dialog is no longer visible, and it is at this point you can query the state of your dialog with the above methods, extracting the pertinent information.
Note that your code uses static methods, something that you don't want to do, as by doing this, your class has no "state", and so querying for the values held by the JTextFields won't work.
Edit
For example:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.*;
public class MySkeleton extends JPanel {
private static final int COLUMN_COUNT = 10;
private static final int I_GAP = 3;
private JTextField userNameField = new JTextField();
private JPasswordField passwordField = new JPasswordField();
public MySkeleton() {
super(new GridBagLayout());
userNameField.setColumns(COLUMN_COUNT);
passwordField.setColumns(COLUMN_COUNT);
GridBagConstraints gbc = getGbc(0, 0, GridBagConstraints.BOTH);
add(new JLabel("User Name:"), gbc);
gbc = getGbc(1, 0, GridBagConstraints.HORIZONTAL);
add(userNameField, gbc);
gbc = getGbc(0, 1, GridBagConstraints.BOTH);
add(new JLabel("Password:"), gbc);
gbc = getGbc(1, 1, GridBagConstraints.HORIZONTAL);
add(passwordField, gbc);
}
public static GridBagConstraints getGbc(int x, int y, int fill) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.insets = new Insets(I_GAP, I_GAP, I_GAP, I_GAP);
gbc.fill = fill;
return gbc;
}
public String getUserName() {
return userNameField.getText();
}
public char[] getPassword() {
return passwordField.getPassword();
}
}
which can be tested in another class via:
public class MySkeletonTest {
private static void createAndShowGui() {
MySkeleton mainPanel = new MySkeleton();
int input = JOptionPane.showConfirmDialog(null, mainPanel, "Login",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
if (input == JOptionPane.OK_OPTION) {
System.out.println("User Name: " + mainPanel.getUserName());
// **** for testing purposes only. Never do this in a real app.
System.out.println("Password: " + new String(mainPanel.getPassword()));
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Are you really sure you need a class just to compare passwords ? This should be the code of your ActionListener. Plus, you don't even instantiate a Skeleton in your code so there is no way you can access those fields. If you really need to do it, just define some getters on Skeleton.
public String getPassword() {
return field2.getText(); //you should really rename this field
}
public String getUser() {
return field.getText(); //you should really rename this field
}

Related

How to set frame visibility conditionally in JSwing?

I'm trying to create a login panel in Java Swing where the user will first get a screen that requires them to enter the credentials and if they match the correct credentials, they will be directed to another java GUI class called UserManager. I'm not sure how I can set the current frame (of the login panel) to be false and the set the frame visible of the new panel that I want to switch to (the UserManger panel) to be true.
Here is what I have so far but it's not working:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JPasswordField;
import javax.swing.JButton;
public class Main implements ActionListener {
private static JLabel label;
private static JTextField userText;
private static JLabel passwordLabel;
private static JPasswordField passwordText;
private static JButton button;
private static JLabel success;
private static boolean loggedIn = false;
public static void main(String[] args) {
// JOptionPane.showMessageDialog(null, "Login");
JFrame f = new JFrame();
JPanel panel = new JPanel();
f.setSize(100, 100);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
panel.setLayout(null);
// username text label
label = new JLabel("User");
label.setBounds(10, 20, 80, 25);
panel.add(label);
userText = new JTextField(20);
userText.setBounds(100, 20, 165, 25);
panel.add(userText);
// pasword label
passwordLabel = new JLabel("Password");
passwordLabel.setBounds(10, 50, 80, 25);
panel.add(passwordLabel);
passwordText = new JPasswordField(20);
passwordText.setBounds(100, 50, 165, 25);
panel.add(passwordText);
button = new JButton("Login");
button.setBounds(10, 80, 80, 25);
button.addActionListener(new Main());
panel.add(button);
success = new JLabel("");
success.setBounds(10, 110, 300, 25);
panel.add(success);
f.setVisible(true);
if (loggedIn) {
UserManager frame = new UserManager();
f.setVisible(false);
frame.setVisible(true);
}
}
#Override
public void actionPerformed(ActionEvent e) {
String user = userText.getText();
String password = passwordText.getText();
System.out.println(user + ", " + password);
if(user.equals("John") && password.equals("hello")) {
success.setText("Login successful");
loggedIn = true;
}
else {
success.setText("Incorrect credentials.");
}
}
}
Use a CardLayout
See for How to Use CardLayout more details.
This will encourage you to isolate you functionality into individual components, there by isolating the workflows and supporting the "single responsibility" concept.
import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
private UserPane userPane;
private LoginPane loginPane;
public MainPane() {
setLayout(new CardLayout());
userPane = new UserPane();
loginPane = new LoginPane(new AuthenticationListener() {
#Override
public void authenticationWasSuccessful(User user) {
userPane.setUser(user);
// The user pane's content size will have changed
SwingUtilities.windowForComponent(userPane).pack();
((CardLayout) getLayout()).show(MainPane.this, "USER");
}
#Override
public void authenticationDidFail() {
JOptionPane.showMessageDialog(MainPane.this, "Authentication failed", "Error", JOptionPane.ERROR_MESSAGE);
}
});
add(userPane, "USER");
add(loginPane, "LOGIN");
((CardLayout) getLayout()).show(this, "LOGIN");
}
}
public interface User {
public String getName();
}
public class DefaultUser implements User {
private String name;
public DefaultUser(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
}
public interface AuthenticationListener {
public void authenticationWasSuccessful(User user);
public void authenticationDidFail();
}
public class LoginPane extends JPanel {
private JTextField user;
private JPasswordField password;
private JButton login;
private AuthenticationListener loginListener;
public LoginPane(AuthenticationListener listener) {
setBorder(new EmptyBorder(32, 32, 32, 32));
this.loginListener = listener;
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.EAST;
add(new JLabel("User name:"), gbc);
gbc.gridy++;
add(new JLabel("Password:"), gbc);
gbc.gridx++;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
user = new JTextField(12);
password = new JPasswordField(12);
add(user, gbc);
gbc.gridy++;
add(password, gbc);
login = new JButton("Login");
gbc.gridx = 0;
gbc.gridy++;
gbc.anchor = GridBagConstraints.CENTER;
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(login, gbc);
login.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
boolean accept = (boolean) (((int) Math.round(Math.random() * 1)) == 0 ? true : false);
if (accept) {
loginListener.authenticationWasSuccessful(new DefaultUser(user.getText()));
} else {
loginListener.authenticationDidFail();
}
}
});
}
}
public class UserPane extends JPanel {
private JLabel userLabel;
public UserPane() {
JLabel label = new JLabel("Welcome!");
Font font = label.getFont();
label.setFont(font.deriveFont(Font.BOLD, 32));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
add(label, gbc);
userLabel = new JLabel();
add(userLabel, gbc);
}
public void setUser(User user) {
userLabel.setText(user.getName());
}
}
}
Use a modal JDialog
See How to Make Dialogs for more details.
More windows isn't always a good choice, but in the context of gathering user credentials, I think you can make an argument.
This makes use of a modal dialog to stop the code execution at the point that the window is made visible and it won't continue until the window is closed. This allows you an opportunity to get and validate the user credentials before the code continues (it's black magic in how it works, but it's a very common workflow)
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
User user = LoginPane.showLoginDialog();
if (user != null) {
JFrame frame = new JFrame();
frame.add(new UserPane(user));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} else {
// Well, you really don't know do you? Did they cancel
// the dialog or did authentication fail?
}
}
});
}
public interface User {
public String getName();
}
public static class DefaultUser implements User {
private String name;
public DefaultUser(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
}
public static class LoginPane extends JPanel {
public interface AuthenticationListener {
public void authenticationWasSuccessful(User user);
public void authenticationDidFail();
}
private JTextField userTextField;
private JPasswordField passwordField;
private JButton loginButton;
private User user;
public LoginPane(AuthenticationListener listener) {
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.EAST;
add(new JLabel("User name:"), gbc);
gbc.gridy++;
add(new JLabel("Password:"), gbc);
gbc.gridx++;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
userTextField = new JTextField(12);
passwordField = new JPasswordField(12);
add(userTextField, gbc);
gbc.gridy++;
add(passwordField, gbc);
loginButton = new JButton("Login");
gbc.gridx = 0;
gbc.gridy++;
gbc.anchor = GridBagConstraints.CENTER;
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(loginButton, gbc);
loginButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
boolean accept = (boolean) (((int) Math.round(Math.random() * 1)) == 0 ? true : false);
if (accept) {
user = new DefaultUser(userTextField.getText());
listener.authenticationWasSuccessful(user);
} else {
user = null;
listener.authenticationDidFail();
}
}
});
}
public User getUser() {
return user;
}
public static User showLoginDialog() {
JDialog dialog = new JDialog();
dialog.setTitle("Login");
dialog.setModal(true);
LoginPane loginPane = new LoginPane(new LoginPane.AuthenticationListener() {
#Override
public void authenticationWasSuccessful(User user) {
dialog.dispose();
}
#Override
public void authenticationDidFail() {
JOptionPane.showMessageDialog(dialog, "Authentication failed", "Error", JOptionPane.ERROR_MESSAGE);
}
});
dialog.add(loginPane);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
return loginPane.getUser();
}
}
public class UserPane extends JPanel {
public UserPane(User user) {
setBorder(new EmptyBorder(32, 32, 32, 32));
JLabel label = new JLabel("Welcome!");
Font font = label.getFont();
label.setFont(font.deriveFont(Font.BOLD, 32));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
add(label, gbc);
JLabel userLabel = new JLabel();
userLabel.setText(user.getName());
add(userLabel, gbc);
}
}
}
You need to unset visibility of this frame and set visible User manager at the action performed level:
private navigateToNextFrame(){
f.dispose(false);
UserManager frame = new UserManager();
frame.setVisible(true);
}
Now you need to call this method in the action performed method instead of loggedin=true and delete block in main main method (if (loggedIn))
A little suggestion : User Manager could be a singleton so you can create it at least 1 time.

Is there any way i can refresh a JDialog and remake it?

I have one main JFrame with one button, when i press this button, one JDialog open with some objects from a Json File. For each object i have a delete button. Everything works great but to see all objects except this one i deleted, i have to close the JDialog and open it again. Is there any way i can refresh JDialog? I found one "solution" witch is to dispose the JDialog and make new one and then set the new one visible, but its not really what i need. I need to see the new results immediately after the button press.The JFrame myFrame bellow is the main Frame dont care about it("i guess").
this is my Dialog:
public class MyFavoriteCoctails extends JDialog {
public MyFavoriteCoctails(JFrame myFrame) {
this.myFrame = myFrame;
setLocationRelativeTo(myFrame);
maker();
}
private void maker() {
setModal(true);
setTitle("My Favortie Cocktails");
setResizable(false);
setLayout(new BorderLayout());
JPanel panelOnTop = new JPanel(new BorderLayout());
JLabel favCocktailLabel = new JLabel("My Favorite Cocktails");
favCocktailLabel.setFont(new Font("Sans Serif", Font.PLAIN, 150));
favCocktailLabel.setForeground(Color.red);
panelOnTop.setBorder(BorderFactory.createMatteBorder(5, 5, 5, 5, Color.red));
panelOnTop.add(favCocktailLabel, BorderLayout.CENTER);
panelOnTop.setBackground(Color.white);
this.add(panelOnTop, BorderLayout.NORTH);
JPanel panelForCocktails = new JPanel();
this.add(panelForCocktails, BorderLayout.CENTER);
List<Coctail> list = SingleObject.getfavCoctailList();
int row;
if ((list.size() % 5) != 0) {
row = list.size() / 5 + 1;
} else {
row = list.size() / 5;
}
panelForCocktails.setLayout(new GridLayout(row, 5));
this.add(panelForCocktails, BorderLayout.CENTER);
for (int i = 0; i < list.size(); i++) {
panelForCocktails.add(new CocktailJPanelForFavorites(list.get(i).getId(), list.get(i).getImg(),
list.get(i).getName(), list.get(i), this, myFrame));
}
pack();
}
JFrame myFrame;
}
This is my JPanel witch it has some details from json file in every panel.:
public class CocktailJPanelForFavorites extends JPanel {
public CocktailJPanelForFavorites(String id, String img, String name, Coctail coctail, JDialog dialog, JFrame myFrame) {
this.coctail = coctail;
this.myFrame=myFrame;
this.id = id;
this.name = name;
this.img = img;
this.dialog=dialog;
maker();
}
#SuppressWarnings({ "rawtypes", "unchecked" })
public void maker() {
setLayout(new BorderLayout(1, 1));
this.setBackground(Color.white);
this.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.black));
JLabel nameLabel = new JLabel(name, SwingConstants.CENTER);
nameLabel.setFont(new Font("Sans Serif", Font.BOLD, 18));
this.add(nameLabel, BorderLayout.NORTH);
JButton deleteFavorite = new JButton("X");
JComboBox comboBox = new JComboBox(Favouritetype.values());
comboBox.setRenderer(new MyComboBoxRenderer("ΚΑΤΗΓΟΡΙΑ"));
comboBox.setSelectedIndex(-1);
;
try {
URL url = new URL(img);
BufferedImage c = ImageIO.read(url);
ImageIcon imageIcon = new ImageIcon(c); // load the image to a imageIcon
Image image = imageIcon.getImage(); // transform it
Image newimg = image.getScaledInstance(200, 200, java.awt.Image.SCALE_SMOOTH); // scale
imageIcon = new ImageIcon(newimg); // transform it back
JLabel jp = new JLabel(imageIcon, JLabel.CENTER);
jp.setBorder(BorderFactory.createMatteBorder(10, 10, 10, 10, Color.white));
jp.addMouseListener(new MouseAdapter(id));
jp.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
add(jp, BorderLayout.CENTER);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JPanel deleteAndCombo = new JPanel(new GridLayout(1, 2));
deleteAndCombo.add(deleteFavorite);
deleteAndCombo.add(comboBox);
add(deleteAndCombo, BorderLayout.SOUTH);
DeleteFavorite act = new DeleteFavorite(coctail, deleteFavorite, dialog, this, myFrame);
deleteFavorite.addActionListener(act);
}
String id, name, img;
Coctail coctail;
JDialog dialog;
JFrame myFrame;
}
And this is my Action Listener of my Delete Button(is the button with the "X" inside):
public class DeleteFavorite implements ActionListener {
public DeleteFavorite(Coctail coctail, JButton deleteFavorite, JDialog dialog, JPanel cockPane, JFrame myFrame) {
this.deleteFavorite = deleteFavorite;
this.coctail = coctail;
this.myFrame=myFrame;
this.dialog=dialog;
this.cockPane=cockPane;
}
#Override
public void actionPerformed(ActionEvent e) {
SingleObject obj = SingleObject.getInstance();
List<Coctail> list = SingleObject.getfavCoctailList();
List<Coctail> favcoctailList = list;
int len = favcoctailList.size();
if (favcoctailList != null) {
for (int i = 0; i < len; i++) {
if ((favcoctailList.get(i).getId().toString().trim().equals(coctail.getId().toString().trim()))) {
favcoctailList.remove(i);
break;
}
}
}
System.out.println(favcoctailList);
obj.make(favcoctailList);
dialog.dispose();
MyFavoriteCoctails dialog1 = new MyFavoriteCoctails(myFrame);
dialog1.setVisible(true);
}
JButton deleteFavorite;
Coctail coctail;
JDialog dialog;
JPanel cockPane;
JFrame myFrame;
}
The basic answer to your question is, your dialog/panel needs some way to get the "next" cocktail. Then all you need to do is update the details of the new cocktail.
The best way to achieve this is to have some kind of "manager", which managers all the cocktails within your system. Before deleting the current cocktail, you'd ascertain the current index of the cocktail within the list, remove the cocktail and then present the cocktail which now occupies this position. You could also do this with some kind of Iterator, but where's the fun in that.
Since I don't have access to all you code (and your UI code is a bit of mess), I devised my own example.
Below is the "detail" pane, which presents details about a give cocktail and allows the user to remove it.
public class CocktailDetailPane extends JPanel {
private JLabel imageLabel;
private JLabel nameLabel;
private CocktailManager cocktailManager;
private Cocktail cocktail;
public CocktailDetailPane(Cocktail cocktail, CocktailManager manager) {
this.cocktailManager = manager;
setLayout(new BorderLayout());
imageLabel = new JLabel();
nameLabel = new JLabel();
JPanel contentPane = new JPanel(new GridBagLayout());
contentPane.setBorder(new EmptyBorder(16, 16, 16, 16));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.PAGE_START;
gbc.insets = new Insets(4, 4, 4, 4);
contentPane.add(imageLabel, gbc);
gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.LINE_START;
contentPane.add(nameLabel, gbc);
gbc.gridy++;
contentPane.add(new JLabel("Drink it fast, drink it often"), gbc);
add(contentPane);
setCocktail(cocktail);
JPanel actionPane = new JPanel(new GridBagLayout());
JButton deleteButton = new JButton("Delete");
deleteButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
CocktailManager manager = getCocktailManager();
List<Cocktail> cocktails = manager.getCocktails();
Cocktail cocktail = getCocktail();
int index = cocktails.indexOf(cocktail);
manager.remove(cocktail);
if (cocktails.isEmpty()) {
JOptionPane.showMessageDialog(CocktailDetailPane.this, "No more cocktails for you", "Empty", JOptionPane.ERROR_MESSAGE);
SwingUtilities.windowForComponent(CocktailDetailPane.this).dispose();
} else {
if (index >= cocktails.size()) {
index = 0;
}
setCocktail(cocktails.get(index));
}
}
});
actionPane.add(deleteButton);
add(actionPane, BorderLayout.SOUTH);
}
protected void setCocktail(Cocktail cocktail) {
imageLabel.setIcon(new ImageIcon(cocktail.getImage()));
nameLabel.setText(cocktail.getName());
this.cocktail = cocktail;
}
public CocktailManager getCocktailManager() {
return cocktailManager;
}
public Cocktail getCocktail() {
return cocktail;
}
}
You will note that I've passed an instance of CocktailManager to the details pane as well as the instance of the Cocktail to be initially presented.
If the current Cocktail is deleted, the next Cocktail is presented (made current) and so on until you have no more cocktails left.
Some of this could have been decoupled through the use of an observer pattern on the CocktailManager itself (so when a cocktail was added or removed, interested parties could react to it, but I took that concept as been out of context for the question).
Runnable example...
Because out of context code can be hard to follow, I've provided a runnable example...
This example makes use of dependency injection (for reference, reference, reference, reference) and "coding to interface" (for reference and reference)
This will allow you to define you own "contract" for the CocktailManager and define your own implementations based on your needs, but the core concept should continue to work
You may also want to take a look at How to Use Lists
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.AbstractListModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
CocktailManager manager = new DefaultCocktailManager();
JFrame frame = new JFrame();
frame.add(new CocktailListPane(manager));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Cocktail {
public String getId();
public Image getImage();
public String getName();
}
public interface CocktailManager {
public List<Cocktail> getCocktails();
public void add(Cocktail coctail);
public void remove(Cocktail coctail);
}
public class CocktailListPane extends JPanel {
private JList<Cocktail> list;
private CocktailManager manager;
public CocktailListPane(CocktailManager manager) {
this.manager = manager;
list = new JList<>(new CocktailListModel(manager));
list.setCellRenderer(new CocktailListCellRenderer());
list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
list.setVisibleRowCount(2);
setLayout(new BorderLayout());
add(new JLabel("My Favorite Cocktails"), BorderLayout.NORTH);
add(new JScrollPane(list));
list.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() != 2) {
return;
}
int index = list.locationToIndex(e.getPoint());
if (index < 0) {
return;
}
Cocktail cocktail = list.getModel().getElementAt(index);
JDialog dialog = new JDialog(SwingUtilities.windowForComponent(CocktailListPane.this));
dialog.setTitle("All your cocktail belong to us");
dialog.setModal(true);
dialog.add(new CocktailDetailPane(cocktail, getCocktailManager()));
dialog.pack();
dialog.setLocationRelativeTo(CocktailListPane.this);
dialog.setVisible(true);
list.setModel(new CocktailListModel(getCocktailManager()));
}
});
}
public CocktailManager getCocktailManager() {
return manager;
}
protected class CocktailListModel extends AbstractListModel<Cocktail> {
private CocktailManager manager;
public CocktailListModel(CocktailManager manager) {
this.manager = manager;
}
#Override
public int getSize() {
return manager.getCocktails().size();
}
#Override
public Cocktail getElementAt(int index) {
return manager.getCocktails().get(index);
}
}
protected class CocktailListCellRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
if (value instanceof Cocktail) {
Cocktail cocktail = (Cocktail) value;
value = cocktail.getName();
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
setIcon(new ImageIcon(cocktail.getImage()));
return this;
}
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
}
}
public class CocktailDetailPane extends JPanel {
private JLabel imageLabel;
private JLabel nameLabel;
private CocktailManager cocktailManager;
private Cocktail cocktail;
public CocktailDetailPane(Cocktail cocktail, CocktailManager manager) {
this.cocktailManager = manager;
setLayout(new BorderLayout());
imageLabel = new JLabel();
nameLabel = new JLabel();
JPanel contentPane = new JPanel(new GridBagLayout());
contentPane.setBorder(new EmptyBorder(16, 16, 16, 16));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.PAGE_START;
gbc.insets = new Insets(4, 4, 4, 4);
contentPane.add(imageLabel, gbc);
gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.LINE_START;
contentPane.add(nameLabel, gbc);
gbc.gridy++;
contentPane.add(new JLabel("Drink it fast, drink it often"), gbc);
add(contentPane);
setCocktail(cocktail);
JPanel actionPane = new JPanel(new GridBagLayout());
JButton deleteButton = new JButton("Delete");
deleteButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
CocktailManager manager = getCocktailManager();
List<Cocktail> cocktails = manager.getCocktails();
Cocktail cocktail = getCocktail();
int index = cocktails.indexOf(cocktail);
manager.remove(cocktail);
if (cocktails.isEmpty()) {
JOptionPane.showMessageDialog(CocktailDetailPane.this, "No more cocktails for you", "Empty", JOptionPane.ERROR_MESSAGE);
SwingUtilities.windowForComponent(CocktailDetailPane.this).dispose();
} else {
if (index >= cocktails.size()) {
index = 0;
}
setCocktail(cocktails.get(index));
}
}
});
actionPane.add(deleteButton);
add(actionPane, BorderLayout.SOUTH);
}
protected void setCocktail(Cocktail cocktail) {
imageLabel.setIcon(new ImageIcon(cocktail.getImage()));
nameLabel.setText(cocktail.getName());
this.cocktail = cocktail;
}
public CocktailManager getCocktailManager() {
return cocktailManager;
}
public Cocktail getCocktail() {
return cocktail;
}
}
public class DefaultCocktailManager implements CocktailManager {
private List<Cocktail> cocktails;
private List<Cocktail> nonmutableCocktails;
public DefaultCocktailManager() {
cocktails = new ArrayList<>(4);
nonmutableCocktails = Collections.unmodifiableList(cocktails);
for (int index = 1; index < 5; index++) {
Image image = null;
try {
image = ImageIO.read(getClass().getResource("/images/ct0" + index + ".png")).getScaledInstance(-1, 50, Image.SCALE_SMOOTH);
} catch (IOException ex) {
ex.printStackTrace();
}
Cocktail cocktail = new DefaultCocktail(Integer.toString(index), image, "Cocktail " + index);
cocktails.add(cocktail);
}
}
#Override
public List<Cocktail> getCocktails() {
return nonmutableCocktails;
}
#Override
public void add(Cocktail cocktail) {
cocktails.add(cocktail);
}
#Override
public void remove(Cocktail cocktail) {
cocktails.remove(cocktail);
}
}
public class DefaultCocktail implements Cocktail {
private String id;
private Image image;
private String name;
public DefaultCocktail(String id, Image image, String name) {
this.id = id;
this.image = image;
this.name = name;
}
#Override
public String getId() {
return id;
}
#Override
public Image getImage() {
return image;
}
#Override
public String getName() {
return name;
}
}
}
nb: BYO your own images
nbb: No cocktails were consumed in the creation of this example, although it probably would have improved the quality 😉

In a java Jframe can I add/remove a Jlabel from view using a checkbox?

Im making an application that lets me perform hashes, at the top I want to have a group of check boxes basically saying the four different hash types I have. When the check boxes are selected I want the labels to appear showing the hashed entered text.
I've attached an image to hopefully make it easier to understand what I mean. The reason I'm doing this is so that when the final program is made with almost 10 rows of text boxes and labels it can be reduced only to show the ones that the user wishes to see.This hopefully should explain what I mean.
I've been able to get it so the checkboxes make it visible or not visible but that also then just leaves a blank space where one row of labels used to be rather than moving everything up a row
I've now added my coding so people can see how I'm doing it currently and help define where needs to be modified
import java.awt.*;
import java.awt.event.*;
import java.security.*;
import javax.swing.*;
public class Hasher extends JFrame implements ActionListener {
String UserInput;
private JTextField textInputField;
private static JLabel MD5Hashed,MD5Label;
private static JCheckBox MD5Check, SHA1Check, SHA256Check, FileCheck;
private JFrame contentPane;
public Hasher() {
this.setTitle("Hasher");
Container contentPane = this.getContentPane();
contentPane.setLayout(new GridLayout(0,1) );
contentPane.setBackground(new Color(88,148,202));
//CheckBoxes
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
JPanel checkBoxPanel = new JPanel();
MD5Check = new JCheckBox("MD5");
MD5Check.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
boolean Visible = MD5Check.isSelected();
MD5Hashed.setVisible(Visible);
MD5Label.setVisible(Visible);
}
});
checkBoxPanel.add(MD5Check);
SHA1Check = new JCheckBox("SHA-1");
checkBoxPanel.add(SHA1Check);
SHA256Check = new JCheckBox("SHA-256");
checkBoxPanel.add(SHA256Check);
FileCheck = new JCheckBox("File Hashing");
checkBoxPanel.add(FileCheck);
mainPanel.add(checkBoxPanel);
contentPane.add(mainPanel);
//Entered data to perform hash on
contentPane.add(new JLabel (" Enter text to hash"));
textInputField = new JTextField();
//HashingProcess inputListener = new HashingProcess( );
//textInputField.addActionListener(inputListener);
contentPane.add( textInputField);
//MD5 hash is completed
MD5Label = new JLabel( " Using MD5 the hash is: " );
contentPane.add( MD5Label);
MD5Hashed = new JLabel( "??") ;
contentPane.add( MD5Hashed );
MD5Hashed.setVisible(false);
MD5Label.setVisible(false);
}
public static void main(String[] args) {
Hasher theWindow = new Hasher( );
theWindow.setSize(400, 400 );
theWindow.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
theWindow.setVisible(true);
}
}
You have two frames...
public class Hasher extends JFrame implements ActionListener {
//...
private JFrame contentPane;
//..
This immediately raises the question, which one is actually on the screen and which one are you actually interacting with? While this might not be directly related to your problem, it is confusing.
As a general rule of thumb, don't extend from top level containers like JFrame, it locks you into a single use case and can cause no end of confusion. Instead, start with a JPanel and add it to an instance of JFrame or any other container you like.
The "main probable" problem is, Swing is lazy. It won't update the UI until you tell it or the UI is resized.
When adding and removing components, you need to call revalidate and repaint on the container to trigger an update - this is what's actually going wrong in your code, you're referencing contentPane, by that is private JFrame contentPane; and not the contentPane of the JFrame from which Hasher extends ... see, confusion.
Happening dug around your code a bit, it's obvious that you have a lot of repeated operations going on, the only core difference is the algorithm used to hash the text.
So, with that in mind, we can create some basic classes to do most of the work, for example...
public class HashPane extends JPanel {
private JLabel hashedLabel;
private JLabel promptLabel;
private HashAlgorithim algorithim;
public HashPane(String labelText, HashAlgorithim algorithim) {
setOpaque(false);
this.algorithim = algorithim;
setLayout(new FlowLayout(FlowLayout.LEFT));
promptLabel = new JLabel(labelText);
add(promptLabel);
hashedLabel = new JLabel("??");
add(hashedLabel);
}
public void setText(String text) {
hashedLabel.setText(algorithim.generateHash(text));
}
}
This is just two labels, which show a prompt and a result. The result is generated via a plug algorithm which is used to generate the hash for the supplied text
The algorithm itself is just a interface which defines the basic contract...
public interface HashAlgorithm {
public String generateHash(String from);
}
You would then need to create an implementation of each algorithm you wanted to use
Now, making a panel visible/invisible simply becomes a matter of associating a JCheckBox with a HashPane which can be achieved through a simple Map...
public class Hasher extends JPanel {
//...
private Map<JCheckBox, HashPane> mapPanes;
public Hasher() {
//...
HashPane md5Pane = new HashPane("MD5 hash = ", new NotAMD5Alorithim());
//...
HashPane sha1Pane = new HashPane("SHA-1 hash = ", new NotAMSHA1Alorithim());
//..
mapPanes = new HashMap<>(25);
mapPanes.put(MD5Check, md5Pane);
mapPanes.put(SHA1Check, sha1Pane);
//...
You can then use a single ActionListener to manage all the JCheckBoxs
public class Hasher extends JPanel {
//...
private Map<JCheckBox, HashPane> mapPanes;
public Hasher() {
//...
ActionHandler listener = new ActionHandler();
for (Entry<JCheckBox, HashPane> entry : mapPanes.entrySet()) {
entry.getKey().addActionListener(listener);
entry.getValue().setVisible(false);
}
}
protected class ActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JCheckBox cb = (JCheckBox) e.getSource();
HashPane hashPane = mapPanes.get(cb);
hashPane.setVisible(cb.isSelected());
revalidate();
repaint();
}
}
And because I pretty much butchered your code...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Hasher extends JPanel {
String UserInput;
private JTextField textInputField;
private static JCheckBox MD5Check, SHA1Check, SHA256Check, FileCheck;
private Map<JCheckBox, HashPane> mapPanes;
public Hasher() {
setLayout(new BorderLayout());
setBackground(new Color(88, 148, 202));
//CheckBoxes
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
JPanel checkBoxPanel = new JPanel();
MD5Check = new JCheckBox("MD5");
checkBoxPanel.add(MD5Check);
SHA1Check = new JCheckBox("SHA-1");
checkBoxPanel.add(SHA1Check);
SHA256Check = new JCheckBox("SHA-256");
checkBoxPanel.add(SHA256Check);
FileCheck = new JCheckBox("File Hashing");
checkBoxPanel.add(FileCheck);
mainPanel.add(checkBoxPanel);
add(mainPanel, BorderLayout.NORTH);
JPanel centerPane = new JPanel(new BorderLayout());
centerPane.setOpaque(false);
JPanel inputPane = new JPanel(new FlowLayout(FlowLayout.LEFT));
inputPane.setOpaque(false);
//Entered data to perform hash on
inputPane.add(new JLabel("Enter text to hash: "));
textInputField = new JTextField(20);
inputPane.add(textInputField);
centerPane.add(inputPane, BorderLayout.NORTH);
JPanel output = new JPanel(new GridBagLayout());
output.setOpaque(false);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
HashPane md5Pane = new HashPane("MD5 hash = ", new NotAMD5Alorithim());
output.add(md5Pane, gbc);
gbc.gridx = 0;
gbc.gridy++;
HashPane sha1Pane = new HashPane("SHA-1 hash = ", new NotAMSHA1Alorithim());
output.add(sha1Pane, gbc);
// last pane
gbc.gridy++;
gbc.weighty = 1;
output.add(new JLabel(), gbc);
centerPane.add(output);
add(centerPane);
mapPanes = new HashMap<>(25);
mapPanes.put(MD5Check, md5Pane);
mapPanes.put(SHA1Check, sha1Pane);
//...
ActionHandler listener = new ActionHandler();
for (Entry<JCheckBox, HashPane> entry : mapPanes.entrySet()) {
entry.getKey().addActionListener(listener);
entry.getValue().setVisible(false);
}
}
protected class ActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JCheckBox cb = (JCheckBox) e.getSource();
HashPane hashPane = mapPanes.get(cb);
hashPane.setVisible(cb.isSelected());
revalidate();
repaint();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Hasher());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface HashAlgorithm {
public String generateHash(String from);
}
public class NotAMD5Alorithim implements HashAlgorithm {
#Override
public String generateHash(String from) {
return "bananas";
}
}
public class NotAMSHA1Alorithim implements HashAlgorithm {
#Override
public String generateHash(String from) {
return "bananas";
}
}
public class HashPane extends JPanel {
private JLabel hashedLabel;
private JLabel promptLabel;
private HashAlgorithm algorithim;
public HashPane(String labelText, HashAlgorithm algorithim) {
setOpaque(false);
this.algorithim = algorithim;
setLayout(new FlowLayout(FlowLayout.LEFT));
promptLabel = new JLabel(labelText);
add(promptLabel);
hashedLabel = new JLabel("??");
add(hashedLabel);
}
public void setText(String text) {
hashedLabel.setText(algorithim.generateHash(text));
}
}
}
Having said all that, I might be tempted to have the JCheckBox in the HashPane and has the HashPane always visible and simply disable the output text ... or simply not bother and always have all the algorithms available all the time
you need to handle Events for all check-box while check/uncheck,
public void actionPerformed(ActionEvent actionEvent) {
if(all check-box un-checked){
// someLable.setVisible(false);
}else if(MD5 checked){
// peform operation based upon MD5
// someLable.setVisible(true);
}
// likewise for all others
}
Change
public void actionPerformed(ActionEvent e) {
boolean Visible = MD5Check.isSelected();
MD5Hashed.setVisible(Visible);
MD5Label.setVisible(Visible);
}
to:
public void actionPerformed(ActionEvent e) {
boolean Visible = MD5Check.isSelected();
MD5Hashed.setVisible(Visible);
MD5Label.setVisible(Visible);
contentPane.validate();
contentPane.repaint();
}
If You want to remove MD5Hashed and MD5Label then something like this:
{
if(MD5Check.isSelected()){
MD5Hashed.remove();
MD5Label.remove();
}
else{
contentPane.add( MD5Label);
contentPane.add( MD5Hashed );
}
contentPane.validate();
contentPane.repaint();
}

Spacing errors while printing vector to JTextArea

So I'm working on making a database system built on top of a Java Swing GUI... I have one button that works to add a person/thing to a vector (in this case the database):
// Database
Vector<String> db = new Vector<String>();
Here is the button's actionlistener to add:
new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newStudent = student.getText();
db.addElement(newStudent);
This part all seems to be working fine, however, when I go to print out the vector on a JTextArea using a string buffer, there are odd spacing issues in the text on the JTextArea
Here is the StringBuffer and section where I print the vector onto the JTextArea:
StringBuffer dbb = new StringBuffer();
for (int i = 0; i < db.size(); i++) {
dbb.append(db.get(i) + '\n');
}
// printDB is the JTextArea
printDB.setText(dbb.toString());
add(printDB);
Screenshot of spacing issues:
Screenshot
Any Ideas on what might be causing this? The spacing seems to be linear as well (1space, 2spaces, 3spaces...)
Link to full project if needed (Sorry for bad code in general lol i'm just beginning): Full Code
Sorry if linear isn't the right word btw I couldn't think of another way to describe it
Code:
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import java.util.Vector.*;
import javax.swing.*;
public class Database extends JFrame implements ActionListener, EventListener {
// Database
Vector<String> db = new Vector<String>();
// Main Menu Buttons:
JButton addStudent = new JButton("Add Student");
JButton deleteStudent = new JButton("Delete Button");
JButton deleteAll = new JButton("Delete All Students");
JButton printAll = new JButton("Print Database");
JTextArea welcome = new JTextArea("Welcome!");
// Add Student Menu:
JTextField student = new JTextField();
JButton submit = new JButton("Add Student");
// Print Students
JTextArea printDB = new JTextArea();
JButton returnMenu = new JButton("Return to Menu");
public Database() {
super("DatabaseGUI");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
setResizable(false);
welcome.setBackground(this.getForeground());
add(welcome);
welcome.setSize(60, 15);
welcome.setLocation(386, 300);
add(addStudent);
addStudent.setSize(150, 50);
addStudent.setLocation(25, 100);
add(deleteStudent);
deleteStudent.setSize(150, 50);
deleteStudent.setLocation(625, 100);
add(deleteAll);
deleteAll.setLocation(225, 100);
deleteAll.setSize(150, 50);
add(printAll);
printAll.setLocation(425, 100);
printAll.setSize(150, 50);
addStudent.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
welcome.setVisible(false);
addStudent.setVisible(false);
deleteStudent.setVisible(false);
deleteAll.setVisible(false);
printAll.setVisible(false);
add(student);
add(submit);
submit.setVisible(true);
submit.setSize(150, 30);
submit.setLocation(425, 250);
student.setVisible(true);
student.setSize(150, 30);
student.setLocation(275, 250);
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newStudent = student.getText();
db.addElement(newStudent);
student.setText(null);
student.setVisible(false);
submit.setVisible(false);
welcome.setVisible(true);
addStudent.setVisible(true);
deleteStudent.setVisible(true);
deleteAll.setVisible(true);
printAll.setVisible(true);
}
});
}
});
printAll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
welcome.setVisible(false);
addStudent.setVisible(false);
deleteStudent.setVisible(false);
deleteAll.setVisible(false);
printAll.setVisible(false);
StringBuffer dbb = new StringBuffer();
for (int i = 0; i < db.size(); i++) {
dbb.append(db.get(i) + '\n');
}
printDB.setText(dbb.toString());
add(printDB);
printDB.setSize(300, 400);
printDB.setEditable(false);
printDB.setLocation(100, 100);
printDB.setVisible(true);
add(returnMenu);
returnMenu.setVisible(true);
returnMenu.setSize(200, 30);
returnMenu.setLocation(500, 400);
returnMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
returnMenu.setVisible(false);
printDB.setVisible(false);
welcome.setVisible(true);
addStudent.setVisible(true);
deleteStudent.setVisible(true);
deleteAll.setVisible(true);
printAll.setVisible(true);
}
});
}
});
setVisible(true);
}
public static void main(String[] args) {
Database student = new Database();
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
You're adding an ActionListener to the submit button repeatedly within the addStudent ActionListener, meaning as addStudent is pressed, more and more ActionListeners will be added to submit and this is not what you want.
Suggestions:
Add an ActionListener just once to your JButtons and not within other event listeners which may be called multiple times. Consider adding all ActionListeners within your class constructor.
Side recs:
Don't use absolute positioning and null layouts. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
Learn how to use and then use CardLayout to allow you to cleanly and easily swap your views.
For example,
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Font;
import java.awt.GridLayout;
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 Database2 extends JPanel {
// constants for the cards
public static final String WELCOME = "welcome";
public static final String ADD_STUDENT = "add student";
public static final String DISPLAY_DATA = "display data";
private JTextArea displayTextArea = new JTextArea(15, 20);
private JTextField addStudentField = new JTextField(10);
private CardLayout cardLayout = new CardLayout();
private List<String> db = new ArrayList<>();
public Database2() {
// prepare JTextArea
displayTextArea.setWrapStyleWord(true);
displayTextArea.setLineWrap(true);
displayTextArea.setFocusable(false);
// set layout as CardLayout and add all JPanels with constants
setLayout(cardLayout);
add(createWelcomePanel(), WELCOME);
add(createAddStudentPanel(), ADD_STUDENT);
add(createDisplayDataPanel(), DISPLAY_DATA);
}
private JPanel createWelcomePanel() {
ShowStudentPanelAction showStudentAction = new ShowStudentPanelAction("Add Student");
DisplayDataAction displayDataAction = new DisplayDataAction("Display Data");
JButton addStudentButton = new JButton(showStudentAction);
JButton displayDataButton = new JButton(displayDataAction);
JPanel topPanel = new JPanel(new GridLayout(1, 0, 5, 0));
topPanel.add(addStudentButton);
topPanel.add(displayDataButton);
topPanel.add(new JButton(new ExitAction("Exit", KeyEvent.VK_X)));
JLabel welcomeLabel = new JLabel("Welcome", SwingConstants.CENTER);
// make JLabel text bigger
welcomeLabel.setFont(welcomeLabel.getFont().deriveFont(Font.BOLD, 42f));
// and give it a border 30 points wide
int ebGap = 30;
welcomeLabel.setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap,
ebGap, ebGap));
JPanel welcomePanel = new JPanel(new BorderLayout());
ebGap = 4;
welcomePanel.setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap, ebGap, ebGap));
welcomePanel.add(topPanel, BorderLayout.PAGE_START);
welcomePanel.add(welcomeLabel, BorderLayout.CENTER);
return welcomePanel;
}
private JPanel createAddStudentPanel() {
AddStudentAction addStudentAction = new AddStudentAction("Add Student");
addStudentField.setAction(addStudentAction);
JPanel addStudentPanel = new JPanel();
addStudentPanel.add(addStudentField);
addStudentPanel.add(new JButton(addStudentAction));
return addStudentPanel;
}
private JPanel createDisplayDataPanel() {
JPanel displayDataPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(displayTextArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
displayDataPanel.add(scrollPane);
displayDataPanel.add(new JButton(new ReturnToWelcomeAction("Return")));
return displayDataPanel;
}
private class ShowStudentPanelAction extends AbstractAction {
public ShowStudentPanelAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(Database2.this, ADD_STUDENT);
addStudentField.requestFocusInWindow();
addStudentField.selectAll();
}
}
private class DisplayDataAction extends AbstractAction {
public DisplayDataAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
StringBuilder sb = new StringBuilder();
for (String studentName : db) {
sb.append(studentName + "\n");
}
displayTextArea.setText(sb.toString());
cardLayout.show(Database2.this, DISPLAY_DATA);
}
}
private class AddStudentAction extends AbstractAction {
public AddStudentAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
String studentText = addStudentField.getText();
db.add(studentText);
cardLayout.show(Database2.this, WELCOME);
}
}
private class ReturnToWelcomeAction extends AbstractAction {
public ReturnToWelcomeAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(Database2.this, WELCOME);
}
}
private class ExitAction extends AbstractAction {
public ExitAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Window window = SwingUtilities.getWindowAncestor(Database2.this);
if (window != null) {
window.dispose();
}
}
}
private static void createAndShowGui() {
Database2 mainPanel = new Database2();
JFrame frame = new JFrame("Database2");
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();
}
});
}
}

Swing: How to create a scrollable list of JPanels that use no Layout

I am trying to find a way to create a list of JPanels which have no Layout manager.
I found several examples on SO providing solutions to the 'scrollable JPanel list' problem. More specifically, I started from this thread and worked on it.
My current problem is that I am having issues when I remove the layout from the JPanels in the list.
They get added correctly but the scrollbar does not appear when needed, and the panels start overlapping.
Note: I know that layouts are heavily preferred but I find it more straightforward to work with pure X, Y coordinates and a mockup program. Please do not bash me for this...
Here is a small working example (taken and modified from this comment):
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.MatteBorder;
public class JScrollPanels {
private int i;
private JPanel listContainer;
private void initUI() {
final JFrame frame = new JFrame(JScrollPanels.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
listContainer = new JPanel();
listContainer.setLayout(new BoxLayout(listContainer, BoxLayout.Y_AXIS));
frame.add(new JScrollPane(listContainer), BorderLayout.CENTER);
JButton button = new JButton("Add");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
final JPanel newPanel = new JPanel();
newPanel.setLayout(null);
newPanel.setSize(272, 110);
JLabel name = new JLabel("Name " + i++);
name.setBounds(18, 13, 84, 21);
newPanel.setBorder(new MatteBorder(0, 0, 1, 0, Color.GRAY));
JLabel date = new JLabel("12/11/2014");
date.setBounds(10, 44, 123, 21);
JButton btn= new JButton(">");
btn.addActionListener( new NameListener(name, date) );
btn.setBounds(205, 44, 48, 30);
newPanel.add(name);
newPanel.add(date);
newPanel.add(btn);
listContainer.add(newPanel);
listContainer.revalidate();
// Scroll down to last added panel
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
newPanel.scrollRectToVisible(newPanel.getBounds());
}
});
}
});
frame.add(button, BorderLayout.PAGE_END);
frame.setSize(272, 300);
frame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JScrollPanels().initUI();
}
});
}
public class NameListener implements ActionListener {
private JLabel name;
private JLabel date;
public NameListener(JLabel name, JLabel date) {
this.name = name;
this.date = date;
}
public void actionPerformed(ActionEvent e) {
System.out.println("Clicked " + name.getText() + " on " + date.getText());
}
}
}
EDIT:
Fixed by using this:
final JPanel newPanel = new JPanel(){
#Override
public Dimension getPreferredSize() {
return new Dimension(272, 110);
}
};
Thanks, mKorbel!
Again, I still persist in my claim that in the long run, a layout manager will work best. For instance, your GUI could use something perhaps like this:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.*;
import javax.swing.border.Border;
#SuppressWarnings("serial")
public class JScrollPanels2 extends JPanel {
private static final int PREF_W = 300;
private static final int PREF_H = 300;
private int i;
private JPanel listContainer;
public JScrollPanels2() {
JPanel outerWrapperPanel = new JPanel(new BorderLayout());
listContainer = new JPanel();
listContainer.setLayout(new BoxLayout(listContainer, BoxLayout.Y_AXIS));
outerWrapperPanel.add(listContainer, BorderLayout.PAGE_START);
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
buttonPanel.add(new JButton(new AddAction("Add")));
setLayout(new BorderLayout());
add(new JScrollPane(outerWrapperPanel), BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class AddAction extends AbstractAction {
public AddAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent evt) {
listContainer.add(new CellPanel(i));
listContainer.revalidate();
listContainer.repaint();
i++;
}
}
private class CellPanel extends JPanel {
private final int gap = 4;
private int index;
private String name;
private Date date;
private final String format = "MM/dd/yyyy";
private SimpleDateFormat sdf = new SimpleDateFormat(format);
public CellPanel(int i) {
this.index = i;
this.name = "Name " + index;
setLayout(new GridBagLayout());
date = new Date();
Border emptyBorder = BorderFactory.createEmptyBorder(gap, gap, gap, gap);
Border lineBorder = BorderFactory.createLineBorder(Color.black);
setBorder(BorderFactory.createCompoundBorder(lineBorder, emptyBorder));
add(new JLabel(name), createGbc(0, 0));
add(new JLabel(""), createGbc(1, 0));
add(new JLabel(sdf.format(date)), createGbc(0, 1));
add(new JButton(new MyBtnAction(">")), createGbc(1, 1));
}
private 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;
if (x % 2 == 0) {
gbc.anchor = GridBagConstraints.WEST;
} else {
gbc.anchor = GridBagConstraints.EAST;
}
return gbc;
}
private class MyBtnAction extends AbstractAction {
public MyBtnAction(String name) {
super(name);
// int mnemonic = (int) name.charAt(0);
// putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("Button pressed for " + name);
}
}
}
private static void createAndShowGui() {
JScrollPanels2 mainPanel = new JScrollPanels2();
JFrame frame = new JFrame("JScrollPanels2");
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();
}
});
}
}
One of the beauties of use of layout managers is their flexibility. If you wanted to add new components to the inner JPanel, you can easily do so without having to manually recalculate every dang other component's position, if they need to be shifted. Instead, let the layout managers do the heavy lifting for you. Also, while your null-layout using GUI might look good on one platform it will usually look terrible on most other platforms or screen resolutions.

Categories