Dynamically generated jbuttons - java

I'm trying to make a GUI for that simulates elevators in a building (really to test threading/c-scan), but when generating the buttons for the elevator control panel and the buttons for each individual floor, I'm kind of stuck. I thinking about trying to generate a new pair of buttons for each floor, and generating a new control panel per elevator. Also there's the difficulty of having a variable amount of floors. Anyway my question what is this best way to go about doing this? Perhaps it's not necessary to generate new buttons for everything and just use one set and change what the actions do per floor/elevator? I'm asking because I'm not very familiar with GUIs. Thanks for the help

If all the elevators, and the control panel are the same, you can use a singular method and pass in the elevator or the control panel. CustomPanel extends JPanel and has a method foo.
public void createElevatorButtons(final CustomPanel panel) {
ArrayList<JButton> buttons = new ArrayList<>(); //arraylist of buttons we can keep track of
JPanel buttonPanel = new JPanel(); //the visible component
for(int i = 1; i <= numberOfFloors;i++) {
JButton button = new JButton(String.valueOf(i)); //creates buttons for floors 1 to max
buttons.add(button);
buttonPanel.add(button);
}
panel.add(buttonPanel);
//add the action listeners
for(JButton button : buttons) {
button.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton floor = (JButton) e.getSource();
int floorNumber = Integer.parseInt(floor.getText());
panel.foo(floorNumber); //we tell the elevator/panel/whatever to do something, you will have to extend JPanel to do foo
}
});
}
}

In this case that the number of floors is variable you can create an array of buttons:
JButton[] buttons = new JButton[MAX_NUMBER_OF_FLOORS];
Then when you determine the exact of number of floors at runtime, you can go to instantiate and add the buttons:
for(int i=0; i<numberOfFloors; i++) {
buttons[i] = new JButton();
controlPanel.add(buttons[i]);
}
Something like this should work.
Assign MAX_NUMBER_OF_FLOORS a big number like 100, there should be a possible limit given by the problem.

Related

How do I make a CardLayout work with an arbitrary amount of cards?

I am trying to make cardLayout work with an arbitrary amount of cards, meaning I will need some kind of a loop through all the objects I have. Now I tried and I made it work with manually created JPanels but once I put a loop in it doesn't work.
#SuppressWarnings("serial")
public class ClassCardLayoutPane extends JPanel{
JPanel cards;
public ClassCardLayoutPane() {
initialiseGUI();
}
private void initialiseGUI() {
String[] listElements = {"A2", "C3"};
cards = new JPanel(new CardLayout());
JLabel label = new JLabel("Update");
add(label);
JList selectionList = new JList(listElements);
selectionList.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent evt) {
if (!evt.getValueIsAdjusting()) {
label.setText(selectionList.getSelectedValue().toString());
CardLayout cl = (CardLayout)(cards.getLayout());
cl.show(cards, label.getText());
}
}
});
// The panels created by this loop don't work, the cards get stuck on the first one
/*
for (int i = 0; i < listElements.length-1; i ++) {
JPanel temp = new JPanel();
temp.add(new JLabel(i+""));
cards.add(temp, listElements[i]);
}*/
JPanel card1 = new JPanel();
card1.add(new JTable(20,20));
JPanel card2 = new JPanel();
card2.add(new JTable(10,20));
cards.add(card1, listElements[0]);
cards.add(card2, listElements[1]);
//the panels here do work. I don't know what I'm doing wrong
add(selectionList);
add(cards);
}
public static void main(String[] args) {
JFrame main = new JFrame("Win");
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setPreferredSize(new Dimension(1366, 768));
main.getContentPane().add(new ClassCardLayoutPane());
main.pack();
main.setVisible(true);
}
}
Okay so the commented out for loop is what doesn't work for me which has me really confused? Can someone explain to me why it doesn't work and how I could make it work? By the way, listElements can be a different size, that's what I'm trying to get working because eventually, listElements will start off as a LinkedList, so when I create the array for the ListItems, it will be a different size every time because I don't know how many items there will be. Can someone please help me make this work? By "It doesn't work", I mean when I use the loop, the JPanel gets stuck on the very first card and doesn't switch to the next card anymore! There is no error message, the program runs fine but it doesn't do what it's meant to do which is switch cards! Note that when I do them individually, the program works perfectly! Thank you.
Okay so the commented out for loop is what doesn't work for me which has me really confused?
Well the first thing you should be doing is adding debug code to the loop to see if unique card names are being used.
If you did that then you would notice the following problem:
for (int i = 0; i < listElements.length-1; i ++) {
Why are you subtracting 1 fro the list length? You only ever add one panel to the CardLayout.
The code should be:
for (int i = 0; i < listElements.length; i ++) {
When code doesn't execute as you think you need to add debug code or use a debugger to step through the code to see if the code executes as you expect.
You can't just always stare at the code.

Grid layout not working?

I am trying to make a 2x2 grid layout that has a JLabel on the top left, and three buttons on the other three spaces. When I do this, I get the unexpected result of one big button (filling up the entire JDialog) that says "Do you want to push me". I don't know why this result shows up, please help, Thanks!
public void sinceyoupressedthecoolbutton() {
JDialog replacementwindow = new JDialog(); //Like a window
JButton best = new JButton("best");
JButton first = new JButton("FIRST");
JButton second = new JButton("Second");
replacementwindow.setLayout(new GridLayout(2,3,0,0)); //Row, column, distance horizontally, distance vertical
JPanel panel = new JPanel();
replacementwindow.add(panel); //adding the JPanel itself
replacementwindow.add(first);
replacementwindow.add(second);
replacementwindow.add(best);
replacementwindow.setSize(500, 500);
replacementwindow.setTitle("NEW WINDOW!");
replacementwindow.setVisible(true);
}
It's because you set the layout of your JButton, and not of your JDialog
Change
label.setLayout(new GridLayout(2,2,0,0));
to
YES.setLayout(new GridLayout(2,2,0,0));
Also, your variable called label is a JButton, you probably want to change that.
Don't add components to a button. You add components to a panel.
So the basic code should be:
JDialog dialog = new JDialog(...);
JPanel panel = new JPanel( new GridLayout(...) );
panel.add(label);
panel.add(button1);
...
dialog.add(panel);
Also, variable names should NOT start with an upper case character! "Yes" does not follow Java standards. The other variables do. Be consistent!

Java Button Action Command

I'm creating a simple Minesweeper game in Java. Size 9x9.
I create an array of JPanels and an array of buttons; I add each button to its respective JPanel. then i add the JPanels to the JFrame.
How do i distinguish between each button on the action event?
Here's some of my code:
int gridx = 9;
int gridy = 9;
JButton[] buttons = new JButton[gridx*gridy];
JPanel[] jpanels = new JPanel[gridx*gridy];
public Minesweeper(){
super("Minesweeper");
setLayout(new GridLayout(9,9));
JPanel panel = new JPanel();
int i = 0;
for(i = 0; i<gridx*gridy; i++){
jpanels[i] = new JPanel();
buttons[i] = new JButton();
buttons[i].addActionListener(buttonEvent);
jpanels[i].setLayout(new GridLayout(1,1));
jpanels[i].add(buttons[i]);
add(jpanels[i]);
}
//buttons[67].setEnabled(false);
setSize(300,300);
setVisible(true);
}
The only way i can think about doing this is adding text to the button like so:
buttons[i] = new JButton(i);
Then calling getActionCommand() but i dont want text to show up on the button. Any other ideas?
You can use AbstractButton#setActionCommand.
In your loop:
buttons[i].setActionCommand(i+"");
Then you'll get i back when you use getActionCommand
Note I did mention in a comment on another answer that I would create a new class Mine which extends JButton which I believe to be a better and more complete solution. This however gets the job done rather quickly.

Need a layout? How it should be used?

So im writing a small test program for fun replicating a inventory from games like minecraft and runescape. Basically a frame with another one inside it, and pictures of your items in it, and a scroll bar to scroll down through all the stuff you have in your inventory. The "Stuff" i would have in my inventory would be buttons added later on with their own functionality, so you can scroll through vertically and see all the "stuff." Right now i have some test buttons being added to deomsntrate the error. Basically i want the buttons to be 100,100 and for them to be in a row of 4, and go onto the next column. I though GridLayout would be the best choice, but it seems to add more rows after being added into a scrollpane. Well heres the code skimmed down:
public class inventory extends JFrame{
public static void main(String[] args){
new inventory();
}
JPanel mainInv = new JPanel();
JScrollPane sp;
public inventory(){
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Toolkit tk = this.getToolkit();
setLocation(tk.getScreenSize().width/2-getWidth()/2, tk.getScreenSize().height/2-getHeight()/2);
setLayout(null);
mainInv.setSize(getWidth()-10, 1000);
mainInv.setBackground(Color.blue);
mainInv.setLayout(new GridLayout(8,4));
sp = new JScrollPane(mainInv, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
sp.setMaximumSize(new Dimension(400,400));
sp.setBounds(5, 5, 500-10, 500-130);
JButton[] testButs = new JButton[100];
for(int i = 0; i < 50; i++){
testButs[i] = new JButton("Test Button " + i);
testButs[i].setSize(100,100);
mainInv.add(testButs[i]);
}
add(sp);
setVisible(true);
}
}
With GridLayout the number of rows is the dominating factor.
If you have 8 rows and 4 columns that can only fit 48 buttons, if you try to add a 49th button it will create a 5th column not a 9th row.
You can solve your problem by setting up the GridLayout with more rows.

How to get values of dynamically generated components?

I am dynamically generating a list of name boxes, sliders and labels, and am trying to figure out how to access the values of the sliders and change the labels. Other posts suggest using an array, but I have no idea where to begin with that.
My code is as such:
public Tailoring(int n) {
/*initComponents();*/
JPanel containerPanel = new JPanel();
containerPanel.setLayout(new BoxLayout(containerPanel, BoxLayout.PAGE_AXIS));
this.add(containerPanel);
JLabel Title = new JLabel("Tailoring:");
containerPanel.add(Title);
for(int i = 0; i < n; i++){
JPanel rowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
JTextField NameBox = new JTextField("Guest " + (i+1));
JSlider TipSlider = new JSlider();
JLabel TipCost = new JLabel();
rowPanel.add(NameBox);
rowPanel.add(TipSlider);
rowPanel.add(TipCost);
containerPanel.add(rowPanel);
}
}
You can create a new class YourPanel which extends JPanel.
Instead of the statement
JPanel rowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
you can use
YourPanel rowPanel = new YourPanel(new FlowLayout(FlowLayout.LEFT));
Define textfield, slider and label as the properties of this YourPanel class.
Provide getters/setters for each field. Then use an array or ArrayList of YourPanel objects in your application. You will be able to reach the nth panel's label with a call like:
panels.get(n).getJLabel();
It appears that you'd like to change the value displayed in the JLabel when the associated JSlider is modified, right? The best way to associate pairs of objects in Java is with a Map structure:
Map<Component, JSlider> sliderToLabel = new HashMap<Component, JSlider>();
for (int i = 0; i < n; i++) {
// after your loop code
sliderToLabel.put(TipSlider, TipCost); // map the slider to its label
}
You will be able to get a reference to the JSlider in the code that listens for changes on that component.
JLabel updateLabel = sliderToLabel.get(targetedSlider);
updateLabel.setText("updated text");
Notes
As a matter of convention, variable names should begin with lower case letters
The event listener I alluded to should also be attached in the loop. See Writing Event ListenersOracle

Categories