Code with near-identical blocks like this makes me cringe. Plus it adds up to where you have a thousand lines of code where half that would suffice. Surely there is a way to make a loop to make it all happen and not have code that looks so unsophisticated and brainless.
Offhand it seems like to do so would be adding as much code as I seek to reduce: loop to make 5 buttons, array of labels for the buttons, array of backgrounds... maybe more. Even if that turned out to be acceptable, how would I make a loop to handle the listeners? I can't have an array of methods, can I? I guess such a loop it would have to include a switch. Yes? I'd probably do that if I didn't want to seek a better solution. So I'm asking...
What would code look like that would listen to the entire group of buttons and take action based on which one was pressed? To which component would I assign the single listener? And how?
(There's a chance that the answer to that question will make me cringe even more than the repetitive nature of the code, if I realize that I already know how to do so and needn't have even asked in the first place, but I'm asking anyway. I'm at one of those I've-had-it-for-today points where the brain just wants out.)
private void makeScoremasterBonuses(){
pnlBonuses = new JPanel(new GridLayout(1, 6));
pnlBonuses.setSize(6,1);
JButton t1 = (new JButton("3W"));
t1.setToolTipText("This is a triple-word cell.");
t1.setBackground(TRIPLE_WORD);
t1.setHorizontalAlignment(JButton.CENTER);
t1.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
Highlighter.shadeSymmetric(currentCell,TRIPLE_WORD);
}});
JButton t2 = (new JButton("3L"));
t2.setToolTipText("This is a triple-letter cell");
t2.setBackground(TRIPLE_LETTER);
t2.setHorizontalAlignment(JButton.CENTER);
t2.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
Highlighter.shadeSymmetric(currentCell,TRIPLE_LETTER);
}});
JButton t3 = (new JButton("2W"));
t3.setToolTipText("This is a double-word cell");
t3.setBackground(DOUBLE_WORD);
t3.setHorizontalAlignment(JButton.CENTER);
t3.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
Highlighter.shadeSymmetric(currentCell,DOUBLE_WORD);
}});
JButton t4 = (new JButton("2L"));
t4.setToolTipText("This is a double-letter cell");
t4.setBackground(DOUBLE_LETTER);
t4.setHorizontalAlignment(JButton.CENTER);
t4.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
Highlighter.shadeSymmetric(currentCell,DOUBLE_LETTER);
}});
JButton t5 = (new JButton(""));
t5.setToolTipText("No bonus");
t5.setBackground(WHITE);
t5.setHorizontalAlignment(JButton.CENTER);
t5.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
Highlighter.shadeSymmetric(currentCell,B_NORMAL);
}});
pnlBonuses.add(new JLabel("Legend: "));
pnlBonuses.add(t1);
pnlBonuses.add(t2);
pnlBonuses.add(t3);
pnlBonuses.add(t4);
pnlBonuses.add(t5);
}
I'm not asking anyone to write the code; I wouldn't even want that (but I couldn't ignore it!).
Here's what the code above does:
Generally any time you have repeated functionality like that, you want to extract that code out into a helper method like this:
private JButton makeJButton(String label, String toolTip, Color bgColor, final Color highlight) {
JButton button = new JButton(label);
button.setToolTipText(toolTip);
button.setBackground(bgColor);
button.setHorizontalAlignment(JButton.CENTER);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Highlighter.shadeSymmetric(currentCell, highlight);
}
});
return button;
}
Then your makeScoremasterBonuses() method becomes much simpler:
private void makeScoremasterBonuses() {
pnlBonuses = new JPanel(new GridLayout(1, 6));
pnlBonuses.setSize(6, 1);
pnlBonuses.add(new JLabel("Legend: "));
pnlBonuses.add(makeJButton("3W", "This is a triple-word cell.", TRIPLE_WORD, TRIPLE_WORD));
pnlBonuses.add(makeJButton("3L", "This is a triple-letter cell.", TRIPLE_LETTER, TRIPLE_LETTER));
pnlBonuses.add(makeJButton("2W", "This is a double-word cell.", DOUBLE_WORD, DOUBLE_WORD));
pnlBonuses.add(makeJButton("3L", "This is a double-letter cell.", DOUBLE_LETTER, DOUBLE_LETTER));
pnlBonuses.add(makeJButton("", "No bonus.", WHITE, B_NORMAL));
}
Identify the aspects that vary, collect them, and iterate over the collection.
Something like this (untested):
pnlBonuses = new JPanel(new GridLayout(1, 6));
pnlBonuses.setSize(6,1);
pnlBonuses.add(new JLabel("Legend: "));
// Create class "CellInfo" with constructor and getters for desired properties.
CellInfo cellInfos[] = {
new CellInfo("3W", "This is a triple-word cell.", TRIPLE_WORD),
new CellInfo("3L", "This is a triple-letter cell.", TRIPLE_LETTER),
// ...
};
// Add a button for each item described by the cellInfos.
for (CellInfo cellInfo : cellInfos) {
Button b = new JButton(cellInfo.getLabel());
b.setToolTipText(cellInfo.getToolTipText());
b.setBackground(cellInfo.getBackground());
b.setHorizontalAlignment(JButton.CENTER);
b.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
Highlighter.shadeSymmetric(currentCell, cellInfo.getBackground());
}});
pnlBonuses.add(b);
}
Note that you might need to create some "final" variables for placeholders for use in the inner anonymous class but the idea should work.
An enum could be your friend here. It's almost an array of methods:
static enum Btn {
TripleWord("3W", "This is a triple word cell.", TRIPLE_WORD),
TripleLetter("3L", "This is a triple letter cell.", TRIPLE_LETTER),
DoubleWord("2W", "This is a double word cell.", DOUBLE_WORD),
DoubleLetter("2L", "This is a double letter cell.", DOUBLE_LETTER),
NoBonus("", "No bonus.", WHITE, B_NORMAL);
final String label;
final String tooltip;
final Color color;
final Color shade;
Btn(String label, String tooltip, Color color, Color shade) {
this.label = label;
this.tooltip = tooltip;
this.color = color;
this.shade = shade;
}
Btn(String label, String tooltip, Color color) {
this(label, tooltip, color, color);
}
public JButton asJButton() {
JButton btn = (new JButton(label));
btn.setToolTipText(tooltip);
btn.setBackground(color);
btn.setHorizontalAlignment(JButton.CENTER);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Highlighter.shadeSymmetric(currentCell, shade);
}
});
return btn;
}
}
private void makeScoremasterBonuses() {
int nBtns = Btn.values().length;
JPanel pnlBonuses = new JPanel(new GridLayout(1, nBtns + 1));
pnlBonuses.setSize(nBtns + 1, 1);
pnlBonuses.add(new JLabel("Legend: "));
for (Btn btn : Btn.values()) {
pnlBonuses.add(btn.asJButton());
}
}
(I know I could have edited my previous answer, but this one's so different...)
Thanks to #OldCurmudgeon, I have come up with what I think is pretty good.
Here's "proof" (I may just leave each label and tooltip as is):
public enum Colors {
TRIPLE_WORD (255, 220, 50),
TRIPLE_LETTER (255, 255, 150),
DOUBLE_WORD ( 0, 255, 0),
DOUBLE_LETTER (214, 245, 214),
NOT_A_BONUS (255, 255, 255);
private final int red, green, blue;
Colors(int r, int g, int b){
this.red = r;
this.green = g;
this.blue = b;
}
public java.awt.Color background(Colors c){
return new java.awt.Color(c.red, c.green, c.blue);
}
}
private void makeScoremasterBonuses(){
Colors c;
Colors all [] = Colors.values();
String labels[] = new String[all.length];
String abbrs [] = new String[all.length];
JButton but;
pnlBonuses = new JPanel();
pnlBonuses.add(new JLabel("Legend:"));
for (int i = 0; i < all.length; i++) {
labels[i] = all[i].name().replace("_", " ").toLowerCase();
abbrs [i] = abbreviate(all[i].name());
c = Colors.values()[i];
but = new JButton(abbrs[i]);
but.setToolTipText(labels[i]);
but.setBackground(c.background(c));
but.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
but.setActionCommand("" + i);
but.addActionListener(this);
pnlBonuses.add(but);
}
}
=== THIS IS A MAJOR EDIT OF WHAT I POSTED AN HOUR AGO ===
I wanted to see if I could implement my own naive method. Here it is:
public class Game implements ActionListener{
public Color [] backgrounds = {TRIPLE_WORD, TRIPLE_LETTER,
DOUBLE_WORD, DOUBLE_LETTER, B_NORMAL};
private void makeScoremasterBonuses(){
String[] labels = {"3W", "3L", "2W", "2L", " "};
JButton but;
pnlBonuses = new JPanel();
pnlBonuses.add(new JLabel("Legend:"));
for (int i = 0; i < labels.length; i++) {
char wt = labels[i].charAt(0);
char tp = labels[i].charAt(1);
but = new JButton(labels[i]);//("" + i);
but.setBackground(backgrounds[i]);
but.setHorizontalAlignment(SwingConstants.CENTER);
but.setActionCommand("" + i);
but.addActionListener(this);
but.setToolTipText("This is a "
+ (i == labels.length - 1 ? "non-bonus" :
(wt == '3' ? "triple" : "double")
+ " " + (tp == 'L' ? "letter" : "word"))
+ " cell.");
pnlBonuses.add(but);
}
}
public void actionPerformed(ActionEvent evt) {
int i = Integer.parseInt(evt.getActionCommand());
Highlighter.shadeSymmetric(currentCell,backgrounds[i]);
}
This has NOW (after edits) EVEN MORE SO been the best thread I've initiated, in terms of quality of responses and all that I've learned because of them. THANK YOU ALL.
BUT I STILL haven't managed to appropriately use setActionCommand. Whatever I did to TRY to use it wound up being so much longer code-wise that I gave up and went for the short and easy but inappropriate.
Any thoughts about how to use set... and getActionCommand the right way (i.e., as Actions) without adding a ton of code to do so?
Related
This is probably the nth time you've received a newbie question regarding calculators, but I just can't figure it out, been working on it for two to three days. The way I have built my calculator at the moment does not suffice and I know I have to start calculating at the time I press the '=' button, but I simply can't figure out how to do so. Due to this reason I have reverted back to my original calculator code, in which it calculates when I press an operation button (like '+') which didn't work, but I was hoping that that would allow me to properly build on it. Here's the code:
package rekenmachine;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.*;
public class Rekenmachine extends JFrame
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(300,500);
frame.setLocation(800,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Rekenmachine");
RekenPaneel rekenpaneel = new RekenPaneel();
frame.setContentPane(rekenpaneel);
frame.setVisible(true);
}
private static int getal, totaalGetal;
private boolean optellen, aftrekken, vermenigvuldigen, delen;
public int Optellen(int getal)
{
reset();
optellen = true;
totaalGetal += getal;
getal = 0;
return totaalGetal;
}
public int Aftrekken(int getal)
{
reset();
aftrekken = true;
totaalGetal -= getal;
getal = 0;
return totaalGetal;
}
public int Delen(int getal)
{
reset();
delen = true;
totaalGetal /= getal;
getal = 0;
return totaalGetal;
}
public int Vermenigvuldigen(int getal)
{
reset();
vermenigvuldigen = true;
totaalGetal *= getal;
getal = 0;
return totaalGetal;
}
public int getGetal()
{
return getal;
}
public int getTotaalGetal()
{
return totaalGetal;
}
public void reset()
{
optellen = false;
aftrekken = false;
delen = false;
vermenigvuldigen = false;
getal = 0;
totaalGetal = 0;
}
}
class RekenPaneel extends JPanel
{
JButton knop0, knop1, knop2, knop3, knop4, knop5, knop6, knop7, knop8, knop9,
knopOptel, knopAftrek, knopVermenigvuldigen, knopDelen, knopUitkomst,
knopWissen;
JTextField invoerVak;
JPanel textPaneel, knopPaneel, logoPaneel;
Rekenmachine rekenmachine;
public RekenPaneel()
{
rekenmachine = new Rekenmachine();
setLayout(new BorderLayout());
textPaneel = new JPanel();
knopPaneel = new JPanel();
logoPaneel = new JPanel();
textPaneel.setLayout(new FlowLayout());
knopPaneel.setLayout(new GridLayout(4,4));
logoPaneel.setLayout(new FlowLayout());
Border rand = BorderFactory.createEmptyBorder(10, 10, 10, 10);
knop0 = new JButton("0");
knop0.addActionListener(new knop0Handler());
knop1 = new JButton("1");
knop1.addActionListener(new knop1Handler());
knop2 = new JButton("2");
knop2.addActionListener(new knop2Handler());
knop3 = new JButton("3");
knop3.addActionListener(new knop3Handler());
knop4 = new JButton("4");
knop4.addActionListener(new knop4Handler());
knop5 = new JButton("5");
knop5.addActionListener(new knop5Handler());
knop6 = new JButton("6");
knop6.addActionListener(new knop6Handler());
knop7 = new JButton("7");
knop7.addActionListener(new knop7Handler());
knop8 = new JButton("8");
knop8.addActionListener(new knop8Handler());
knop9 = new JButton("9");
knop9.addActionListener(new knop9Handler());
knopOptel = new JButton("+");
knopOptel.addActionListener(new knopOptelHandler());
knopAftrek = new JButton("-");
knopAftrek.addActionListener(new knopAftrekHandler());
knopVermenigvuldigen = new JButton("*");
knopVermenigvuldigen.addActionListener(new knopVermenigvuldigenHandler());
knopDelen = new JButton("/");
knopDelen.addActionListener(new knopDelenHandler());
knopUitkomst = new JButton("=");
knopUitkomst.addActionListener(new knopUitkomstHandler());
knopWissen = new JButton("C");
knopWissen.addActionListener(new knopWissenHandler());
invoerVak = new JTextField(25);
invoerVak.setHorizontalAlignment(invoerVak.RIGHT);
invoerVak.setEditable(false);
invoerVak.setBackground(Color.WHITE);
textPaneel.add(invoerVak);
knopPaneel.add(knop7);
knopPaneel.add(knop8);
knopPaneel.add(knop9);
knopPaneel.add(knopDelen);
knopPaneel.add(knop4);
knopPaneel.add(knop5);
knopPaneel.add(knop6);
knopPaneel.add(knopVermenigvuldigen);
knopPaneel.add(knop1);
knopPaneel.add(knop2);
knopPaneel.add(knop3);
knopPaneel.add(knopOptel);
knopPaneel.add(knop0);
knopPaneel.add(knopWissen);
knopPaneel.add(knopUitkomst);
knopPaneel.add(knopAftrek);
add(textPaneel, BorderLayout.NORTH);
add(knopPaneel, BorderLayout.CENTER);
add(logoPaneel, BorderLayout.SOUTH);
}
class knop0Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "0");
}
}
class knop1Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "1");
}
}
class knop2Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "2");
}
}
class knop3Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "3");
}
}
class knop4Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "4");
}
}
class knop5Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "5");
}
}
class knop6Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "6");
}
}
class knop7Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "7");
}
}
class knop8Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "8");
}
}
class knop9Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "9");
}
}
class knopOptelHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Optellen(invoerGetal);
invoerVak.setText("");
}
}
class knopAftrekHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Aftrekken(invoerGetal);
invoerVak.setText("");
}
}
class knopVermenigvuldigenHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Vermenigvuldigen(invoerGetal);
invoerVak.setText("");
}
}
class knopDelenHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Delen(invoerGetal);
invoerVak.setText("");
}
}
class knopUitkomstHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText("" + rekenmachine.getTotaalGetal());
rekenmachine.reset();
}
}
class knopWissenHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
rekenmachine.reset();
invoerVak.setText("");
}
}
}
What it basically does is look like a calculator, all buttons work, yet the way it calculates is way off, if at all. I think what I need to do is save a number, when I press + it should add the next number, if I press - it should substract the next number, if I press * it should multiply by the next number and if I press / it should divide by the next number, then when I press = it should show the result, yet I have no idea how to do that.
Should it be done with an arraylist? If so, how could I properly save the result? I mean, using it with two numbers isn't that hard, you just save two numbers and do something with them, then show the result, but a person doesn't always use just two numbers.
To explain the problem I'm having more clearly: for example, when I enter '50' and then press '+' it SHOULD convert "50" to getal = 50 and start the Optellen method, then totaalGetal should become 50, it then empties the textfield. If I then add '3', it should say 53 when I press '=' yet it still shows 50 if I'm lucky. To solve that I assume I have to make the calculation WHEN I press '=' but I don't know how to save/calculate numbers before having done that.
Can anybody tell me what to do before I've lost all my hair? :P
When you click on the +, you're calling this:
knopOptel.addActionListener((ActionEvent e) ->
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.addition(invoerGetal);
invoerVak.setText("");
});
But when you click on +, you're not doing the calculation yet! What you should be doing is:
The user type a number
The user click on + (for example)
In your ActionListener, you read the number on the screen, you store it in getal, you clear the screen, and you set your boolean optel to true
The user types another number
The user click on equal
In your equal Listener, you read the number you read the number on the screen, and depending on the flag (optel in the example), you calculate the result
you display the result
So indeed, the calculation is done when you press equal.
A small code example:
knopOptel.addActionListener((ActionEvent e) ->
{
int invoerGetal = Integer.parseInt(invoerVak.getText()); // get the number
calculate(invoerGetal); //sets totalNumber to what it should be by looking at the flags
invoerVak.setText(totalNumber); // we write the temporary result
additionFlag = true; // next number must be added
});
And your calculate function should just be something like:
private void calculate(int aInvoerGetal) {
if (addition)
totalNumber += aInvoerGetal;
else if (substract)
totalNumber -= aInvoerGetal;
else if (divide)
totalNumber /= aInvoerGetal;
else if (multiply)
totalNumber *= aInvoerGetal;
resetFlags();
}
TO GO FURTHER:
Now, if you want to support multiple caculations (5+5+5+3), it's easy. When you click on +, -, *, /, you first call the equalActionListener.
This way, you get this kind of sequence:
5, + // ==> equal called ==> 5 (because the flags are all false) ==> flag + to true
10, + // ==> equal called ==> 15 because 5 in memory and + flag was on. + flag goes off, then on again (because you pressed + again)
4, = // ==> equal called ==> 19
When developing something, you have to think first how you want to solve a problem. Work from there by designing a solution. If you have a programmable solution, implement it. The UI may come later. That's a core skill that a developer should have.
1) You want to have a calculator that support +, -, / and *. The output should be shown if "=" is clicked.
2) Think with classes. That concept may be new for you, but you will discover later from. Your main class that does the calculations is Rekenmachine. (From a design perspective, it should be a stand alone class, but that's not important now). You need to separate it from your UI layer.
Your class supports the actions that you have implemented with the UI. That's good. But I also see things that shouldn't be there
public int Vermenigvuldigen(int getal)
{
reset(); // reset the calculator ?
vermenigvuldigen = true; // purpose ?
totaalGetal *= getal;
getal = 0; // resetting argument getal ?
return totaalGetal;
}
Here, I'm not sure why you're calling reset() because what it does is
public void reset()
{
optellen = false;
aftrekken = false;
delen = false;
vermenigvuldigen = false;
getal = 0;
totaalGetal = 0;
}
When reading the above method, you see that it resets the value that you tried to add on. Of course your calculation would go wrong because you're erasing previous data... resetting everything back to initial state. I also don't understand the setting to "true" or "false" on the actions. Perhaps for the UI? That is not required.
Make it simple:
When creating Rekenmachine, set the variable totaalGetal to 0 as default. That variable holds the value of your calculations performed so far. That's the start. When you have an addition, use
public void add(int getal) {
totaalGetal+= getal; // means totaalGetal = totaalGetal + getal.
}
Before calling add() you have to parse the string to an integer. This can be done in the button action:
class knop1Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// get input
String input = invoerVak.getText();
// convert
int converted = convertToInt(input);
// instruct myRekenmachine to add the value
myRekenmachine.add(converted);
}
}
Important note ... use concise naming ... "knop1handler" is difficult to read. Use "addButtonHandler" to indicate that this class handles the add button.
convertToInt is a method that reads in a String and returns with an integer. You have to implement that yourself. myRekenmachine is an instance of your Rekenmachine class.
This above is for addition. Implement the same for other operands. If you want to adjust the UI, do that in the handler.
Now, when you press =, just return the totaalGetal value.
PS: Not sure, but ask if you are allowed to write names in English. My native language is Dutch, but during my CS courses, I am allowed to program completely in English. Please try to ask it because English is the main language in IT world if you're aiming for a career in IT.
Wesley, did you think about what you wanted the calculator to do before you started coding? e.g. would it support brackets, sin/cos, memory. Did you think about how logically these functions would work and then think of how they could be implemented in Java? A few flow charts and some pesudocode can go a long way when you're starting out in a new language if only to help you comprehend what it is you are trying to do.
BTW I know it's tempting to start with the GUI code and move into the logic of the application but it is usually better to start with the logic and then move onto the GUI. You can hard code the values for inputs and see if the functionaly behaves as expected and then introduce parameters with values passed in from else where.
EDIT
I think I know why your + key is not working. The reset() method is setting getal and totalGetal to 0 before adding them. 0 + 0 is 0.
knopOptel = new JButton("+");
knopOptel.addActionListener(new knopOptelHandler());
class knopOptelHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Optellen(invoerGetal);
invoerVak.setText("");
}
}
public int Optellen(int getal)
{
reset();
public void reset()
{
optellen = false;
aftrekken = false;
delen = false;
vermenigvuldigen = false;
getal = 0;
totaalGetal = 0;
}
optellen = true;
totaalGetal += getal;
getal = 0;
return totaalGetal;
}
I'm doing a color pencil project using 100 JButtons as pixels positioned like a 10x10 matrix. I also have 10 other jButtons representing colors and 2 other representing the tools "pencil" and "bucket".
Im only working with the pencil jButton for now, so you can paint any of the 100 JButtons by clicking the pencil JButton and then picking one of the color JButtons.
The algorithm works fine, the problem is the fact I need to apply the same coloring method (colorButton) to all the 100 JButtons so i wanted to make an Array to store all the JButtons and then call my colorButton method for each of them.
I have no clue on how to store all my 100 JButtons into the JButton array, since they are already created and named.
This is what im trying:
public void colorButton(JButton button){
if (type == "pencil"){
if(color.equals("gray")){
button.setBackground( new Color(101,101,101));
}else if(color.equals("white")){
button.setBackground( new Color(255,255,255));
}else if(color.equals("black")){
button.setBackground( new Color(0,0,0));
}else if(color.equals("blue")){
button.setBackground( new Color(0,0,255));
}else if(color.equals("red")){
button.setBackground( new Color(255,0,0));
}
public void buttonArray(){
JButton[] button = new JButton[100];
for (int i = 0; i < 100; i++){
button[i] = jButton1; //I need to get each of the 100 buttons here
colorButton(button[i]);
}
}
So other than only JButton1 i need a way to store all of the 100.
Any idea?
Thanks
*Edited to clarify the question and situation
Without knowing the context of what this is used for and assuming the colorButton() method is a mock as it is missing a couple of braces.
The following Java code uses reflection to populate an ArrayList using the existing JButtons defined in the ColorButtons class.
I am still unsure why you need to assign the Array in a loop with another List, but here it is.
public class ColorButtons {
// JButton sample.
private JButton button1 = new JButton("1");
private JButton button2 = new JButton("2");
private JButton button3 = new JButton("3");
// This is used to store the buttons.
ArrayList<JButton> jbuttons = new ArrayList<JButton>();
// Boilerplate, as I have no idea what this does.
private String type = "pencil";
private String color = "white";
/**
* Populate the JButton List on instantiation.
*
* #see ColorButtons#populateJButtonList()
*/
public ColorButtons() {
// Populate "jbuttons" ArrayList with JButtons.
this.populateJButtonList();
}
public void colorButton(JButton button) {
if (type == "pencil") {
if (color == "gray") {
button.setBackground(new Color(101, 101, 101));
} else if (color == "white") {
button.setBackground(new Color(255, 255, 255));
} else if (color == "black") {
button.setBackground(new Color(0, 0, 0));
} else if (color == "blue") {
button.setBackground(new Color(0, 0, 255));
} else if (color == "red") {
button.setBackground(new Color(255, 0, 0));
}
}
}
public void buttonArray() {
JButton[] button = new JButton[100];
for (int i = 0; i < 100; i++) {
// Assign each JButton in the list to array element.
for (JButton jbutton : jbuttons) {
button[i] = jbutton; // I need to get each of the 100 buttons
// here
System.out.println("Button" + button[i].getText());
colorButton(button[i]);
}
}
}
/**
* This is used to add the JButtons to a list using reflection. Used in the
* constructor.
*
* #see ColorButtons#ColorButtons()
*/
public void populateJButtonList() {
// Gets the class attributes, e.g. JButton, String, Integer types, everything.
// In this case it is this class, but can define any other class in your project.
Field[] fields = ColorButtons.class.getDeclaredFields();
// Loop over each field to determine if it is a JButton.
for (Field field : fields) {
// If it is a JButton then add it to the list.
if (field.getType().equals(JButton.class)) {
try {
// De-reference the field from the object (ColorButtons) and cast it to a JButton and add it to the list.
jbuttons.add((JButton) field.get(this));
} catch (IllegalArgumentException | IllegalAccessException
| SecurityException e) {
e.printStackTrace();
}
}
}
}
public static void main(String... args) {
ColorButtons color = new ColorButtons();
color.buttonArray();
}
}
I'm self learning java beginner
i'm trying to create simple calculator using java swing and i want to create array of JButtons to create all the buttons in the project , i had some issues so i declare all variables outside the constructor
public class SimpleCalculator extends JFrame implements ActionListener {
JButton btnArray[] = new JButton[16];
JLabel nameLabel = new JLabel("Ghanayem's Calculator",
SwingConstants.CENTER);
JTextField txt = new JTextField();
JPanel numPanel = new JPanel(new GridLayout(4, 3, 15, 5));
JPanel opPanel = new JPanel(new GridLayout(4, 1, 0, 5));
JPanel panel = new JPanel(new GridLayout(2, 1, 0, 5));
int counter;
char operation;
double operand1;
double operand2;
like that ,and i think to add actions to buttons inside for-loop no compiler errors every thing is ok
for (counter = 0; counter < 10; counter++) {
btnArray[counter] = new JButton("" + counter);
btnArray[counter].addActionListener(this);
}
and here is action performed implementation
#Override
public void actionPerformed(ActionEvent e) {
txt.setText(txt.getText() + counter);
}
just like that ,when i try to run the program and press any number button the number added to text field is "16" for all buttons, and this is main method
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SimpleCalculator frame = new SimpleCalculator();
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setResizable(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
i am getting crazy i don't know what is wrong , please i need your help this my first swing application i am so disperate
thank you
Try something like this (I can't test right now so it may contain some lesser errors):
#Override
public void actionPerformed(ActionEvent e) {
String value = ((JButton)e.getSource()).getText();
Integer intValue = Integer.parseInt(value);
Integer intValue2 = Integer.parseInt(txt.getText());
txt.setText( "" + (intValue + intValue2));
}
#Override
public void actionPerformed(ActionEvent e) {
JButton b = (JButton) e.getSource();
txt.replaceSelection(b.getActionCommand());
}
this is a solution for my question i found here
java-action-listener
#Override
public void actionPerformed(ActionEvent e) {
String value = (JButton) e.getSource().getText();
txt.setText(txt.getText() + value);
}
and this is another solution #Paco Abato helps me to find
I'm using a JTabbedPane, and on each tab there's a panel, which changes when the user does things like click buttons. The problem I'm getting is that elements from the previous panel get left behind. Usually you can't see them until you run the mouse over them, but sometimes you can't see elements of the new panel until you run your mouse over where they should be. So quite often at first only a little is visible, then:
when you run your mouse over more stuff it becomes visible
Then for some reason when you hit 'multiple choice', which is supposed to create the four new buttons, everything becomes perfectly visible.
I've got repaint(); as pretty much every other line, and before I change anything on the GUI I do removeAll(); first, but it all keeps coming back! Any suggestions? The code for this panel is below, if it might help...
package com.GC01.gui;
import java.awt.Color;
public class PracticeQuizPanel extends JPanel implements MouseListener {
/**
* This panel will allow the user to practice quiz questions.
*/
private static final long serialVersionUID = 1L;
private User user = new User("misha");
boolean isMultipleChoice=false;
boolean usedClue=false;
boolean isStarted=false;
Calendar calendar = Calendar.getInstance();
AnswerAnalysis aA = new AnswerAnalysis();
private Quiz qz = new Quiz( Quiz.getQuestionsFromDisk(), 4, TabbedQuiz.getUser().getNumLogins() );
private JTextArea questionArea;
private JTextArea clueArea;
private JTextArea answerArea;
private JButton clueButton;
private JButton multiButton;
private JButton answerButton;
private JButton startButton;
private int index=0;
private Calendar startCalendar, endCalendar;
private JPanel backPanel;
public PracticeQuizPanel(){
add(new StartButtonPanel());
}
PracticeQuizPanel(int index) {
createVisualElements(index);
}
public void offerAnswer(){
endCalendar = Calendar.getInstance();
aA.setTimeSpent((int) (endCalendar.getTimeInMillis()-startCalendar.getTimeInMillis()));
aA.setRight(answerArea.getText());
JOptionPane.showMessageDialog(null, aA.toString());
answerArea.setEditable(false);
qz.setAnswersAnalysis(index, aA);
index++;
removeAll();
if( index<qz.getLength() ) createVisualElements(index);
else {
removeAll();
JOptionPane.showMessageDialog(null, qz.toFriendlyString());
addQuizResultsToUserProgress();
JOptionPane.showMessageDialog(null, qz.toFriendlyString());
UserProgress uP = new UserProgress(user);
System.out.println(uP.toString());
}
repaint();
startCalendar = Calendar.getInstance();
//JOptionPane.showMessageDialog(null, isStarted);
}
public void addQuizResultsToUserProgress(){
UserProgress userProgress = new UserProgress(user);
ArrayList<AnswerAnalysis> asA = userProgress.getAnswersAnalysis();
for (int i=0; i<qz.getLength(); i++){
asA.add( qz.getAnswersAnalysis()[i]);
}
userProgress.setAnswersAnalysis(asA);
userProgress.saveProgress();
}
/**
* This method creates/recreates all the text boxes, buttons etc. without resetting the quiz and
* the objects in memory.
*/
private void createVisualElements(int index){
if (TabbedQuiz.getUser().getNumLogins()<0)
JOptionPane.showMessageDialog(null, "There was an error. You may have done this quiz before.");
removeAll();
repaint();
startCalendar = Calendar.getInstance();
this.index=index;
setBackground(new Color(112, 128, 144));
setBounds(0,0,728,380);
setLayout(null);
questionArea = new JTextArea();
questionArea.setFont(TabbedQuiz.getDefaultFont().deriveFont(20));//new Font("Courier New", 0, 20));
questionArea.setEditable(false);
questionArea.setLineWrap(true);
questionArea.setWrapStyleWord(true);
questionArea.setBounds(295, 11, 423, 74);
add(questionArea);
//int index=0;
Question q = qz.getQuestions().get(index);
aA = new AnswerAnalysis(q.getQuestionID());
questionArea.setText(q.getQuestionText() );
clueArea = new JTextArea();
clueArea.setFont(TabbedQuiz.getDefaultFont().deriveFont(20));
clueArea.setEditable(false);
clueArea.setLineWrap(true);
clueArea.setWrapStyleWord(true);
clueArea.setBounds(295, 104, 423, 55);
add(clueArea);
JLabel lblQuestion = new JLabel("QUESTION:");
lblQuestion.setFont(TabbedQuiz.getDefaultFont().deriveFont(40));
lblQuestion.setBounds(43, 11, 216, 61);
add(lblQuestion);
answerArea = new JTextArea();//index+"");
answerArea.setFont(TabbedQuiz.getDefaultFont().deriveFont(20));
answerArea.setLineWrap(true);
answerArea.setWrapStyleWord(true);
answerArea.setBounds(295, 301, 423, 50);
answerArea.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER) offerAnswer();
}
});
add(answerArea);
answerArea.setFocusable(true);
answerArea.requestFocusInWindow();
clueButton = new JButton("CLUE?");
clueButton.setFont(TabbedQuiz.getDefaultFont().deriveFont(40));
clueButton.addMouseListener(this);
clueButton.setBounds(15, 104, 244, 55);
add(clueButton);
multiButton = new JButton("MULTIPLE CHOICE?");
multiButton.setFont(TabbedQuiz.getDefaultFont().deriveFont(20));
multiButton.addMouseListener(this);
multiButton.setBounds(15, 195, 244, 55);
add(multiButton);
answerButton = new JButton("ANSWER!");
answerButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
answerButton.setFont(TabbedQuiz.getDefaultFont().deriveFont(40));
answerButton.setBounds(15, 301, 244, 55);
answerButton.addMouseListener(this);
add(answerButton);
backPanel = new JPanel();
backPanel.setBounds(0, 0, 728, 380);
//add(backPanel);
this.setVisible(true);
repaint();
}
#Override
public void mouseClicked(MouseEvent e) {
if ( e.getSource().equals(startButton) ) {
remove(startButton); repaint(); isStarted=true;
startCalendar = Calendar.getInstance();
}
else if ( e.getSource().equals(answerButton) ) offerAnswer();
else if ( e.getSource().equals(clueButton ) ) {
clueArea.setText(clueArea.getText() + qz.getQuestions().get(index).getClueText() + "\n");
aA.setUsedClue(true);
//JOptionPane.showMessageDialog(null, "hi");
}
else if ( e.getSource().equals(multiButton) ) {
String[] answerOptions = qz.getQuestions().get(index).getAnswerOptions(3);
JButton[] optionsButtons = new JButton[4];
for(int j=0;j<4;j++){
optionsButtons[j]=new JButton(answerOptions[j]);
if(optionsButtons[j].getText().length()>13)
optionsButtons[j].setFont(TabbedQuiz.getDefaultFont().deriveFont(10));
else optionsButtons[j].setFont(TabbedQuiz.getDefaultFont().deriveFont(15));
if(j<2) optionsButtons[j].setBounds(295+211*j , 170, 211, 55);
else optionsButtons[j].setBounds(295+211*(j-2) , 226, 211, 55);
optionsButtons[j].addMouseListener(this);
optionsButtons[j].setName("optionsButton"+"["+j+"]");
add(optionsButtons[j]);
repaint();
}
aA.setMultipleChoice(true);
}
else if ( ( (JButton) e.getSource() ).getName().startsWith("optionsButton") ) {
String answerOffered = ( (JButton) e.getSource() ).getText();
answerArea.setText(answerOffered);
offerAnswer();
}
}
#Override
public void mouseEntered(MouseEvent e) {
if(e.getSource()!=startButton && e.getSource().getClass().equals( answerButton.getClass()) ){
( (JButton) e.getSource() ).setBackground(Color.green);
}if(index>0 && e.getSource()==startButton) remove(startButton);
}
#Override
public void mouseExited(MouseEvent e) {
if(e.getSource()!=startButton && e.getSource().getClass().equals( answerButton.getClass()) ){
( (JButton) e.getSource() ).setBackground(UIManager.getColor("control"));
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
}
and on each tab there's a panel, which changes when the user does things like click buttons.
and before I change anything on the GUI I do removeAll();
Whenever I see comments like that it sounds to me like you should be using a Card Layout so you don't have to worry about all these problems.
You need to call revalidate after removing or adding components to a container if using layout managers. Then after that you call repaint.
You've posted a lot of code, and most of it is completely unrelated to the problem at hand, but on the other hand, the code posted is incomplete, won't compile, and thus is not code that we can test. Please next time, try not posting a lot of code that's not relevant to the problem. Try to isolate the problem by continually cutting out code, and then if still stuck, post a minimal compiable program that we can study, test, run, and modify ourselves, an sscce.
I've gone through some of your GUI code (for gosh's sake, not all!), and there's some big time badness there where you're stepping on Swing painting such as this code from ProgressPanel.java:
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
createAndShowGUI(g2d);
// drawDifficultyChart(g2d, fontComboBox.getSelectedIndex());
}
private void createAndShowGUI(Graphics2D g2d) {
JButton showChartButton = new JButton("Show new chart!");
user = TabbedQuiz.getUser();
showChartButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
if (categoryComboBox.getSelectedIndex() == 0
&& difficultyComboBox.getSelectedIndex() != 0) {
drawDifficultyChart((Graphics2D) getGraphics(),
difficultyComboBox.getSelectedIndex());
} else if (difficultyComboBox.getSelectedIndex() == 0
&& categoryComboBox.getSelectedIndex() != 0) {
drawCategoryChart((Graphics2D) getGraphics(),
(String) categoryComboBox.getSelectedItem());
} else
drawGeneralChart((Graphics2D) getGraphics(),
(String) categoryComboBox.getSelectedItem(),
difficultyComboBox.getSelectedIndex());
} catch (NullPointerException e1) {
JOptionPane.showMessageDialog(null, "Sign in first.");
}
}
});
showChartButton.setBounds(10, 90, 96, 26);
showChartButton.setFont(font);
add(showChartButton);
}
The problem is that you're creating and adding components to a container from within a paint/paintComponent method, something you should never be doing and something that is bound to mess up your program's graphics.
To anyone else with this issue: I eventually solved the problem. setVisible(false); setVisible(true);. Put it EVERYWHERE.
I have the following code:
public class Test extends JFrame implements ActionListener{
private static final Color TRANSP_WHITE = new Color(new Float(1), new Float(1), new Float(1), new Float(0.5));
private static final Color TRANSP_RED = new Color(new Float(1), new Float(0), new Float(0), new Float(0.1));
private static final Color[] COLORS = new Color[]{ TRANSP_RED, TRANSP_WHITE};
private int index = 0;
private JLabel label;
private JButton button;
public Test(){
super();
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
label = new JLabel("hello world");
label.setOpaque(true);
label.setBackground(TRANSP_WHITE);
getContentPane().add(label);
button = new JButton("Click Me");
button.addActionListener(this);
getContentPane().add(button);
pack();
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(button)){
label.setBackground(COLORS[index % (COLORS.length - 1)]);
index++;
}
}
public static void main(String[] args) {
new Test();
}
}
When I run it I get the label with the TRANSP_WHITE background and then when I click the button this color changes to TRANSP_RED but when I click it again I see no change in color. Does anyone know why?
Thanks
Well, what were you expecting to happen?
label.setBackground(COLORS[index % (COLORS.length - 1)]);
The index variable is hard coded to 0. and COLORS.length -1 is essentially a constant. So every time you click your setting the background to COLORS[0];
If you change your action method to the following you'll get the results you are looking for:
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(button)){
label.setBackground(COLORS[index % COLORS.length]);
index++;
}
}
First: The modulo operator will always return a value between 0 and one less than the value passed to it. So
index % COLORS.length
Will always return a value between 0 and COLORS.length -1.
Second: You were forgetting to increment index after every call.
Hey! You forgot to increment index. In this expression:
label.setBackground(COLORS[index % (COLORS.length - 1)]);
index % (COLORS.length - 1) is always 0.
BTW. you don't have to use new Float(1) when creating Color. 1F should work too.
Here is the code you have to use
label.setBackground(COLORS[index % (COLORS.length)]);
index++;
You are doing it wrong. It should be done like that
label = new JLabel("hello world"){
public void paintComponent(Graphics g)
{
//draw background
Color old=g.getColor();
g.setColor(getBackground());
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(old);
super.paintComponent(g);
}
};
label.setOpaque(false); // your component is not opaque!