To start with -- I'm not sure, that I have properly formulated the question (I'm new in Java and in making programs with GUI).
It is the following thing, I'm trying to do. I have a window with several similar parameters (numbers are just for distinction between lines and it ist just very simplified example, of what should my GUI be):
Initial Window
Then, by clicking on the "+"-button I would like to add an new line, like here:
Line 35 is added
It should be also possible to delete lines, like here: Line 30 was deleted, by pressing "-"-Button.
As I wrote at the beginning, it is possible, that there was such a question, but I couldn't find anything (probably, because I do not now the keywords or I was looking with a wrong ones).
How such window can be done? The only idea I have is to draw a new window after every +/-.
Addition: Code (not working in the part of changing the number of rows).
import javax.swing.*;
import java.awt.event.*;
public class Test extends JFrame {
public Test() {
setSize(200, 600);
JButton plusButton[] = new JButton[100];
JButton minusButton[] = new JButton[100];
JTextField fields[] = new JTextField[100];
JPanel panel1 = new JPanel();
for (int i=0; i<plusButton.length; i++) {
plusButton[i]=new JButton("+");
minusButton[i]=new JButton("-");
fields[i] = new JTextField("Text "+ i);
}
for (int i=1; i<4; i++) {
panel1.add(plusButton[i*10]);
plusButton[i*10].setActionCommand("add after " +String.valueOf(i));
panel1.add(minusButton[i*10]);
minusButton[i*10].setActionCommand("remove " +String.valueOf(i));
panel1.add(fields[i*10]);
}
panel1.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
this.getContentPane().add(panel1);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
for (int i=0; i<100; i++) {
String stand1 = "add after "+String.valueOf(i);
String stand2 = "remove "+String.valueOf(i);
if (stand1.equals(e.getActionCommand())) {
//add "row" of elements
panel1.add(plusButton[i]);
plusButton[i+1].setActionCommand("add");
panel1.add(minusButton[i+1]);
minusButton[i+1].setActionCommand("remove");
panel1.add(fields[i+1]);
} else if (stand2.equals(e.getActionCommand())) {
//delete "row" of elements
}
}
}
public static void main(String[] args) {
Test a = new Test();
}
}
The Problem, that is obvious -- when I want to add 2 rows (i think it is proper definition) of buttons after button 20, there will be an doubling of numbers. As a solution I see here a creation of a new panel for each new row. But it is sounds wrong for me.
P.S. Unfortunately I do not have time to end this topic or to post a working example. I actually found some kind of solution, beginning from the Question here, on Stack Overflow:
Adding JButton to JTable as cell.
So, in case somebody will be looking for such topic, it should sounds like "jButton in jTable".
There are multiple GUI frameworks for Java. First decide which one you wanna use.
As for your particular query
Add functionality to the + and - such that it will create an instance of a field object (that line with parameters as you call them) or destroy that particular instance of the object.
+ is clicked -> Create new object on consecutive line and increase the pointer-count(?) of the following fields.
- is clicked -> Call destructor for the particular object and decrease the pointer-count of the following fields.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I build a calculator with Java swing library. Every thing else works except multiplication and division operators in the actionEvent loop. All other Operators work completely.
This is were the error occurs:
I have tried a try statement on this part of the code
Calculator:
Calculator Multiplication Error:
First you enter the number
Then you press operator which is suppose to clear textfield - error occurs at this step
Then you enter second number
Then press = button to output answer
Picture of Error:
if(e.equals("*"))
{
fnum = txt.getText();
logic.setTotal(fnum);
op = "*";
txt.setText(""); // error occurs here, textfield isn't cleared
JOptionPane.showMessageDialog(null, fnum); //messagebox to see if fnum contains the string from the textfield
}
if(e.equals("/"))
{
fnum = txt.getText();
op = "/";
txt.setText("");
}
ActionEvent Loop/function:
public void actionPerformed(ActionEvent ea)
{
else if(op.equals("*"))
{
logic.setTotal(fnum);
logic.multiplication(snum);
total1 = logic.total;
}
else if(op.equals("/"))
{
logic.setTotal(fnum);
logic.divide(snum);
total1 = logic.total;
}
txt.setText(""+total1);
}
Logic is Inner class
Inner Class:
public class Inner extends Calculators{
public double total;
public Inner()
{
total = 0;
}
public void setTotal(String n)
{
total = convertToNumber(n);
}
public void divide(String n)
{
total /= convertToNumber(n);
}
public void multiplication(String n)
{
total *=convertToNumber(n);
}
}
If you are confused please ask for more code because I can't include all of the code.
Code if you want to try it out yourself
You are at first creating your buttons like this:
...
JButton plus = new JButton("+");
JButton multiplication = new JButton("*");
JButton divide = new JButton("/");
JButton minus = new JButton("-");
...
and then adding this as action listener. But some lines are missing:
...
plus.addActionListener(this);
// missing: multiplication.addActionListener(this);
// missing: divide.addActionListener(this);
minus.addActionListener(this);
...
How I found the bug:
Downloaded the code, compiled, etc.
Ran the code, tried addition, multiplication, etc. (checking the behaviour of the application). This is kind of black box testing.
Looked for differences between addition and multiplication by analyzing the code. This is related to white box testing.
I saw, that JOptionPane.showMessageDialog(null, fnum); should be called - but has not been called. So I sat a break point (in eclipse) for debugging.
When I realized, that the actionPerformed method has not been called at I, I searched for the lines of code, that are registering the ActionListeners.
Besides that: I would strongly recommend to refactor your code. You could benefit from rethinking the structure of your code. You will get better readability, the code will be easier to maintain and new features can be implemented faster.
I would recommend to:
Reduce the visibility of your fields. Make your fields private, so that you can easily find all references to them.
Avoid repetitions (called Don't repead yourself technique). For example: Instead of calling addActionListener for each button make a collection of Buttons (i.e. ArrayList<JButton> and use a for loop to call addActionListener for each one of them.
Also avoid duplicated code fragments, by defining more, but shorter methods
Consider deleting your class Calculators and put that code directly into the methods of Inner.
Find a more meaningful name for Inner. Maybe IntermediateResult or similar.
Create a separate ActionListener instance for each button. This will cost a little bit of performance (not noticable by humans), but will avoid long if-chains
Post your code on Code Review (in the StackExchange network) for getting even more help and new ideas
Just a side recommendation, one not related to your main question, which is why I'm posting this as a community Wiki and not as an answer: Avoid use of null layouts at all costs. Sure 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.
For example, if you used a smart combination of layouts, your GUI would be able to assemble itself, and be much more flexible, should you decide to change the location of buttons or add new buttons. For example:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.*;
public class Calc2 extends JPanel {
private static final String[][] INITIAL_BTNS = {
{"1", "2", "3", "+"},
{"4", "5", "6", "-"},
{"7", "8", "9", "*"},
{"C", "0", ".", "/"},
{"1/x", "\u221A", "Ln", "="}
};
private static final String[][] EXTRA_BTNS = {
{"sin", "cos", "tan"},
{"csc", "sec", "cot"}
};
private static final int GAP = 5;
private JTextField displayField = new JTextField(10);
public Calc2() {
int rows = INITIAL_BTNS.length;
int cols = INITIAL_BTNS[0].length;
JPanel initialBtnPanel = new JPanel(new GridLayout(rows, cols, GAP, GAP));
rows = EXTRA_BTNS.length;
cols = EXTRA_BTNS[0].length;
JPanel extraBtnPanel = new JPanel(new GridLayout(rows, cols, GAP, GAP));
JPanel combinedBtnPanel = new JPanel();
combinedBtnPanel.setLayout(new BoxLayout(combinedBtnPanel, BoxLayout.PAGE_AXIS));
combinedBtnPanel.add(initialBtnPanel);
combinedBtnPanel.add(Box.createVerticalStrut(GAP));
combinedBtnPanel.add(extraBtnPanel);
for (int r = 0; r < INITIAL_BTNS.length; r++) {
for (int c = 0; c < INITIAL_BTNS[r].length; c++) {
JButton button = new JButton(INITIAL_BTNS[r][c]);
initialBtnPanel.add(button);
// add action here
}
}
for (int r = 0; r < EXTRA_BTNS.length; r++) {
for (int c = 0; c < EXTRA_BTNS[r].length; c++) {
JButton button = new JButton(EXTRA_BTNS[r][c]);
extraBtnPanel.add(button);
// add action here
}
}
setLayout(new BorderLayout(GAP, GAP));
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
add(displayField, BorderLayout.PAGE_START);
add(combinedBtnPanel, BorderLayout.CENTER);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Calc2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which displays as:
If later you decide to add 3 buttons to the top of the extra buttons section, all you'd need to do with my code is to add one line of code (not counting the logic code changes needed which would be the same for yours and mine), and change this:
private static final String[][] EXTRA_BTNS = {
{"sin", "cos", "tan"},
{"csc", "sec", "cot"}
};
to this:
private static final String[][] EXTRA_BTNS = {
{"foo", "bar", "baz"},
{"sin", "cos", "tan"},
{"csc", "sec", "cot"}
};
There would be no need to manually change the locations of all the other buttons or manually re-size the JFrame since the layout manager would take care of this for you, and the GUI would display as:
I tried to figure this out myself but I can't. I'm stuck at a strange problem.
I have a Java Program with multiple classes and forms (I use Intellij and the build in GUI-Creator). When I switch from one Screen to another I just call frame.setVisible(false); at the leafing window and frame.setVisible(true); at the window I want to show next.
On a Button Click I make this:
In Class 1:
if (e.getSource() == umschaltenButton) {
this.mainW.goToMainWindow();
logger.log(Level.INFO, "Switched Back to MainMenu");
frame.setVisible(false);
}
And here is the weird part.
In Class 2:
public void goToMainWindow() {
frame = tvElectronics.drawMainWindow(); // I get a new Frame with new Images and so on
frame.addMouseListener(al);
frame.add(BotomPanel); // in here is the JComboBox
frame.setSize(LENGTH, HEIGHT);
comboBox1.removeAllItems(); // Here it tryes to refere to the old frame before i made frame = tvElectronics.drawMainWindow();
Vector<String[]> content = tvElectronics.getContent();
for (int i = 0; i < tvElectronics.getAnz(); ++i) {
comboBox1.addItem((i + 1) + ". " + content.get(i)[3]);
}
comboBox1.setSelectedIndex(chanel);
frame.setVisible(true);
}
And so it tries to update the old frame from class2 which no longer exists because of the new one I just created. And so I have 2 frames open: one as I want it and one strange old frame form class2.
My problem is that I want bind my JComboBox to a new Frame and update it but it is still connected to the old one and that causes weird problems like jumping back in the function. I mean it is at the last line of goToMainWindow() and then it starts again at the first line.
First off you should avoid swapping JFrames as your program does since this is a very annoying GUI design. Please read The Use of Multiple JFrames, Good/Bad Practice? for more on this.
Next, it's impossible for us to tell what GUI view your JComboBox is associated with.
But having said that, it really shouldn't matter. Instead of doing what you're doing, I would give the display class that holds a JCombBox a public method that you call on the containing display class that clears the contained JComboBox's model or that places items in the model. This way, there will be no ambiguity as to which JComboBox you're referring to, and this way you avoid directly exposing a view's inner components.
As an aside, I try to gear my display or view classes towards creating JPanels, not JFrames as this will give my code much greater flexibility.
For example
// my display class
class Display1 {
private DefaultComboBoxModel<String> myModel = new DefaultComboBoxModel<>();
private JComboBox<String> myCombo = new JComboBox<>(myModel);
public void removeAllComboElements() {
myModel.removeAllElements();
}
public void addElement(String ele) {
myModel.addElement(ele);
}
}
Same for your Display2 class. Then you can call the correct method on the JComboBox that is held by the correct view/display.
This way, when you swap displays, perhaps by using a CardLayout, you can clear the JComboBox in the display that is being shown by calling its own method to clear its own combobox's model.
I am working on a lab, it's a connect four game. I'm having trouble specifically with basic concepts like how classes communicate with each other, how to use private instance variables, how to use an ArrayList, how to compare JLabels or set them as something comparable...
To give a brief breakdown I have four classes GUI, Game, Player, Name
I can create the GUI by using two four loops, the game is a grid with 7 columns of 6 pieces. The pieces are images,
JLabel Piece = new JLabel("images/blank.png");
for example to denote an empty spot.
The GUI is based on a JFrame, single content pane and four panels, one for a header which indicates who is playing and who won, another for the 7 buttons accompanying the 7 rows, the grid itself of the possible places to be played and then a button panel which gives you the option to replay.
I'm lacking in a lot of concepts. For instance, the replay button shouldn't appear until the game has ended.
I don't understand how to use an ArrayList. I tried to use
ArrayList<ArrayList<JLabel>> myList = new ArrayList<ArrayList<JLabel>>();
So when I create the GUI by running two for loops like so
For ( c = 0 ; c<8 ; c++) {
ArrayList<JLabel> column = new ArrayList<JLabel>();
For ( r = 0 ; r<7 ; r++) {
ArrayList<JLabel> row = new ArrayList<JLabel>();
JLabel empty = new JLabel("images/blank.png");
row.add(empty);
}
column.add(row);
}
Even this small step I've already got confused.
I know the two for loops above are not correct specifically the ArrayList.
I don't know how to create the arraylist and then use them.
using something like
column.get().get();
myList.get().get();
to get a specific piece.
I don't know how to pass that to an argument so that for example if I push on button 7 for column 7, and no pieces have been played yet, I can start from the lowest area column 7 row 6 and update that to a played piece, red or yellow for the appropriate player.
This is vague and I doubt I'll get anywhere but I am desperate for help. There isn't much time available from the TA's / Teacher and I believe I am lacking significantly to be able to finish this project.
I understand how it works/what I have to do in words but in terms of applying Java code...
I'd appreciate any help.
OK first off you should use an array of Enums. ArrayLists are intended for lots of items and that can have rapidly changing numbers. Arrays are intended to house data in a grid of some sorts. Since you are using a static board, use arrays! They are also much less memory-intensive. Example:
//Note you should use [column][row] as that is common practice.
States[][] grid = new States[7][6];
//And initialize it:
for(int i = 0; i < grid.length; i++)
for(int o = 0; o < grid[i].length; o++)
grid[i][o] = EMPTY_JLABEL;
Then declare an enum (this is a new class) (NOTE: replace FULL_PLAYER_ONE_JLABEL and FULL_PLAYER_TWO_JLABEL with the JLabels that have the image for each.):
public enum States {
FULL_PLAYER_ONE(FULL_PLAYER_ONE_JLABEL), FULL_PLAYER_TWO(FULL_PLAYER_TWO_JLABEL), EMPTY(EMPTY_JLABEL);
//The image of the appropriate state.
private JLabel label;
//Enum constructors must be private
private States(JLabel label) {
this.label = label;
}
public JLabel getLabel() {
return label;
}
}
In your GUI, have a JButton that is only added to the frame when the game is over. Also add a button to indicate when each column has been clicked by the player.
JButton button = new JButton();
//Initialize JButton and add to frame...
//Anytime before the frame is set to visible:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
/* Perform tests for for what should happen.
For example test whose turn it is then call a method to add a piece to that column. Then call a checker to see if someone has won. If so, display the replay button, otherwise do nothing (allow other player to move).
*/
}
}
I'm a beginner in GUI.
Is there a quick way of setting the same JButton/Image to multiple locations within the GUI? For better clarification, if I want to use this JButton 10 times at different locations in my GUI, would I have to create a new JButton(new ImageIcon...) 10 times?
The buttons don't have to lead to anything, this is just for show.
JButton jb = new JButton(new ImageIcon("myImage.png"));
jb.setLocation(10,10);
jb.setSize(40, 40);
getContentPane().add(jb);
The short answer is, yes, you will need multiple instances of JButton.
You can use an Action which can be applied to multiple instance of a button (the same instance of Action). The Action class carries properties which will be used to configure the buttons, such as text and icon properties.
A component (like JButton) can only reside within in a single container, therefore, you will need multiple instances of JButton.
Take a look at How to Use Actions and How to Use Buttons, Check Boxes, and Radio Buttons for more details...
Generally, you should avoid using setLocation and setSize and rely more on the use of layout managers, but you've not provided enough context to say if this useful to you or not.
Yes, you need to create a Jbutton object for each desired instance.
Since you have so many JButton that are all similar, I suggest that you declare an array JButton[] buttons = new JButton[10]; and use a for loop to create each individual button and set their attributes.
If it is just for a show, I would do the following to show the 10 button in a row:
int buttonHeight = 10;
int buttonWidth = 10;
for (int i = 0; i < 10; i++) {
JButton button = new Button("Button " + i);
button.setSize(buttonWidth, buttonHeight);
button.setLocation(10 + i * buttonWidth, 10);
getContentPane().add(button);
}
import java.util.Scanner;
import javax.swing.*;
import java.awt.*;
class PROB4_CHAL1 extends JFrame
{
JButton b[]=new JButton[10];
public PROB4_CHAL1()
{
setLayout(null);
setVisible(true);
setSize(100,100);
for(int i=0;i<10;i++)
{
b[i]=new JButton(""+i);// or b[i]=new JButton(new ImageIcon("path"));
b[i].setBounds(i*10,i*20,50,20);
add(b[i]);
}
}
public static void main(String[] args)
{
new PROB4_CHAL1();
}
}
You can Create array of 'JButton [10]' .
For this program, the JButton doesn't seem to show up unless you click the area where the JButton should be; the JFrame starts up blank. The moment you click the button, the respective code runs and the button finally shows up.
How do I get the buttons to show up upon starting the program?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
/*
The Amazing BlackJack Advisory Tool by JoshK,HieuV, and AlvinC.
Prepare to be amazed :O
*/
public class BlckJackUI {
//main class, will contain the JFrame of the program, as well as all the buttons.
public static void main(String args[])
{
//Creating the JFrame
JFrame GUI = new JFrame("Blackjack Advisor");
GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUI.setSize(1300, 900);
GUI.setContentPane(new JLabel(new ImageIcon("C:\\Users\\Hieu Vo\\Desktop\\Green Background.png")));
GUI.setVisible(true);
// Because each button needs to run through the Math class.
final Math math = new Math();
// The Ace Button:
ImageIcon Ace = new ImageIcon("/Users/computerscience2/Downloads/Ace.jpg");
JButton ace = new JButton(Ace);
ace.setSize(300, 100);
ace.setLocation(100, 100);
ace.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//Automatically default the the Ace to 11, and if Bust, Ace becomes 1.
if (math.array.playerhandtotal <= 21)
{
math.cardvalue = math.cardvalue + 11;
}
else
{
math.cardvalue = math.cardvalue + 1;
}
math.array.clicktracker++;
math.calcResult();
JOptionPane.showMessageDialog(null,math.array.result);
}
});
GUI.add(ace);
ImageIcon Two = new ImageIcon("/Users/computerscience2/Downloads/2.jpg");
JButton two = new JButton(Two);
two.setSize(300, 100);
two.setLocation(100, 200);
two.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
/*
This generally repeats throughout the whole class, and the only
thing different is the changing cardvalue. When a button is pressed,
respective cardvalues are added into the playerhand ArrayList, and
totaled up to form playerhandtotal, which is a major factor in
bringing up the advice.
*/
math.cardvalue = math.cardvalue + 2;
math.array.clicktracker++;
math.calcResult();
JOptionPane.showMessageDialog(null,math.array.result);
}
});
GUI.add(two);
Et cetera, Et cetera... Just a bunch of the same stuff, more buttons coded the same exact way as JButton two, but with different value associated to them.
JButton start = new JButton("Start/Reset");
start.setSize(300, 100);
start.setLocation(500,500);
start.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
/*
The start button also acts like a reset button, and the concept is fairly
simple. If we reset all the important values to 0 or "null," then the
program acts as if it was just opened.
*/
Arrays array = new Arrays();
array.playerhand.clear();
array.dealer = 0;
math.array.starttracker++;
math.array.clicktracker = 0;
array.playerhandtotal = 0;
math.cardvalue = 0;
array.result = null;
JOptionPane.showMessageDialog(null,"Please select the card \nthat the dealer is showing :)");
}
});
GUI.add(start);
GUI.setLayout(null);
This is all in the same class, and I understand a layout would be nicer, but perhaps there's a way to fix this issue using what I have now?
The program starts blank because you are calling setVisible before you add components. Call setVisible after you add components (in the end of contructor) and it should work fine.
Also, avoid absolute positioning and call of set|Preferred|Minimum|MaximumSize methods for your components. Learn how to use layout managers.
Write GUI.validate(); after you add all the components to your frame. Any time you add something to a frame you have to validate it like this. Otherwise, you will get the behavior that you have described.
No. The problem is caused by the layout. Before adding anything to a JFrame or a JPanel which you want it to have an absolute position, you have to setLayout(null). Otherwise, you'll have unexpected behaviours all the time. I just figured it out by myself after three hours of experimenting; suddenly, I connected your post with other different subject, and it worked, but this isn't well explained on the Internet yet.