How do I create an arraylist in and add and view it with buttons? - user-interface

I'm trying to make a GUI program that enters and removes cars from an arraylist and displays the cars using JButtons. I am unable to get the arraylist to print from clicking on one of the buttons. I'm also unsure if my arraylist is made correctly. Any help would be greatly appreciated.
import java.util.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Window extends JFrame {
public Window() {
super ("Rent-a-Car");
setSize(400, 100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
JPanel p = new JPanel();
JButton b1 = new JButton("Add Car");
JButton b2 = new JButton("Rent Car");
JButton b3 = new JButton("Library");
p.add(b1);
p.add(b2);
p.add(b3);
add(p);
final ArrayList<String> cars = new ArrayList<String>();
cars.add("Audi");
cars.add("VolksWagon");
cars.add("Mercedes");
cars.add("BMW");
cars.add("Ford");
cars.add("Subaru");
cars.add("Lexus");
cars.add("Acura");
cars.add("Nissan");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Scanner sc = new Scanner(System.in);
JOptionPane.showInputDialog("Enter car model");
String model = sc.next();
JOptionPane.showMessageDialog(null, "Car added");
cars.add(model);
}
});
/*b3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for(int i=0 < cars.size(); i++) {
System.out.println();
}
}
});*/
}
}

In your ActionListener for b1 you're trying to scan it from the wrong place. If you run this, you've probably noticed that the JOptionPane doesn't do anything when you submit a car with the add button. However, if you enter a string into the terminal, an dialog will pop up saying "Car added". This is because Scanner sc is scanning System.in! This is not meant for GUIs.
Fortunately, it's really simple to get input from a JOptionPane.
EDIT: Added a few things like a JTextArea in a JScrollPane that is easy to append to and changed it to a simple GridLayout.
I also moved the ActionListeners into an inner class so that you don't clutter up your code with anonymous functions everywhere. It's also a bit easier to add stuff with the (e.getSource()) conditionals, too.
Set model equal to the result of showInputDialog as such:
import java.util.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.GridLayout;
import javax.swing.*;
public class Window extends JFrame {
private JPanel p;
private JButton b1, b2, b3;
private JTextArea textArea;
private JScrollPane scrollPane;
private ArrayList<String> cars;
public Window() {
super ("Rent-a-Car");
setLayout(new GridLayout(2, 1));
setSize(400, 100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
p = new JPanel();
b1 = new JButton("Add Car");
b2 = new JButton("Rent Car");
b3 = new JButton("Library");
b1.addActionListener(new ButtonListener());
b2.addActionListener(new ButtonListener());
b3.addActionListener(new ButtonListener());
textArea = new JTextArea("");
textArea.setEditable(false);
scrollPane = new JScrollPane(textArea);
p.add(b1);
p.add(b2);
p.add(b3);
add(p);
//add(textArea);
add(scrollPane);
cars = new ArrayList<String>();
cars.add("Audi");
cars.add("VolksWagon");
cars.add("Mercedes");
cars.add("BMW");
cars.add("Ford");
cars.add("Subaru");
cars.add("Lexus");
cars.add("Acura");
cars.add("Nissan");
}
public void displayText(String s) {
textArea.append(s + "\n");
textArea.setCaretPosition(textArea.getDocument().getLength());
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == b1) {
String model = JOptionPane.showInputDialog("Enter car model");
cars.add(model);
displayText("Added car: " + model);
}
else if (e.getSource() == b2) {
//add something later
}
else if (e.getSource() == b3) {
for (String car : cars) {
displayText(car);
}
}
}
}
}

Related

How to separate a JavaFX Appliciation

I want to seperate a JavaFX project to model, view and controller.
I use netbeans when creating a JavaFX application.
But I want the code seperate, an own GUI, own logic and a Main class just to start the application (I want 3 seperate classes).
But I am not able to solve this problem.
The automatic created code looks like this:
package at.wueschn.www;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you are using NetBeans, first choose File -> New Project. Then JavaFX -> JavaFX FXML Application
Note: This is a basic MVC setup. You could do all of this using pure code. James_D could probably help you with more advanced MCV ideas.
Note: If you are going to take this simple approach, I suggest you download SceneBuilder to help you with the view.
Tutorial
Here is a "Java-only" (i.e. no FXML) example of MVC. Note that there are many different variants of MVC, which is a very loosely-defined pattern. This is a kind of "classical" variant: the model has no knowledge of the view(s) or controller(s) (which is the common theme to all MVC-type designs), the controller has a reference to the model and invokes methods on it, implementing some simple logic, and the view has a reference to both the model and controller; observing the model and updating the view components when the data changes, and invoking methods on the controller in response to user input. Other variants of this pattern (MVVM, MVP, etc) typically vary in the relationship between the view and the controller.
This simple application implements a very basic calculator, which simply knows how to add two single-digit integers.
The model:
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
public class Model {
private boolean firstNumberEntered ;
private final IntegerProperty firstNumber = new SimpleIntegerProperty();
private final IntegerProperty secondNumber = new SimpleIntegerProperty();
private final NumberBinding sum = firstNumber.add(secondNumber);
public Model() {
firstNumber.addListener((obs, oldValue, newValue) -> firstNumberEntered = true );
}
public IntegerProperty firstNumberProperty() {
return firstNumber ;
}
public int getFirstNumber() {
return firstNumberProperty().get();
}
public void setFirstNumber(int number) {
firstNumberProperty().set(number);
}
public IntegerProperty secondNumberProperty() {
return secondNumber ;
}
public int getSecondNumber() {
return secondNumberProperty().get();
}
public void setSecondNumber(int number) {
secondNumberProperty().set(number);
}
public NumberBinding sumBinding() {
return sum ;
}
public int getSum() {
return sum.intValue();
}
public boolean isFirstNumberEntered() {
return firstNumberEntered ;
}
public void reset() {
setFirstNumber(0);
setSecondNumber(0);
firstNumberEntered = false ;
}
}
The controller:
public class Controller {
private final Model model ;
public Controller(Model model) {
this.model = model ;
}
public void enterFirstNumber(int number) {
model.setFirstNumber(number);
}
public void enterSecondNumber(int number) {
model.setSecondNumber(number);
}
public void clear() {
model.reset();
}
public void enterNumber(int number) {
if (model.isFirstNumberEntered()) {
enterSecondNumber(number) ;
} else {
enterFirstNumber(number);
}
}
}
The view:
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
public class View {
private final BorderPane root ;
private final Controller controller ;
public View(Model model, Controller controller) {
this.controller = controller ;
root = new BorderPane();
GridPane buttons = new GridPane();
configureButtons(buttons);
createAndAddButtons(controller, buttons);
Label resultLabel = new Label();
configureDisplay(model, resultLabel);
root.setTop(resultLabel);
root.setCenter(buttons);
root.setStyle("-fx-font-size: 36pt;");
}
private void configureDisplay(Model model, Label resultLabel) {
BorderPane.setAlignment(resultLabel, Pos.CENTER_RIGHT);
BorderPane.setMargin(resultLabel, new Insets(5));
resultLabel.textProperty().bind(Bindings.createStringBinding(
() -> String.format("%d + %d = %d", model.getFirstNumber(), model.getSecondNumber(), model.getSum()),
model.firstNumberProperty(), model.secondNumberProperty(), model.sumBinding()));
}
private void createAndAddButtons(Controller controller, GridPane buttons) {
for (int i = 1 ; i <= 9 ; i++) {
int row = (9 - i) / 3 ;
int column = (i -1) % 3 ;
buttons.add(createNumberButton(i), column, row);
}
buttons.add(createNumberButton(0), 0, 3);
Button clearButton = createButton("C");
clearButton.setOnAction(e -> controller.clear());
buttons.add(clearButton, 1, 3, 2, 1);
}
private void configureButtons(GridPane buttons) {
for (int row = 0 ; row < 4 ; row++) {
RowConstraints rc = new RowConstraints();
rc.setFillHeight(true);
rc.setPercentHeight(100.0 / 4);
buttons.getRowConstraints().add(rc);
}
for (int column = 0 ; column < 3 ; column++) {
ColumnConstraints cc = new ColumnConstraints();
cc.setFillWidth(true);
cc.setPercentWidth(100.0 / 3);
buttons.getColumnConstraints().add(cc);
}
buttons.setVgap(5);
buttons.setHgap(5);
buttons.setPadding(new Insets(5));
}
public Parent getRoot() {
return root ;
}
private Button createNumberButton(int number) {
Button button = createButton(Integer.toString(number));
button.setOnAction(e -> controller.enterNumber(number));
return button ;
}
private Button createButton(String text) {
Button button = new Button(text);
button.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
return button ;
}
}
and finally the "main" class which creates each piece and displays the view in a window:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TrivialCalcaulatorApp extends Application {
#Override
public void start(Stage primaryStage) {
Model model = new Model();
Controller controller = new Controller(model);
View view = new View(model, controller);
Scene scene = new Scene(view.getRoot());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Animating a sprite with JavaFX on key input

I'm new to JavaFX but have a good understanding of object orientated Java. The following program is a combination of two examples, one that animates and moves shapes , the other animates an object on a mouse button press. Much of the functionality has been removed or changed for my needs.
I've searched through many examples but haven't found one I fully understand regarding moving a sprite and animating on key press.In my program I'm sure that I'm not using the right classes to create the game object, even though with some tweaking I'm sure it could work.
I added some println functions to test the animation. The problem seems to be that the KeyFrame part in the walkSouth animation isn't working/playing.
My question is:
Should I be using different JavaFX classes to create the sprite-sheet animation?
Can this code be easily adapted to function so I can get a better understanding of how JavaFX works.
Here is the main class:
package testing;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private enum UserAction{
NONE,NORTH,SOUTH;
}
private static int APP_W = 200;
private static int APP_H = 200;
private Scene scene;
private UserAction action = UserAction.NONE;
private Timeline timeline = new Timeline();
private boolean running = true;
private int FPS = 60;
private Parent createContent(){
Pane root = new Pane();
root.setPrefSize(APP_W,APP_H);
Image cat_image = new Image("file:res/cata.png");
GameObject obj = new GameObject(cat_image,12,8);
obj.setTranslateX(100);
obj.setTranslateY(100);
KeyFrame frame = new KeyFrame(Duration.millis(1000/FPS), event -> {
if(!running)
return;
switch(action){
case NORTH:
obj.setTranslateY(obj.getTranslateY()-1);
break;
case SOUTH:
obj.walkSouth();
obj.setTranslateY(obj.getTranslateY()+1);
break;
case NONE:
obj.pauseAnimation();
break;
}
});
timeline.getKeyFrames().add(frame);
timeline.setCycleCount(Timeline.INDEFINITE);
root.getChildren().add(obj);
return root;
}
private void restartGame(){
stopGame();
startGame();
}
private void stopGame(){
running = false;
timeline.stop();
}
private void startGame(){
timeline.play();
running = true;
}
public void start(Stage primaryStage) throws Exception{
scene = new Scene(createContent());
scene.setOnKeyPressed(event -> {
switch (event.getCode()) {
case W:
action = UserAction.NORTH;
break;
case S:
action = UserAction.SOUTH;
break;
}
});
scene.setOnKeyReleased(event -> {
switch (event.getCode()) {
case W:
action = UserAction.NONE;
break;
case S:
action = UserAction.NONE;
break;
}
});
primaryStage.setTitle("Simple Animation");
primaryStage.setScene(scene);
primaryStage.show();
startGame();
}
public static void main(String[] args) {
launch(args);
}
}
Here is the GameObject class:
package testing;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Rectangle2D;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.util.Duration;
/**
* Created by matt on 26/02/17.
*/
public class GameObject extends Pane {
ObjectImage objectImage;
public GameObject( Image image, int columns, int rows){
objectImage = new ObjectImage(image,columns,rows);
getChildren().setAll(objectImage);
}
public void pauseAnimation(){
getChildren().setAll(objectImage);
objectImage.pauseAnimation();
}
public void walkSouth(){
getChildren().setAll(objectImage);
objectImage.walkSouth();
}
}
class ObjectImage extends ImageView {
private Rectangle2D[] clips;
private double width,height;
private Timeline timeline = new Timeline();
public ObjectImage(Image image,int columns,int rows){
width = image.getWidth()/columns;
height = image.getHeight()/rows;
clips = new Rectangle2D[rows*columns];
int count=0;
for(int row =0;row < rows;row++ )
for(int column = 0 ; column < columns; column++,count++)
clips[count] = new Rectangle2D(width * column, height * row,width,height);
setImage(image);
setViewport(clips[0]);
}
public void pauseAnimation(){
timeline.pause();
}
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
KeyFrame frame = new KeyFrame( Duration.millis(1000/5), event -> {
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
System.out.println("frame test");
});
timeline.setCycleCount(timeline.INDEFINITE);
timeline.getKeyFrames();
timeline.play();
}
}
This is the sprite-sheet image I'm working with
This is the outcome
As hinted by the comment, you did forget to add the frame in the walkSouth method. (Also you set each picture frame in walkSouth method to 200ms. Did you meant to change that?) Here's the code after changing:
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
KeyFrame frame = new KeyFrame( Duration.millis(1000/FPS), event -> {
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
});
timeline.setCycleCount(timeline.INDEFINITE);
timeline.getKeyFrames().add(frame); //This was the offending line.
timeline.play();
}
To answer your first question, yes there are many other options of classes you could use. Two options you could do is use the AnimationTimer or the Transition class. Here's a brief explanation for both (with code samples).
AnimationTimer is called every cycle or frame of rendering, which I believe you might be wanting this one:
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
AnimationTimer tmr = new AnimationTimer() {
#Override
public void handle(long nanoTime)
{
//nanoTime specifies the current time at the beginning of the frame in nano seconds.
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
}
};
tmr.start();
//call tmr.stop() to stop/ pause timer.
}
If however, you don't want an animation to be called each frame, you could extend Transition. A transition has an frac (fractional) value ranging from 0 to 1 that increases with respect to time. I'm not going to go into a whole lot detail, but I'm sure you could look up some more information on the api.
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
Transition trans = new Transition() {
{
setCycleDuration(Duration.millis(1000 / 60.0));
}
#Override
public void interpolate(double frac)
{
if (frac != 1)
return;
//End of one cycle.
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
}
};
trans.setCycleCount(Animation.INDEFINITE);
trans.playFromStart();
//Use trans.pause to pause, trans.stop to stop.
}

Can't stop javafx tables from ignoring my the setter function validation

I'm using javafx to do some table stuff. I want to validate my textfields in the myTextRow Class. In the "setText2" method I check the input if it is not bigger than 6 symbols, but it has no effects at all.
import java.util.ArrayList;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TextArea;
import javafx.util.Callback;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Supermain extends Application {
#Override
public void start(Stage primaryStage) {
ArrayList myindizes=new ArrayList();
final TableView<myTextRow> table = new TableView<>();
table.setEditable(true);
table.setStyle("-fx-text-wrap: true;");
//Table columns
TableColumn<myTextRow, String> clmID = new TableColumn<>("ID");
clmID.setMinWidth(160);
clmID.setCellValueFactory(new PropertyValueFactory<>("ID"));
TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
clmtext.setMinWidth(160);
clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));
clmtext.setCellFactory(new TextFieldCellFactory());
TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2");
clmtext2.setMinWidth(160);
clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2"));
clmtext2.setCellFactory(new TextFieldCellFactory());
//Add data
final ObservableList<myTextRow> data = FXCollections.observableArrayList(
new myTextRow(5, "Lorem","bla"),
new myTextRow(2, "Ipsum","bla")
);
table.getColumns().addAll(clmID, clmtext,clmtext2);
table.setItems(data);
HBox hBox = new HBox();
hBox.setSpacing(5.0);
hBox.setPadding(new Insets(5, 5, 5, 5));
Button btn = new Button();
btn.setText("Get Data");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
for (myTextRow data1 : data) {
System.out.println("data:" + data1.getText2());
}
}
});
hBox.getChildren().add(btn);
BorderPane pane = new BorderPane();
pane.setTop(hBox);
pane.setCenter(table);
primaryStage.setScene(new Scene(pane, 640, 480));
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public static class TextFieldCellFactory
implements Callback<TableColumn<myTextRow, String>, TableCell<myTextRow, String>> {
#Override
public TableCell<myTextRow, String> call(TableColumn<myTextRow, String> param) {
TextFieldCell textFieldCell = new TextFieldCell();
return textFieldCell;
}
public static class TextFieldCell extends TableCell<myTextRow, String> {
private TextArea textField;
private StringProperty boundToCurrently = null;
public TextFieldCell() {
textField = new TextArea();
textField.setWrapText(true);
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
this.setGraphic(textField);
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
// Show the Text Field
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
// myindizes.add(getIndex());
// Retrieve the actual String Property that should be bound to the TextField
// If the TextField is currently bound to a different StringProperty
// Unbind the old property and rebind to the new one
ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
SimpleStringProperty sp = (SimpleStringProperty) ov;
if (this.boundToCurrently == null) {
this.boundToCurrently = sp;
this.textField.textProperty().bindBidirectional(sp);
} else if (this.boundToCurrently != sp) {
this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
this.boundToCurrently = sp;
this.textField.textProperty().bindBidirectional(this.boundToCurrently);
}
double height = real_lines_height(textField.getText(), this.getWidth(), 30, 22);
textField.setPrefHeight(height);
textField.setMaxHeight(height);
textField.setMaxHeight(Double.MAX_VALUE);
// if height bigger than the biggest height in the row
//-> change all heights of the row(textfields ()typeof textarea) to this height
// else leave the height as it is
//System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
//this.textField.setText(item); // No longer need this!!!
} else {
this.setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
}
public class myTextRow {
private final SimpleIntegerProperty ID;
private final SimpleStringProperty text;
private final SimpleStringProperty text2;
public myTextRow(int ID, String text,String text2) {
this.ID = new SimpleIntegerProperty(ID);
this.text = new SimpleStringProperty(text);
this.text2 = new SimpleStringProperty(text2);
}
public void setID(int id) {
this.ID.set(id);
}
public void setText(String text) {
this.text.set(text);
}
public void setText2(String text) {
if(text2check(text)){
this.text2.set(text);}
else
{System.out.println("wrong value!!!");}
}
public int getID() {
return ID.get();
}
public String getText() {
return text.get();
}
public StringProperty textProperty() {
return text;
}
public String getText2() {
return text2.get();
}
public StringProperty text2Property() {
return text2;
}
public IntegerProperty IDProperty() {
return ID;
}
public boolean text2check(String t)
{
if(t.length()>6)return false;
return true;
}
}
private static double real_lines_height(String s, double width, double heightCorrector, double widthCorrector) {
HBox h = new HBox();
Label l = new Label("Text");
h.getChildren().add(l);
Scene sc = new Scene(h);
l.applyCss();
double line_height = l.prefHeight(-1);
int new_lines = s.replaceAll("[^\r\n|\r|\n]", "").length();
// System.out.println("new lines= "+new_lines);
String[] lines = s.split("\r\n|\r|\n");
// System.out.println("line count func= "+ lines.length);
int count = 0;
//double rest=0;
for (int i = 0; i < lines.length; i++) {
double text_width = get_text_width(lines[i]);
double plus_lines = Math.ceil(text_width / (width - widthCorrector));
if (plus_lines > 1) {
count += plus_lines;
//rest+= (text_width / (width-widthCorrector)) - plus_lines;
} else {
count += 1;
}
}
//count+=(int) Math.ceil(rest);
count += new_lines - lines.length;
return count * line_height + heightCorrector;
}
private static double get_text_width(String s) {
HBox h = new HBox();
Label l = new Label(s);
l.setWrapText(false);
h.getChildren().add(l);
Scene sc = new Scene(h);
l.applyCss();
// System.out.println("dubbyloop.FXMLDocumentController.get_text_width(): "+l.prefWidth(-1));
return l.prefWidth(-1);
}
}
A rule of the JavaFX Properties pattern is that for a property x, invoking xProperty().setValue(value) should always be identical to invoking setX(value). Your validation makes this not true. The binding your cell implementation uses invokes the setValue method on the property, which is why it bypasses your validation check.
(Side note: in all the code I am going to change the names so that they adhere to proper naming conventions.)
The default way to implement a property in this pattern is:
public class MyTextRow {
private final StringProperty text = new SimpleStringProperty();
public StringProperty textProperty() {
return text ;
}
public final void setText(String text) {
textProperty().set(text);
}
public final String getText() {
return textProperty().get();
}
}
By having the set/get methods delegate to the appropriate property methods, you are guaranteed these rules are enforced, even if the textProperty() methods is overridden in a subclass. Making the set and get methods final ensures that the rule is not broken by a subclass overriding those methods.
One approach might be to override the set and setValue methods in the property, as follows:
public class MyTextRow {
private final StringProperty text2 = new StringPropertyBase() {
#Override
public String getName() {
return "text2";
}
#Override
public Object getBean() {
return MyTextRow.this ;
}
#Override
public void setValue(String value) {
if (text2Check(value)) {
super.setValue(value);
}
}
#Override
public void set(String value) {
if (text2Check(value)) {
super.set(value);
}
}
}
public StringProperty text2Property() {
return text2 ;
}
public final void setText2(String text2) {
text2Property().set(text2);
}
public final String getText2() {
return text2Property().get();
}
// ...
}
however, I think this will break the bidirectional binding that you have with the text property in the TextArea (basically, there is no way to communicate back to the text area when a change is vetoed, so the text area will not know to revert to the previous value). One fix would be to implement your cell using listeners on the properties instead of bindings. You could use a TextFormatter on the text area that simply updates the property and vetoes the text change if the change doesn't occur.
Here is a complete SSCCE using this approach:
import java.util.function.Function;
import java.util.function.UnaryOperator;
import javafx.application.Application;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.property.StringPropertyBase;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextFormatter.Change;
import javafx.stage.Stage;
public class VetoStringChange extends Application {
#Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView<>();
table.setEditable(true);
table.getColumns().add(column("Item", Item::nameProperty));
table.getColumns().add(column("Description", Item::descriptionProperty));
for (int i = 1; i <= 20 ; i++) {
table.getItems().add(new Item("Item "+i, ""));
}
primaryStage.setScene(new Scene(table, 600, 600));
primaryStage.show();
}
public static <S> TableColumn<S,String> column(String title, Function<S,Property<String>> property) {
TableColumn<S,String> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
col.setCellFactory(tc -> new TextAreaCell<S>(property));
col.setPrefWidth(200);
return col ;
}
public static class TextAreaCell<S> extends TableCell<S, String> {
private TextArea textArea ;
public TextAreaCell(Function<S, Property<String>> propertyAccessor) {
textArea = new TextArea();
textArea.setWrapText(true);
textArea.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textArea.setMaxHeight(Double.MAX_VALUE);
UnaryOperator<Change> filter = c -> {
String proposedText = c.getControlNewText() ;
Property<String> prop = propertyAccessor.apply(getTableView().getItems().get(getIndex()));
prop.setValue(proposedText);
if (prop.getValue().equals(proposedText)) {
return c ;
} else {
return null ;
}
};
textArea.setTextFormatter(new TextFormatter<String>(filter));
this.setGraphic(textArea);
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
if (! textArea.getText().equals(item)) {
textArea.setText(item);
}
// Show the Text Field
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
this.setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
public static class Item {
private final StringProperty name = new StringPropertyBase() {
#Override
public Object getBean() {
return Item.this;
}
#Override
public String getName() {
return "name" ;
}
#Override
public void set(String value) {
if (checkValue(value)) {
super.set(value);
}
}
#Override
public void setValue(String value) {
if (checkValue(value)) {
super.setValue(value);
}
}
};
private final StringProperty description = new SimpleStringProperty();
public Item(String name, String description) {
setName(name);
setDescription(description);
}
private boolean checkValue(String value) {
return value.length() <= 6 ;
}
public final StringProperty nameProperty() {
return this.name;
}
public final String getName() {
return this.nameProperty().get();
}
public final void setName(final String name) {
this.nameProperty().set(name);
}
public final StringProperty descriptionProperty() {
return this.description;
}
public final String getDescription() {
return this.descriptionProperty().get();
}
public final void setDescription(final String description) {
this.descriptionProperty().set(description);
}
}
public static void main(String[] args) {
launch(args);
}
}
Another approach is to allow a "commit and revert" type strategy on your property:
public class MyTextRow {
private final StringProperty text2 = new SimpleStringProperty();
public MyTextRow() {
text2.addListener((obs, oldText, newText) -> {
if (! checkText2(newText)) {
// sanity check:
if (checkText2(oldText)) {
text2.set(oldText);
}
}
});
}
public StringProperty text2Property() {
return text ;
}
public final void setText2(String text2) {
text2Property().set(text2);
}
public final String getText2() {
return text2Property().get();
}
}
In general I dislike validation by listening for an invalid value and reverting like this, because other listeners to the property will see all the changes, including changes to and from invalid values. However, this might be the best option in this case.
Finally, you could consider vetoing invalid changes as in the first option, and also setting a TextFormatter on the control in the cell that simply doesn't allow text entry that results in an invalid string. This isn't always possible from a usability perspective (e.g. if empty strings are invalid, you almost always want to allow the user to temporarily delete all the text), and it means keeping two validation checks in sync in your code, which is a pain.

Count-- incrementing wrong

I have made a GUI program in Java that you can start and stop a timer after you have picked 10 seconds, 5mins, or 1min. The numbers will count down but they are incrementing in 2. So it will go 10, 8, 6, 4, 2, 0
Everything else is working fine but i cant seem to figure out what is wrong with the counter. Here is my code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class countdownPanel extends JPanel
{
private ImageIcon banner;
private JComboBox selectCombo;
private JButton stopButton, startButton;
private JLabel picture, theCount;
private Timer timer;
public countdownPanel()
{
setLayout(new BorderLayout());
setBackground(Color.black);
//Banner Image
banner = new ImageIcon ("banner.jpg");
picture = new JLabel(banner);
//Count Down selecter
JComboBox selectCombo = new JComboBox();
selectCombo.addItem("10 Seconds");
selectCombo.addItem("1 Minute");
selectCombo.addItem("5 Minutes");
//countdown components
theCount = new JLabel(" 0");
theCount.setFont(new Font("Helvetica", Font.BOLD, 200));
timer = new Timer(1000, new TimerListener());
//Stop Start Buttons
startButton = new JButton("Start");
stopButton = new JButton("Stop");
ButtonListener listener = new ButtonListener();
startButton.addActionListener(new ButtonListener());
stopButton.addActionListener(new ButtonListener());
selectCombo.addActionListener(new ComboListener());
timer.addActionListener(new TimerListener());
//GUI set up
add(picture, BorderLayout.NORTH);
add(startButton, BorderLayout.WEST);
add(selectCombo, BorderLayout.CENTER);
add(stopButton, BorderLayout.EAST);
add(theCount, BorderLayout.SOUTH);
}
//combo box listener
private class ComboListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
JComboBox levelCombo = (JComboBox) event.getSource();
Object selected = levelCombo.getSelectedItem();
if(selected.toString().equals("10 Seconds"))
theCount.setText("10");
if(selected.toString().equals("1 Minute"))
theCount.setText("60");
if(selected.toString().equals("5 Minutes"))
theCount.setText("300");
}
}
//Start and stop button listeners
private class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
Object source = event.getSource();
//starts timer
if (event.getSource()== startButton)
timer.start();
//stops timer
if (event.getSource()== stopButton)
timer.stop();
}
}
private class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
String A = theCount.getText();
int count = Integer.parseInt(A);
while(count < 0)
{
count--;
theCount.setText(""+ count);
}
if(count == 0)
theCount.setText(" GO!");
}
}
}

How to retrieve data from mysql database from what is the input on my textfield

For example I have entered my pin to 123 in my text field I want that program to Show the balance, card number and account number of that certain pin
i used setters and getters to get the pin from the previous frame (login)
Here is my code
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.event.*;
import java.sql.*;
import javax.swing.table.*;
public class Test extends JFrame
{
private static final Test sh1 = new Test();
public static Test getInstance()
{
return sh1;
}
Container c;
Connection con;
Statement st;
ResultSet rs;
ResultSetMetaData rm;
JTable tb;
JButton btnback = new JButton("Back");
JTextField pin = new JTextField("");
public void setUser(String user) {this.pin.setText(user);}
public String getUser() {return this.pin.getText();}
public Test(){
this.setTitle("Data");
this.setSize(500,500);
this.setLocation(800, 80);
this.setBackground(Color.black);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
c=this.getContentPane();
c.setLayout(new FlowLayout());
c.add(btnback);
c.add(pin);
stud();
}
public void stud()
{
Vector ColName = new Vector();
Vector Data = new Vector();
try{
String driver="com.mysql.jdbc.Driver";
String db="jdbc:mysql://localhost:3306/atm";
String user="root";
String pass="";
Class.forName(driver);
con=DriverManager.getConnection(db,user,pass);
st=con.createStatement();
String pincodee = pin.getText().trim();
String sqltb = "Select balance,cardnumber , accountnumber from accounts WHERE "
+ "pincode = '"+pincodee+"' ";
rs = st.executeQuery(sqltb);
rm = rs.getMetaData();
int col = rm.getColumnCount();
for(int i = 1; i <= col; i++)
{
ColName.addElement(rm.getColumnName(i));
}
while(rs.next())
{
Vector row = new Vector(col);
for(int i = 1; i <= col; i++)
{
row.addElement(rs.getObject(i));
String s = rs.getString(2);
pin.setText(s);
}
Data.addElement(row);
}
}
catch (Exception ex)
{
}
tb = new JTable( Data, ColName);
tb.repaint();
JScrollPane sc = new JScrollPane(tb);
sc.validate();
c.add(sc);
}
public static void main(String[] args)
{
Test s = new Test();
s.setVisible(true);
}
}
You need to create a button which says 'Go!' or something like that and add an action listener to it that calls your stud() method.
look here for example..
http://www.javaprogrammingforums.com/java-swing-tutorials/278-how-add-actionlistener-jbutton-swing.html
Your code is not going to work either way, you need to rewrite a great deal of it but the ActionListener class is your friend if you want actions on the user interface to call logic code.

Resources