I have created this app with many other classes and it seems to run okay. However, when I finish the quiz, I cant add a button to restart the quiz? I have tried Jbutton and Jframe but I have no idea how to do it? Is there a simple code to add?
package sample;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import javafx.event.ActionEvent;
import javafx.stage.Stage;
import javax.xml.bind.JAXBException;
public class Controller implements Initializable{
static int count = 1;
static int score=0;
static int multiplayerCounter = 1;
static int scoreOfComputer = 0;
static int scoreOfHuman = 0;
static String level;
static XmlToObject ob = new XmlToObject();
static List<String[]> questionsList = ob.readQuestionsAndAnswers("easy");
static boolean isCheatSet;
static boolean isSkipSet;
static String username;
public static String getLevel() {
return level;
}
public static void setLevel(String level) {
Controller.level = level;
}
#FXML
public RadioButton rdEasy;
#FXML
public RadioButton rdHard;
#FXML
public TextField txtAnswer;
#FXML
private Label lblMessage;
#FXML
private TextField txtUsername;
#FXML
private PasswordField txtPassword;
#FXML
private ListView lstHistoryScore;
#FXML
private Button btnNext;
#FXML
private Button btnCheat;
#FXML
private Button btnSkip;
#FXML
private Button btnStart;
#FXML
private Label headerCaption;
#FXML
private Label quizCaption;
#FXML
public Label question;
#FXML
public RadioButton optionOne;
#FXML
public RadioButton optionTwo;
#FXML
public Button btnPass;
#FXML
public RadioButton rdSinglePlayer;
#FXML
public ToggleGroup answerGroup;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
#FXML
private void btnLoginAction(ActionEvent actionEvent) throws IOException {
List<String[]> loginList = ob.readUserLogins();
for(String[] s:loginList ){
if(txtUsername.getText().equals(s[0]) && txtPassword.getText().equals(s[1])){
lblMessage.setText("Success");
((Node) (actionEvent.getSource() )).getScene().getWindow().hide();
Parent parent = FXMLLoader.load(getClass().getResource("/sample/Start.fxml"));
username = txtUsername.getText();
Stage stage = new Stage();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
}else{
lblMessage.setText("Invalid username or password");
}
}
}
public void btnNextAction(ActionEvent actionEvent) throws IOException, JAXBException {
Stage stage = (Stage) ((Node)actionEvent.getSource()).getScene().getWindow();
int index = count - 1;
String[] criteria = questionsList.get(index);
if(getLevel().equals("hard")){
if (criteria[2].toLowerCase().equals(txtAnswer.getText().toLowerCase()) && !isCheatSet && !isSkipSet) {
score++;
}
if(count == 10) {
quizCaption.setText("Over");
question.setText("Your Score: " + score);
txtAnswer.setVisible(false);
btnNext.setVisible(false);
btnCheat.setVisible(false);
btnSkip.setVisible(false);
lstHistoryScore.setVisible(true);
lstHistoryScore.setItems(new XmlToObject().readXml());
ObjectToXML obx = new ObjectToXML();
obx.saveToXml(score);
}else {
txtAnswer.setText("");
String[] cr = questionsList.get(count);
quizCaption.setText("Quiz " + (count + 1));
question.setText(cr[1]);
isCheatSet = false;
isSkipSet = false;
count++;
}
}else {
RadioButton selectedRadio = (RadioButton) answerGroup.getSelectedToggle();
optionOne.setSelected(false);
optionTwo.setSelected(false);
if(!isSkipSet) {
if (getAnswer(criteria[4], selectedRadio.getText()) && !isCheatSet) {
score++;
}
}
if(count == 10) {
quizCaption.setText("Over");
question.setText("Your Score: " + score);
optionOne.setVisible(false);
optionTwo.setVisible(false);
btnNext.setVisible(false);
btnCheat.setVisible(false);
btnSkip.setVisible(false);
lstHistoryScore.setVisible(true);
lstHistoryScore.setItems(new XmlToObject().readXml());
ObjectToXML obx = new ObjectToXML();
obx.saveToXml(score);
}else {
String[] cr = questionsList.get(count);
quizCaption.setText("Quiz " + (count + 1));
question.setText(cr[1]);
optionOne.setText(cr[2]);
optionTwo.setText(cr[3]);
isCheatSet = false;
isSkipSet = false;
count++;
}
}
}
public void btnCheatAction(ActionEvent actionEvent) throws IOException, JAXBException {
isCheatSet = true;
int index = count -1;
if(getLevel().equals("hard")){
txtAnswer.setText(getCheatAnswerForHardLevel(index));
}else {
if(getCheatAnswer(index) == 1){
optionOne.setSelected(true);
}else {
optionTwo.setSelected(true);
}
}
Task<Void> sleeper = new Task<Void>() {
#Override
protected Void call() throws Exception {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
return null;
}
};
sleeper.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
try {
btnNextAction(actionEvent);
} catch (IOException e) {
e.printStackTrace();
} catch (JAXBException e) {
e.printStackTrace();
}
}
});
new Thread(sleeper).start();
}
public void btnSkipAction(ActionEvent actionEvent) throws IOException, JAXBException {
isSkipSet = true;
btnNextAction(actionEvent);
}
public void setName(String name) {
quizCaption.setText(name);
}
public void btnStartAction(ActionEvent actionEvent) throws IOException, JAXBException {
if(rdSinglePlayer.isSelected()){
((Node) (actionEvent.getSource())).getScene().getWindow().hide();
if(rdHard.isSelected()) {
final FXMLLoader loader = new FXMLLoader(getClass().getResource("/sample/SinglePlayerHardLevel.fxml"));
questionsList = ob.readQuestionsAndAnswers("hard");
String[] criteria = questionsList.get(0);
setLevel("hard");
loader.getNamespace().put("caption", ("Quiz"+ criteria[0]) );
loader.getNamespace().put("quiz", criteria[1]);
Parent root = loader.load();
Stage stage = new Stage();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}else {
final FXMLLoader loader = new FXMLLoader(getClass().getResource("/sample/SinglePlayerEasyLevel.fxml"));
String[] criteria = questionsList.get(0);
loader.getNamespace().put("caption", ("Quiz" + criteria[0]));
loader.getNamespace().put("quiz", criteria[1]);
loader.getNamespace().put("one", criteria[2]);
loader.getNamespace().put("two", criteria[3]);
Parent root = loader.load();
setLevel("easy");
Stage stage = new Stage();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}else{
((Node) (actionEvent.getSource())).getScene().getWindow().hide();
final FXMLLoader loader = new FXMLLoader(getClass().getResource("/sample/Multiplayer.fxml"));
String[] criteria = questionsList.get(0);
loader.getNamespace().put("player", "Human");
loader.getNamespace().put("caption", ("Quiz" + criteria[0]));
loader.getNamespace().put("quiz", criteria[1]);
loader.getNamespace().put("one", criteria[2]);
loader.getNamespace().put("two", criteria[3]);
Parent root = loader.load();
Stage stage = new Stage();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
public void btnPassAction(ActionEvent actionEvent) {
RadioButton selectedRadio = (RadioButton) answerGroup.getSelectedToggle();
optionOne.setSelected(false);
optionTwo.setSelected(false);
int index = multiplayerCounter - 1;
if (multiplayerCounter == 10) {
question.setText("Computer score: " + scoreOfComputer);
quizCaption.setText("Your Score: " + scoreOfHuman);
optionOne.setVisible(false);
optionTwo.setVisible(false);
btnPass.setVisible(false);
}else {
String[] criteria = questionsList.get(index);
if (multiplayerCounter % 2 == 0) {
headerCaption.setText("Human");
optionOne.setDisable(false);
optionTwo.setDisable(false);
if (getAnswer(criteria[4], selectedRadio.getText())) {
scoreOfComputer++;
}
} else {
headerCaption.setText("Computer");
int ans = findRandomAnswer(Math.random());
if (ans == 1) {
optionOne.setSelected(true);
optionTwo.setDisable(true);
} else {
optionTwo.setSelected(true);
optionOne.setDisable(true);
}
if (getAnswer(criteria[4], selectedRadio.getText())) {
scoreOfHuman++;
}
}
String[] cr = questionsList.get(multiplayerCounter);
quizCaption.setText("Quiz " + cr[0]);
question.setText(cr[1]);
optionOne.setText(cr[2]);
optionTwo.setText(cr[3]);
multiplayerCounter++;
}
}
public boolean getAnswer(String answer, String quizOption){
if(answer.equals(quizOption)){
return true;
}else{
return false;
}
}
public int findRandomAnswer(double rand){
if(rand <= 0.7){
return 1;
}else{
return 2;
}
}
public int getCheatAnswer(int quizNumber){
String[] criteria = questionsList.get(quizNumber);
if(criteria[4].equals(criteria[2])){
return 1;
}else{
return 2;
}
}
public String getCheatAnswerForHardLevel(int quizNumber){
String[] criteria = questionsList.get(quizNumber);
return criteria[2];
}
public void rdSelectSinglePlayer(ActionEvent actionEvent) {
rdEasy.setVisible(true);
rdHard.setVisible(true);
btnStart.setDisable(false);
}
public void rdSelectMultiPlayer(ActionEvent actionEvent) {
rdEasy.setVisible(false);
rdHard.setVisible(false);
btnStart.setDisable(false);
}
}
Related
I get the error "java.lang.ClassCastException". I'm trying to make a calculator and with JAVAFX (with SceneBuilder - if that's necessary), and I can't trace where I did wrong on the code.
I'm trying to make a new window appear when the button "HISTORY" is clicked and it should show all the previous operations performed.
java.lang.ClassCastException: application.controller.MainWindowController cannot be cast to application.controller.HistoWindowController
MainWindowController is:
public class MainWindowController {
private Main main;
#FXML
TextField input1;
#FXML
TextField input2;
#FXML
Label showAnswer;
public void setMain(Main main){
this.main = main;
}
public void showAnswerSTR(String str) {
showAnswer.setText("Answer: " + str);;
}
#FXML
public void showHistory() {
main.HistoryViewer();
}
#FXML
public void addNumbers(){
Float inputA = Float.parseFloat(input1.getText());
Float inputB = Float.parseFloat(input2.getText());
Addition x = new Addition();
String ans = x.operation(inputA, inputB);
showAnswerSTR(ans);
}
#FXML
public void subtractNumbers(){
Float inputA = Float.parseFloat(input1.getText());
Float inputB = Float.parseFloat(input2.getText());
Subtraction x = new Subtraction();
String ans = x.operation(inputA, inputB);
showAnswerSTR(ans);
}
#FXML
public void multiplyNumbers(){
Float inputA = Float.parseFloat(input1.getText());
Float inputB = Float.parseFloat(input2.getText());
Multiplication x = new Multiplication();
String ans = x.operation(inputA, inputB);
showAnswerSTR(ans);
}
#FXML
public void divideNumbers(){
Float inputA = Float.parseFloat(input1.getText());
Float inputB = Float.parseFloat(input2.getText());
Division x = new Division();
String ans = x.operation(inputA, inputB);
showAnswerSTR(ans);
}
}
HistoWindowController is:
public class HistoWindowController {
#FXML
VBox HistoryViewer;
public void showHistory(){
StringTokenizer str = new StringTokenizer(getHistory(),";");
while(str.hasMoreTokens()){
HistoryViewer.getChildren().add(new Label(str.nextToken().toString()));
}
}
private String history = "H I S T O R Y;";
public void addHistory(String history) {
this.history += history + ";";
}
public String getHistory() {
return history;
}
/*public String historyReader() {
StringTokenizer str = new StringTokenizer(getHistory(),";");
String temp = "";
if(str.hasMoreTokens()) {
temp += str.nextToken();
temp += "\n";
}
return temp;
}*/
}
Main is:
public class Main extends Application {
private Stage primaryStage;
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("view/mainView.fxml"));
AnchorPane mainFXML = (AnchorPane) loader.load();
Scene scene = new Scene(mainFXML);
primaryStage.setScene(scene);
primaryStage.show();
MainWindowController mainWindow = loader.getController();
mainWindow.setMain(this);
} catch(Exception e) {
e.printStackTrace();
}
}
public void HistoryViewer(){
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("view/HistoryView.fxml"));
AnchorPane histoView = (AnchorPane) loader.load();
Scene scene = new Scene(histoView);
primaryStage.setScene(scene);
primaryStage.show();
HistoWindowController histoControl = loader.getController();
histoControl.showHistory();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Thanks in advance
I guess this is the line where it happens (check the stacktrace): HistoWindowController histoControl = loader.getController();
the value of the fx:controller attribute in HistoryView.fxml is MainWindowController
Thanks #fabian
I'm stuck on figuring out how to add a decimal place function to a very simple calculator gui I am building. The current implementation I have for the makeDecimalButton function throws an error at runtime. Should I not be parsing the decimal to a double? Maybe I should be using BigDecimal? Any help is appreciated.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import java.util.HashMap;
import java.util.Map;
public class Calculator extends Application {
private static final String[][] template = {
{ "7", "8", "9", "/" },
{ "4", "5", "6", "*" },
{ "1", "2", "3", "-" },
{ "0", "C", "=", "+", "." } };
private final Map<String, Button> accelerators = new HashMap<>();
private DoubleProperty stackValue = new SimpleDoubleProperty();
private DoubleProperty value = new SimpleDoubleProperty();
private enum Operation {
NOOP, ADD, SUBTRACT, MULTIPLY, DIVIDE
}
private Operation curOp = Operation.NOOP;
private Operation stackOp = Operation.NOOP;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
final TextField screen = createScreen();
final TilePane buttons = createButtons();
stage.setTitle("Calculator");
stage.initStyle(StageStyle.UTILITY);
stage.setResizable(false);
stage.setScene(new Scene(createLayout(screen, buttons)));
stage.show();
}
private VBox createLayout(TextField screen, TilePane buttons) {
final VBox layout = new VBox(20);
layout.setAlignment(Pos.CENTER);
layout.setStyle("-fx-background-color: black; -fx-padding: 20; -fx-font-size: 20;");
layout.getChildren().setAll(screen, buttons);
handleAccelerators(layout);
screen.prefWidthProperty().bind(buttons.widthProperty());
return layout;
}
private void handleAccelerators(VBox layout) {
layout.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent keyEvent) {
Button activated = accelerators.get(keyEvent.getText());
if (activated != null) {
activated.fire();
}
}
});
}
private TextField createScreen() {
final TextField screen = new TextField();
screen.setStyle("-fx-background-color: white;");
screen.setAlignment(Pos.CENTER_RIGHT);
screen.setEditable(false);
screen.textProperty().bind(Bindings.format("%f", value));
return screen;
}
private TilePane createButtons() {
TilePane buttons = new TilePane();
buttons.setVgap(7);
buttons.setHgap(7);
buttons.setPrefColumns(template[0].length);
for (String[] r : template) {
for (String s : r) {
buttons.getChildren().add(createButton(s));
}
}
return buttons;
}
private Button createButton(final String s) {
Button button = makeStandardButton(s);
if (s.matches("[0-9]")) {
makeNumericButton(s, button);
} else {
final ObjectProperty<Operation> triggerOp = determineOperand(s);
if (triggerOp.get() != Operation.NOOP) {
makeOperandButton(button, triggerOp);
} else if ("C".equals(s)) {
makeClearButton(button);
} else if ("=".equals(s)) {
makeEqualsButton(button);
} else if (".".equals(s)) {
makeDecimalButton(button);
}
}
return button;
}
private void makeDecimalButton(Button button) {
button.setStyle("-fx-base: mistyrose;");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
value.set(value.get() + Double.parseDouble("."));
}
});
}
private ObjectProperty<Operation> determineOperand(String s) {
final ObjectProperty<Operation> triggerOp = new SimpleObjectProperty<>(Operation.NOOP);
switch (s) {
case "+":
triggerOp.set(Operation.ADD);
break;
case "-":
triggerOp.set(Operation.SUBTRACT);
break;
case "*":
triggerOp.set(Operation.MULTIPLY);
break;
case "/":
triggerOp.set(Operation.DIVIDE);
break;
}
return triggerOp;
}
private void makeOperandButton(Button button, final ObjectProperty<Operation> triggerOp) {
button.setStyle("-fx-base: lightgray;");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
curOp = triggerOp.get();
}
});
}
private Button makeStandardButton(String s) {
Button button = new Button(s);
button.setStyle("-fx-base: beige;");
accelerators.put(s, button);
button.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
return button;
}
private void makeNumericButton(final String s, Button button) {
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
if (curOp == Operation.NOOP) {
value.set(value.get() * 10 + Integer.parseInt(s));
} else {
stackValue.set(value.get());
value.set(Integer.parseInt(s));
stackOp = curOp;
curOp = Operation.NOOP;
}
}
});
}
private void makeClearButton(Button button) {
button.setStyle("-fx-base: mistyrose;");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
value.set(0);
}
});
}
private void makeEqualsButton(Button button) {
button.setStyle("-fx-base: ghostwhite;");
button.setOnAction(new EventHandler<ActionEvent>() {
#SuppressWarnings("incomplete-switch")
#Override
public void handle(ActionEvent actionEvent) {
switch (stackOp) {
case ADD:
value.set(stackValue.get() + value.get());
break;
case SUBTRACT:
value.set(stackValue.get() - value.get());
break;
case MULTIPLY:
value.set(stackValue.get() * value.get());
break;
case DIVIDE:
value.set(stackValue.get() / value.get());
break;
}
}
});
}
}
from the documentation:
parseDouble(String s)
Returns a new double initialized to the value represented by the specified String, as performed by the valueOf method of class Double.
so you are trying to parse a double from the string "." which isn't a valid decimal number.
I am rewriting an application from swing to javafx.
I do not understand how to implement a double click event and a right click event on the same row of a tableview.
Separately they work ok.
Thi is my code for right click behaviour.
words_table.setRowFactory(
new Callback<TableView<WordsToFind>, TableRow<WordsToFind>>() {
#Override
public TableRow<WordsToFind> call(TableView<WordsToFind> tableView) {
final TableRow<WordsToFind> row = new TableRow<>();
final ContextMenu rowMenu = new ContextMenu();
MenuItem removeItem = new MenuItem("Delete");
removeItem.setOnAction(e -> {
int wordid = words_table.getSelectionModel().getSelectedItem().getWordToFindId();
deleteWord(wordid);
words_table.getItems().remove(row.getItem());
});
rowMenu.getItems().addAll(removeItem);
row.contextMenuProperty().bind(
Bindings.when(Bindings.isNotNull(row.itemProperty()))
.then(rowMenu)
.otherwise((ContextMenu)null));
return row;
}
});
This is my code for double click behaviour
words_table.setRowFactory(
new Callback<TableView<WordsToFind>, TableRow<WordsToFind>>() {
#Override
public TableRow<WordsToFind> call(TableView<WordsToFind> tableView) {
final TableRow<WordsToFind> row = new TableRow<>();
row.setOnMouseClicked(new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event){
if (event.getClickCount() == 2 && (! row.isEmpty()) ) {
some code here .....
}
}
});
return row;
}
});
Thanks Alb
Just put the row.setOnMouseClicked call in the call() method of the first row factory.
words_table.setRowFactory(tableView -> {
final TableRow<WordsToFind> row = new TableRow<>();
final ContextMenu rowMenu = new ContextMenu();
MenuItem removeItem = new MenuItem("Delete");
removeItem.setOnAction(e -> {
int wordid = words_table.getSelectionModel().getSelectedItem().getWordToFindId();
deleteWord(wordid);
words_table.getItems().remove(row.getItem());
});
rowMenu.getItems().addAll(removeItem);
row.contextMenuProperty().bind(
Bindings.when(Bindings.isNotNull(row.itemProperty()))
.then(rowMenu)
.otherwise((ContextMenu)null));
row.setOnMouseClicked(event -> {
if (event.getClickCount() == 2 && (! row.isEmpty()) ) {
// some code here .....
}
});
return row;
});
(I converted the anonymous inners classes to lambda expressions for readability.)
Here is a complete example that demonstrates this working:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class RowFactoryExample extends Application {
#Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView<>();
table.getColumns().add(column("Item", Item::nameProperty));
table.getColumns().add(column("Value", Item::valueProperty));
table.getItems().setAll(createData());
table.setRowFactory(tableView -> {
final TableRow<Item> row = new TableRow<>();
final ContextMenu rowMenu = new ContextMenu();
MenuItem removeItem = new MenuItem("Delete");
removeItem.setOnAction(e -> {
table.getItems().remove(row.getItem());
});
rowMenu.getItems().addAll(removeItem);
row.contextMenuProperty().bind(
Bindings.when(Bindings.isNotNull(row.itemProperty()))
.then(rowMenu)
.otherwise((ContextMenu)null));
row.setOnMouseClicked(event -> {
if (event.getClickCount() == 2 && (! row.isEmpty()) ) {
System.out.println("Double click on "+row.getItem().getName());
}
});
return row;
});
Scene scene = new Scene(table, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private <S,T> TableColumn<S,T> column(String text, Function<S, ObservableValue<T>> prop) {
TableColumn<S,T> col = new TableColumn<>(text);
col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
return col ;
}
private List<Item> createData() {
Random rng = new Random();
List<Item> data = new ArrayList<>();
for (int i = 1 ; i <= 100; i++) {
data.add(new Item("Item "+i, rng.nextInt(1000))) ;
}
return data ;
}
public static class Item {
private final StringProperty name = new SimpleStringProperty();
private final IntegerProperty value = new SimpleIntegerProperty();
public Item(String name, int value) {
setName(name);
setValue(value);
}
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 IntegerProperty valueProperty() {
return this.value;
}
public final int getValue() {
return this.valueProperty().get();
}
public final void setValue(final int value) {
this.valueProperty().set(value);
}
}
public static void main(String[] args) {
launch(args);
}
}
You can add both events to the row by doing row.setOnMouseClicked(..) itself as shown below
words_table.setRowFactory(
new Callback<TableView<WordsToFind>, TableRow<WordsToFind>>() {
#Override
public TableRow<WordsToFind> call(TableView<WordsToFind> tableView) {
final TableRow<WordsToFind> row = new TableRow<>();
row.setOnMouseClicked(new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event){
if (event.getClickCount() == 2 && (! row.isEmpty()) ) {
//double click code here
}
else if(event.isSecondaryButtonDown()){
//right click code here
}
}
});
return row;
}
});
I have a Javafx TableView where I can add new Rows by double Click on an empty Row at the End of my "filled" / Textfield filled Rows.
My Problem is,if i add some Rows ,Java don't give me more of the empty Rows I could double click to add some Rows.
Edit:removed some unnessary log
To see what i mean, here is the Code:
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
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.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
interface inside_table
{
public void Select_Row_by_Col(int index);
}
public class Supermain extends Application {
ObservableList<myTextRow> data;
#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("text"));
TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2");
clmtext2.setMinWidth(160);
clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2"));
clmtext2.setCellFactory(new TextFieldCellFactory("text2"));
//Add data
data = FXCollections.observableArrayList(
new myTextRow(5, "Lorem","bla"),
new myTextRow(2, "Ipsum","bla")
);
table.getColumns().addAll(clmID, clmtext,clmtext2);
table.setItems(data);
table.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
if (mouseEvent.getClickCount() == 2 && mouseEvent.getY()>24) {
data.add(new myTextRow(td_get_biggest_ID() + 1,"",""));
table.selectionModelProperty().get().select(data.size()-1);
}
}
}
});
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();
class I_table implements inside_table{
#Override
public void Select_Row_by_Col(int index) {
table.getSelectionModel().select(index);
}
}
}
/**
* #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>> {
private String ColumnName;
public TextFieldCellFactory(String ColumnName){
this.ColumnName=ColumnName;
}
#Override
public TableCell<myTextRow, String> call(TableColumn<myTextRow, String> param) {
TextFieldCell textFieldCell = new TextFieldCell(this.ColumnName);
return textFieldCell;
}
public static class TextFieldCell extends TableCell<myTextRow, String> {
private TextArea textField;
private StringProperty boundToCurrently = null;
private String last_text;
private String ColumnName;
public TextFieldCell(String cname) {
textField = new TextArea();
textField.setWrapText(true);
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
last_text="";
this.ColumnName=cname;
this.setGraphic(textField);
textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
if(this.ColumnName=="text2"){
if(isNowFocused){last_text=textField.getText();System.out.println("NOW focus "+last_text);}
if (! isNowFocused && ! isValid(textField.getText())) {
textField.setText(last_text);
//textField.setText("00:00:00:00");
textField.selectAll();
System.out.println("blur");
}
}
});
}
#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);
}
}//update
private boolean isValid(String s){
String splitArray[] = s.split(":");
if (splitArray.length != 4) {
System.out.println("false");
return false;
}
for (int i = 0; i < splitArray.length; i++) {
if (splitArray[i].length() != 2) {
System.out.println("false");
return false;
}
if (!splitArray[i].substring(0, 1).matches("[0-9]")) {
System.out.println("no number1");
return false;
}
if (!splitArray[i].substring(1, 2).matches("[0-9]")) {
System.out.println("no number2");
return false;
}
if (i < 3) {
int itest = Integer.parseInt(splitArray[i]);
if (itest > 59) {
System.out.println(itest + " ist zu groß!");
return false;
}
} else {
int itest2 = Integer.parseInt(splitArray[i]);
if (itest2 > Math.floor(25)) {
System.out.println(itest2 + " ist zu groß!");
return false;
}
//framerate!!!!!
}
System.out.println("splits: " + splitArray[i]);
//if( el.charAt(0).)
}
return true;
}
}
}
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);
}
//setter
public void setID(int id) {
this.ID.set(id);
}
public void setText(String text) {
this.text.set(text);
}
public void setText2(String text) {
this.text2.set(text);
}
//getter
public int getID() {
return ID.get();
}
public String getText() {
return text.get();
}
public String getText2() {
return text2.get();
}
//properties
public StringProperty textProperty() {
return text;
}
public StringProperty text2Property() {
return text2;
}
public IntegerProperty IDProperty() {
return ID;
}
}
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("FXMLDocumentController.get_text_width(): "+l.prefWidth(-1));
return l.prefWidth(-1);
}
public int td_get_biggest_ID() {
int biggest = 0;
for (int i = 0; i < data.size(); i++) {
if (((myTextRow) data.get(i)).getID() > biggest) {
biggest = ((myTextRow) data.get(i)).getID();
}
}
return biggest;
}
}
Just click anywhere else on the TableView but make sure it's at least 24 pixels from the top; This will work since you've added the event handler is added to the TableView...
If you only want to use the last row, then use a custom rowFactory and handle the events there.
Add a placeholder item to the TableView items that marks the row that is used for adding new elements (for some reason the selection model doesn't like null):
final myTextRow addPlaceHolder = new myTextRow(Integer.MIN_VALUE, null, null);
...
//Add data
data = FXCollections.observableArrayList(
new myTextRow(5, "Lorem", "bla"),
new myTextRow(2, "Ipsum", "bla"),
addPlaceHolder
);
make sure your TextFieldCells treat null values as empty rows:
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
// Show the Text Field
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
...
make sure the first column does not display anything for the placeholder
//Table columns
TableColumn<myTextRow, Number> clmID = new TableColumn<>("ID");
clmID.setMinWidth(160);
clmID.setCellValueFactory(cdf -> {
myTextRow item = cdf.getValue();
return item == addPlaceHolder ? Bindings.createObjectBinding(() -> null) : item.IDProperty();
});
and use the following rowFactory to handle adding the items (you don't need the updateItem part unless you need to add a style class to the TableRow; you need not extend TableRow in this case)
table.setRowFactory(tv -> new TableRow<myTextRow>() {
{
setOnMouseClicked(mouseEvent -> {
if (mouseEvent.getButton() == MouseButton.PRIMARY
&& mouseEvent.getClickCount() == 2
&& !isEmpty()
&& getItem() == addPlaceHolder) {
data.add(data.size() - 1, new myTextRow(td_get_biggest_ID() + 1, "", ""));
table.selectionModelProperty().get().select(data.size() - 1);
mouseEvent.consume();
}
});
}
#Override
protected void updateItem(myTextRow item, boolean empty) {
super.updateItem(item, empty);
// add style class for row containing addPlaceHolder
List<String> classes = getStyleClass();
final String clazz = "add-row";
if (item == addPlaceHolder) {
if (!classes.contains(clazz)) {
classes.add(clazz);
}
} else {
classes.remove(clazz);
}
}
});
I am developing a download manager.I can not update label. I am trying to update label with downloading in run() method but exception occurred. How I update Label.Where I write code of updating label and ProgressBar.
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.geometry.*;
import javafx.scene.effect.*;
import javafx.scene.paint.*;
import javafx.event.*;
import javafx.scene.image.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.io.*;
import java.net.*;
public class DownloadFile implements Runnable
{
Thread thread;
private static final int BUFFER_SIZE=1024;
public final int DOWNLOADING=0;
public final int PAUSED=1;
public final int COMPLETE=2;
public final int CANCELLED=3;
public final int ERROR=4;
private URL url;
private int size;
private int downloaded;
private int status;
static int check=0;
Stage dStage;
Label fileNameLabel;
Label fileNameValueLabel;
Label statusLabel;
Label statusValueLabel;
Label fileSizeLabel;
Label fileSizeValueLabel;
Label downloadedLabel;
Label downloadedValueLabel;
Label speedLabel;
Label speedValueLabel;
Label timeRemainingLabel;
Label timeRemainingValueLabel;
ProgressBar downloadingProgressBar;
public void startStage()
{
dStage=new Stage();
dStage.setResizable(false);
dStage.getIcons().add(new Image("images\\webdownloadmanager.png"));
dStage.setTitle("Friends Download Manager");
BorderPane root=new BorderPane();
root.setPadding(new Insets(10, 10, 10, 10));
Scene dScene=new Scene(root,520,250);
dStage.setScene(dScene);
Label titleLabel=new Label(" Download Status ");
titleLabel.setStyle("-fx-background-color:#FFFFFF;");
GridPane gpCenter=new GridPane();
gpCenter.setPadding(new Insets(10, 10, 10, 10));
gpCenter.setStyle("-fx-background-color:#FFFFFF;");
fileNameLabel =new Label("File Name");
fileNameValueLabel=new Label();
statusLabel =new Label("Status");
statusValueLabel =new Label();
fileSizeLabel =new Label("File size");
fileSizeValueLabel =new Label();
downloadedLabel =new Label("Downloaded");
downloadedValueLabel =new Label();
speedLabel =new Label("Speed");
speedValueLabel =new Label();
timeRemainingLabel =new Label("Time Remaining ");
timeRemainingValueLabel =new Label();
gpCenter.add(fileNameLabel,0,0);
gpCenter.add(fileNameValueLabel,2,0);
gpCenter.add(statusLabel ,0,3);
gpCenter.add(statusValueLabel ,2,3);
gpCenter.add(fileSizeLabel ,0,4);
gpCenter.add(fileSizeValueLabel ,2,4);
gpCenter.add(downloadedLabel ,0,5);
gpCenter.add(downloadedValueLabel ,2,5);
gpCenter.add(speedLabel ,0,6);
gpCenter.add(speedValueLabel ,2,6);
gpCenter.add(timeRemainingLabel ,0,7);
gpCenter.add(timeRemainingValueLabel ,2,7);
AnchorPane anchorPaneBottom=new AnchorPane();
VBox vb=new VBox();
HBox progressBarHB=new HBox();
progressBarHB.setPadding(new Insets(10, 0, 30, 0));
downloadingProgressBar=new ProgressBar();
downloadingProgressBar.prefWidthProperty().bind(root.widthProperty().subtract(20));
progressBarHB.getChildren().add(downloadingProgressBar);
vb.getChildren().addAll(progressBarHB);
HBox labelHB=new HBox();
Label message=new Label("Whould you like to perform ?");
labelHB.getChildren().add(message);
HBox buttonHB=new HBox();
buttonHB.setSpacing(20);
Button startPauseButton=new Button("Start");
startPauseButton.setPrefWidth(80);
Button cancelButton=new Button("Cancel");
cancelButton.setPrefWidth(80);
buttonHB.getChildren().addAll(startPauseButton,cancelButton);
anchorPaneBottom.getChildren().addAll(vb,labelHB,buttonHB);
AnchorPane.setTopAnchor(buttonHB, 40.0);
AnchorPane.setRightAnchor(buttonHB,30.0);
AnchorPane.setLeftAnchor(labelHB,40.0);
AnchorPane.setTopAnchor(labelHB,40.0);
AnchorPane.setTopAnchor(vb, 0.0);
root.setTop(titleLabel);
root.setCenter(gpCenter);
root.setBottom(anchorPaneBottom);
dStage.show();
dStage.setOnCloseRequest(new EventHandler<WindowEvent>()
{
public void handle(WindowEvent we)
{ /*
if(WebDownloadManager.check==0)
Platform.exit();
else
check--;
*/
}
});
}
public DownloadFile(URL url)
{
this.url=url;
size=-1;
downloaded=0;
status=DOWNLOADING;
startStage();
fileNameValueLabel.setText(getFileName(url).toString());
statusValueLabel.setText("Waiting..");
fileSizeValueLabel.setText(getSize()+"");
downloadedValueLabel.setText("0.00 MB ("+getProgress()+" %)");
speedValueLabel.setText("450.123 KB/sec");
timeRemainingValueLabel.setText("1 hr ");
download();
}
public String getUrl()
{
return url.toString();
}
public int getSize()
{
return size;
}
public float getProgress()
{
float tf=(downloaded/size)*100;
return tf;
}
public int getStatus()
{
return status;
}
public void pause()
{
status=PAUSED;
}
public void resume()
{
status=DOWNLOADING;
download();
}
public void cancel()
{
status=CANCELLED;
}
private void error()
{
status=ERROR;
}
private void download()
{
thread=new Thread(this);
thread.start();
}
private String getFileName(URL url)
{
String fileName=url.getFile();
String str=fileName.substring(fileName.lastIndexOf('/')+1).replace("%20"," ");
return str;
}
public void run()
{
RandomAccessFile file=null;
InputStream stream=null;
try
{
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setRequestProperty("Range","bytes="+downloaded+"-");
conn.connect();
if(conn.getResponseCode()/100!=2)
{
error();
}
int contentLength=conn.getContentLength();
if(contentLength<1)
{
error();
}
if(size==-1)
{
size=contentLength;
}
file=new RandomAccessFile(getFileName(url),"rw");
file.seek(downloaded);
stream=conn.getInputStream();
while(status==DOWNLOADING)
{
statusValueLabel.setText("Running..");
byte buffer[];
if(size-downloaded>BUFFER_SIZE)
{
buffer=new byte[BUFFER_SIZE];
}
else
{
buffer=new byte[size-downloaded];
}
int read=stream.read(buffer);
if(read== -1)
{
break;
}
file.write(buffer,0,read);
downloaded+=read;
}
if(status==DOWNLOADING)
{
status=COMPLETE;
}
}
catch(Exception exp)
{
error();
System.out.println("Error :"+exp);
}
finally
{
if(file!=null)
{
try
{
file.close();
}
catch(Exception e)
{
}
}
if(stream!=null)
{
try
{
stream.close();
}
catch(Exception exp)
{
}
}
}
}
}
You cannot update JavaFX element outside FX threads. what you need to do is :
Platform.runLater(new Runnable(updateMethod());