I am new to java and i am trying a small project on my own, i want to list the first and lastname of users from a sql database (this all works fine, but i don't just want to list them
I want to list all users in a GUI with a delete button, naturally this delete button will be generated dynamically and i want to pass the userID of the button to the action performed.
like this:
John Doe 'Delete button'
Jane Doe 'Delete button'
In my code below i just generate 16 buttons dynamically (without a users table) instead of passing the userID i am trying to pass the 'i' value of the for loop, but my code does not seem to work
CODE
public class UsersView implements ActionListener {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
public UsersView() {
//Create the 16 buttons.
for (int i=0; i<16; i++) {
Button button = new Button("Click "+i);
button.setId(i); //this gives me and error 'Symbol not find' on the 'setId'
panel.add(button);
button.addActionListener(this);
}
panel.setBorder(BorderFactory.createBevelBorder(0, Color.lightGray, Color.yellow));
//panel.setBorder(BorderFactory.createEmptyBorder(300, 300, 100, 300));
panel.setLayout(new GridLayout(4,4)); //Rows Cols
frame.add(panel, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("App GUI");
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// TODO code application logic here
new UsersView();
}
//On button click.
#Override
public void actionPerformed(ActionEvent e) {
//I know i have nothing here (yet) that is because the 'setId' gives me an error.
}
}
One of the issues you're having is creating a monolithic action listener, and then expecting to delegate actions from that. One nice feature of java are anonymous classes, or since java 7 lambdas.
JButton button = new JButton("Click " + i);
panel.add(button);
int id = i;
button.addActionListener( evt->{
performActionOnId( id );
});
Now instead of having the main class be an action listener, the main class has methods that are descriptive.
public void addUser( User a ){
//just showing delete button.
JButton delete = new JButton("X");
delete.addActionListener( evt ->{
removeUser( a );
//clean up gui.
});
}
This puts some of the steps of delegation at the creation of the user. Otherwise you'll have to delegate in your action performed.
public void actionPerformed( ActionEvent evt ){
//has to be a new class to have id attribute.
CustomButton b = (CustomButton)evt.getSource();
int id = b.getId();
User u = getUserById(id);
removeUser(u);
}
Use a JButton instead of Button. Mixing AWT and Swing components rarely works well, if at all. If you want to set a custom field for a component, just subclass it (use direct subclassing or a decorator pattern with composition). E.g.:
public class IdButton extends JButton {
private int id;
public IdButton(String label, int id) {
super(label);
this id = id;
}
public int getId() {
return id;
}
}
The J/Button classes do not have set/getId methods on it's own.
Related
So i am making a shop system with a gui. I have a menu item that when i press it opens another jframe to input the number of each item sold in a jtextfield, like this:
JPanel salesPanel = new JPanel();
setSize(new Dimension(520,270));
setResizable(false);
setLocation(200,200);
title = new JLabel("<html><u><b>Fill in the number of products sold.</b></u></html>");
salesPanel.setSize(new Dimension(230,30*sw.getProductList().size()));
salesPanel.setLayout(new GridLayout(sw.getProductList().size()+1,3));
...
sw.getProductList().forEach(n ->{
salesPanel.add(new JLabel(Integer.toString(n.getProductID())+":"));
salesPanel.add(new JLabel(Integer.toString(n.getQuantity())));
salesPanel.add(new JLabel(n.getName()));
salesPanel.add(new JTextField());
});
This is how it looks.
Note that sw is the object of the main class which has an ArrayList of the type product which contains the information of each product.
Is there any way that I can text from these JTextFields ? And if not what is another way that I can do this.
EDIT:
in the main ShopWindow class, I have an ArrayList
private ArrayList<Product> productList = new ArrayList<Product>();
class product:
public class Product {
private int productID;
private String name;
private double price;
private int quantity;
private boolean isPerishable;
private double totalProdValue;
...getters and setters for each field
This is a mock solution (only meant to show how to update qty label and clear fields using action listeners)
public class MockFrame {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel framePanel = new JPanel();
ProductPanel bananaPanel = new ProductPanel("268", "25", "Bananas");
ProductPanel sugarPanel = new ProductPanel("321", "200", "Sugar");
JPanel buttonPanel = new JPanel();
JButton update = new JButton("Update");
JButton cancel = new JButton("Cancel");
buttonPanel.setSize(400, 30);
update.setSize(50, 20);
cancel.setSize(50, 20);
buttonPanel.add(update);
buttonPanel.add(cancel);
update.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
bananaPanel.setNewQty();
sugarPanel.setNewQty();
}
});
cancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
bananaPanel.clearField();
sugarPanel.clearField();
}
});
frame.setSize(400, 400);
framePanel.setLayout(new BoxLayout(framePanel, BoxLayout.PAGE_AXIS));
framePanel.add(bananaPanel);
framePanel.add(sugarPanel);
framePanel.add(buttonPanel);
frame.add(framePanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static class ProductPanel extends JPanel {
private JLabel productId = new JLabel();
private JLabel qty = new JLabel();
private JLabel name = new JLabel();
private JTextField field = new JTextField();
public ProductPanel(String id, String amount, String itemName) {
this.setSize(400, 30);
this.field.setSize(100, 20);
this.field.setColumns(5);
productId.setText(id);
qty.setText(amount);
name.setText(itemName);
this.add(productId);
this.add(qty);
this.add(name);
this.add(field);
}
public void clearField() {
field.setText("");
}
public void setNewQty() {
String newQty = field.getText();
if (newQty != null && !newQty.isBlank()) {
qty.setText(newQty);
}
}
}
}
Main points of this mocked solution:
Use a JPanel to encapsulate a product line item. This will make it easier if you need to remove and/or add product rows.
The product panel contains a method to update qty or clear the fields that will be invokable by the frame buttons (depending on which is clicked).
Simplicity of design - Creating a generic panel for the product eliminate repetitive code.
Obviously, you would have to modify this so that you use the proper layout manager or use absolute positioning to properly aligned components to your liking. Also, you would need to create a Panel for the table header and add the remaining of your products. Also, you may want to break this into public classes and even maybe create a separate class for your frame.
The action listeners could also have a "for-each" loop to update each ProductPanel instead of hard coding each panel individually. That should look something like this:
public void actionPerformed(ActionEvent e) {
JPanel panel = (JPanel)((JButton) e.getSource()).getParent().getParent();
Component[] components = panel.getComponents();
for (Component c : components) {
if (c instanceof ProductPanel) {
((ProductPanel)c).setNewQty();
}
}
}
});
Obviously, your solution will depend on how you decide to encapsulate your components in containers. For this mock, the product panels are inside the frame panel which contains the panels where the buttons were placed. Therefore, I need to get the "grandparent" container for the update and cancel buttons to take advantage of calling the appropriate methods to update and clear in a more dynamic way.
Lastly, you may want to do something more elegant for creating your product panels. For example, you may want to add some factory method to create your product panel instead of having hard-coded product panels like my mock solution. Anyway, I think I demonstrated the solution you were looking for.
UPDATE: If you don't follow Andrew Thompson's recommendation of not using text fields for numeric values, the panel's getNewQty method would need to validate the text obtained to make sure it contains a valid numeric value (which was his point). I would STRONGLY recommend you follow his advice.
I have a frame with a combo box that displays different shapes and a button, for the button I added an action listener which will get the selected item from the combo box and store it as a string which i declared as a public class variable, in my main method i want to access this string to make a finch robot draw that shape but I can't seem to access it no matter what I try
public class DrawShape
{
private JFrame frame;
private String[] choices = {"circle", "square", "triangle", "rectangle", "quit"};
public String choice = "";
//class constructor
public DrawShape()
{
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
JPanel p = new JPanel();
final JComboBox cb = new JComboBox(choices);
JButton button = new JButton("Done");
p.add(cb);
p.add(button);
frame.add(p);
//create an action listener that, when button is clicked, gets the selected choice and stores it to
//the string variable 'choice'
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
choice = (String)cb.getSelectedItem();
}
}) ;
frame.pack();
}
public static void main(String[] args)
{
new DrawShape();
System.out.println(choice);
}
}
I wouldn't recommend the use of non-private variables. However, you need to keep a reference to the object you created and then access the fields through that reference as if you were calling methods on an object.
DrawShape draw = new DrawShape();
System.out.println(draw.choice);
However, you should see null as this is called immediately after you construct the object rather than from the listener.
You probably want the code executed from the listener. So either put the print code in the listener, or have the listener call another method with that in.
GUI programming tends to be event driven. Don't expect to be able to sequence the user interaction - the user drives.
you should use getters/setters in this case. Your action listener would call the getter method which would in turn get what is in the combobox.
Here is an example of how that works: https://www.codejava.net/coding/java-getter-and-setter-tutorial-from-basics-to-best-practices
Hope this helps.
I want to be able to pass user input from my GUI to one of my classes. However, the input is not passed over and immediately checks the if statement.
How do I get program to wait for the input and only checks after the button is clicked?
Main class
public class MainTest {
public static void main(String[] args) {
String weaponCategory;
//Create Java GUI
GUITest window = new GUITest();
if(window.getCategory() != "")
{
System.out.println("test");
}
}
}
GUITest class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GUITest implements ActionListener{
private JFrame frmInventorysystem;
private JPanel frameBottom;
private JComboBox equipList;
private String category = "";
private JButton confirmBtn, cancelBtn;
/**
* Create the application.
*/
public GUITest()
{
frmInventorysystem = new JFrame();
frmInventorysystem.setTitle("InventorySystem");
frmInventorysystem.setBounds(100, 100, 450, 300);
frmInventorysystem.getContentPane().setLayout(new BorderLayout(0, 0));
frmInventorysystem.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/*JFrame inside another JFrame is not recommended. JPanels are used instead.
* Creating a flow layout for the bottom frame
*/
frameBottom = new JPanel();
frameBottom.setLayout(new FlowLayout());
//creates comboBox to find out which of the three items player is looking to insert
String[] weaponCategories = {"Weapon", "Armor", "Mod"};
equipList = new JComboBox(weaponCategories);
frmInventorysystem.getContentPane().add(equipList, BorderLayout.NORTH);
//Converting BorderLayout.south into a flow layout
frmInventorysystem.getContentPane().add(frameBottom, BorderLayout.SOUTH);
confirmBtn = new JButton("Confirm");
confirmBtn.addActionListener(this);
frameBottom.add(confirmBtn);
cancelBtn = new JButton("Cancel");
cancelBtn.addActionListener(this);
frameBottom.add(cancelBtn);
frmInventorysystem.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
//creates new windows to sort equipment when confirmBtn is clicked
if(e.getSource() == confirmBtn)
{
if(equipList.getSelectedItem().equals("Weapon"))
{
//GUIWeaponCategory weapon = new GUIWeaponCategory();
category = equipList.getSelectedItem().toString();
}
}
//Exits when cancelBtn is clicked
if(e.getSource() == cancelBtn)
{
System.exit(0);
}
}
public String getCategory()
{
return category;
}
public void setCategory(String a)
{
category = a;
}
}
GUITest launches as expected.
However, the first println is missing.
How would I go about doing this?
What concepts or pieces of code am I missing?
EDIT1: Added a couple more details to make the program reproducible and complete.
EDIT2: Making the code more readable for easy understanding.
There are some changes to make on your program
Remove extends JFrame as stated in my comments above, see Extends JFrame vs. creating it inside the program
Place your program on the EDT, see point #3 on this answer and the main method for an example on how to do that.
You're confused about how the ActionListeners work, they wait until you perform certain action in your program (i.e. you press Confirm button) and then do something. "Something" in your program means: Print the selected item and check if it's a weapon then, do something else.
So, in this case, you don't need to return back to main to continue with your program, main only serves to initialize your application and nothing else. You need to think in the events and not in a sequential way. That's the tricky and most important part.
You need to change your programming paradigm from console applications and do-while that everything happens in a sequential manner rather than events that are triggered when the user does something with your application.
For example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GUITest implements ActionListener {
private JFrame frmInventorysystem;
private JPanel frameBottom;
private JComboBox equipList;
private JButton confirmBtn, cancelBtn;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new GUITest()); //Java 8+ if using an earlier version check the point #2 in this answer and modify the code accordingly.
}
/**
* Create the application.
*/
public GUITest() {
frmInventorysystem = new JFrame();
frmInventorysystem.setTitle("InventorySystem");
frmInventorysystem.setBounds(100, 100, 450, 300);
frmInventorysystem.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmInventorysystem.getContentPane().setLayout(new BorderLayout(0, 0));
/*
* JFrame inside another JFrame is not recommended. JPanels are used instead
* Creating a flow layout for the bottom frame
*/
frameBottom = new JPanel();
frameBottom.setLayout(new FlowLayout());
// creates comboBox to find out which of the three items player is looking to
// insert
String[] weaponCategories = { "Weapon", "Armor", "Mod" };
equipList = new JComboBox(weaponCategories);
frmInventorysystem.getContentPane().add(equipList, BorderLayout.NORTH);
// Converting BorderLayout.south into a flow layout
frmInventorysystem.getContentPane().add(frameBottom, BorderLayout.SOUTH);
confirmBtn = new JButton("Confirm");
confirmBtn.addActionListener(this);
frameBottom.add(confirmBtn);
cancelBtn = new JButton("Cancel");
cancelBtn.addActionListener(this);
frameBottom.add(cancelBtn);
frmInventorysystem.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
// creates new windows to sort equipment when confirmBtn is clicked
if (e.getSource() == confirmBtn) {
String category = equipList.getSelectedItem().toString(); //Get the selected category
doSomething(category); //Pass it as a parameter
}
// Exits when cancelBtn is clicked
if (e.getSource() == cancelBtn) {
frmInventorysystem.dispose();
}
}
// Do something with the category
private void doSomething(String selectedEquipment) {
System.out.println(selectedEquipment);
if (selectedEquipment.equals("Weapon")) {
System.out.println("It's a weapon!"); //You can open dialogs or do whatever you need here, not necessarily a print.
} else {
System.out.println("Not a weapon");
}
}
}
Notice that I removed inheritance, I'm not returning back to main and still printing the selected item and checking if it's a weapon or not.
I also exit the application in a safer way.
This is a sample output:
Weapon
It's a weapon!
Armor
Not a weapon
I'm a beginner at java and want to make a JFrame with tabs containing a seperate JPanel. One panel has a list where it displays things that you select in a different panel, so I want this panel to always display a list of stuff that you have selected in a different panel (I hope that makes sense). To do this, I need to make a method to refresh the JList. This is the Farthest that I've gotten on that:
public class PanelClass extends JPanel {
private JList list;
private DefaultListModel listModel = new DefaultListModel();
private ArrayList<SomeOtherClass> objectArray = new ArrayList<SomeOtherClass>();
public PanelClass() {
list.setModel(listModel);
}
public void refresh() {
updateListModel();
list.setModel(listModel);
}
public void updateListModel() {
if (objectArray.isEmpty()) {
System.out.println("No Objects In Array!");
} else {
listModel.clear();
for (SomeOtherClass SOC : objectArray) {
// SOC.getName() just returns a string
listModel.addElement(SOC.getName());
}
}
}
public void addObjectToArray(SomeOtherClass SOC) {
objectArray.add(SOC);
}
}
Could someone please tell me how to make a "refresh" method to constantly keep the JList up to date?
The AWT/Swing event model is based upon the widgets being event sources (in the MVC paradigm, they are both view and controller). Different widgets source different event types.
Look at the java.awt.event (primarily), and javax.swing.event packages for the listener interfaces you'll need to implement and register in order to produce your desired effect.
Basically, you write a Listener implementation, and register it with Widget1. When Widget1 detects an event, it will notify you, and you can then use the information it provides to update Widget2.
For instance, if a button being clicked would add an object to your list, you might have something like below (I usually put this code in the encompassing JFrame class, and make it implement the listener interfaces; but you can choose to use inner classes or separate listener classes):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyFrame extends JFrame implements ActionListener {
private JButton button = new JButton("Click me!");
private DefaultListModel<String> listModel = new DefaultListModel<String>();
private JList<String> list = new JList<String>(listModel);
private int counter = 1;
public MyFrame() {
setTitle("Test Updates");
JTabbedPane tabs = new JTabbedPane();
add(tabs, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.add(list);
tabs.add("Selections", panel);
panel = new JPanel();
button.addActionListener(this);
panel.add(button);
tabs.add("Options", panel);
pack();
}
#Override
public void actionPerformed(final ActionEvent event) {
if (button.equals(event.getSource())) {
listModel.addElement("Item " + counter++);
}
}
/* Test it! */
public static void main(String[] args) {
final MyFrame frame = new MyFrame();
frame.addWindowListener(new WindowAdapter() {
#Override public void windowClosing(final WindowEvent e) {
frame.setVisible(false);
frame.dispose();
System.exit(0);
}
});
frame.setVisible(true);
}
}
This code sample is minimal, but it should give you an idea of how to go about implementing what you want.
You can do it in two way. First : Write it in infinite thread loop so that it will constantly update JList. Second : You can call refresh() method whenever new SOC objects are added in your ArrayList. It means you can call refresh() method from addObjectToArray() method which ultimately call the refresh method only when you have some change in your ArrayList.
FYI : I did it in my project and I went for second option.
I am making an applet and as part of my applet, I want this to happen: When the user presses "OK", the old components (some radio buttons) are removed, and a new JPanel is added, with a bunch of textfields.
However, I cannot figure out how to add a new component to the applet after it has started. I made the problem simpler by ignoring the removal part (Which I know how to do) and just adding a simple JLabel instead, but even that won't add!
Here is my code so far:
// imports omitted
public class Class extends Applet implements ActionListener
{
Button okButton;
CheckboxGroup radioGroup;
Checkbox radio1;
Checkbox radio2;
Checkbox radio3;
JLabel j;
public void init()
{
setLayout(new FlowLayout());
okButton = new Button("OK");
j = new JLabel("hello");
radioGroup = new CheckboxGroup();
radio1 = new Checkbox("Red", radioGroup,false);
radio2 = new Checkbox("Blue", radioGroup,true);
radio3 = new Checkbox("Green", radioGroup,false);
add(okButton);
add(radio1);
add(radio2);
add(radio3);
okButton.addActionListener(this);
}
public void repaint(Graphics g)
{
if (radio1.getState()) add(j);
}
public void actionPerformed(ActionEvent evt)
{
if (evt.getSource() == okButton) repaint();
}
}
What am I doing wrong?
You shouldn't override the repaint method, and certainly not add a component in this method. Just remove the radio buttons from the applet (using its remove method) and add the label in the applet in your actionPerformed method, the same way you add them in the init method.
You might have to call validate after.
Add components and then call validate() of your container. In this case yourApplet.validate(). This will trigger repainting and rearranging of all elements.
you could do something like
JFrame fr= new JFrame(); // global variables
JPanel panelToBeAdded = new JPanel();
JPanel initialPanel = new JPanel();
JTextField fieldToBeAdded = new JTextField();
panelToBeAdded.setPreferredSize( new Dimension(400,400));
initialPanel.setPreferredSize( new Dimension(400,400));
initialPanel.setVisible(true);
fr.add(initialPanel);
fr.setVisible(true);
fr.pack();
public void actionPerformed(ActionEvent ae) {
initialPanel.setVisible(false);
//radiobuttons.setVisible(false);---> hide the radio buttons
panelToBeAddedd.add(fieldToBeAddedd);
panelToBeAddedd.setVisible(true);
fr.add(panelToBeAddedd);
}
public void repaint( Graphics g ) {
// do something
}
What am I doing wrong?
Your repaint(Graphics) method is not the same method you are calling in your actionPerformed method.
Also, repaint is a pretty bad name for a method which is adding a new component.
public void swapComponents()
{
if (radio1.getState()) {
remove(radio1);
remove(radio2);
remove(radio3);
add(j);
validate();
}
}
public void actionPerformed(ActionEvent evt)
{
if (evt.getSource() == okButton) {
swapComponents();
}
}
When the user presses "OK", the old components (some radio buttons) are removed, and a new JPanel is added, with a bunch of textfields.
Use a CardLayout, as shown here. It is perfect for situations like this.