How can I create actions for a variable number of buttons? - java

I'm creating a user interface for a game that I have to do as a class project, and needless to say I'm not experienced with Swing.
I did learn about actionevents and whatnot for simple button pushes, but in those cases I knew how many buttons would be on screen. Here, I need to create a board with an arbitrary number of tiles, which will be represented as buttons in Swing. I need to push a button and "move" my character from one tile to another, so I need to call a method on one tile object to remove the player from that tile, and then add it to another tile.
So my question is, given that the number of buttons is generated at runtime (and stored in a 2d array) how can I make an actionlistener that is able to distinguish between each unique button?

Set all your buttons to the same handler:
ActionListener a = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == buttons[0][0]) {
}
// etc
// common handling
}
};
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
buttons[i][j].addActionListener(a);

Related

How to rewrite the text of buttons that are not separately defined

I have started trying to write a code similar to the game 2048, however the size of the board can have any value depending on what the user inputs. I decided to make the numbers on the board, for style purposes, separate buttons.
This is the current GUI:
How can I make it so that when the buttons: up, down left, or right are pressed each of the button's in the board texts are changed? I know about event listeners I just mean how can I replace the button's in the same grid with different values when I defined the buttons on the board as:
`for(int i = 2; i < rows + 2; i++) {
for(int j = 2; j < columns + 2; j++) {
gbc.gridx = j;
gbc.gridy = i;
num = new JButton(board.board[j-2][i-2].getValue()+"");
num.setFont(new Font("monospaced", Font.PLAIN, screenSize.height/50));
num.setEnabled(false);
this.add(num, gbc);
}
}`
The only ideas I've had was to create an array of buttons and then change the button's text in the array of buttons and then replace the old array of buttons with the new one. Also sorry if it has some super simple answer that I just couldn't find, I am just about finished with one semester of coding courses in college.
You could store the JButtons on a HashMap and use column number and row number as a key to find the correct button.
Something like:
Map<String, JButton> grid = new HashMap<String, JButton>;
for(int i = 2; i < rows + 2; i++) {
for(int j = 2; j < columns + 2; j++) {
grid.put(String.valueOf(i) + String.valueOf(i), new JButton("some text"));
// we transform the integers into String, otherwise the operator "+" will sum them
// instead of concatenate them.
}
}
Now you cant get the desired button with grid.get(row + column);
JButton bt;
JButton bt = grid.get("4" + "6");
bt.setText("different text");
grid.put("4" + "6", bt);
I don't think you should use Buttons to do such a game button it's something that you can click on it since your are not supposed to click on numbers. If I were you I would use a gamePanel which contains fixed labels since it's easier changing text of label than moving label.
I would add MouseListener to the gamePanel and then fill implemented methods in order to manage when the mouse left button is pressed and move to left and so on.
So create an array of Label.
Create a method which add and move numbers according to the direction of the move. For instance if you make a left to right move you will start to add the numbers of the first column into the second column when they have same values. Next you just have to do it recursively until the last column.
If you need a bit more explainations ,I'll be pleased to help you.

press buttons one by one

Hello I am new to java language,and I have created a JFrame in NetBeans IDE 8.2 .
The JFrame contains 8 buttons created diretly from swing palette.The case is that I am trying to open another JFrame form after clicking for example 5 buttons.
I know that for appearing another JFrame form it is used setVisible(true) method, in the last btnActionPerformed;
What I am asking is that how to make possible clicking 5 buttons and then appear the other Jframe form??If somebody knows what I am asking please help me to find the solution?
You could have a counter variable that each time you clic on a button it increases by 1 its value and when that value is 5, you call setVisible on your second JFrame.
However I suggest you to read The use of multiple JFrames, Good / Bad practice?. The general consensus says it's a bad practice.
As you provided not code, I can only show you that it's possible with the below image and the ActionListener code, however you must implement this solution on your own:
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
if (e.getSource().equals(buttons[i][j])) {
clics++;
sequenceLabel.setText("Number of Clics: " + clics);
if (clics == 5) {
clics = 0;
frame2.pack();
frame2.setLocationRelativeTo(frame1);
frame2.setVisible(true);
}
}
}
}
}
};

JButton not working for me?

I am making a program where you choose a selection sort or a merge sort using JButtons and it sorts an int array in the form of a bar graph using Graphics where each element in the array is a bar.
but for some reason the compiler isn't receiving my button presses, i have tried to use
(selection.equals(e.getSource()) in the if statement but it isnt working, am i missing something obvious or what?
public class Animation extends Canvas implements ActionListener{
JPanel panel;
JButton Selection;
JButton Merge;
boolean selection, merge;
int[] random = new int[25];
Sorter sort = new Sorter();
public Animation(){
Selection = new JButton("Selection sort");
Selection.addActionListener(this);
Selection.setActionCommand("select");
Merge = new JButton("Merge sort");
Merge.addActionListener(this);
Merge.setActionCommand("merge");
panel = new JPanel();
panel.add(Selection);
panel.add(Merge);
setBackground(Color.WHITE);
selection=false;
merge=false;
}
public void actionPerformed(ActionEvent e) {
if("select".equals(e.getActionCommand())){
selection = true;
repaint();
}
else if("merge".equals(e.getActionCommand())){
merge = true;
repaint();
}
}
public void paint (Graphics window){
Random r = new Random();
for(int i=0; i<random.length; i++){
int randomInt = r.nextInt(100) + 1;
random[i] = randomInt;
}
window.setColor(Color.MAGENTA);
if(selection==true){
for(int i=0; i< random.length-1; i++){
int smallest = i;
for(int j = i+1; j< random.length; j++){
if(random[j] < random[smallest])
smallest = j;
}
if( smallest != i) {
int least = random[smallest];
random[smallest] = random[i];
random[i] = least;
drawIt(random, window);
window.setColor(Color.WHITE);
drawIt(random, window);
window.setColor(Color.MAGENTA);
}
}
}
drawIt(random, window);
}
public void drawIt (int[] a, Graphics window1){
int x=128;
int height = 200;
for(int i=0; i<a.length; i++){
window1.drawLine(x, 200, x, height-a[i]);
window1.drawLine(x+1, 200, x+1, height-a[i]);
window1.drawLine(x+2, 200, x+2, height-a[i]);
x+=20;
}
try {
Thread.currentThread().sleep(100);
} catch(Exception ex) {
}
}
}
heres the main class to run it:
public class AnimationRunner extends JFrame{
private static final int WIDTH = 800;
private static final int HEIGHT = 250;
JButton Selection;
JButton Merge;
public AnimationRunner()
{
super("Sorting Animation");
setSize(WIDTH,HEIGHT);
Animation a = new Animation();
Merge = new JButton("Merge sort");
Selection = new JButton("Selection sort");
Merge.setSize(120, 30);
Selection.setSize(120,30);
Merge.setLocation(200, 30);
Selection.setLocation(400, 30);
this.add(Merge);
this.add(Selection);
((Component)a).setFocusable(true);
getContentPane().add(new Animation());
setVisible(true);
}
public static void main( String args[] )
{
AnimationRunner run = new AnimationRunner();
}
}
You create a button for each action in your main class and add these to your JFrame. You also create a two instances of your Animation class. One which you create, setfocusable then do nothing with. Then another which you create and add to the contentPane of the JFrame.
In your Animation constructor you again create a button for each action, this time setting the action commands. You then add these to a panel. This panel is never added to anything and so these buttons will never be seen.
The buttons you see are not the buttons that you have defined the action commands for.
Also you should avoid using setSize() and Use Layout Managers to defines the sizes of your components.
There are a series of cascading problems...
In the AnimationRunner class you create two JButtons called Merge sort and Selection sort and add these to the main frame. This is what's actually on the screen. This buttons have no listeners attached, therefore never notify any body when they are clicked...
In the Animation class you create two JBttonss called Merge sort and Selection sort and add these to panel (and instance of JPanel), which is never added to anything. This means you can never possibly click them...
You don't seem to have an understanding of how painting works in Swing and seem to be assuming that you control the paint process in some way.
Painting is controlled by the paint sub system in Swing, which schedules and performs paint cycles when and where it sees fit. This means that your paint method may be called for any number of reasons, many of which you don't control.
Remove the logic of the sort out of the paint process and place into some kind of model, whose state you can control. Then use the custom painting capabilities to render the state of the model.
paint is an inappropriate method to be using for custom painting and you should be using paintComponent. You have broken the paint chain which may prevent the component from rendering child components and/or introduce series paint artifacts into your program
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
Swing is a single threaded framework work. That means that anything that blocks the Event Dispatching Thread will prevent it from process new repaint requests or events into the system. This will cause your program to look like it's "hung". In your case, you will most likely only ever see the end result of the painting process...after a short delay.
Instead, consider using a javax.swing.Timer to introduce a safe delty and update the model each time it ticks.
Take a look at Concurrency in Swing and How to use Swing Timers for more details
Swing programs are expected to run on a variety of hardware and software platforms, all with there own notions of DPI and font rendering approaches. This makes it very difficult to accommodate your design to all the possible needs of these systems.
Swing makes this easier by providing a layout management API, which takes the fiddle work out of making these decisions. Take a look at Laying Out Components Within a Container for more details
You should also take a look at Code Conventions for the Java Programming Language, it will make it eaiser for people to read your code.
You might find this example of some benifit

Creating a GUI with for loop using Java Swing

I have a GUI, from this GUI I choose an input file with the dimensions of a Booking system(new GUI) If the plane has 100 seats the GUI will be for example 10x10, if the plane has 200 seats it will be 10x20, all the seats are going to be buttons, and should store passenger information on them if they are booked.Also a booked seat shall not be booked again.
The question is the dimensions of the GUI will change according to the seat numbers and orientation, which means in one version there can be lots of buttons on another less, also more seats means the GUI will be longer or wider maybe 10 cm x 10 cm or 10 cm x 20 cm, or 15 cm x 25 cm...
I am thinking to do this with a for loop but I dont want to put buttons out of the GUI.I dont know how can I add a button next to the other button arbitrarily. I always used Eclipse Window Builder for building GUIs but I guess I need to write this one on my own... can someone help me?Some hints?Thanks for your time!
Try something like this:
// The size of the window.
Rectangle bounds = this.getBounds();
// How many rows of buttons.
int numOfRows = 100;
// How many buttons per row.
int numOfColumns = 50;
int buttonWidth = bounds.width / numOfRows;
int buttonHeight = bounds.height / numOfColumns;
int x = 0;
int y = 0;
for(int i = 0; i < numOfColumns; i++){
for(int j = 0; j < numOfRows; j++){
// Make a button
button.setBounds(x, y, buttonWidth, buttonHeight);
y += buttonHeight;
}
x += buttonWidth;
}
This will make all the buttons fit inside of your window.
Here's a link on rectangles, they come in pretty handy when doing things like this.
http://help.eclipse.org/helios/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fswt%2Fgraphics%2FRectangle.html
Also, you can still use windowbuilder, infact I recommend you do. It really helps you to visualize the dimensions you want. AND you can also create stuff (buttons, lists, dropdowns... etc) manually with code and, assuming you put the variables where WindowBuilder would, it will still display them in the 'design' tab.
Hope this helps!
EDIT: I was kinda vague on how to make buttons using a loop
To make buttons with a loop you will need a buffer (to store a temporary button long enough to add to a list) and... a list :D.
This is how it should look:
Outside loop:
// The list to store your buttons in.
ArrayList<Button> buttons = new ArrayList<Button>();
// The empty button to use as a buffer.
Button button;
Inside loop (where the '//Make a button' comment is):
button = new Button(this, SWT.NONE);
buttons.add(button);
Now you have a list of all the buttons, and can easily access them and make changes such as change the buttons text like so;
buttons.get(indexOfButton).setText("SomeText");
EDIT:
Seeing as you're new to swt (and I couldn't get awt/JFrame to work) here's the full code.
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class ButtonTest extends Shell {
/**
* Launch the application.
* #param args
*/
// Code starts here in main.
public static void main(String args[]) {
try {
Display display = Display.getDefault();
// Creates a window (shell) called "shell"
ButtonTest shell = new ButtonTest(display);
// These two lines start the shell.
shell.open();
shell.layout();
// Now we can start adding stuff to our shell.
// The size of the window.
Rectangle bounds = shell.getBounds();
// How many rows of buttons.
int numOfRows = 5;
// How many buttons per row.
int numOfColumns = 3;
int buttonWidth = bounds.width / numOfRows;
int buttonHeight = bounds.height / numOfColumns;
Button button;
int x = 0;
int y = 0;
for(int i = 0; i < numOfColumns; i++){
for(int j = 0; j < numOfRows; j++){
button = new Button(shell, SWT.NONE);
button.setBounds(x, y, buttonWidth, buttonHeight);
x += buttonWidth;
}
x = 0;
y += buttonHeight;
}
// This loop keeps the shell from killing itself the moment it's opened
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Create the shell.
* #param display
*/
public ButtonTest(Display display) {
super(display, SWT.SHELL_TRIM);
createContents();
}
/**
* Create contents of the shell.
*/
protected void createContents() {
setText("SWT Application");
setSize(800, 800);
}
#Override
protected void checkSubclass() {
// Disable the check that prevents subclassing of SWT components
}
Also, I made a little typo in my nested loop (and forgot to reset the x value to 0 after each row). It's fixed in this edit.
Also you will need to import swt for this to work.
Go here: http://www.eclipse.org/swt/ and download the latest version for your operating system, then go in eclipse, right click your project > Build Path > configure Build Path > Libraries tab > Add external JAR's > find the swt file you downloaded and click.
Sorry for such a long answer, hope it helps :D
Start with a GridLayout. Each time you need to change the seat layout, reapply the GridLayout.
Ie, if you need 100 seats, use something like, new GridLayout(20, 10)...
Personally, I'd use a GridBagLayout, but it might be to complex for the task at hand
Its a little more difficult to add/rmove new content. I would, personally, rebuild the UI and reapply the model to it.
As for the size, you may not have much control over it, as it will appear differently on different screens. Instead, you should provide means by which you can prevent the UI from over sizing the screen.
This is achievable by placing the seating pane within a JScrollPane. This will allow the seating pane to expand and shrink in size without it potentially over sizing on the screen
Take a look at
Creating a UI with Swing
Using Layout Managers
A Visual Guide to Layout Managers

Trying to display from arraylist on a JPanel

im new to java swing, and Ive got a little problem.
So I've got a class Flight.java. In there I have a method displaySeat2D().
First I had this done with the scanner. Now Im using swing. So basically I made text fields to take in a number of seats and a number of rows. Now Im trying to display this in JPanel. Guess Id have to use JLabel and display it there. Not realy sure. So instead of 0 and 1, id like to have seats and rows displayed like squares for example. Or if its possible id try to keep it simple and display it like in Eclipse console with 0.
This is the code.
// FLIGHT class:
public void displaySeat2D(){
for (int i = 0; i < arraySeatPassenger.length; i++) {//line
System.out.println("");
for (int j = 0; j < arraySeatPassenger[i].length; j++) {// seat
if (arraySeatPassenger[i][j] == null) {
System.out.print("0");//
} else {
System.out.print("1");
}
}
}
System.out.println("");
}
// UI (display part):
lblDisplay.setForeground(new Color(0, 128, 0));
btnDisplayv.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
// Piece of UI
http://i44.tinypic.com/ajnlo3.jpg
That's basically it. I could use help when I click this button some field would appear with for example 4(seats)x4(rows). Thanks for the help.
Have a look at using a JTable. Each seat can be represented by individual cells with the table managing the alignment of the characters in the ArrayList. For more see How to Use Tables

Categories