I am trying to get the table cells to show the string when i create new rows. But all the rows are just empty. Do anyone know what i am doing wrong?
Here is the main class:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Cursor;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("/fxml/BasketCase_GUI_0.3.fxml"));
Scene scene = new Scene(root,1110,740);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setResizable(false);
primaryStage.setScene(scene);
primaryStage.setTitle("Basket Case_Beta");
primaryStage.show();
scene.setCursor(Cursor.DEFAULT);
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
This is normal and working so i dont think you need to worry about that one.
Here is the controller class. Where I think the problem might be.
package application;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
public class MainController implements Initializable {
#FXML
TableView<Table> TableID;
#FXML
TableColumn<Table, Integer> aPlayerID;
#FXML
TableColumn<Table, String> aLeague;
#FXML
TableColumn<Table, String> aName;
private int aNumber = 1;
SimpleStringProperty str = new SimpleStringProperty();
public MainController() {
str.set("Hello");
}
final ObservableList<Table> data = FXCollections.observableArrayList(
new Table(aNumber++, "hehe", "hoho"),
new Table(aNumber++, "hehe", "hoho"),
new Table(aNumber++, "hehe", "hoho")
);
public void buttonClick(ActionEvent event) {
data.add(new Table(aNumber++, "hehe", "hoho"));
TableID.getColumns().addAll(aPlayerID, aLeague, aName);
}
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
aPlayerID.setCellValueFactory( new PropertyValueFactory<Table, Integer>("bPlayerID"));
aLeague.setCellValueFactory( new PropertyValueFactory<Table, String>("bLeague"));
aName.setCellValueFactory( new PropertyValueFactory<Table, String>("bName"));
TableID.setItems(data);
}
}
And here is also the table class thats needed for the tableviewer
package application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
public class Table {
private final SimpleIntegerProperty bPlayerID;
private final SimpleStringProperty bLeague;
private final SimpleStringProperty bName;
public Table(int cPlayerID, String cLeague, String cName) {
this.bPlayerID = new SimpleIntegerProperty(cPlayerID);
this.bLeague = new SimpleStringProperty(cLeague);
this.bName = new SimpleStringProperty(cName);
}
public int getbPlayerID() {
return bPlayerID.get();
}
public void setbPlayerID(int v) {
bPlayerID.set(v);
}
public String getbLeague() {
return bLeague.get();
}
public void setbLeague(String v) {
bLeague.set(v);
}
public String getbName() {
return bName.get();
}
public void setbName(String v) {
bName.set(v);
}
}
Do you guys know what could be wrong or maybe suggest how I could add just the tableviewer with code that still works with the rest of the fxml file from the scenebuilder?
The names of your get methods are wrong. According to the PropertyValueFactory documentation, if you pass in a property name of "xyz", the property value factory will first look for a method xyzProperty() belonging to the object in the table row. If it doesn't find that, it will fall back on looking for a method called getXyz() (carefully look at the capitalization there), wrapping the result in a ReadOnlyObjectWrapper.
So the following would work:
package application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
public class Table {
private final SimpleIntegerProperty bPlayerID;
private final SimpleStringProperty bLeague;
private final SimpleStringProperty bName;
public Table(int cPlayerID, String cLeague, String cName) {
this.bPlayerID = new SimpleIntegerProperty(cPlayerID);
this.bLeague = new SimpleStringProperty(cLeague);
this.bName = new SimpleStringProperty(cName);
}
public int getBPlayerID() {
return bPlayerID.get();
}
public void setBPlayerID(int v) {
bPlayerID.set(v);
}
public String getBLeague() {
return bLeague.get();
}
public void setBLeague(String v) {
bLeague.set(v);
}
public String getBName() {
return bName.get();
}
public void setBName(String v) {
bName.set(v);
}
}
However, as stated in the PropertyValueFactory documentation, the properties in this case would not be "live": in other words if the values change, the table will not automatically update. Additionally, if you wanted to make the table editable, it wouldn't update the properties without some explicit wiring to call the set methods.
It's better to define your table model using the outline in the Properties and Bindings tutorial:
package application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Table {
private final IntegerProperty bPlayerID;
private final StringProperty bLeague;
private final StringProperty bName;
public Table(int cPlayerID, String cLeague, String cName) {
this.bPlayerID = new SimpleIntegerProperty(cPlayerID);
this.bLeague = new SimpleStringProperty(cLeague);
this.bName = new SimpleStringProperty(cName);
}
public int getBPlayerID() {
return bPlayerID.get();
}
public void setBPlayerID(int v) {
bPlayerID.set(v);
}
public IntegerProperty bPlayerIDProperty() {
return bPlayerID ;
}
public String getBLeague() {
return bLeague.get();
}
public void setBLeague(String v) {
bLeague.set(v);
}
public StringProperty bLeagueProperty() {
return bLeague ;
}
public String getBName() {
return bName.get();
}
public void setBName(String v) {
bName.set(v);
}
public StringProperty bNameProperty() {
return bName ;
}
}
If you do that, then (in Java 8) you can use the following cell value factories, instead of the PropertyValueFactory:
aPlayerID.setCellValueFactory(cellData -> cellData.getValue().bPlayerIDProperty());
which will allow the compiler to catch any errors, instead of it just failing silently at runtime.
in stringproperty you gotto add asobjects() method after cellData.getValue().bPlayerIDProperty())... so I hope that would help
Related
When working with azure BlobStorage I'm quite new to this topic but I managed to get it working in java. So we have some xml files saved there and collect the file list as strings. Now I've tried to create a unit tests to verify it stays working and since the getFiles() function is a very small I expected it to be very simple to test.
#Override
public List<String> getFiles(ExecutionContext context) {
return StreamSupport.stream(blobContainerClient.listBlobs().spliterator(), true)
.map(BlobItem::getName)
.collect(Collectors.toList());
}
I can mock the com.azure.storage.blob.blobContainerClient and its function listBlobs, but when trying to create the PagedIterable from a simple List I cannot make it fit the right data types or it runs into an endless loop.
Since the functionality is so minimal, we would just skip to test this, but ou of curiosity I just want to know if it could be tested or what is wrong with my code:
import com.azure.core.http.rest.*;
import com.azure.core.util.IterableStream;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.models.BlobItem;
import com.microsoft.azure.functions.ExecutionContext;
import lombok.SneakyThrows;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import reactor.core.CoreSubscriber;
import reactor.core.Fuseable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Supplier;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*;
class BlobstoreConnectorListFilesTest {
private final BlobContainerClient blobContainerClientMock = mock(BlobContainerClient.class);
private final ExecutionContext context = mock(ExecutionContext.class);
private final String id1 = UUID.randomUUID().toString();
private final String id2 = UUID.randomUUID().toString();
#BeforeEach
void setUp() {
BlobItem item1 = mock(BlobItem.class);
when(item1.getName()).thenReturn(id1 + ".xml");
BlobItem item2 = mock(BlobItem.class);
when(item2.getName()).thenReturn(id2 + ".xml");
List<BlobItem> arrayList = new ArrayList<>();
arrayList.add(item1);
arrayList.add(item2);
Mono<PagedResponse<BlobItem>> monoSource = new Mono<>() {
private final Page<BlobItem> page = new Page<>() {
#Override
public IterableStream<BlobItem> getElements() {
return new IterableStream<>(Flux.fromIterable(arrayList));
}
#Override
public String getContinuationToken() {
return null;
}
};
final PagedResponseBase<String, BlobItem> pagedResponseBase = new PagedResponseBase<>(null, 200, null, page
, null);
final Fuseable.QueueSubscription<BlobItem> fuseableQueueSubscription = new Fuseable.QueueSubscription<>() {
#Override
public void request(long l) {
}
#SneakyThrows
#Override
public void cancel() {
throw new InterruptedException();
}
#Override
public int size() {
return arrayList.size();
}
#Override
public boolean isEmpty() {
return arrayList.isEmpty();
}
#Override
public void clear() {
arrayList.clear();
}
#Override
public BlobItem poll() {
var value = arrayList.stream().findFirst().orElse(null);
if(value!=null){
arrayList.remove(value);
}
return value;
}
#Override
public int requestFusion(int i) {
return 0;
}
};
#Override
public void subscribe(CoreSubscriber<? super PagedResponse<BlobItem>> coreSubscriber) {
coreSubscriber.onNext(pagedResponseBase);
coreSubscriber.onSubscribe(fuseableQueueSubscription);
}
};
Supplier<Mono<PagedResponse<BlobItem>>> blobItemSupplier = () -> monoSource;
PagedFlux<BlobItem> pagedFlux = new PagedFlux<>(blobItemSupplier);
PagedIterable<BlobItem> leaflets = new PagedIterable<>(pagedFlux);
doReturn(leaflets).when(blobContainerClientMock).listBlobs();
}
#Test
void getAllFiles() {
BlobstoreConnector connector = new BlobstoreConnector(blobContainerClientMock);
List<String> actual = connector.getFiles(context);
assertEquals(2, actual.size());
assertTrue(actual.stream().anyMatch(fileName -> fileName.equals(id1 + ".xml")));
assertTrue(actual.stream().anyMatch(fileName -> fileName.equals(id2 + ".xml")));
}
}
I am trying to build a Kafka source connector for audio files. from my understanding, I have to read the audio files as a Byte array.
I am using the confluent-quick-start project as a skeleton for development. the connector is not working, I can't tell why, because I don't know how to make it print logs for errors. I need help to make this work, I am not an expert in java, you can probably tell by the code.
is my approach correct? and do I have to do anything to the pom.xml file or just leave it as is?
I have examined previously available projects and tried to apply the concept for audio files. the following are the classes:
AudioSourceConnectorConfig
package org.othman.example;
import org.apache.kafka.common.config.AbstractConfig;
import org.apache.kafka.common.config.ConfigDef;
import org.apache.kafka.common.config.ConfigDef.Type;
import org.apache.kafka.common.config.ConfigDef.Importance;
import java.util.Map;
public class AudioSourceConnectorConfig extends AbstractConfig {
public static final String FILENAME_CONFIG="fileName";
private static final String FILENAME_DOC ="Enter the name of the audio file";
public static final String TOPIC_CONFIG = "topic";
private static final String TOPIC_DOC = "Enter the topic to write to..";
public AudioSourceConnectorConfig(ConfigDef config, Map<String, String> parsedConfig) {
super(config, parsedConfig);
}
public AudioSourceConnectorConfig(Map<String, String> parsedConfig) {
this(conf(), parsedConfig);
}
public static ConfigDef conf() {
return new ConfigDef()
.define(FILENAME_CONFIG, Type.STRING, Importance.HIGH, FILENAME_DOC)
.define(TOPIC_CONFIG, Type.STRING, Importance.HIGH, TOPIC_DOC);
}
public String getFilenameConfig(){
return this.getString("fileName");
}
public String getTopicConfig(){
return this.getString("topic");
}
}
AudioSourceConnector
package org.othman.example;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.kafka.common.config.ConfigDef;
import org.apache.kafka.connect.connector.Task;
import org.apache.kafka.connect.source.SourceConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AudioSourceConnector extends SourceConnector {
private static Logger log = LoggerFactory.getLogger(AudioSourceConnector.class);
private AudioSourceConnectorConfig config;
private Map<String, String> configProps;
#Override
public String version() {
return VersionUtil.getVersion();
}
#Override
public void start(Map<String, String> map) {
//config = new AudioSourceConnectorConfig(map);
this.configProps = new HashMap(map);
//TODO: Add things you need to do to setup your connector.
}
#Override
public Class<? extends Task> taskClass() {
//TODO: Return your task implementation.
return AudioSourceTask.class;
}
#Override
public List<Map<String, String>> taskConfigs(int maxTasks) {
return (List) IntStream.range(0, maxTasks).mapToObj((i) -> {
return new HashMap(this.configProps);
}).collect(Collectors.toList());
//TODO: Define the individual task configurations that will be executed.
}
#Override
public void stop() {
//TODO: Do things that are necessary to stop your connector.
this.configProps=null;
}
#Override
public ConfigDef config() {
return AudioSourceConnectorConfig.conf();
}
}
AudioSourceTask
package org.othman.example;
import org.apache.kafka.connect.data.Schema;
import org.apache.kafka.connect.source.SourceRecord;
import org.apache.kafka.connect.source.SourceTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class AudioSourceTask extends SourceTask {
static final Logger log = LoggerFactory.getLogger(AudioSourceTask.class);
AudioSourceConnectorConfig config;
private Process inputProcess;
byte [] audioFile;
#Override
public String version() {
return VersionUtil.getVersion();
}
#Override
public void start(Map<String, String> map) {
//TODO: Do things here that are required to start your task.
// This could be open a connection to a database, etc.
this.config = new AudioSourceConnectorConfig(map);
try{
audioFile = Files.readAllBytes(Paths.get(this.config.getFilenameConfig()));
// this.inputProcess = (new ProcessBuilder((new String[]{this.config.getFilenameConfig()}))).redirectError().start();
}
catch(IOException e){
System.out.println("ERROR WHILE TRYING TO READ AUDIO FILE...");
e.printStackTrace();
}
}
#Override
public List<SourceRecord> poll() throws InterruptedException {
//TODO: Create SourceRecord objects that will be sent the kafka cluster.
final ArrayList<SourceRecord> records = new ArrayList<>();
SourceRecord record;
for (int i=0;i < audioFile.length - 1;i++) {
record= new SourceRecord(null, null, this.config.getTopicConfig(), 0, Schema.BYTES_SCHEMA, audioFile[i]);
records.add(record);
}
return records;
}
#Override
public void stop() {
//TODO: Do whatever is required to stop your task.
}
}
This question already has answers here:
Javafx tableview not showing data in all columns
(3 answers)
Closed 4 years ago.
I have been trying out to create a tableview in javafx. For some reason, the tableview has the right columns, but doesn't have any data filled in it.
Here's what i've tried so far.
I have also tried the code on Eclipse and Intellij so I don't think there is any issue with my compiler or environment.
Thanks for the help in advance. :)
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.*;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.collections.*;
public class MainScreen extends Application{
private TableView<Item> table = new TableView<Item>();
private final ObservableList<Item> data =
FXCollections.observableArrayList(new Item("AZZZZ", "3"),new Item("ASD","33"));
public static void main(String args[]) {
launch(args);
}
public void start(Stage stage) {
stage.setTitle("Inventory Management");
FlowPane root = new FlowPane();
table.setEditable(true);
TableColumn<Item,String> nameCol = new TableColumn<>("Name");
TableColumn<Item,String> qtyCol = new TableColumn<>("Quantity");
nameCol.setMinWidth(100);
nameCol.setCellValueFactory(
new PropertyValueFactory<>("name"));
qtyCol.setMinWidth(100);
qtyCol.setCellValueFactory(
new PropertyValueFactory<>("number"));
//data.add(new Item("ZZZ","5"));
table.setItems(data);
table.getColumns().addAll(nameCol,qtyCol);
root.getChildren().addAll(table);
stage.setScene(new Scene(root,300,300));
stage.show();
}
public static class Item{
String name;
String number;
Item(String n,String num){
name=n;
number=num;
}
}
}
}
You need to expose your data through getter/setter and properties, see https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TableView.html
public static class Item {
private final StringProperty nameProp = new SimpleStringProperty();
private final StringProperty numberProp = new SimpleStringProperty();
Item(String n, String num) {
nameProp.set(n);
numberProp.set(num);
}
public String getName() {
return nameProp.get();
}
public void setName(String name) {
nameProp.set(name);
}
public StringProperty nameProperty() {
return nameProp;
}
public String getNumber() {
return numberProp.get();
}
public void setNumber(String number) {
numberProp.set(number);
}
public StringProperty numberProperty() {
return numberProp;
}
}
I need help creating a null-safe BooleanBinding. It has to be null-safe since I can not provide default values for all attributes in the model (one reason: the model contains enumerations). My first approach has been as follows:
executeButtonDisabled.bind(missionProperty().isNotNull().and(missionProperty().get().statusProperty().isNotEqualTo(MissionStatus.CREATED)));
final BooleanBinding isNotExecutingBinding = missionProperty().isNotNull().and(missionProperty().get().statusProperty().isNotEqualTo(MissionStatus.EXECUTING));
completeButtonDisabled.bind(isNotExecutingBinding);
cancelButtonDisabled.bind(isNotExecutingBinding)
But that approach does not work because the complete expression is evaluated which results in a NullPointerException (but it correctly updates the buttons, when a property is provided). Now I am trying to use the Bindings class as suggested in JavaFX binding and null values, but I can't make it work. Here's my current approach:
final BooleanBinding isNotCreatedBinding = Bindings.createBooleanBinding(
() -> mission.isNull().getValue()
? true
: missionProperty().get().statusProperty().isNotEqualTo(MissionStatus.CREATED).getValue());
final BooleanBinding isNotExecutingBinding = Bindings.createBooleanBinding(
() -> mission.isNull().getValue()
? true
: missionProperty().get().statusProperty().isNotEqualTo(MissionStatus.EXECUTING).getValue());
executeButtonDisabled.bind(isNotCreatedBinding);
completeButtonDisabled.bind(isNotExecutingBinding);
cancelButtonDisabled.bind(isNotExecutingBinding);
But this does not work and I do not understand why. It seems that the property binding for modelProperty() does not work here! Can you explain to me how-to convert the first working solution (at least without null) to a proper null-safe solution?
Edit 2016-04-26: The suggested solution does not work, therefore I created a simple fully-working example:
Mission.java:
package de.florianwolters.example.javafx.bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Mission {
enum Status {
CREATED,
EXECUTING,
COMPLETED,
CANCELED;
}
private final StringProperty shortName = new SimpleStringProperty();
private final ObjectProperty<Status> status = new SimpleObjectProperty<>();
public Mission(final String shortName) {
this.setShortName(shortName);
this.setStatus(Status.CREATED);
}
public String getShortName() {
return shortNameProperty().get();
}
public void setShortName(final String shortName) {
shortNameProperty().set(shortName);
}
public StringProperty shortNameProperty() {
return shortName;
}
public Status getStatus() {
return statusProperty().get();
}
public void setStatus(final Status status) {
statusProperty().set(status);
}
public ObjectProperty<Status> statusProperty() {
return status;
}
}
MissionDetailsViewModel.java:
package de.florianwolters.example.javafx.bindings;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleObjectProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class MissionDetailsViewModel {
/**
* The logger used for logging in the `MissionDetailsViewModel` class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(
MissionDetailsViewModel.class);
private ObjectProperty<Mission> mission = new SimpleObjectProperty<>();
private final ReadOnlyBooleanWrapper executeButtonDisabled = new ReadOnlyBooleanWrapper(true);
private final ReadOnlyBooleanWrapper completeButtonDisabled = new ReadOnlyBooleanWrapper(true);
private final ReadOnlyBooleanWrapper cancelButtonDisabled = new ReadOnlyBooleanWrapper(true);
/**
* Constructs a `MissionDetailsViewModel`.
*/
public MissionDetailsViewModel(final ObjectProperty<Mission> mission) {
this.mission.bind(mission);
// partialWorkingBinding();
notWorkingBinding();
}
private void notWorkingBinding() {
final BooleanBinding isNotCreatedBinding = Bindings.createBooleanBinding(
() -> missionProperty().isNull().get()
? true
: missionProperty().get().statusProperty().isNotEqualTo(Mission.Status.CREATED).get(),
missionProperty());
final BooleanBinding isNotExecutingBinding = Bindings.createBooleanBinding(
() -> mission.isNull().get()
? true
: missionProperty().get().statusProperty().isNotEqualTo(Mission.Status.EXECUTING).get(),
missionProperty());
executeButtonDisabled.bind(isNotCreatedBinding);
completeButtonDisabled.bind(isNotExecutingBinding);
cancelButtonDisabled.bind(isNotExecutingBinding);
}
private void partialWorkingBinding() {
executeButtonDisabled.bind(missionProperty().isNotNull().and(missionProperty().get().statusProperty().isNotEqualTo(Mission.Status.CREATED)));
final BooleanBinding isNotExecutingBinding = missionProperty().isNotNull().and(missionProperty().get().statusProperty().isNotEqualTo(Mission.Status.EXECUTING));
completeButtonDisabled.bind(isNotExecutingBinding);
cancelButtonDisabled.bind(isNotExecutingBinding);
}
public boolean isExecuteButtonDisabled() {
return executeButtonDisabledProperty().get();
}
public ReadOnlyBooleanProperty executeButtonDisabledProperty() {
return executeButtonDisabled;
}
public boolean isCompleteButtonDisabled() {
return completeButtonDisabledProperty().get();
}
public ReadOnlyBooleanProperty completeButtonDisabledProperty() {
return completeButtonDisabled;
}
public boolean isCancelButtonDisabled() {
return cancelButtonDisabledProperty().get();
}
public ReadOnlyBooleanProperty cancelButtonDisabledProperty() {
return cancelButtonDisabled;
}
public Mission getMission() {
return missionProperty().get();
}
public void setMission(final Mission mission) {
missionProperty().set(mission);
}
public ObjectProperty<Mission> missionProperty() {
return mission;
}
}
MissionDetailsViewModelTest.java:
package de.florianwolters.example.javafx.bindings;
import static eu.lestard.assertj.javafx.api.Assertions.assertThat;
import javafx.beans.property.SimpleObjectProperty;
import org.junit.Before;
import org.junit.Test;
public final class MissionDetailsViewModelTest {
private Mission mission;
private MissionDetailsViewModel viewModel;
#Before
public void setUp() {
mission = new Mission("My Short Name");
viewModel = new MissionDetailsViewModel(new SimpleObjectProperty<Mission>(mission));
}
#Test
public void testInitialValues() {
assertThat(viewModel.executeButtonDisabledProperty()).isFalse();
assertThat(viewModel.completeButtonDisabledProperty()).isTrue();
assertThat(viewModel.cancelButtonDisabledProperty()).isTrue();
}
#Test
public void testMissionStatusSetToExecuting() {
mission.setStatus(Mission.Status.EXECUTING);
assertThat(viewModel.executeButtonDisabledProperty()).isTrue();
assertThat(viewModel.completeButtonDisabledProperty()).isFalse();
assertThat(viewModel.cancelButtonDisabledProperty()).isFalse();
}
#Test
public void testMissionStatusSetToCompleted() {
mission.setStatus(Mission.Status.COMPLETED);
assertThat(viewModel.executeButtonDisabledProperty()).isTrue();
assertThat(viewModel.completeButtonDisabledProperty()).isTrue();
assertThat(viewModel.cancelButtonDisabledProperty()).isTrue();
}
#Test
public void testMissionStatusSetToCanceled() {
mission.setStatus(Mission.Status.CANCELED);
assertThat(viewModel.executeButtonDisabledProperty()).isTrue();
assertThat(viewModel.completeButtonDisabledProperty()).isTrue();
assertThat(viewModel.cancelButtonDisabledProperty()).isTrue();
}
}
The unit test fails with the code above (the method notWorkingBinding() is used) but works with the method partialWorkingBinding(). What am I doing wrong?
You set up the calculation function for isNotCreatedBinding, but you didn't set the dependencies for the binding. You need to add mision as dependency:
Bindings.createBooleanBinding(
() -> mission.isNull().getValue()
? true
: missionProperty().get().statusProperty().isNotEqualTo(MissionStatus.CREATED).getValue(), mission);
EDIT
You need to listen to the statusProperty instead of missionProperty, which will not work with createBooleanBinding when missionProperty().get() == null.
But you can use a When binding:
(is causing a NullPointerException as already mentioned in the question)
BooleanBinding isNotCreatedBinding = new When(mission.isNotNull()).then(mission.get().statusProperty().isNotEqualTo(Mission.Status.CREATED)).otherwise(false);
Or a more low-level solution:
missionProperty().addListener((ov, m, m1) -> {
if (m1 != null) {
executeButtonDisabled.bind(m1.statusProperty().isNotEqualTo(Mission.Status.CREATED));
}else {
executeButtonDisabled.unbind();
executeButtonDisabled.set(false);
}
});
Tomas Mikula's ReactFX framework (v 2.0) has this functionality built in:
import org.reactfx.value.Val;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
public class NestedBindingTest {
public static void main(String[] args) {
BooleanProperty disable = new SimpleBooleanProperty();
disable.addListener((obs, wasDisabled, isNowDisabled) ->
System.out.println("disable: "+wasDisabled+" -> "+isNowDisabled));
ObjectProperty<Item> item = new SimpleObjectProperty<>();
Val<Item.Status> status = Val.flatMap(item, Item::statusProperty);
disable.bind(status.map(s -> s == Item.Status.PENDING).orElseConst(true));
Item i = new Item();
System.out.println("Setting item");
item.set(i);
System.out.println("Setting item status to PENDING");
i.setStatus(Item.Status.PENDING);
System.out.println("Setting item status to READY");
i.setStatus(Item.Status.READY);
System.out.println("Setting item to null");
item.set(null);
}
public static class Item {
public enum Status {PENDING, READY}
private final ObjectProperty<Status> status = new SimpleObjectProperty<>();
public final ObjectProperty<Status> statusProperty() {
return this.status;
}
public final NestedBindingTest.Item.Status getStatus() {
return this.statusProperty().get();
}
public final void setStatus(final NestedBindingTest.Item.Status status) {
this.statusProperty().set(status);
}
}
}
This is my first post here, so I hope this question isn't a duplicate. I'm a hobbyist who is trying to use JavaFX to create an application which can manage a debating tournament.
I want to create a Singleton object in TournamentCreation, which TournamentEditor can also access and manipulate.
It seems that when my Singleton GlobalInstance object is created (which holds a tournament inside it that can be accessed and edited from elsewhere), a NullPointerException is thrown. Using debugging I've managed to figure out that it is occurring when GlobalInstance calls the default Tournament constructor.
Code time. Here is the TournamentCreationController where the error begins with the line GlobalInstance.getInstance().currentTournament().setRounds(roundsIn);
import java.net.URL;
import java.util.ResourceBundle;
import BusinessLogic.GlobalInstance;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextField;
public class TournamentCreationController implements Initializable , ControlledScreen {
ScreensController myController;
#FXML
TextField nameChooser;
#FXML
ChoiceBox roundNumberChooser;
#FXML
ChoiceBox breakNumberChooser;
#FXML
ChoiceBox noviceBreakNumberChooser;
#FXML
ChoiceBox eslBreakNumberChooser;
#FXML
ChoiceBox proAmBreakNumberChooser;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb)
{
roundNumberChooser.setItems(FXCollections.observableArrayList(1,2,3,4,5,6,7,8,9));
roundNumberChooser.getSelectionModel().select(4);
breakNumberChooser.setItems(FXCollections.observableArrayList(4,8,16,32,64));
breakNumberChooser.getSelectionModel().selectFirst();
noviceBreakNumberChooser.setItems(FXCollections.observableArrayList(0,4,8,16,32,64));
noviceBreakNumberChooser.getSelectionModel().selectFirst();
eslBreakNumberChooser.setItems(FXCollections.observableArrayList(0,4,8,16,32,64));
eslBreakNumberChooser.getSelectionModel().selectFirst();
proAmBreakNumberChooser.setItems(FXCollections.observableArrayList(0,4,8,16,32,64));
proAmBreakNumberChooser.getSelectionModel().selectFirst();
}
public void setScreenParent(ScreensController screenParent)
{
myController = screenParent;
}
#FXML
private void goToEditor(ActionEvent event)
{
String nameIn = nameChooser.getText();
int roundsIn = (int)roundNumberChooser.getSelectionModel().getSelectedItem();
int openBreakTeamsIn = (int)breakNumberChooser.getSelectionModel().getSelectedItem();
int eslBreakTeamsIn = (int)eslBreakNumberChooser.getSelectionModel().getSelectedItem();
int noviceBreakTeamsIn = (int)noviceBreakNumberChooser.getSelectionModel().getSelectedItem();
int proAmBreakTeamsIn = (int)proAmBreakNumberChooser.getSelectionModel().getSelectedItem();
GlobalInstance.getInstance().currentTournament().setRounds(roundsIn);
GlobalInstance.getInstance().currentTournament().setOpenBreakTeams(openBreakTeamsIn);
GlobalInstance.getInstance().currentTournament().setESLBreakTeams(eslBreakTeamsIn);
GlobalInstance.getInstance().currentTournament().setNoviceBreakTeams(noviceBreakTeamsIn);
GlobalInstance.getInstance().currentTournament().setProAmBreakTeams(proAmBreakTeamsIn);
myController.setScreen(ScreensFramework.screen4ID);
}
}
And here is the Singleton class:
public class GlobalInstance
{
private final static GlobalInstance instance = new GlobalInstance();
private Tournament tournament = new Tournament();
public static GlobalInstance getInstance()
{
return instance;
}
public Tournament currentTournament()
{
return tournament;
}
}
And finally here is the Tournament class (ignore most of it, the exact error occurs at name.set("name") in the default constructor):
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.StringProperty;
public class Tournament
{
private StringProperty name;
private IntegerProperty rounds;
private BooleanProperty eslBreak;
private BooleanProperty noviceBreak;
private BooleanProperty proAmBreak;
private IntegerProperty openBreakTeams;
private IntegerProperty eslBreakTeams;
private IntegerProperty noviceBreakTeams;
private IntegerProperty proAmBreakTeams;
public Tournament()
{
name.set("name");
rounds.set(0);
eslBreak.set(false);
noviceBreak.set(false);
proAmBreak.set(false);
openBreakTeams.set(4);
eslBreakTeams.set(0);
noviceBreakTeams.set(0);
proAmBreakTeams.set(0);
}
public Tournament(String nameIn, int roundsIn, int openBreakTeamsIn, int eslBreakTeamsIn, int noviceBreakTeamsIn, int proAmBreakTeamsIn)
{
name.set(nameIn);
rounds.set(roundsIn);
openBreakTeams.set(openBreakTeamsIn);
if(eslBreakTeamsIn==0)
{
eslBreak.set(false);
eslBreakTeams.set(0);
}
else
{
eslBreak.set(true);
eslBreakTeams.set(eslBreakTeamsIn);
}
if(noviceBreakTeamsIn==0)
{
noviceBreak.set(false);
noviceBreakTeams.set(0);
}
else
{
noviceBreak.set(true);
noviceBreakTeams.set(noviceBreakTeamsIn);
}
if(proAmBreakTeamsIn==0)
{
proAmBreak.set(false);
proAmBreakTeams.set(0);
}
else
{
proAmBreak.set(true);
proAmBreakTeams.set(noviceBreakTeamsIn);
}
}
public String getName()
{
return name.get();
}
public void setName(String nameIn)
{
name.set(nameIn);
}
public int getRounds()
{
return rounds.get();
}
public void setRounds(int roundsIn)
{
rounds.set(roundsIn);
}
public int getOpenBreakTeams()
{
return openBreakTeams.get();
}
public void setOpenBreakTeams(int openBreakTeamsIn)
{
openBreakTeams.set(openBreakTeamsIn);
}
public boolean getESLBreak()
{
return eslBreak.get();
}
public int getESLBreakNumber()
{
return eslBreakTeams.get();
}
public void setESLBreakTeams(int eslBreakTeamsIn)
{
if (eslBreakTeamsIn==0)
{
eslBreak.set(false);
eslBreakTeams.set(0);
}
else
{
eslBreak.set(true);
eslBreakTeams.set(eslBreakTeamsIn);
}
}
public boolean getNoviceBreak()
{
return noviceBreak.get();
}
public int getNoviceBreakNumber()
{
return noviceBreakTeams.get();
}
public void setNoviceBreakTeams(int noviceBreakTeamsIn)
{
if (noviceBreakTeamsIn==0)
{
noviceBreak.set(false);
noviceBreakTeams.set(0);
}
else
{
noviceBreak.set(true);
noviceBreakTeams.set(noviceBreakTeamsIn);
}
}
public boolean getProAmBreak()
{
return proAmBreak.get();
}
public int getProAmBreakNumber()
{
return proAmBreakTeams.get();
}
public void setProAmBreakTeams(int proAmBreakTeamsIn)
{
if (proAmBreakTeamsIn==0)
{
proAmBreak.set(false);
proAmBreakTeams.set(0);
}
else
{
proAmBreak.set(true);
proAmBreakTeams.set(proAmBreakTeamsIn);
}
}
}
While programming, the error messages are the best helpers for resolving issues. In Java, the root cause of exception can tell the actual problem. So if we look at your use case,
Caused by: java.lang.ExceptionInInitializerError
at TabIt.TournamentCreationController.goToEditor(TournamentCreationController.java:84)
tells us, the error occurred in goToEditor() method at line 84 of TournamentCreationController class. Then if we continue to read the rest of exception tracktrace message, we see the actual root error (cause) of it,
Caused by: java.lang.NullPointerException
at BusinessLogic.Tournament.<init>(Tournament.java:24)
Here it is saying that the type of error is NullPointerException and is at line 24 of Tournament class.
These hints are enough to determine the problem.
UPDATE
Based on your updated question, the problem is that name variable is not initialized yet. Trying to use uninitialized object throws null pointer exception. the Tournament's constructor should be:
public Tournament()
{
name = new SimpleStringProperty("name");
rounds = new SimpleIntegerProperty(0);
eslBreak = new SimpleBooleanProperty(false);
// etc.
}
public Tournament(String nameIn, int roundsIn, int openBreakTeamsIn, int eslBreakTeamsIn, int noviceBreakTeamsIn, int proAmBreakTeamsIn)
{
name = new SimpleStringProperty(nameIn);
rounds = new SimpleIntegerProperty(roundsIn);
eslBreak = new SimpleBooleanProperty(openBreakTeamsIn);
// etc.
}