Working on a school project, I am trying to get the action of clicking a button pull the selected index of a Combo Box string array, and associated that index with an int array so that a final price can be computed. Doesn't seem to work the price just remains at zero when button is pressed.
private final String[] deckArray = {"The Master
Thrasher ", "The Dictator", "The Street King"};
private final String[] trucksArray = {"7.75-inch
axle", "8-inch axle", "8.5-inch axle"};
private final String[] wheelsArray = {"51mm", "55mm",
"58mm", "61mm"};
private final int[] deckPrice = {60,45,50};
private final int[] trucksPrice = {35,40,45};
private final int[] wheelsPrice = {20,22,24,28};
comboDecks = new ComboBox();
comboDecks.getItems().addAll(deckArray);
comboTrucks = new ComboBox();
comboTrucks.getItems().addAll(trucksArray);
comboWheels = new ComboBox();
comboWheels.getItems().addAll(wheelsArray);
btnCalc = new Button("Calculate Total");
lblFinalPrice = new Label("Final Price:");
txtSubtotal = new Text("Subtotal: " + finalSubPrice);
txtTax = new Text("Tax:" + finalTaxPrice);
txtFinalPrice = new Text("Final Price: " +
finalTotalPrice);
EventHandler<ActionEvent> calcHandler = new
EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
finalDeckPrice = deckPrice[comboDecks.getSelectionModel().getSelectedIndex()];
finalTruckPrice = trucksPrice[comboTrucks.getSelectionModel().getSelectedIndex()];
finalWheelsPrice = wheelsPrice[comboWheels.getSelectionModel().getSelectedIndex()];
finalSubPrice = finalDeckPrice + finalTruckPrice + finalWheelsPrice;
finalTaxPrice = finalSubPrice * salesTax;
finalTotalPrice = finalSubPrice + finalTaxPrice;
}
};
You made the button, you made the event handler, but you never connected the event handler to the button. Same goes for the calculation and the label, you calculated but did not update the label with the calculated value.
Add the following line to your code after you create the handler.
btnCalc.setOnAction(calcHandler);
And add txtFinalPrice.setText(""+finalTotalPrice); after you finish calculations inside handle() method.
public void handle(ActionEvent actionEvent) {
...
finalTotalPrice = finalSubPrice + finalTaxPrice;
txtFinalPrice.setText("Final Price: " + finalTotalPrice);
}
Explanation (Abstract)
(1) When you create an Event Handler object you just wrote the code you want it to run but it won't run in serial as the code executes top to bottom, since as you said you want it to work when you click the button. So you have to let the Button know that when it gets clicked to execute this code. setOnAction() method takes as parameter an Event Handler object and executes it when some action happens to the Button, the action for the Button is when it gets clicked.
(2) Just by calculating the value, doesn't mean the Label knows that the value got calculated or something. The point where you calculating the price is the point that you have to tell to the Label take this value and use this as your content.
Suggestion
Event handlers, action events etc need a bit of good understanding to use them correctly. The baseline is that all of that work asynchronously and you gotta get at least the idea of it so you can understand the rest (no offense but from the question i believe you need some work on it).
Writing a program to increment a counter when a +1 button is pressed, then when the counter reaches a certain number, remove the +1 button and replace it with a +2 button and so on. I create both buttons at first but just set btnCount1 to setVisible(false). When the certain number passes, I make btnCount invisible and btnCount1 visible and increment by two from there. When it reaches 10 clicks, the btnCount disappears, but btnCount1 does not appear.
I have tried making an if(arg0.equals(btnCount1)), and incrementing by two from there. I tried putting the add(btnCount1) inside the else if statement to create it after the elseif condition is true.
public class AWTCounter extends Frame implements ActionListener
private Label lblCount;
private TextField tfCount;
private Button btnCount;
private Button btnCount1;
private int count = 0;
public AWTCounter() {
setLayout(new FlowLayout());
lblCount = new Label("Counter");
add(lblCount);
tfCount = new TextField(count + "",10);
tfCount.setEditable(false);
add(tfCount);
btnCount = new Button("Add 1");
btnCount1 = new Button("Add 2");
add(btnCount);
add(btnCount1);
btnCount1.setVisible(false);
btnCount.addActionListener(this);
btnCount1.addActionListener(this);
setTitle("AWT Counter");
setSize(500,500);
}
public static void main(String[]args) {
AWTCounter app = new AWTCounter();
}
public void actionPerformed(ActionEvent arg0) {
if(count <= 10) {
++count; //Increase the counter value
tfCount.setText(count + "");
}else if(count > 10) {
btnCount.setVisible(false);
btnCount1.setVisible(true);
count += 2;
tfCount.setText(count + "");
}
}
The better solution here is to just have one button object and a separate variable for the current increment amount. When you hit the required count, increase the increment amount and change the button's label to the new value.
There are also a few other things you could do better here.
Use String.valueOf() instead of int + "" for String representations of integers if you're not adding words before or after the integer.
Don't add obvious comments for code. (e.g. 'increment variable x', 'set textString to the new value')
Use descriptive names for method parameters and variables.
Use Labels instead of TextFields for text that doesn't need to be editable or selectable like counter displays.
I'd personally change the name of lblCount to something like lblTitle as well, since changing your tfCount to a Label would logically take up that name and lblTitle makes more sense.
Here's a better way to implement actionPerformed:
private int increment = 1;
private Label lblCount;
...
public void actionPerformed(ActionEvent ignore) {
if(count == 10) {
btnCount.setLabel("Add " + (++increment));
}
lblCount.setText(String.valueOf(count += increment));
}
I am working on a javafx project in which I'm providing a textbox to be filled in.I want to calculate % of textbox filled in..say for eg 100 characters is a limit and 50 are filled in so 50 should be the % value but it should change automatically as i keep typing .I don't know exactly how to do that (specially the Automatic thing). I want to show that % value on progressbar like this :
(Ignore buttons)
Need help! Thank you in advance
You can define yourself a DoubleBinding which is bound to the textProperty and on each change revaluates it's value.
final double max = 100;
TextField text = new TextField();
DoubleBinding percentage = new DoubleBinding() {
{
super.bind(text.textProperty());
}
#Override
protected double computeValue() {
return text.getText().length() / max;
}
};
In the static initializer block of the DoubleBinding you bind the textProperty of your TextField. This will cause the reevaluation of the binding through the computeValue method. Then you can bind it to the textProperty of a Label:
Label lbl = new Label();
lbl.textProperty().bind(percentage.asString());
Of course you can also bind it to other controls than a Label like a ProgressBar or ProgressIndicator:
ProgressBar bar = new ProgressBar();
bar.progressProperty().bind(percentage);
ProgressIndicator indicator = new ProgressIndicator();
indicator.progressProperty().bind(percentage);
This binding then can be used to display the percentage already filled in. You might also take a look at this documentation by Oracle. The type of this binding is a low-level binding.
public ComplexNum add(ComplexNum c){
double addedReal = (this.real + c.real);
double addedImag = (this.imag + c.imag);
System.out.println(addedReal);
return new ComplexNum(addedReal,addedImag);
}
This is one of the simpler methods. I want to make a controller class that lets a user enter the first number, press an addition button, enter the second number, press enter, and then have the string representation of the return value printed to a label. I'm not sure how I can call the right method using the controller. I though that maybe I should have a method that checks for specific text(say "add") from the button pressed and executes the correct method for it but I feel like that's not the right way.
I basically want the first number entered to be treated as the "this" pointer for each of the methods, and any following numbers as the parameter.
You have to set an action listener on the button. Example using JavaFX 8:
Button button = new Button();
button.setText("Button Text");
button.setOnAction((ActionEvent event) -> {
System.out.println("Button Clicked!");
});
For you ENTER input, you need to add an event handler to your node. E.g.:
Scene scene = new Scene(root);
scene.addEventHandler(KeyEvent.KEY_PRESSED, (KeyEvent key) -> {
if(key.getCode().equals(KeyCode.ENTER)) {
System.out.println("ENTER pressed");
}
}
You could do something like this (this obviously is incomplete) hopefully can point you in a direction:
long runningTotal = 0;
Button plusButton = new Button("+");
Button enterButton = new Button("Enter");
TextField tf = new TextField();
Label displayLabel = new Label();
//Setup you UI here
plusButton.setOnAction(event -> {
String stringValue = tx.getText();
long value = Long.parseLong(stringValue);
runningTotal = runningTotal + value;
});
enterButton.setOnAction(event -> {
//if you need to remember your last pressed button, you could have done that also, then perform that action here
displayLabel.setText("" + runningTotal);
});
I am trying to make cleaner code in my programs. So I was trying to compress my code to create buttons:
Before, I needed to copy this every single time:
Dimension JButton_Cryption_Size = JButton_Cryption.getPreferredSize();
JButton_Cryption.setBounds(5, 5, JButton_Cryption_Size.width + 50, JButton_Cryption_Size.height);
JButton_Cryption.setFocusPainted(false);
JButton_Cryption.addActionListener(this);
add(JButton_Cryption);
but now I made this method: (Don't pay attention to the button names, they are for testing)
public JButton JButton_Testing1,
JButton_Testing2,
JButton_3;
private void addJButton(JButton ButtonName, String Name, int x, int y, int width, int height, String ToolTip, boolean FocusedPainted, boolean Opaque, boolean ContentAreaFilled, boolean BorderPainted){
ButtonName = new JButton(Name);
Dimension Button_Size = ButtonName.getPreferredSize();
if(width == 0){
ButtonName.setBounds(x, y, Button_Size.width, height);
}if(height == 0){
ButtonName.setBounds(x, y, width, Button_Size.height);
}if(width == 0 && height == 0){
ButtonName.setBounds(x, y, Button_Size.width, Button_Size.height);
}if(width != 0 && height != 0){
ButtonName.setBounds(x, y, width, height);
}
ButtonName.addActionListener(this); // class: implements ActionListener
ButtonName.setToolTipText(ToolTip);
ButtonName.setFocusPainted(FocusedPainted);
ButtonName.setOpaque(Opaque);
ButtonName.setContentAreaFilled(ContentAreaFilled);
ButtonName.setBorderPainted(BorderPainted);
add(ButtonName);
}
private void addButtonToFrame(){
addJButton(JButton_Testing1, "Testing 1", 150, 100, 172, 0, null, false, true, true, true);
addJButton(JButton_Testing2, "Testing 2", 0, 0, 0, 0, null, false, true, true, true);
addJButton(JButton_Testing3, "Testing 3", 200, 150, 250, 100, "YO", false, true, true, true);
}
But when I want to add an action to the button, it wont work
#Override
public void actionPerformed(ActionEvent e){
Object src = e.getSource();
if(src == JButton_Testing1){
System.out.println("yo");
}
}
How can I make so I can keep my thing (or modify it a bit) so I can use the ActionListener correctly
Your question is about clean code, and you ask us to not pay attention to the button names. Half of having clean code is about having good names. Respect the Java conventions, and assign meaningful names to your variables and methods. Variables and methods start with a lowercase character in Java. And they don't contain underscores.
Also, Swing has layout managers. Stop setting bounds. Use layout managers.
Avoid having methods with 11 parameters.
Avoid having public fields. Fields should be private.
And finally, don't use this as the action listener. Use a separate class as your listener.
Regarding your problem: your addJButton() method doesn't add a listener to the button passed as argument. It ignores this argument, creates a new button, and adds the listener to this new button:
public void addJButton(JButton ButtonName, ...) {
ButtonName = new JButton(Name);
A bad strategy is also the addButtonToFrame() method.
It hard codes the number of buttons, their names, and everything. This way if you want to add one more button (for any reason) you have to write one more (custom) line of code to this method.
The right way here is to make an addButtonToFrame(ArrayList <Button> buttons) method. You pass an ArrayList of (as many as you please) buttons in this method. Then add them in the panel, given the objects have been created with Dimension parameter.
But again, this is kind of making a new layout manager, and java has some really nice layout managers. In other words you are reinventing the wheel. That is not always bad (it is a good practice), but to make a good manager you have to spend time and (as I said) there are good managers.
Example:
class ButtonExample{
ArrayList <JButton> buttons = new ArrayList<JButton>();
ActionListener beh = new ButtonEventHandler() //this is a custom class that contains actionPerformed() method
createButtons(){
for (int i = 0; i < buttons.size(); i++)
buttons.get(i) = new JButton();
}
addListeners(){
for (int i = 0; i < buttons.size(); i++)
buttons.get(i).addActionListener(beh);
}
}
The ArrayList is a kind of array without standard size. It is implemented using some nice tricks (that there is no need to know to use it) and you can access its objects with get() method (instead of [] operator like in regular arrays)
The addListeners() and createButtons() methods are dummies just to see how ArrayLists work. You can pass them as parameters in other methods the way you pass any regular object.