TreeTableView cells does not get updated when underlying data changes - javafx-8

I am writing a Market Watch program which displays live quotes in a JFXTreeTableView, but when I update the data in the ObservableList, it doesn't get updated in the JFXTreeTableView. The changeDataDemo() method is actually tracking changes in the prices and is working fine (I'm using RethinkDB changefeeds to do it.) However I have removed the changefeed code here to increase readability. There is a method that adds rows to TreeTableView and is working perfectly but I have removed the code from here.
This is my code:
public class MainWindow implements Initializable {
private ObservableList<MarketWatchEntry> marketWatchEntries = FXCollections.observableArrayList();
private JFXTreeTableColumn<MarketWatchEntry, String> instrument_token_col;
private JFXTreeTableColumn<MarketWatchEntry, String> exchange_col;
private JFXTreeTableColumn<MarketWatchEntry, String> instrument_type_col;
private JFXTreeTableColumn<MarketWatchEntry, String> symbol_col;
private JFXTreeTableColumn<MarketWatchEntry, String> expiry_col;
private JFXTreeTableColumn<MarketWatchEntry, Number> buy_qty_col;
private JFXTreeTableColumn<MarketWatchEntry, Number> buy_price_col;
private JFXTreeTableColumn<MarketWatchEntry, Number> seller_price_col;
private JFXTreeTableColumn<MarketWatchEntry, Number> sell_qty_col;
#FXML
private JFXTreeTableView<MarketWatchEntry> MarketWatch;
#Override
public void initialize(URL location, ResourceBundle resources) {
populateMarketWatch();
}
private void populateMarketWatch() {
instrument_token_col = new JFXTreeTableColumn<>("Instrument Token");
instrument_token_col.setPrefWidth(80);
instrument_token_col.setVisible(false);
instrument_token_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, String> param) -> param.getValue().getValue().instrument_token);
exchange_col = new JFXTreeTableColumn<>("Exchange");
exchange_col.setPrefWidth(80);
exchange_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, String> param) -> param.getValue().getValue().exchange);
instrument_type_col = new JFXTreeTableColumn<>("Instrument");
instrument_type_col.setPrefWidth(80);
instrument_type_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, String> param) -> param.getValue().getValue().instrument_type);
symbol_col = new JFXTreeTableColumn<>("Symbol");
symbol_col.setPrefWidth(80);
symbol_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, String> param) -> param.getValue().getValue().trading_symbol);
expiry_col = new JFXTreeTableColumn<>("Expiry");
expiry_col.setPrefWidth(80);
expiry_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, String> param) -> param.getValue().getValue().expiry);
buy_qty_col = new JFXTreeTableColumn<>("Buy Qty");
buy_qty_col.setPrefWidth(80);
buy_qty_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, Number> param) -> param.getValue().getValue().buy_qty);
buy_price_col = new JFXTreeTableColumn<>("Buyer Price");
buy_price_col.setPrefWidth(80);
buy_price_col.setCellValueFactory((JFXTreeTableColumn.CellDataFeatures<MarketWatchEntry, Number> param) -> param.getValue().getValue().buyer_price);
seller_price_col = new JFXTreeTableColumn<>("Seller Price");
seller_price_col.setPrefWidth(80);
seller_price_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, Number> param) -> param.getValue().getValue().seller_price);
sell_qty_col = new JFXTreeTableColumn<>("Sell Qty");
sell_qty_col.setPrefWidth(80);
sell_qty_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, Number> param) -> param.getValue().getValue().sell_qty);
final TreeItem<MarketWatchEntry> root = new RecursiveTreeItem<>(marketWatchEntries, RecursiveTreeObject::getChildren);
MarketWatch.getColumns().setAll(instrument_token_col, exchange_col, instrument_type_col, symbol_col, expiry_col,
buy_qty_col, buy_price_col, seller_price_col, sell_qty_col, ltp_col, ltq_col, open_price_col, high_price_col,
low_price_col, close_price_col, average_price_col, change_col, net_change_col);
MarketWatch.setRoot(root);
MarketWatch.setShowRoot(false);
}
private void changeDataDemo() {
marketWatchEntries.get(0).buyer_price = new SimpleDoubleProperty(100);
}
}
I have removed irrelevant code blocks to increase readability.
My question is how to get TreeTableView to update all the cells when the collection is updated with new data.
MarketWatchEntry class
class MarketWatchEntry extends RecursiveTreeObject<MarketWatchEntry> {
StringProperty instrument_token;
StringProperty exchange;
StringProperty instrument_type;
StringProperty trading_symbol;
StringProperty expiry;
DoubleProperty buy_qty;
DoubleProperty buyer_price;
DoubleProperty seller_price;
DoubleProperty sell_qty;
DoubleProperty last_price;
DoubleProperty last_qty;
DoubleProperty open_price;
DoubleProperty high_price;
DoubleProperty low_price;
DoubleProperty close_price;
DoubleProperty average_price;
DoubleProperty change;
DoubleProperty net_change;
public MarketWatchEntry(String instrument_token, String exchange, String instrument_type, String trading_symbol,
String expiry, double buy_qty, double buy_price, double sell_price, double sell_qty,
double last_price, double last_qty, double open_price, double high_price, double low_price,
double close_price, double average_price, double change, double net_change) {
this.instrument_token = new SimpleStringProperty(instrument_token);
this.exchange = new SimpleStringProperty(exchange);
this.instrument_type = new SimpleStringProperty(instrument_type);
this.trading_symbol = new SimpleStringProperty(trading_symbol);
this.expiry = new SimpleStringProperty(expiry);
this.buy_qty = new SimpleDoubleProperty(buy_qty);
this.buyer_price = new SimpleDoubleProperty(buy_price);
this.sell_qty = new SimpleDoubleProperty(sell_qty);
this.seller_price = new SimpleDoubleProperty(sell_price);
this.last_price = new SimpleDoubleProperty(last_price);
this.last_qty = new SimpleDoubleProperty(last_qty);
this.open_price = new SimpleDoubleProperty(open_price);
this.high_price = new SimpleDoubleProperty(high_price);
this.low_price = new SimpleDoubleProperty(low_price);
this.close_price = new SimpleDoubleProperty(close_price);
this.average_price = new SimpleDoubleProperty(average_price);
this.change = new SimpleDoubleProperty(change);
this.net_change = new SimpleDoubleProperty(net_change);
}
#Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return this.instrument_token.getValue().equals(((MarketWatchEntry) obj).instrument_token.getValue());
}
#Override
public int hashCode() {
return 7 + 5 * Integer.valueOf(instrument_token.getValue());
}
}

The problem is in your changeDataDemo method:
private void changeDataDemo() {
marketWatchEntries.get(0).buyer_price = new SimpleDoubleProperty(100);
}
You are creating new instances of your properties instead of changing their values.
Something like this works:
private void changeDataDemo() {
marketWatchEntries.get(0).buyer_price.set(100);
}
But it is recommended to provide setters/getters on your Entity class:
class MarketWatchEntry extends RecursiveTreeObject<MarketWatchEntry> {
private final DoubleProperty buyer_price;
...
public MarketWatchEntry(String instrument_token, String exchange, String instrument_type, String trading_symbol,
String expiry, double buy_qty, double buy_price, double sell_price, double sell_qty) {
...
this.buyer_price = new SimpleDoubleProperty(buy_price);
...
}
public final DoubleProperty buyer_priceProperty() {
return buyer_price;
}
public final double getBuyer_price() {
return buyer_price.get();
}
public final void setBuyer_price(double value) {
buyer_price.set(value);
}
...
}
so you can just call:
private void changeDataDemo() {
marketWatchEntries.get(0).setBuyer_price(100);
}

Related

TableView, TableColumns vanish off the right edge when resizing

Using some custom resizing behaviour I'm losing columns off the right side of the TableView. I have to use UNCONSTRAINED_RESIZE_POLICY (or maybe write a custom POLICY) so that I can size some of the columns to their content.
I have some custom behaviour for the resizing of columns in the TableViews I use in my application.
I use the reflection pattern to autoresize some columns to their content when the data first populates. The remaining columns width is set to a proportion of the remaining width (if there are 3 columns not being autoresized then remaining width/3=column width).
I also have a column width listener which will listen for when a user drags column widths or double clicks on the header divider to size the column to it's content. I also listen to the width of the table itself and then assign any new extra width to the last column.
The above works ok but the issue is when a user resizes a column or multiple columns to the point the last column is as small as it can go columns will start to getting pushed off the right side of the TableView. It makes sense it would do this as I have my POLICY set to UNCONSTRAINED. I obviously can't use CONSTRAINED_RESIZE_POLICY or the above logic won't work.
Is there a custom policy out there that will reduce the rightmost columns inside 1 by 1 as the user increases the column width, so the right column first until it's as small as it can be, then the next rightmost and so on. Or do I need to write this behaviour? I did come across a Koitlin based POLICY in TorpedoFX that looked interesting but I'd rather stay pure Java.
Basically the outcome I want is what I have now but any user resizing just reduces the right-most column to a minimum size, then the next right-most and so on until all the columns to the right of the column the user is resizing are at minimum size but are still visible on the TableView. If there are no columns to the right that can be resized then the user shouldn't be able to resize their column without first resizing a column to the left.
Columns should never disappear off the right side of the TableView.
I've written a test class that mimics this behaviour, it's slightly verbose in places and would be refactored in the real application.
package application;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Skin;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableColumnBase;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableViewSample extends Application {
private TableView<TableData> table = new TableView<TableData>();
private ObservableList<TableData> data = FXCollections.observableArrayList();
private boolean columnResizeOperationPerformed = false;
private String resizeThreeColumn = "";
private String resizeFourColumn = "";
private String resizeSixColumn = "";
private final ExecutorService executorService = Executors.newFixedThreadPool(1);
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setWidth(1300);
stage.setHeight(600);
TableColumn<TableData, String> oneColumn = new TableColumn<>("One");
TableColumn<TableData, String> twoColumn = new TableColumn<>("Two");
TableColumn<TableData, String> threeColumn = new TableColumn<>("Three");
TableColumn<TableData, String> fourColumn = new TableColumn<>("Four");
TableColumn<TableData, String> fiveColumn = new TableColumn<>("Five");
TableColumn<TableData, String> sixColumn = new TableColumn<>("Six");
TableColumn<TableData, String> sevenColumn = new TableColumn<>("");
TableColumn<TableData, String> eightColumn = new TableColumn<>("");
TableColumn<TableData, String> nineColumn = new TableColumn<>("Nine");
TableColumn<TableData, String> tenColumn = new TableColumn<>("Ten");
TableColumn<TableData, String> elevenColumn = new TableColumn<>("Eleven");
TableColumn<TableData, String> twelveColumn = new TableColumn<>("Twelve");
TableColumn<TableData, String> thirteenColumn = new TableColumn<>("Thirteen");
TableColumn<TableData, String> lastColumn = new TableColumn<>("Last");
table.setEditable(false);
table.setPrefWidth(1100);
table.setMaxWidth(1100);
table.setItems(data);
table.getColumns().addAll(oneColumn, twoColumn, threeColumn, fourColumn, fiveColumn, sixColumn, sevenColumn, eightColumn, nineColumn, tenColumn, elevenColumn, twelveColumn, thirteenColumn, lastColumn);
table.setFixedCellSize(25.0);
// This cellValueFactory code could be refactored in the real application
oneColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("oneColumn"));
oneColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getOneColumn());
}
});
twoColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("twoColumn"));
twoColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getTwoColumn());
}
});
threeColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("threeColumn"));
threeColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getThreeColumn());
}
});
fourColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("fourColumn"));
fourColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getFourColumn());
}
});
fiveColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("fiveColumn"));
fiveColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getFiveColumn());
}
});
sixColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("sixColumn"));
sixColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getSixColumn());
}
});
sevenColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("sevenColumn"));
sevenColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getSevenColumn());
}
});
eightColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("eightColumn"));
eightColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getEightColumn());
}
});
nineColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("nineColumn"));
nineColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getNineColumn());
}
});
tenColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("tenColumn"));
tenColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getTenColumn());
}
});
elevenColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("elevenColumn"));
elevenColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getElevenColumn());
}
});
twelveColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("twelveColumn"));
twelveColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getTwelveColumn());
}
});
thirteenColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("thirteenColumn"));
thirteenColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getThirteenColumn());
}
});
lastColumn.setCellValueFactory(new PropertyValueFactory<TableData, String>("lastColumn"));
lastColumn.setCellValueFactory(new Callback<CellDataFeatures<TableData, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<TableData, String> p) {
return new ReadOnlyObjectWrapper(p.getValue().getLastColumn());
}
});
// using CONSTRAINED_RESIZE_POLICY will cause all kinds of odd behaviour because of the autoresize and then the columnWidthListener below.
table.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);
table.getItems().addListener(new ListChangeListener<TableData>() {
#Override
public void onChanged(Change<? extends TableData> c) {
// check to see if any of the data coming in has column 3 or 4 values that columns can be resized with
if (!columnResizeOperationPerformed) {
boolean outerBreak = false;
while (c.next() && !outerBreak) {
List<? extends TableData> addedSubList = c.getAddedSubList();
if (!addedSubList.isEmpty()) {
for (TableData data : addedSubList) {
outerBreak = checkForColThreeOrFourData(data);
}
}
}
}
// resize some columns to fit contents, other columns to take up remaining space
if (!columnResizeOperationPerformed && !table.getItems().isEmpty()) {
// only prevent future column resizing if the threeColumn has some valid data to size on
if (resizeThreeColumn.length() > 0) {
columnResizeOperationPerformed = true;
}
double totalWidth = 0;
totalWidth = autosizeColumn(oneColumn);
totalWidth += autosizeColumn(threeColumn);
totalWidth += autosizeColumn(fourColumn);
totalWidth += autosizeColumn(sixColumn);
totalWidth += autosizeColumn(sevenColumn);
totalWidth += autosizeColumn(eightColumn);
totalWidth += autosizeColumn(nineColumn);
totalWidth += autosizeColumn(tenColumn);
totalWidth += autosizeColumn(elevenColumn);
totalWidth += autosizeColumn(twelveColumn);
totalWidth += autosizeColumn(lastColumn);
double remainingWidth = table.getWidth() - totalWidth;
sizeColumn(twoColumn, remainingWidth / 4.0);
sizeColumn(fiveColumn, remainingWidth / 4.0);
sizeColumn(thirteenColumn, remainingWidth / 4.0);
table.requestLayout();
}
}
});
ChangeListener<? super Number> columnWidthListener = (obs, ov, nv) -> {
double totalWidth = table.getColumns().stream()
.filter(tc -> !tc.equals(lastColumn))
.mapToDouble(TableColumnBase::getWidth)
.sum();
sizeColumn(lastColumn, table.getWidth() - totalWidth);
};
// listen for any column resizing or table width changes and assign extra width to the lastColumn above
table.getColumns().stream()
.filter(tc -> !tc.equals(lastColumn)).forEach(tc -> {
tc.widthProperty().addListener(columnWidthListener);
});
table.widthProperty().addListener(columnWidthListener);
HBox hBox = new HBox(table);
HBox.setHgrow(table, Priority.ALWAYS);
((Group) scene.getRoot()).getChildren().addAll(hBox);
stage.setScene(scene);
stage.show();
// create Task to update the table data after the UI is constructed so that the column autoresizing code above is applied as data is populated.
Task task = new Task() {
#Override
protected Object call() {
try {
Thread.sleep(100);
Platform.runLater(() -> {
updateTableData();
});
}
catch (Exception ex) {}
return null;
}
};
executorService.submit(task);
}
/**
* A test version of a check from the real application to make sure resizing of columns happens when column data of specific columns is valid
*
* #param tableData
* #return
*/
private boolean checkForColThreeOrFourData(TableData tableData) {
if (resizeThreeColumn.length() == 0) {
resizeThreeColumn = tableData.getThreeColumn();
}
if (resizeFourColumn.length() == 0) {
resizeFourColumn = tableData.getFourColumn();
}
if (resizeSixColumn.length() == 0) {
resizeSixColumn = tableData.getSixColumn();
}
if ((resizeThreeColumn.length() > 0) && resizeFourColumn.length() > 0 && resizeSixColumn.length() > 0) { return true; }
return false;
}
public void sizeColumn(TableColumn<?, ?> column, double width) {
column.setPrefWidth(width);
}
public static double autosizeColumn(TableColumn<?, ?> column) {
final TableView<?> tableView = column.getTableView();
final Skin<?> skin = tableView.getSkin();
final int rowsToMeasure = -1;
try {
Method method = skin.getClass().getDeclaredMethod("resizeColumnToFitContent", TableColumn.class, int.class);
method.setAccessible(true);
method.invoke(skin, column, rowsToMeasure);
}
catch (Exception e) {
e.printStackTrace();
}
return column.getWidth();
}
private void updateTableData() {
data.setAll(Arrays.asList(new TableData("Manufacturer1", "User 1", "value12345", "desc12345", "defaultName", "17:04:49 15/05/19", "200", "0", "0", "3", "12", "2", "16-15-14", "80"),
new TableData("Manufacturer2", "User 2", "value67890", "desc67890", "", "17:06:38 15/05/19", "100", "0", "0", "3", "11", "2", "16-15-14", "82")));
}
class TableData implements Serializable {
private static final long serialVersionUID = 1L;
private String oneColumn;
private String twoColumn;
private String threeColumn;
private String fourColumn;
private String fiveColumn;
private String sixColumn;
private String sevenColumn;
private String eightColumn;
private String nineColumn;
private String tenColumn;
private String elevenColumn;
private String twelveColumn;
private String thirteenColumn;
private String lastColumn;
public TableData(String oneColumn, String twoColumn, String threeColumn, String fourColumn, String fiveColumn, String sixColumn, String sevenColumn, String eightColumn, String nineColumn, String tenColumn, String elevenColumn,
String twelveColumn, String thirteenColumn, String lastColumn) {
this.oneColumn = oneColumn;
this.twoColumn = twoColumn;
this.threeColumn = threeColumn;
this.fourColumn = fourColumn;
this.fiveColumn = fiveColumn;
this.sixColumn = sixColumn;
this.sevenColumn = sevenColumn;
this.eightColumn = eightColumn;
this.nineColumn = nineColumn;
this.tenColumn = tenColumn;
this.elevenColumn = elevenColumn;
this.twelveColumn = twelveColumn;
this.thirteenColumn = thirteenColumn;
this.lastColumn = lastColumn;
}
public String getOneColumn() {
return oneColumn;
}
public String getTwoColumn() {
return twoColumn;
}
public String getThreeColumn() {
return threeColumn;
}
public String getFourColumn() {
return fourColumn;
}
public String getFiveColumn() {
return fiveColumn;
}
public String getSixColumn() {
return sixColumn;
}
public String getSevenColumn() {
return sevenColumn;
}
public String getEightColumn() {
return eightColumn;
}
public String getNineColumn() {
return nineColumn;
}
public String getTenColumn() {
return tenColumn;
}
public String getElevenColumn() {
return elevenColumn;
}
public String getTwelveColumn() {
return twelveColumn;
}
public String getThirteenColumn() {
return thirteenColumn;
}
public String getLastColumn() {
return lastColumn;
}
}
}
As mentioned above this code will auto resize the selected columns and assign the remaining width equally to the other columns.
It will listen to user column width adjustments correctly.
What it won't do is prevent the columns to the right edge vanishing off the view. I would like the right columns to be reduced in width to accomodate the user column width increase in the order described above, right-most first continuing in from the right as columns reach their minimum.
Thanks for any help.

How to evaluate consuming time in kafka stream application

I have 1.0.0 kafka stream application with two classes as below 'class FilterByPolicyStreamsApp' and 'class FilterByPolicyTransformerSupplier'. In my application, I read the events, perform some conditional checks and forward to same kafka in another topic. I able to get the producing time with 'eventsForwardTimeInMs' variable in FilterByPolicyTransformerSupplier class. But I unable to get the consuming time (with and without (de)serialization). How will I get this time? Please help me.
FilterByPolicyStreamsApp .java:
public class FilterByPolicyStreamsApp implements CommandLineRunner {
String policyKafkaTopicName="policy";
String policyFilterDataKafkaTopicName = "policy.filter.data";
String bootstrapServers="11.1.1.1:9092";
String sampleEventsKafkaTopicName = 'sample-.*";
String applicationId="filter-by-policy-app";
String policyFilteredEventsKafkaTopicName = "policy.filter.events";
public static void main(String[] args) {
SpringApplication.run(FilterByPolicyStreamsApp.class, args);
}
#Override
public void run(String... arg0) {
String policyGlobalTableName = policyKafkaTopicName + ".table";
String policyFilterDataGlobalTable = policyFilterDataKafkaTopicName + ".table";
Properties config = new Properties();
config.put(StreamsConfig.APPLICATION_ID_CONFIG, applicationId);
config.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
config.put(StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, WallclockTimestampExtractor.class);
KStreamBuilder builder = new KStreamBuilder();
builder.globalTable(Serdes.String(), new JsonSerde<>(List.class), policyKafkaTopicName,
policyGlobalTableName);
builder.globalTable(Serdes.String(), new JsonSerde<>(PolicyFilterData.class), policyFilterDataKafkaTopicName,
policyFilterDataGlobalTable);
KStream<String, SampleEvent> events = builder.stream(Serdes.String(),
new JsonSerde<>(SampleEvent.class), Pattern.compile(sampleEventsKafkaTopicName));
events = events.transform(new FilterByPolicyTransformerSupplier(policyGlobalTableName,
policyFilterDataGlobalTable));
events.to(Serdes.String(), new JsonSerde<>(SampleEvent.class), policyFilteredEventsKafkaTopicName);
KafkaStreams streams = new KafkaStreams(builder, config);
streams.start();
streams.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
logger.error(e.getMessage(), e);
}
});
}
}
FilterByPolicyTransformerSupplier.java:
public class FilterByPolicyTransformerSupplier
implements TransformerSupplier<String, SampleEvent, KeyValue<String, SampleEvent>> {
private String policyGlobalTableName;
private String policyFilterDataGlobalTable;
public FilterByPolicyTransformerSupplier(String policyGlobalTableName,
String policyFilterDataGlobalTable) {
this.policyGlobalTableName = policyGlobalTableName;
this.policyFilterDataGlobalTable = policyFilterDataGlobalTable;
}
#Override
public Transformer<String, SampleEvent, KeyValue<String, SampleEvent>> get() {
return new Transformer<String, SampleEvent, KeyValue<String, SampleEvent>>() {
private KeyValueStore<String, List<String>> policyStore;
private KeyValueStore<String, PolicyFilterData> policyMetadataStore;
private ProcessorContext context;
#Override
public void close() {
}
#Override
public void init(ProcessorContext context) {
this.context = context;
// Call punctuate every 1 second
this.context.schedule(1000);
policyStore = (KeyValueStore<String, List<String>>) this.context
.getStateStore(policyGlobalTableName);
policyMetadataStore = (KeyValueStore<String, PolicyFilterData>) this.context
.getStateStore(policyFilterDataGlobalTable);
}
#Override
public KeyValue<String, SampleEvent> punctuate(long arg0) {
return null;
}
#Override
public KeyValue<String, SampleEvent> transform(String key, SampleEvent event) {
long eventsForwardTimeInMs = 0;
long forwardedEventCouunt = 0;
List<String> policyIds = policyStore.get(event.getCustomerCode().toLowerCase());
if (policyIds != null) {
for (String policyId : policyIds) {
/*
PolicyFilterData policyFilterMetadata = policyMetadataStore.get(policyId);
Do some condition checks on the event. If it satisfies then will forward them.
if(policyFilterMetadata == null){
continue;
}
*/
// Using context forward as event can map to multiple policies
long startForwardTime = System.currentTimeMillis();
context.forward(policyId, event);
forwardedEventCouunt++;
eventsForwardTimeInMs += System.currentTimeMillis() - startForwardTime;
}
}
return null;
}
};
}
}

JavaFX 8 TableView not populating from ObservableList (no FXML)

I believe I've searched all of the similar questions, but still am not seeing my issue anywhere. I am populating an ObservableList from a database which is succeeding per my Console output. I have a multiple controller setup for a school project to create a scheduler app. I have a root controller which functions as the borderPane, two functional controllers for Appointments and Customers which are all Singleton, and a shared DataView controller which is not to allow each view to instantiate its' own DataView. I've implemented toString on each of the controllers to spit out what the values and/or object Ids of each element are and everything seems to line up. I can't for the life of me figure out why the ListView or TableView aren't outputting the bound data. Here's the view data that I'm trying to bind to both ListView and TableView
public class AppointmentView implements IAppointmentView {
private final ZonedDateTime createdDate;
private final String createdBy;
// Interface needs these components
private ReadOnlyStringProperty title;
private ReadOnlyStringProperty description;
private ReadOnlyStringProperty location;
private ReadOnlyStringProperty contact;
private ReadOnlyStringProperty url;
private ReadOnlyStringProperty customerName;
private ReadOnlyObjectProperty<ZonedDateTime> start;
private ReadOnlyObjectProperty<ZonedDateTime> end;
private ReadOnlyProperty<ZonedDateTime> lastUpdated;
/***
*
* #param title
* #param description
* #param location
* #param contact
* #param url
* #param customerName
* #param start
* #param end
* #param createDate
* #param createdBy
* #param lastUpdate
*/
public AppointmentView(String title, String description, String location, String contact, String url, String customerName, Timestamp start, Timestamp end, Timestamp createDate, String createdBy, Timestamp lastUpdate) {
this.title = new SimpleStringProperty(title);
this.description = new SimpleStringProperty(description);
this.location = new SimpleStringProperty(location);
this.contact = new SimpleStringProperty(contact);
this.customerName = new SimpleStringProperty(customerName);
this.start = new SimpleObjectProperty<>(ZonedDateTime.ofInstant(start.toInstant(), ZoneId.systemDefault()));
this.end = new SimpleObjectProperty<>(ZonedDateTime.ofInstant(end.toInstant(), ZoneId.systemDefault()));
this.lastUpdated = new SimpleObjectProperty<>(ZonedDateTime.ofInstant(lastUpdate.toInstant(), ZoneId.systemDefault()));
this.url = new SimpleStringProperty(url);
this.createdDate = ZonedDateTime.ofInstant(createDate.toInstant(), ZoneId.systemDefault());
this.createdBy = createdBy;
}
public String getTitle() {
return title.getValue();
}
ReadOnlyStringProperty titleProperty() {
return title;
}
public String getDescription() {
return description.getValue();
}
ReadOnlyStringProperty descriptionProperty() {
return description;
}
public String getLocation() {
return location.getValue();
}
ReadOnlyStringProperty locationProperty() {
return location;
}
public String getContact() {
return contact.getValue();
}
ReadOnlyStringProperty contactProperty() {
return contact;
}
public String getUrl() {
return url.getValueSafe();
}
ReadOnlyStringProperty urlProperty() {
return url;
}
public String getCustomerName() {
return customerName.getValue();
}
ReadOnlyStringProperty customerNameProperty() {
return customerName;
}
public ZonedDateTime getStart() {
return ZonedDateTime.ofInstant(start.getValue().toInstant(), ZoneId.systemDefault());
}
ReadOnlyProperty<ZonedDateTime> startProperty() {
return start;
}
public ZonedDateTime getEnd() {
return ZonedDateTime.ofInstant(end.getValue().toInstant(), ZoneId.systemDefault());
}
ReadOnlyProperty<ZonedDateTime> endProperty() {
return end;
}
public LocalDate getCreateDate() {
return createdDate.toLocalDate();
}
public String getCreatedBy() {
return createdBy;
}
public ZonedDateTime getLastUpdate() {
return ZonedDateTime.ofInstant(lastUpdated.getValue().toInstant(), ZoneId.systemDefault());
}
ReadOnlyProperty<ZonedDateTime> lastUpdatedProperty() {
return lastUpdated;
}
#Override
public String toString() {
final StringBuffer sb = new StringBuffer("AppointmentView{");
sb.append("createdDate=").append(createdDate);
sb.append(", createdBy='").append(createdBy).append('\'');
sb.append(", titleProperty=").append(title);
sb.append(", descriptionProperty=").append(description);
sb.append(", locationProperty=").append(location);
sb.append(", contactProperty=").append(contact);
sb.append(", urlProperty=").append(url);
sb.append(", customerName=").append(customerName);
sb.append(", startProperty=").append(start);
sb.append(", endProperty=").append(end);
sb.append(", lastUpdated=").append(lastUpdated);
sb.append('}');
return sb.toString();
}
}
Here's the AppViewController:
public class AppViewController extends BorderPane {
private BorderPane rootPane;
private MenuBar menuBar;
private Menu fileMenu;
private Menu editMenu;
private Menu reportMenu;
private Menu helpMenu;
private MenuItem closeMenuItem;
private MenuItem copyMenuItem;
private MenuItem monthlyAppointmentReportMenuItem;
private MenuItem consultantScheduleMenuItem;
private MenuItem customersByCountryMenuItem;
private MenuItem aboutMenuItem;
private VBox vbAppView;
private TabPane tpAppPane;
private Tab tabCustomers;
private ScrollPane spCustomerEditor;
private Tab tabAppointments;
private ScrollPane spAppointmentEditor;
private MainApp mainApp;
private static AppViewController instance;
private static AppointmentViewController appointmentViewController = AppointmentViewController.getInstance();
private static CustomerViewController customerViewController = CustomerViewController.getInstance();
private static DataViewController dataViewController;
private AppViewController() {
initialize();
}
public static AppViewController getInstance() {
if (instance == null) {
new AppViewController();
}
return instance;
}
/**
* Called to initialize a controller after its root element has been
* completely processed.
**/
public void initialize() {
instance = this;
this.rootPane = new BorderPane();
this.menuBar = new MenuBar();
this.fileMenu = new Menu("_File");
this.editMenu = new Menu("_Edit");
this.reportMenu = new Menu("_Report");
this.helpMenu = new Menu("_Help");
this.closeMenuItem = new MenuItem("Close");
this.copyMenuItem = new MenuItem("Copy");
this.monthlyAppointmentReportMenuItem = new MenuItem("Monthly Appointment Report");
this.consultantScheduleMenuItem = new MenuItem("Consultant Schedule Report");
this.customersByCountryMenuItem = new MenuItem("Customers by Country Report");
this.aboutMenuItem = new MenuItem("About");
this.vbAppView = new VBox();
this.tpAppPane = new TabPane();
this.tabCustomers = new Tab("Customers");
this.tabCustomers.setClosable(false);
this.spCustomerEditor = new ScrollPane();
this.tabAppointments = new Tab("Appointments");
this.tabAppointments.setClosable(false);
this.spAppointmentEditor = new ScrollPane();
// populate menus and menuBar and add them to top pane
this.fileMenu.getItems().setAll(closeMenuItem);
this.fileMenu.setMnemonicParsing(true);
this.editMenu.getItems().setAll(copyMenuItem);
this.editMenu.setMnemonicParsing(true);
this.reportMenu
.getItems()
.setAll(monthlyAppointmentReportMenuItem, consultantScheduleMenuItem, customersByCountryMenuItem);
this.reportMenu.setMnemonicParsing(true);
this.helpMenu.getItems().setAll(aboutMenuItem);
this.helpMenu.setMnemonicParsing(true);
this.menuBar.getMenus().addAll(fileMenu, editMenu, reportMenu, helpMenu);
this.rootPane.setTop(menuBar);
// populate scroll panes with included views
this.spAppointmentEditor.setContent(getAppointmentView());
this.spCustomerEditor.setContent(getCustomerView());
// populate tab panes and controllers and add them to the center pane
this.tabAppointments.setContent(spAppointmentEditor);
this.tabCustomers.setContent(spCustomerEditor);
this.tpAppPane.getTabs().addAll(tabAppointments, tabCustomers);
vbAppView.getChildren().addAll(tpAppPane);
this.rootPane.setCenter(vbAppView);
// add data view to bottom pane
this.rootPane.setBottom(AppointmentViewController.getDataView());
setupEventHandlers(this);
}
private void setupEventHandlers(AppViewController appViewController) {
this.tabCustomers.setOnSelectionChanged((event -> {
if (tabCustomers.isSelected()) {
// Change to Customer View
setCustomerView();
} else {
setAppointmentView();
}
}));
this.tabAppointments.setOnSelectionChanged(event -> {
if (tabAppointments.isSelected()) {
setAppointmentView();
} else {
setCustomerView();
}
});
this.closeMenuItem.setOnAction(event -> quitApp());
this.tpAppPane.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
if(newValue.getText().toLowerCase().equals("Customer".toLowerCase())){
setCustomerView();
}
if (newValue.getText().toLowerCase().equals("Appointments".toLowerCase())){
setAppointmentView();
}
});
}
private void setCustomerView() {
CustomerViewController customerViewController = CustomerViewController.getInstance();
setDataView(customerViewController.getDataViewController().tabPane);
customerViewController.getGpCustomerEditor().getChildren().filtered(node -> toggleTextFields(node, true));
}
private void setAppointmentView() {
AppointmentViewController controller = AppointmentViewController.getInstance();
setDataView(controller.getDataViewController().tabPane);
controller.getGpAppointmentEditor().getChildren().filtered(node -> toggleTextFields(node, true));
}
/***
* Sets whether text fields are enabled or disabled
* true = disable Text Fields
* false = enable Text Fields
* #param node the child nodes of the editor
* #param disabled whether to disable or enable the text fields
* #return whether node was affected or not
*/
public static boolean toggleTextFields(Node node, boolean disabled) {
if (node instanceof TextField) {
((TextField) node).setEditable(!disabled);
node.setDisable(disabled);
return true;
}
return false;
}
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
private void quitApp() {
Platform.exit();
}
public Parent getBorderPane() {
return rootPane;
}
public TabPane getTpAppPane() {
return tpAppPane;
}
public Tab getTabCustomers() {
return tabCustomers;
}
public Tab getTabAppointments() {
return tabAppointments;
}
#Override
public String toString() {
final StringBuffer sb = new StringBuffer("AppViewController{");
sb.append("\nrootPane=").append(rootPane);
sb.append(",\n menuBar=").append(menuBar);
sb.append(",\n fileMenu=").append(fileMenu);
sb.append(",\n editMenu=").append(editMenu);
sb.append(",\n reportMenu=").append(reportMenu);
sb.append(",\n helpMenu=").append(helpMenu);
sb.append(",\n closeMenuItem=").append(closeMenuItem);
sb.append(",\n copyMenuItem=").append(copyMenuItem);
sb.append(",\n monthlyAppointmentReportMenuItem=").append(monthlyAppointmentReportMenuItem);
sb.append(",\n consultantScheduleMenuItem=").append(consultantScheduleMenuItem);
sb.append(",\n customersByCountryMenuItem=").append(customersByCountryMenuItem);
sb.append(",\n aboutMenuItem=").append(aboutMenuItem);
sb.append(",\n vbAppView=").append(vbAppView);
sb.append(",\n tpAppPane=").append(tpAppPane);
sb.append(",\n tabCustomers=").append(tabCustomers);
sb.append(",\n spCustomerEditor=").append(spCustomerEditor);
sb.append(",\n tabAppointments=").append(tabAppointments);
sb.append(",\n spAppointmentEditor=").append(spAppointmentEditor);
sb.append(",\n dataViewController=").append(dataViewController);
sb.append("\n}");
return sb.toString();
}
public void setDataViewController(DataViewController dataViewController) {
this.dataViewController = dataViewController;
}
public DataViewController getDataViewController() {
return dataViewController;
}
}
And the AppointmentView:
private TableView<AppointmentView> tvAppointments = new TableView<>();
private TableColumn<AppointmentView, String> tcTitle = new TableColumn<>("Title");
private TableColumn<AppointmentView, String> tcDescription = new TableColumn<>("Description");
private TableColumn<AppointmentView, String> tcLocation = new TableColumn<>("Location");
private TableColumn<AppointmentView, String> tcContact = new TableColumn<>("Contact");
private TableColumn<AppointmentView, String> tcUrl = new TableColumn<>("URL");
private TableColumn<AppointmentView, String> tcCustomerName = new TableColumn<>("Customer Name");
private TableColumn<AppointmentView, ZonedDateTime> tcStart = new TableColumn<>("Start Time");
private TableColumn<AppointmentView, ZonedDateTime> tcEnd = new TableColumn<>("End Time");
private TableColumn<AppointmentView, ZonedDateTime> tcCreateDate = new TableColumn<>("Created Date");
private TableColumn<AppointmentView, String> tcCreatedBy = new TableColumn<>("Created By");
private TableColumn<AppointmentView, Timestamp> tcLastUpdate = new TableColumn<>("Last Updated");
---- snip ----
this.tcTitle.setCellValueFactory(new PropertyValueFactory<>("title"));
this.tcTitle.setVisible(true);
this.tcTitle.setMinWidth(50);
this.tcCustomerName.setCellValueFactory(new PropertyValueFactory<>("customerName"));
this.tcCustomerName.setVisible(true);
this.tcCustomerName.setMinWidth(40);
this.tcDescription.setCellValueFactory(new PropertyValueFactory<>("description"));
this.tcDescription.setVisible(true);
this.tcDescription.setMinWidth(100);
this.tcLocation.setCellValueFactory(new PropertyValueFactory<>("location"));
this.tcLocation.setVisible(true);
this.tcLocation.setMinWidth(40);
this.tcContact.setCellValueFactory(new PropertyValueFactory<>("contact"));
this.tcContact.setVisible(true);
this.tcContact.setMinWidth(40);
this.tcUrl.setCellValueFactory(new PropertyValueFactory<>("url".toUpperCase()));
this.tcUrl.setVisible(true);
this.tcUrl.setMinWidth(40);
this.tcStart.setCellValueFactory(new PropertyValueFactory<>("start"));
this.tcStart.setVisible(true);
this.tcStart.setMinWidth(40);
this.tcEnd.setCellValueFactory(new PropertyValueFactory<>("end"));
this.tcEnd.setVisible(true);
this.tcEnd.setMinWidth(40);
this.tcCreateDate.setCellValueFactory(new PropertyValueFactory<>("createDate"));
this.tcCreateDate.setVisible(true);
this.tcCreateDate.setMinWidth(40);
this.tcCreatedBy.setCellValueFactory(new PropertyValueFactory<>("createdBy"));
this.tcCreatedBy.setVisible(true);
this.tcCreatedBy.setMinWidth(40);
this.tcLastUpdate.setCellValueFactory(new PropertyValueFactory<>("lastUpdate"));
this.tcLastUpdate.setVisible(true);
this.tcLastUpdate.setMinWidth(40);
this.tvAppointments = new TableView<>();
this.tvAppointments.setItems(appointmentViews);
this.tvAppointments.getColumns().addAll(
tcTitle,
tcDescription,
tcLocation,
tcContact,
tcUrl,
tcCustomerName,
tcStart,
tcEnd,
tcCreateDate,
tcCreatedBy,
tcLastUpdate);
this.lvListView = new ListView<>();
this.lvListView.setItems(appointmentViews);
this.dataViewController.setTableView(this.tvAppointments);
this.dataViewController.setLblListView(new Label("Appointment List"));
this.dataViewController.setListView(this.lvListView);
this.dataViewController.setLblTableView(new Label("Appointments"));
And the base DataViewController that I'm trying to manipulate:
public class DataViewController extends TabPane {
// private static DataViewController instance;
public TabPane tabPane;
private Tab tabTableView;
private Tab tabListView;
private VBox vbListView;
private VBox vbTableView;
private Label lblListView;
private Label lblTableView;
protected ScrollPane spListView;
protected ScrollPane spTableView;
private ListView<?> listView;
private TableView<?> tableView;
private MainApp mainApp;
public DataViewController() {
initialize();
}
/* public static DataViewController getInstance(){
if(instance == null){
new DataViewController();
}
return instance;
}*/
/**
* Called to initialize a controller after its root element has been
* completely processed.
*
*/
public void initialize() {
// this.instance = this;
this.tabPane = new TabPane();
this.tabPane.setPrefHeight(250.0);
this.tabPane.setMaxHeight(400.0);
this.tabPane.setMaxWidth(Integer.MAX_VALUE);
this.tabTableView = new Tab("Table View");
this.tabTableView.setClosable(false);
this.tabListView = new Tab("List View");
this.tabListView.setClosable(false);
this.spListView = new ScrollPane();
this.spTableView = new ScrollPane();
this.lblListView = new Label("List View");
this.lblTableView = new Label("Table View");
this.vbListView = new VBox();
this.vbTableView = new VBox();
this.listView = new ListView<>();
this.tableView = new TableView<>();
this.vbListView.getChildren().setAll(this.lblListView, this.listView);
this.spListView.setContent(this.listView);
this.tabListView.setContent(this.spListView);
this.vbTableView.getChildren().setAll(this.lblTableView, this.spTableView);
this.spTableView.setContent(this.tableView);
this.tabTableView.setContent(vbTableView);
this.tabPane.getTabs().setAll(tabListView, tabTableView);
}
public Label getLblListView() {
return lblListView;
}
public void setLblListView(Label lblListView) {
this.lblListView = lblListView;
}
public Label getLblTableView() {
return lblTableView;
}
public void setLblTableView(Label lblTableView) {
this.lblTableView = lblTableView;
}
public ListView<?> getListView() {
return listView;
}
public void setListView(ListView<?> listView) {
this.listView = listView;
}
public TableView<?> getTableView() {
return tableView;
}
public void setTableView(TableView<?> tableView) {
this.tableView = tableView;
}
public void setMainApp(MainApp mainApp){
this.mainApp = mainApp;
}
/* public static DataViewController getInstance() {
if (instance == null){
instance = new DataViewController();
}
return instance;
}*/
#Override
public String toString() {
return new StringBuilder()
.append("DataViewController{")
.append("\ntabPane=")
.append(tabPane)
.append(", \ntabTableView=")
.append(tabTableView)
.append(", \ntabListView=")
.append(tabListView)
.append(", \nvbListView=")
.append(vbListView)
.append(", \nvbTableView=")
.append(vbTableView)
.append(", \nlblListView=")
.append(lblListView.getText())
.append(", \nlblTableView=")
.append(lblTableView.getText())
.append(", \nspListView=")
.append(spListView)
.append(", \nspTableView=")
.append(spTableView)
.append(", \nlistView=")
.append(listView.getItems())
.append(", \ntableView=")
.append(tableView.getColumns())
.append("\n}")
.toString();
}
}
As mentioned, I put in a few toString calls and implementations and I keep seeing the objects in DataViewController per this:
listView=[AppointmentView{createdDate=2017-09-02T00:00-07:00[America/Los_Angeles], createdBy='test1', titleProperty=StringProperty [value: Meet with Amari], descriptionProperty=StringProperty [value: Meeting WR of the Raiders], locationProperty=StringProperty [value: Raiders HQ, Alameda], contactProperty=StringProperty [value: Jack DelRio], urlProperty=StringProperty [value: raiders.com], customerName=StringProperty [value: Amari Cooper], startProperty=ObjectProperty [value: 2017-09-04T16:00-07:00[America/Los_Angeles]], endProperty=ObjectProperty [value: 2017-09-04T16:15-07:00[America/Los_Angeles]], lastUpdated=ObjectProperty [value: 2017-09-02T23:07-07:00[America/Los_Angeles]]}, AppointmentView{createdDate=2017-09-02T00:00-07:00[America/Los_Angeles], createdBy='test1', titleProperty=StringProperty [value: Meet with Amari], descriptionProperty=StringProperty [value: Meeting WR of the Raiders], locationProperty=StringProperty [value: Raiders HQ, Alameda], contactProperty=StringProperty [value: Jack DelRio], urlProperty=StringProperty [value: raiders.com], customerName=StringProperty [value: Amari Cooper], startProperty=ObjectProperty [value: 2017-09-04T16:00-07:00[America/Los_Angeles]], endProperty=ObjectProperty [value: 2017-09-04T16:15-07:00[America/Los_Angeles]], lastUpdated=ObjectProperty [value: 2017-09-02T23:07-07:00[America/Los_Angeles]]}],
tableView=[javafx.scene.control.TableColumn#6167e82, javafx.scene.control.TableColumn#50658769, javafx.scene.control.TableColumn#f65aae1, javafx.scene.control.TableColumn#2d5ab3ab, javafx.scene.control.TableColumn#180d2aec, javafx.scene.control.TableColumn#64afb84b, javafx.scene.control.TableColumn#463f349d, javafx.scene.control.TableColumn#3e80101a, javafx.scene.control.TableColumn#4fab076c, javafx.scene.control.TableColumn#565f8332, javafx.scene.control.TableColumn#697bdeb8]
And here's the MainApp method that's calling it:
private void initLayout() {
// rootPane = new BorderPane();
appointmentViewController = AppointmentViewController.getInstance();
appointmentView = appointmentViewController.apAppointmentView;
appointmentViewController.setMainApp(this);
dataViewController = appointmentViewController.getDataViewController();
dataView = dataViewController.tabPane;
dataViewController.setMainApp(this);
customerViewController = CustomerViewController.getInstance();
customerView = customerViewController.apCustomerView;
customerViewController.setMainApp(this);
appViewController = AppViewController.getInstance();
appView = appViewController.getBorderPane();
appViewController.setMainApp(this);
appViewController.setDataViewController(appointmentViewController.getDataViewController());
System.out.println(this.dataViewController);
System.out.println(this.dataView);
System.out.println(appointmentViewController.toString());
System.out.println(customerViewController.toString());
System.out.println(appViewController.toString());
rootPane = (BorderPane) appView;
scene = new Scene(rootPane);
scene.getStylesheets().add("/styles/Styles.css");
primaryStage.setScene(scene);
primaryStage.show();
}
I've setup the CellValueFactories,etc. What am I missing here?
This is how the UI is shown:
In DataViewController the scene structure is initialized from the constructor. Using any of the setters in this class modifies the fields, it does not modify the scene in any way leaving the old empty ListView in the scene but printing the new one containing items from the toString method.

JavaFX Table searching with optional column

I have a tableview that i populate using an observablelist, ObservableList<Member>. The some attributes in Member object are optional, so the table cell for that row will be empty.
I have implemented FilteredList<Member> and SortedList<Member> although when i search, because of those null values in some cells, a java.lang.NullPointerException is thrown. I have no idea on how to solve this problem.
The following is SSCCE, that demonstrate my problem
package com.yunusfx.javafxcustomcontrols.yunusreproduceproblem;
import javafx.application.Application;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TableSearch extends Application{
private TableView<Member> tv = new TableView();
private TextField tfSearch = new TextField();
ObservableList<Member> memberList = FXCollections.observableArrayList();
ListProperty<Member> memberListProperty = new SimpleListProperty<>();
public static void main(String[] args) { launch(args); }
#Override
public void start(Stage primaryStage) throws Exception {
TableColumn<Member, String> name = createNameColumn();
TableColumn<Member, Integer> age = createAgeColumn();
TableColumn<Member, String> account = createAccountColumn();
TableColumn<Member, String> location = createLocationColumn();
tfSearch.setPromptText("Search here");
tv.getColumns().addAll(name, age, account, location);
memberListProperty.set(memberList);
tv.itemsProperty().bindBidirectional(memberListProperty);
tv.setItems(memberListProperty);
setData();
FilteredList<Member> filteredData = new FilteredList<>(memberList, p -> true);
tfSearch.textProperty().addListener((observable, oldValue, newValue) -> {
filteredData.setPredicate(Member -> {
if (newValue == null || newValue.isEmpty()) {
return true;
}
String lowerCaseFilter = newValue.toLowerCase();
if (Member.getName().toLowerCase().contains(lowerCaseFilter)) {
return true;
// } else if(Member.getAge().toLowerCase().contains(lowerCaseFilter)){
// No idea how to search if is integer
// return true;
}else if(Member.getLocation().toString().toLowerCase().contains(lowerCaseFilter)){
return true;
}else if(Member.getAccount().toLowerCase().contains(lowerCaseFilter)){
return true;
}
return false;
});
});
SortedList<Member> sortedData = new SortedList<>(filteredData);
sortedData.comparatorProperty().bind(tv.comparatorProperty());
tv.setItems(sortedData);
BorderPane borderPane = new BorderPane();
borderPane.setTop(tfSearch);
borderPane.setCenter(tv);
Scene scene = new Scene(borderPane, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private TableColumn createNameColumn() {
TableColumn<Member, String> colName = new TableColumn("Name");
colName.setMinWidth(25);
colName.setId("colName");
colName.setCellValueFactory(new PropertyValueFactory("name"));
return colName;
}
private TableColumn createAgeColumn() {
TableColumn<Member, Integer> colAge = new TableColumn("Age");
colAge.setMinWidth(25);
colAge.setId("colAge");
colAge.setCellValueFactory(new PropertyValueFactory("age"));
return colAge;
}
private TableColumn createAccountColumn() {
TableColumn<Member, String> colAccount = new TableColumn("Account");
colAccount.setMinWidth(25);
colAccount.setId("colAccount");
colAccount.setCellValueFactory(new PropertyValueFactory("account"));
return colAccount;
}
private TableColumn createLocationColumn() {
TableColumn<Member, String> colAccount = new TableColumn("Location");
colAccount.setMinWidth(25);
colAccount.setId("colLocation");
colAccount.setCellValueFactory(new PropertyValueFactory("location"));
return colAccount;
}
private void setData(){
Member m = new Member();
m.setAccount("we123");
m.setAge(456);
m.setLocation("Nairobi");
m.setName("Member 1");
memberList.add(m);
Member m1 = new Member();
m1.setAccount("OP5623");
m1.setAge(321);
m1.setLocation("Mombasa");
m1.setName("Doe");
memberList.add(m1);
Member m2 = new Member();
m2.setAge(569);
m2.setLocation("Meru");
m2.setName("John");
memberList.add(m2);
Member m3 = new Member();
m3.setAccount("YGTR665");
m3.setAge(666);
m3.setLocation("Eldoret");
m3.setName("Arif");
memberList.add(m3);
Member m4 = new Member();
m4.setAccount("BHJI58966");
m4.setAge(397);
m4.setName("Yunus");
memberList.add(m4);
}
public class Member {
private int id;
private String name;
private Integer age;
private String account;
private String location;
public Member(){}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
}
Clarification
By optional i mean some attributes in Member object might not have been set hence its table cell will be empty
I wasn't able to add age column to be searchable
Based on James_D's comment i was able to make search work but first check if value is null for optional attributes. For integer, convert it to string then use the string value. The important point is, the code is only dealing with actual data.
Following is what i updated:
FilteredList<Member> filteredData = new FilteredList<>(memberList, p -> true);
tfSearch.textProperty().addListener((observable, oldValue, newValue) -> {
filteredData.setPredicate(Member -> {
if (newValue == null || newValue.isEmpty()) {
return true;
}
String lowerCaseFilter = newValue.toLowerCase();
if (Member.getName().toLowerCase().contains(lowerCaseFilter)) {
return true;
} else if(Integer.toString(Member.getAge()).contains(lowerCaseFilter)){
return true;
}else if(Member.getLocation() != null && Member.getLocation().toLowerCase().contains(lowerCaseFilter)){
return true;
}else if(Member.getAccount() != null && Member.getAccount().toLowerCase().contains(lowerCaseFilter)){
return true;
}
return false;
});
});

clickable Imagemap in Gwt

hii i want clickable image map in gwt project...i have created a simple XY map but now i want clickable imagemap...please help me for that
i just want to create a chart where mouse over effect take place....
here is my code
public class ChartGenerator extends ApplicationFrame{
private List<String> trainTypeArray = new ArrayList<String>();
private String lineType;
private List<Long> startTimeOfTrain = new ArrayList<Long>();
private List<Boolean> labelVisibility = new ArrayList<Boolean>();
private List<Integer> stationDistance= new ArrayList<Integer>();
private List<String> lineColorArray = new ArrayList<String>();
private List<String> lineShadeArray = new ArrayList<String>();
private List<String> stationNames = new ArrayList<String>();
private List<String> trainArray = new ArrayList<String>();
private JFreeChart chart =null;
private int startTimeLong;
private int endTimeLong;
private String timezone;
private boolean prediction;
public ChartGenerator(String title, Date dt, String startTime, String endTime, String serviceDirection, String lineType, int delay, boolean prediction) throws BombardierBaseException, BombardierException {
/*super(title)*/;
String[] startSplit = startTime.split(":");
String[] endTimeSplit = endTime.split(":");
this.timezone = startTime +"-"+endTime;
startTimeLong = Integer.parseInt(startSplit[0])*60*60*1000+Integer.parseInt(startSplit[1])*60*1000;
endTimeLong = Integer.parseInt(endTimeSplit[0])*60*60*1000+Integer.parseInt(endTimeSplit[1])*60*1000;
endTimeLong = endTimeLong+(60*1000);
this.prediction = prediction;
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yy");
String dtOfJourney = "'" +sdf.format(dt)+"'";
this.lineType = lineType;
System.out.println("Create data-set now");
final XYDataset dataset = createDataset(dtOfJourney, startTimeLong,endTimeLong,serviceDirection);
chart= createChart(dataset, dtOfJourney, serviceDirection);
}
public int getStartTimeLong() {
return startTimeLong;
}
public void setStartTimeLong(int startTimeLong) {
this.startTimeLong = startTimeLong;
}
public int getEndTimeLong() {
return endTimeLong;
}
public JFreeChart getChart(){
return chart;
}
public BufferedImage getBufferedImage(int width, int height){
ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
return this.chart.createBufferedImage(width,height, info);
}
private double getStationDistion(String name){
return InitializeProperties.getStationDistance(name);
}
private XYDataset createDataset(String dtOfJourney, long startTime,long endTime,String serviceDirection) throws BombardierBaseException {
ResultSet resultSet =null;
Statement readstatement = null;
Connection con = null;
System.out.println("Entering get Connection now");
System.out.flush();
try{
System.out.println("Getting connection");
System.out.flush();
con = InitializeProperties.getConnection();
System.out.println("Connection initialized");
System.out.flush();
readstatement= con.createStatement();
final XYSeriesCollection dataset1 = new XYSeriesCollection();
String lineTypeFilter = "";
if(!this.lineType.equals("A")){
if(lineType.equals("L")){
lineTypeFilter = "and lt.act_lineType like ' '";
}else{
lineTypeFilter = "and lt.act_lineType like '" + this.lineType + "'";
}
}
int n = 0;
String serviceDirectionClause = "";