This question already has answers here:
Passing Parameters JavaFX FXML
(10 answers)
Closed 4 years ago.
Reading in instructions.txt from instructions.java from a comma(,) delimited method for InstructionsController so that I may present it into a TextArea on Instructions.xml.
Having trouble figuring out once I've read in the file, how to pass over the ArrayList to another class to successfully use that data.
Using about in handle as a test button in the InstructionsController class.
Instructions.java
public class Instructions {
private String[] identifier;
private ArrayList<String> listName;
private ArrayList<String> listDesc;
public void dataLoader() {
String fileName = "instructions.txt";
Scanner scan;
/*
* Shows working path System.out.println(newFile(".").getAbsoluteFile());
*/
try {
scan = new Scanner(new File(fileName));
// Iteration rather than iterable
while (scan.hasNext()) {
int i = 0;
String line = scan.nextLine();
identifier = line.split(">");
if(identifier[i].equals("TITLE")) {
listName.add(identifier[i+1]);
} else if (identifier[i].equals("DESC")) {
listDesc.add(identifier[i+1]);
} else if (identifier[i].equals("END")) {
i++;
}
}
scan.close();
} catch (FileNotFoundException exception) {
System.err.println("Failed to open instructions");
System.exit(1);
}catch (Exception e) {
e.printStackTrace();
}
}
public ArrayList<String> getListName() {
return listName;
}
public void setListName(ArrayList<String> listName) {
this.listName = listName;
}
public ArrayList<String> getListDesc() {
return listDesc;
}
public void setListDesc(ArrayList<String> listDesc) {
this.listDesc = listDesc;
}
}
InstructionsController.java
public class InstructionsController implements EventHandler<ActionEvent>, Initializable {
#FXML
private Button about, constants, professionPerks, teamCilantro, mainMenu, exit;
#FXML
private AnchorPane background;
#FXML
private TextArea text;
Main main = new Main();
private List<String> name;
private List<String> desc;
#Override
public void initialize(URL location, ResourceBundle resources) {
Instructions instructions = new Instructions();
name = instructions.getListName();
desc = instructions.getListDesc();
}
#FXML
public void handle(ActionEvent event) {
Button selected = (Button) event.getSource();
Stage stage = (Stage) selected.getScene().getWindow();
if (selected == about)
if(selected == mainMenu)
main.switchScene("fxml/Title.fxml", stage);
if(selected == exit)
stage.close();
}
}
sample text
file input: instructions.txt
TITLE> Profession Perks:
DESC> Investor: Starts with $150 bonus "Starting Cash" for a total of $650 "Starting Cash".
Farmer: Starts with 250 "Pounds of Food" and has a perk to consume food for the party at a 75% rate compared to normal.
Handyman: Significantly less likelyhood of "Wagon" breaking down.
END>
You can attempt to create an instance of the first class in the second class file. Or you can attempt to set your 'get' methods to static. Take a look at this previous SO answer.
You need to create an instance of Class A and then access the values from Class B, for example:
public class ClassA {
private int someInt;
public ClassA() {
someInt = 5;
}
public int getSomeInt() {
return someInt;
}
}
public class ClassB {
public void someMethod() {
ClassA instanceOfClassA = new ClassA();
int someIntFromClassA = instanceOfClassA.getSomeInt(); //This is now 5;
// Rest of your code here
}
}
Alternatively you can create it as a static method in ClassA and then call it in ClassB by using ClassA.getSomeInt();
Passing an array from class A to class B
Related
So I have have 2 types of files, one for level definition and other for blocks structure definition.
I need to parse both of them into list of strings which contains the lines, and go over the list and over each line, split and parse and map them into java objects.
I have no lead how to do it, I have read about java io reader but I do get confused here where and how to use it.
Understanding the content of the level specification of a single level: this will go over the strings, split and parse them, and map them to java objects, resulting in a LevelInformation object.
P.S I already wrote and built the LevelInformation interface(which works if I manually write a level that implements this interface), which contains every thing that is in the text file (level name, velocities,background and etc..)
So basically I just need to parse those texts file and map them into this interface.
public interface LevelInformation {
int numberOfBalls();
// The initial velocity of each ball
// Note that initialBallVelocities().size() == numberOfBalls()
// velocities created by (a,s) format. a = angle, s = speed.
List<Velocity> initialBallVelocities();
int paddleSpeed();
int paddleWidth();
// the level name will be displayed at the top of the screen.
String levelName();
// Returns a sprite with the background of the level
Sprite getBackground();
// The Blocks that make up this level, each block contains
// its size, color and location.
List<Block> blocks();
// Number of blocks that should be removed
// before the level is considered to be "cleared".
// This number should be <= blocks.size();
int numberOfBlocksToRemove();
}
An example of the files:
level_definition.txt
START_LEVEL
level_name:Square Moon
ball_velocities:45,500
background:image(background_images/night.jpg)
paddle_speed:650
paddle_width:160
block_definitions:definitions/moon_block_definitions.txt
blocks_start_x:25
blocks_start_y:80
row_height:100
num_blocks:4
START_BLOCKS
--ll--
--ll--
END_BLOCKS
END_LEVEL
block_definitions.txt
#block definitions
bdef symbol:l width:100 height:100 fill:color(RGB(154,157,84))
#spacers definitions
sdef symbol:- width:30
So I need to create a list and get a reader and somehow parse it.
I'll be glad to get some tips, ideas and help for doing this.
Thanks.
public class LevelSpecificationReader {
public List<LevelInformation> fromReader(java.io.Reader reader) {
// ...
}
}
I think I need to:
Split the file into lines and make a list of strings out of them.
Which means each line will get into the list as a string.
Get each line, and also split it into I don't know what, but in order
to get info and map in into the needed object. For example:
level_name: something
i'll have to get "something" into "level name" in my interface.
This is my failed attempt:
public List<LevelInformation> fromReader(java.io.Reader reader) throws IOException {
ArrayList<String> listOfLines = new ArrayList<>();
BufferedReader bufReader = new BufferedReader(new FileReader("file.txt"));
String line = bufReader.readLine();
while (line != null) {
listOfLines.add(line);
line = bufReader.readLine();
}
return listOfLines;
}
This code brings an error bcause I return a list of string but I need a list of LevelInformation.
This is not a complete solution, since the code in your question is not a reproducible example since it is not complete. Where are the definitions of classes Block and Sprite and Velocity? Well I guessed those and made up minimal definitions for them.
My hope is that the below code will be enough to help you complete your project. It is based on the details you posted including the sample file: level_definition.txt
Class Sprite
import java.awt.Image;
public class Sprite {
private Image image;
public Sprite(Image image) {
this.image = image;
}
}
class Velocity
public class Velocity {
private int speed;
public Velocity(int speed) {
this.speed = speed;
}
}
Class LevelDtl which implements your interface: LevelInformation.
Personally, I don't see the need for an interface. I think it should be a class.
public class LevelDtl implements LevelInformation {
private String levelName;
private List<Velocity> ballVelocities;
private Sprite background;
private int paddleSpeed;
private int paddleWidth;
private List<Block> blocks;
private int numBlocks;
#Override
public int numberOfBalls() {
return ballVelocities == null ? 0 : ballVelocities.size();
}
#Override
public List<Velocity> initialBallVelocities() {
return ballVelocities;
}
#Override
public int paddleSpeed() {
return paddleSpeed;
}
#Override
public int paddleWidth() {
return paddleWidth;
}
#Override
public String levelName() {
return levelName;
}
#Override
public Sprite getBackground() {
return background;
}
#Override
public List<Block> blocks() {
return blocks;
}
#Override
public int numberOfBlocksToRemove() {
return numBlocks;
}
public void setBackground(Sprite bg) {
background = bg;
}
public void setBallVelocities(List<Velocity> velocities) {
ballVelocities = velocities;
}
public void setLevelName(String name) {
levelName = name;
}
public void setPaddleSpeed(int speed) {
paddleSpeed = speed;
}
public void setPaddleWidth(int width) {
paddleWidth = width;
}
public String toString() {
return String.format("Level: %s , Paddle: [speed = %d , width = %d]",
levelName,
paddleSpeed,
paddleWidth);
}
}
All the methods with #Override annotation are implementations of methods in LevelInformation interface. Also, note that method toString() is only for debugging purposes since I use it in the final class which is the one you named: LevelSpecificationReader. It reads the file level_definition.txt line by line, assuming the format shown in your question and builds and configures an instance of class LevelDtl which it then adds to a List. Finally, the below code prints the contents of the List. Of-course, using the sample data you provided in your question, the List contains only one element.
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.imageio.ImageIO;
public class LevelSpecificationReader {
private static final String BACKGROUND = "background:";
private static final String BALL_VELOCITIES = "ball_velocities:";
private static final String END_BLOCKS = "END_BLOCKS";
private static final String END_LEVEL = "END_LEVEL";
private static final String IMAGE = "image(";
private static final String LEVEL_NAME = "level_name:";
private static final String PADDLE_SPEED = "paddle_speed:";
private static final String PADDLE_WIDTH = "paddle_width:";
private static final String START_BLOCKS = "START_BLOCKS";
private static final String START_LEVEL = "START_LEVEL";
private static void setBackground(LevelDtl level, String data) throws IOException {
Objects.requireNonNull(level, "Null level.");
if (data != null && !data.isEmpty()) {
// image(background_images/night.jpg)
if (data.startsWith(IMAGE)) {
String path = data.substring(IMAGE.length(), data.length() - 1);
BufferedImage image = ImageIO.read(new File(path));
level.setBackground(new Sprite(image));
}
}
}
private static void setInitialBallVelocities(LevelDtl level, String data) {
Objects.requireNonNull(level, "Null level.");
if (data != null && !data.isEmpty()) {
String[] numbers = data.split(",");
if (numbers.length > 0) {
List<Velocity> velocities = new ArrayList<>();
for (String number : numbers) {
try {
int speed = Integer.parseInt(number);
Velocity velocity = new Velocity(speed);
velocities.add(velocity);
}
catch (NumberFormatException xNUmberFormat) {
// Ignore.
}
}
level.setBallVelocities(velocities);
}
}
}
private static void setPaddleSpeed(LevelDtl level, String data) {
Objects.requireNonNull(level, "Null level.");
if (data != null && !data.isEmpty()) {
int speed;
try {
speed = Integer.parseInt(data);
}
catch (NumberFormatException xNumberFormat) {
speed = 0;
}
level.setPaddleSpeed(speed);
}
}
private static void setPaddleWidth(LevelDtl level, String data) {
Objects.requireNonNull(level, "Null level.");
if (data != null && !data.isEmpty()) {
int width;
try {
width = Integer.parseInt(data);
}
catch (NumberFormatException xNumberFormat) {
width = 0;
}
level.setPaddleWidth(width);
}
}
/**
* Start here.
*/
public static void main(String[] args) {
try (FileReader fr = new FileReader("level_definition.txt");
BufferedReader br = new BufferedReader(fr)) {
List<LevelInformation> levels = new ArrayList<>();
LevelDtl level = null;
String line = br.readLine();
while (line != null) {
if (START_LEVEL.equals(line)) {
// End current level.
if (level != null) {
levels.add(level);
}
// Start next level.
level = new LevelDtl();
}
else if (line.startsWith(LEVEL_NAME)) {
level.setLevelName(line.substring(LEVEL_NAME.length()));
}
else if (line.startsWith(BALL_VELOCITIES)) {
setInitialBallVelocities(level, line.substring(BALL_VELOCITIES.length()));
}
else if (line.startsWith(BACKGROUND)) {
setBackground(level, line.substring(BACKGROUND.length()));
}
else if (line.startsWith(PADDLE_SPEED)) {
setPaddleSpeed(level, line.substring(PADDLE_SPEED.length()));
}
else if (line.startsWith(PADDLE_WIDTH)) {
setPaddleWidth(level, line.substring(PADDLE_WIDTH.length()));
}
line = br.readLine();
}
if (level != null) {
levels.add(level);
}
System.out.println(levels);
}
catch (IOException xIo) {
xIo.printStackTrace();
}
}
}
The above code only handles lines in file level_definition.txt up to and including this line:
paddle_width:160
Good luck with adding code to handle the rest of the contents of the file.
Maybe what you want is to break it into pieces first so that you don't need to worry about all the things at once and focus on parsing the strings. All you need to do is make a constructor that accepts string and then parse it in the constructor
public List<LevelInformation> fromReader(java.io.Reader reader) throws IOException {
ArrayList<LevelInformation> listOfLines = new ArrayList<>();
BufferedReader bufReader = new BufferedReader(new FileReader("file.txt"));
String line = bufReader.readLine();
while (line != null) {
listOfLines.add(new LevelInformation(line));
line = bufReader.readLine();
}
return listOfLines;
}
public class LevelInformation {
LevelInformation (String text) {
parseText(text);
}
private void parseText(String text) {
//do something here
}
}
I'm making a basic Movie Rental simulator application, and I am currently having a problem storing the input from my TextFields and my ComboBox into variables. I managed to convert most of my variables to Strings, however when I try and print the output to test it, it always returns "null."
I need to essentially figure out how to GET the selection the user has made in the combo box and store it as a string, and I need to figure out how to properly store the results from my methods. I have never ran into this problem before, so I am not really sure how to tackle it. My code is as follows:
public class RentGameDialogController extends RentalStoreGUIController implements Initializable{
/** TextField Objects **/
#FXML private TextField nameField, rentedOnField, dueBackField;
/** String for NameField **/
String name, rentedOn, dueBack;
/** Game ComboBox ID's **/
#FXML private ObservableList<GameType> cbGameOptions;
#FXML private ComboBox<GameType> cbGame;
/** Console ComboBox ID's **/
#FXML private ObservableList<PlayerType> cbConsoleOptions;
#FXML private ComboBox<PlayerType> cbConsole;
/** GameType object **/
private GameType game;
/** PlayerType Object **/
private PlayerType console;
/** Button ID's **/
#FXML Button cancel, addToCart;
/** Counter for calculating total **/
int gameCounter;
/** Stage for closing GUI **/
private Stage currentStage;
#Override
public void initialize(URL location, ResourceBundle resources) {
/** Select Console **/
cbConsoleOptions = FXCollections.observableArrayList();
for (PlayerType p : PlayerType.values()) { cbConsoleOptions.addAll(p); }
cbConsole.getItems().addAll(cbConsoleOptions);
/** Select Game **/
cbGameOptions = FXCollections.observableArrayList();
for (GameType g : GameType.values()){ cbGameOptions.addAll(g); }
cbGame.getItems().addAll(cbGameOptions);
}
public String getName(){
name = nameField.getText();
try {
String[] firstLast = name.split(" ");
String firstName = firstLast[0];
String lastName = firstLast[1];
} catch (Exception e){
e.printStackTrace();
}
return name;
}
public void getGame() {
GameType gameChoice = cbGame.getSelectionModel().getSelectedItem();
}
public void getConsole() {
PlayerType player = cbConsole.getSelectionModel().getSelectedItem();
}
public String getRentedOn() throws ParseException {
rentedOn = rentedOnField.getText();
DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
Date rentedOnDate = format.parse(rentedOn);
Calendar cal = Calendar.getInstance();
cal.setLenient(false);
cal.setTime(rentedOnDate);
try {
cal.getTime();
} catch (Exception e) {
System.exit(0);
}
return rentedOn;
}
public String getDueBack() throws ParseException {
dueBack = dueBackField.getText();
DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
Date dueBackDate = format.parse(dueBack);
Calendar cal = Calendar.getInstance();
cal.setLenient(false);
cal.setTime(dueBackDate);
try {
cal.getTime();
} catch (Exception e) {
System.exit(0);
}
return dueBack;
}
/*************************************
* This is the method to call the other
* String methods so their output can be
* put into my main GUI
*
* Current problem: game.toString() and console.toString() throw an InvocationTargetException
* #return
* #throws ParseException
*************************************/
public String storePurchaseData() throws ParseException {
gameCounter++; //Problem //Problem
String toList = getName() + " " + game.toString() + " " + console.toString() + " " +
getRentedOn() + " " + getDueBack();
return toList; //Returns "null null null"
}
#FXML
public void handleCancelButtonAction (ActionEvent event) {
currentStage = (Stage) cancel.getScene().getWindow();
currentStage.close();
}
#FXML
public void addToCartButton (ActionEvent event) throws ParseException {
System.out.println(storePurchaseData());
currentStage = (Stage) cancel.getScene().getWindow();
currentStage.close();
}}
Enum Classes for GameType and PlayerType(Console selection):
public enum PlayerType {
Xbox360("Xbox 360"),
PS4("Playstation 4"),
XBoxOne("Xbox One"),
WiiU("Wii - U"),
PS3("Playstation 3"),
Wii("Nintendo Wii");
private String console;
PlayerType(String console) { this.console = console; }
public String PlayerType() { return console; }
#Override public String toString() { return console; }}
GameType:
public enum GameType {
THE_WITCHER("The Witcher 3"),
CALL_OF_DUTY_AW("Call of Duty: Advanced Warfare"),
CALL_DUTY_BLOP3("Call of Duty: Black Ops 3"),
CALL_OF_DUTY_IW("Call of Duty: Infinite Warfare"),
THE_ELDER_SCROLLS("The Elder Scrolls IV: Skyrim");
private String game;
GameType(String game) {
this.game = game;
}
public String GameType() { return game; }
#Override public String toString() { return game; }}
The only method that will return the selected value is getName()
The rest of the methods you are using don't return anything
public void getGame() //Void return type
{
GameType gameChoice = cbGame.getSelectionModel().getSelectedItem();
}
All this does is create a GameType object that is accessible only inside of that method.
Instead it should be
public GameType getGame() //Instead of void, the type you are trying to get
{
return cbGame.getSelectionModel().getSelectedItem();
}
That way, you can then access the result by
GameType selectedGame = getGame();
If you want it as a String use
public String getGame()
{
return cbGame.getSelectionModel().getSelectedItem().toString();
}
Can anyone tell me why the array size of the titles array in the data definition class doesn't equal the value the user inputted that was passed in from the implementation class and set as an instance variable in the data definition class?
This is the Data Definition Class.
public class Photograph {
private int maxTakes;
public Photograph() {
this.titles = new String[this.maxTakes];
numPhotosTaken = 0;
}
public void setMaxTakes(int maxTakes) {
this.maxTakes = maxTakes;
}
public boolean setTitle(String title) {
if (this.numPhotosTaken < this.titles.length) {
this.titles[numPhotosTaken] = title;
numPhotosTaken++;
return true;
}
else {
return false;
}
}
}
This is the implementation class.
import javax.swing.JOptionPane;
public class MakePhotographs {
public static void main (String[] args) {
Photograph photo;
do {
photo = create();
} while (JOptionPane.showConfirmDialog(null, "Enter another couple?") == JOptionPane.YES_OPTION);
}
private static Photograph create() {
Photograph photo = new Photograph();
photo.setMaxTakes(Integer.parseInt(JOptionPane.showInputDialog("Enter maximum number of photos to take")));
do {
String title = JOptionPane.showInputDialog("Enter title of photo");
if (!photo.setTitle(title)) {
JOptionPane.showMessageDialog(null, "No more photos allowed!");
}
} while (JOptionPane.showConfirmDialog(null, "Enter another photo?") == JOptionPane.YES_OPTION);
return photo;
}
}
Create a constructor that takes in the maxTakes value and use that:
Photograph photo = new Photograph(Integer.parseInt(JOptionPane.showInputDialog("Enter maximum number of photos to take")));
You don't need the setMaxTakes anymore since it's been set within the constructor.
class Photograph {
private int maxTakes;
private String[] titles;
private int numPhotosTaken;
public Photograph(int maxTakes) {
this.maxTakes = maxTakes;
this.titles = new String[maxTakes];
numPhotosTaken = 0;
}
public boolean setTitle(String title) {
if (this.numPhotosTaken < this.titles.length) {
this.titles[numPhotosTaken] = title;
numPhotosTaken++;
return true;
}
else {
return false;
}
}
}
Your array is created before you can call setMaxTakes(). After you have already created your array with the length of maxTakes, changing the value of maxTakes does not accomplish anything.
You need to either change the method of setMaxTakes() to the following:
public void setMaxTakes(int maxTakes) {
titles = new String[maxTakes];
}
or go with the answer posted by #Gremash here (which is the proper way to do it).
if anyone can help please ,
i have an issue assign the values from a text file to the class fields.
i have created a class called process and it has a fields like
private String agent;
private String request_type;
private String class_type;
private String num_of_seats;
private String arrivaltime;
my motive is to assign 1block in the file to agent separated by space another block to request type and so on...
say Agent3 R F 10 1 here Agent3 is going to be assign to agent and R going to assign to request_type F to class_type, 10 to num_of_seats,1 to arrivaltime
i am using arraylist to saveinput file (not compulsory i know this only thats y) and another arraylist to save the objects of my class.i am using substring method to assign the values manually is there any way instead of that so that i can simply take block which is seprated by space and do my job.
The input file(input.txt is )
Agent1 R F 2 0
Agent3 R F 10 1
Agent1 C F 1 4
Agent2 C B 2 1
Agent2 R B 10 0
................................................................................
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* #author Navdeep
*
*/
class Process
{
private String agent;
private String request_type;
private String class_type;
private String num_of_seats;
private String arrivaltime;
public Process()
{
setProcess("0", null, null, "0", "0");
}
public Process(String a, String b,String c,String d,String e)
{
setProcess(a,b,c,d,e);
}
public void setProcess(String a, String b,String c,String d,String e)
{
setAgent(a);
setRequest_type(b);
setClass_type(c);
setNum_of_seats(d);
setArrivaltime(e);
}
public void setAgent(String a){
agent = a;
}
public void setRequest_type(String b){
request_type = b;
}
public void setClass_type(String c)
{
class_type = c;
}
public void setNum_of_seats(String d) {
num_of_seats = d;
}
public void setArrivaltime(String e)
{
arrivaltime=e;
}
public String getAgent(){
return agent;
}
public String getRequest_type(){
return request_type ;
}
public String getClass_type()
{
return class_type;
}
public String getNum_of_seats() {
return num_of_seats ;
}
public String getArrivaltime()
{
return arrivaltime;
}
#Override
public String toString() {
return String.format("%s,%s,%s,%s,%s",getAgent(),getRequest_type(),getClass_type(),getNum_of_seats(),getArrivaltime());
}
}
public class main
{
public static void main(String[] args) throws FileNotFoundException
{
File temp = new File(args[0]);
Scanner sc = new Scanner(temp);
ArrayList<String> input = new ArrayList<String>();
while(sc.hasNext())
{
input.add(sc.nextLine());
}
List<Process> mylist = new ArrayList<Process>();
for (int i= 0; i <input.size();i++)
{
Process processobject = new Process();
processobject.setAgent(input.get(i).substring(0, 6));
processobject.setRequest_type(input.get(i).substring(7,8));
processobject.setClass_type(input.get(i).substring(9,10));
if(input.get(i).length() == 15)
{
processobject.setNum_of_seats(input.get(i).substring(11,13));
processobject.setArrivaltime(input.get(i).substring(14,15));
}
if(input.get(i).length() == 14)
{
processobject.setNum_of_seats(input.get(i).substring(11,12));
processobject.setArrivaltime(input.get(i).substring(13,14));
}
mylist.add(processobject); // fill arraylist with objects of my class
}
System.out.println("array list of the input from the file" + input);
System.out.println("\n \nobjects in my list"+ mylist);
}
}
the overall motive of my project is to sort the objects according to the field priorities.
If your objective is to create Process class instance then you can use the following code:
while(sc.hasNext())
{
String line = sc.nextLine();
String elements[] = line.split(" ");
Process processobject = new Process();
processobject.setProcess(elements[0],elements[1],elements[2],elements[3],elements[4]);
}
You can improve the your setProcess method by setting accessing directly class attributes with this reference. Also you can pass the same parameters to Process class constructor then you won't need setProcess method. Check the below code.
public Process(String agent, String request_type, String class_type, String num_of_seats, String arrivaltime) {
this.agent = agent;
this.request_type = request_type;
this.class_type = class_type;
this.num_of_seats = num_of_seats;
this.arrivaltime = arrivaltime;
}
Try this:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource(configFileName).getFile());
input = new FileInputStream(someFilePath);
prop.load(input);
String someString=prop.getProperty("someString");
int someintValue=new Integer(prop.getProperty("someintValue"));
I use two text fields and a button to add entries to a two column table.
If I add a new entry the table is updated right away:
private void addBtn(ActionEvent event) {
Test o = new Test();
o.setTitle(title.getText());
o.setCount(Integer.parseInt(count.getText()));
mainApp.getData().add(o);
}
In a second step I added an additional button to amend the highlighted count cell:
private void editBtn(ActionEvent event) {
Test o = getSelection();
o.setCount(Integer.parseInt(count.getText()));
mainApp.getData().set(tablePosition, o);
}
If I click the button, the cell will update the value, but it's not visible in the table. If I click the button a second time it will update the table.
To check for which row is highlighted I use the following functions:
private final ListChangeListener<Test> selector = new ListChangeListener<Test>() {
#Override
public void onChanged(ListChangeListener.Change<? extends Test> c) {
setSelection();
}
};
public Test getSelection() {
if (testTable != null) {
List<Test> table = testTable.getSelectionModel().getSelectedItems();
if (table.size() == 1) {
final Test selection = table.get(0);
return selection;
}
}
return null;
}
private void setSelection() {
final Test o = getSelection();
tablePosition = mainApp.getData().indexOf(o);
if (o != null) {
title.setText(o.getTitle());
count.setText(o.getCount().toString());
}
}
In the initialize method I add a listener to the observable list:
final ObservableList<Test> t1 = testTable.getSelectionModel().getSelectedItems();
t1.addListener(selector);
My Test class:
public class Test {
private final SimpleStringProperty title = new SimpleStringProperty();
private final SimpleIntegerProperty count = new SimpleIntegerProperty();
public void setTitle(String title) {
this.title.set(title);
}
public String getTitle() {
return title.get();
}
public void setCount(Integer count) {
this.count.set(count);
}
public Integer getCount() {
return count.get();
}
}
How can I make the Edit button to update the cell value right away?
Assuming you are using a PropertyValueFactory as the cell factory for your table columns, you need to provide property accessor methods in order that the table cell provided by the PropertyValueFactory can listen to those properties for changes.
One correct implementation of using the JavaFX Property model looks like
public class Test {
private final IntegerProperty count = new SimpleIntegerProperty(this, "count", 0);
private final StringProperty title = new SimpleStringProperty(this, "title", "");
public final int getCount() {
return count.get();
}
public final void setCount(int count) {
this.count.set(count);
}
public IntegerProperty countProperty() {
return count ;
}
public final String getTitle() {
return title.get();
}
public final void setTitle(String title) {
this.title.set(title);
}
public StringProperty titleProperty() {
return title ;
}
}
With that, the following method will then correctly update the selected row in the table:
private void editBtn(ActionEvent event) {
Test o = testTable.getSelectionModel().getSelectedItem();
if (o != null) {
o.setCount(Integer.parseInt(count.getText()));
}
}
If that doesn't fix the problem for you, I recommend you edit your question completely and provide a sscce that demonstrates the problem.