JavaFX printing rows into TextFields - java

I have a table with on my SQL server with 16 rows, I am trying to print out the BasePT column into a bunch of TextFields but I cannot figure out how. Am I suppose to create a separate string for each row? How can I minimize code and be able to get each row to show up on each TextField?
//Table 100
// Button
public void loadButton(){
connection = SqlConnection.FormulaConnection();
try {
String SQL = "Select * FROM '100';";
ResultSet rs = connection.createStatement().executeQuery(SQL);
while (rs.next()) {
//insert BasePT from Row Yellow into YellowText TextField
String Yellow = rs.getString("BasePt");
YellowText.setText(Yellow);
//insert BasePT from Row 012 Yellow into TwoYellowText TextField
String TwoYellow = rs.getString("BasePT");
TwoYellowText.setText(TwoYellow);
}
} catch (Exception e) {
e.printStackTrace();
}
}

If you do NOT want to use a Tableview as yelliver suggested, you can try this:
public VBox loadButton(){
connection = SqlConnection.FormulaConnection();
VBox vBox = new VBox();
try {
String SQL = "Select * FROM '100';";
ResultSet rs = connection.createStatement().executeQuery(SQL);
while (rs.next()) {
String yellow = rs.getString("BasePt");
TextField textField = new TextField(yellow);
vBox.getChildren().add(textField);
}
} catch (Exception e) {
e.printStackTrace();
}
return vBox;
}
You can then add the VBox where you want to have all the textFields.

In the following examples I use a array of String[] arrays with elements for the row data. It should be easy enough to use the data from the database instead.
The standard way: TableView
Simply use a Item class containing a property for each table column:
public class Item {
public Item(String baseFormula, String basePt) {
this.baseFormula = new SimpleStringProperty(baseFormula);
this.basePt = new SimpleStringProperty(basePt);
}
private final StringProperty basePt;
private final StringProperty baseFormula;
public final String getBaseFormula() {
return this.baseFormula.get();
}
public final void setBaseFormula(String value) {
this.baseFormula.set(value);
}
public final StringProperty baseFormulaProperty() {
return this.baseFormula;
}
public final String getBasePt() {
return this.basePt.get();
}
public final void setBasePt(String value) {
this.basePt.set(value);
}
public final StringProperty basePtProperty() {
return this.basePt;
}
#Override
public String toString() {
return "Item{" + "basePt=" + basePt.get() + ", baseFormula=" + baseFormula.get() + '}';
}
}
And use a TableView with a column for each database column. Use a cellFactory that displays TextFields and modifies the property belonging to the column on a change of the TextField's text property:
#Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView<>();
Callback<TableColumn<Item, String>, TableCell<Item, String>> factory = column -> new TableCell<Item, String>() {
private final TextField textField;
{
textField = new TextField();
textField.textProperty().addListener((observable, oldValue, newValue) -> {
// write to property
WritableValue<String> property = (WritableValue<String>) getTableColumn().getCellObservableValue(getIndex());
property.setValue(newValue);
});
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
setGraphic(textField);
if (!Objects.equals(textField.getText(), item)) {
// only modify if TextField wasn't source of the change
// to prevent carret movement
textField.setText(item);
}
}
}
};
TableColumn<Item, String> formulaColumn = new TableColumn<>("baseFormula");
formulaColumn.setCellValueFactory(cd -> cd.getValue().baseFormulaProperty());
formulaColumn.setCellFactory(factory);
TableColumn<Item, String> ptColumn = new TableColumn<>("basePt");
ptColumn.setCellValueFactory(cd -> cd.getValue().basePtProperty());
ptColumn.setCellFactory(factory);
table.getColumns().addAll(formulaColumn, ptColumn);
String[][] data = {
{"Hello", "World"},
{"Hello2", "World2"},
{"Hello3", "World3"},
{"Hello4", "World4"},
{"Hello5", "World5"},
{"Hello6", "World6"}
};
for (String[] d : data) {
table.getItems().add(new Item(d[0], d[1]));
}
Button btn = new Button("print");
btn.setOnAction(evt -> System.out.println(table.getItems()));
Scene scene = new Scene(new VBox(table, btn));
primaryStage.setScene(scene);
primaryStage.show();
}
Alternative
If you don't want to use a TableView, GridPane would be a suitable Pane to produce a layout like this:
#Override
public void start(Stage primaryStage) {
String[][] data = {
{"Hello", "World"},
{"Hello2", "World2"},
{"Hello3", "World3"},
{"Hello4", "World4"},
{"Hello5", "World5"},
{"Hello6", "World6"}
};
Insets margin = new Insets(4);
int nextRow = 1;
GridPane gridPane = new GridPane();
Text heading1 = new Text("BaseFormula");
Text heading2 = new Text("BasePT");
GridPane.setMargin(heading1, margin);
GridPane.setMargin(heading2, margin);
gridPane.addRow(0, heading1, heading2);
for (String[] d : data) {
TextField tf = new TextField(d[0]);
TextField tf2 = new TextField(d[1]);
GridPane.setMargin(tf, margin);
GridPane.setMargin(tf2, margin);
gridPane.addRow(nextRow++, tf, tf2);
}
// add lines
// subtract stroke width
DoubleBinding height = gridPane.heightProperty().subtract(1);
// margin = 1/2 stroke width
Insets vMargin = new Insets(0.5, 0, 0.5, 0);
// add vertical lines
for (int i = 0; i < 3; i++) {
Line vLine = new Line();
GridPane.setMargin(vLine, vMargin);
System.out.println(vLine.getStrokeWidth());
vLine.endYProperty().bind(height);
gridPane.add(vLine, i, 0, 1, nextRow);
}
// procede accordingly with horizontal lines
DoubleBinding width = gridPane.widthProperty().subtract(1);
Insets hMargin = new Insets(0, 0.5, 0, 0.5);
for (int i = 0; i <= nextRow; i++) {
Line hLine = new Line();
GridPane.setMargin(hLine, hMargin);
hLine.setStartX(1);
hLine.endXProperty().bind(width);
// Insert at the top of the cell
GridPane.setValignment(hLine, VPos.TOP);
gridPane.add(hLine, 0, i, 2, 1);
}
Scene scene = new Scene(new StackPane(new Group(gridPane)), 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}

you can replace this snippet with your ResultSet rs
ResultSet rs = null;//reference it to your rs
TableView<String[]> tv = new TableView<String[]>();
final int columnCount = rs.getMetaData().getColumnCount();
for(int i =1; i <= columnCount; i++){
TableColumn<String[], String> tc = new TableColumn<String[], String>();
tc.setText(rs.getMetaData().getColumnName(i));
final int k = i-1;
tc.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<
String[],String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<String[],
String> param) {
return new SimpleStringProperty(param.getValue()[k]);
}
});
tc.setCellFactory(new Callback<TableColumn<String[],String>,
TableCell<String[],String>>() {
#Override
public TableCell<String[], String> call(TableColumn<String[],
String> param) {
return new TableCell<String[], String>(){
#Override
protected void updateItem(String arg0, boolean arg1) {
super.updateItem(arg0, arg1);
if(arg1){
setText("");
return;
}else{
setText(arg0);
}
}
};
}
});
}
while(rs.next()){
String[] s = new String[columnCount];
for(int i = 1; i <= columnCount; i++){
s[i -1] = rs.getString(i);
}
tv.getItems().add(s);
}
This will put you in the right direction. Hope it helps/.

Related

TreeItem is Overwritten in JavaFX. How to solve this?

Treeitem is overwriting every time I add a new class. How to solve this?
While adding a new object treeitem should be dynamically increase tried:
adding without using the list
added using the list
tried to add using a loop
This is an example code sorry for naming errors.thanks in advance
marked the place of issue with --------
PanesClass.java
public class PanesClass extends Application {
ObservableList<Connections> cList = FXCollections.observableArrayList();
public static void main(String[] args) {
launch(args);
}
#SuppressWarnings("all")#Override
public void start(Stage primaryStage) throws Exception {
NewConnection newConnection = new NewConnection();
SplitPane root = new SplitPane();
AnchorPane first = new AnchorPane();
AnchorPane second = new AnchorPane();
TreeTableView activeConnections = new TreeTableView();
HBox buttonBox = new HBox();
BorderPane topBar = new BorderPane();
Button nConnection = new Button("+");
Button deleteConnection = new Button("X");
Button connect = new Button("Connect");
buttonBox.setSpacing(10);
buttonBox.getChildren().addAll(nConnection, deleteConnection, connect);
topBar.setTop(buttonBox);
TreeTableColumn<String, Connections > cNameColoumn = new TreeTableColumn<>("Name");
cNameColoumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("cname"));
TreeTableColumn<String, Connections> cStatusColoumn = new TreeTableColumn<>("Status");
cStatusColoumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("cstatus"));
activeConnections.getColumns().addAll(cNameColoumn, cStatusColoumn);
activeConnections.setLayoutX(20);
activeConnections.setLayoutY(40);
activeConnections.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY);
first.getChildren().addAll(topBar, activeConnections);
root.getItems().addAll(first, second);
Scene sc = new Scene(root, 600, 480);
primaryStage.setScene(sc);
primaryStage.show();
nConnection.setOnAction(new EventHandler<ActionEvent>() {#Override
public void handle(ActionEvent event) {
newConnection.getConnection(activeConnections);
}
});
}
}
NewConnection.java
public class NewConnection {
Connections connection = null;
ObservableList<Connections> cList = FXCollections.observableArrayList();
PanesClass panesClass = new PanesClass();
TreeItem cItem = null;
TreeItem nItem = null;
public void getConnection(TreeTableView<Connections> activeConnections) {
Stage secondaryStage = new Stage();
VBox root = new VBox();
GridPane cDetails = new GridPane();
HBox actionButtons = new HBox();
Button connect = new Button("Connect");
Button save = new Button("Save");
Button cancel = new Button("Cancel");
actionButtons.getChildren().addAll(connect, save, cancel);
actionButtons.setSpacing(10);
Label name = new Label("Username : ");
cDetails.add(name, 0, 0);
TextField uName = new TextField();
cDetails.setHgrow(uName, Priority.ALWAYS);
cDetails.add(uName, 1, 0);
Label password = new Label("Password : ");
cDetails.add(password, 0, 1);
TextField pwd = new TextField();
cDetails.add(pwd, 1, 1);
Label urllink = new Label("URL : ");
cDetails.add(urllink, 0, 2);
TextField url = new TextField();
cDetails.add(url, 1, 2);
cDetails.setVgap(10);
cDetails.setStyle("-fx-padding: 10;" + "-fx-border-style: solid inside;" + "-fx-border-width: 1;" + "-fx-border-insets: 5;" + "-fx-border-radius: 5;" + "-fx-border-color: black;");
root.getChildren().addAll(cDetails, actionButtons);
Scene sc = new Scene(root, 500, 200);
secondaryStage.setScene(sc);
secondaryStage.initModality(Modality.APPLICATION_MODAL);
secondaryStage.show();
save.setOnAction(new EventHandler<ActionEvent>() {
//*-----------------------------------------------------------------------*
#Override
public void handle(ActionEvent event) {
cItem = getitem(cItem);
activeConnections.setRoot(cItem);
activeConnections.setShowRoot(false);
secondaryStage.close();
}
private TreeItem getitem(TreeItem cItem) {
cList.add(new Connections(uName.getText()));
System.out.println(cList);
for (Connections temp: cList) {
System.out.println(temp);
nItem = new TreeItem<Connections>(temp);
System.out.println(nItem);
cItem.getChildren().add(nItem);
}
return cItem;
}
});
System.out.println(cList);
}
}
Connections.java
public class Connections {
private String cname = null;
private String cstatus = null;
private String cpwd = null;
private String curl = null;
public Connections() {
}
public Connections(String cname, String cpwd, String curl) {
super();
this.cname = cname;
this.cpwd = cpwd;
this.curl = curl;
}
public Connections(String cname, String cstatus) {
super();
this.cname = cname;
this.cstatus = cstatus;
}
public String getCpwd() {
return cpwd;
}
public void setCpwd(String cpwd) {
this.cpwd = cpwd;
}
public String getCurl() {
return curl;
}
public void setCurl(String curl) {
this.curl = curl;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public String getCstatus() {
return cstatus;
}
public void setCstatus(String cstatus) {
this.cstatus = cstatus;
}
#Override
public String toString() {
return "Connections [cname=" + cname + ", cstatus=" + cstatus + ", cpwd=" + cpwd + ", curl=" + curl + "]";
}
}
You're not populating your tree, you're creating new items without adding them to your tree.
First thing, you need to create a root:
// Instead of this line
// TreeItem nItem = null;
TreeItem rootItem = new TreeItem();
Then:
activeConnections.setRoot(rootItem);
save.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// clear old connections
rootItem.getChildren().clear();
// Add new connection
cList.add(new Connections(uName.getText(), pwd.getText(), url.getText()));
// create new items and add them to rootItem
for (Connections temp : cList) {
rootItem.getChildren().add(new TreeItem<Connections>(temp));
}
secondaryStage.close();
event.consume();
}
});
NOTE: If you don't have another reason to keep cList, you can remove it and add your new Items directly (no need to clear and regenerate items everytime):
save.setOnAction(event -> {
Connections newConnection = new Connections(uName.getText(), pwd.getText(), url.getText());
rootItem.getChildren().add(new TreeItem<>(newConnection));
secondaryStage.close();
event.consume();
});

Add Tooltip and change color of tablecells in javafx tableview

I want to display a db-result in a tablview. Therefore i have a dynamically created tableview :
public void createTableView() throws Exception {
List<String> columnNames = new ArrayList<>();
columnNames = test.getColumnNames();
for (int i = 0; i < test.getColumnCount(); i++) {
TableColumn<ObservableList<String>,String> column = new TableColumn<>(columnNames.get(i));
final int j = i;
column.setCellValueFactory(new Callback<CellDataFeatures<ObservableList<String>, String>, ObservableValue<String>>(){
public ObservableValue<String> call(CellDataFeatures<ObservableList<String>, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString());
}
});
tableView.getColumns().add(column);
}
Add db-result:
public void initializeTableView(List<List<String>> result) throws Exception {
ObservableList<ObservableList<String>> data = FXCollections.observableArrayList();
if (tableView.getColumns().size() == 0) {
createTableView();
}
for (int i = 0; i < result.size(); i++) {
ObservableList<String> row = FXCollections.observableArrayList();
row.addAll(result.get(i));
data.add(row);
}
tableView.setItems(data);
Now im getting a second db-result that I´m showing in the same tableview. Now i want to compare the first resultlist with the second resultlist and if the values are not equal, I want to show the first result in a tooltip and change the cellcolor to red.
You can use a custom TableCell that compares the data. Of course it may be better to not store the whole data twice. In case the changes are sparse, using a Map to store the original values would be more memory efficient, but the idea of styling the cells is just the same.
Example:
#Override
public void start(Stage primaryStage) {
// create sample data
List<List<String>> result = Arrays.asList(
Arrays.asList("a", "b"),
Arrays.asList("c", "d"),
Arrays.asList("e", "f"),
Arrays.asList("g", "h"),
Arrays.asList("i", "j")
);
TableView<ObservableList<String>> tableView = new TableView<>();
List<String> columnNames = Arrays.asList("column1", "column2");
for (int i = 0; i < columnNames.size(); i++) {
TableColumn<ObservableList<String>, String> column = new TableColumn<>(columnNames.get(i));
final int j = i;
column.setCellValueFactory((CellDataFeatures<ObservableList<String>, String> param) -> Bindings.stringValueAt(param.getValue(), j));
// use custom cells
column.setCellFactory(tc -> new TableCell<ObservableList<String>, String>() {
private final Tooltip tooltip = new Tooltip();
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
// clear the cell
setStyle(null);
setText(null);
setTooltip(null);
} else {
setText(item);
String original = result.get(getIndex()).get(j);
if (Objects.equals(original, item)) {
// same value as original -> no tooltip, no background
setStyle(null);
setTooltip(null);
} else {
// different -> red background + tooltip
setStyle("-fx-background-color: red;");
setTooltip(tooltip);
tooltip.setText(original);
}
}
}
});
tableView.getColumns().add(column);
}
ObservableList<ObservableList<String>> data = FXCollections.observableArrayList();
for (int i = 0; i < result.size(); i++) {
ObservableList<String> row = FXCollections.observableArrayList();
row.addAll(result.get(i));
data.add(row);
}
tableView.setItems(data);
// do some modifications
data.get(0).set(1, "1");
data.get(3).set(0, "3");
Scene scene = new Scene(tableView);
primaryStage.setScene(scene);
primaryStage.show();
}

How to dynamically populate tableview with columns created automatically

I have the following problem: I created a code to separate each variable of Euclid's algorithm and store in a Array or object . I can not think of a way to retrieve the data and populate a tableView so that , depending on the MDC (a, b ) if fore very large, the columns are added automatically.
In fact , it is a representation of the resolution of the MDC by successive divisions. I did a test , but I can not run it. Follows the code .
MDC
public List<Inteiros_old> listMdc(Inteiros_old inteiros) {
//List<Integer> lista_resto = new ArrayList<Integer>();
System.out.println(" Dividendo" + "\t" + " Divisor " + "\t" + " Quociente" + "\t" + " Resto ");
System.out.println("----------" + "\t" + "----------" + "\t" + "----------" + "\t" + "----------");
int max_inteiros = Math.max(inteiros.getDividendo(), inteiros.getDivisor());
int min_inteiros = Math.min(inteiros.getDividendo(), inteiros.getDivisor());
//System.out.println(k + "\t" + m);
List<Inteiros_old> lista = new ArrayList<Inteiros_old>();
while( min_inteiros != 0) {
inteiros.setResto(max_inteiros % min_inteiros);
inteiros.setQuociente(max_inteiros/min_inteiros);
System.out.println(max_inteiros + "\t\t " + min_inteiros + "\t\t " + inteiros.getQuociente() + "\t\t" + inteiros.getResto());
max_inteiros = min_inteiros;
min_inteiros = inteiros.getResto();
//lista.add(inteiros.getResto());
}
return lista;
}
JAVAFX
public class TabelaDinamica extends Application {
private TableView<Inteiros> table = new TableView<Inteiros>();
private final ObservableList<Inteiros> data = FXCollections.observableArrayList();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
// -------------------------------------------------------------------------
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(300);
stage.setHeight(500);
final Label label = new Label("Dynamic Table with autoColumns");
label.setFont(new Font("Arial", 16));
table.setEditable(true);
// -------------------------------------------------------------------------
int sizeColumns = 4;
for (int j = 0; j < sizeColumns; j++) {
data.add(new Inteiros(1,2,3,4));
String nome = new String("col"+j);
TableColumn col = new TableColumn();
col.setMinWidth(100);
col.setCellValueFactory(
new PropertyValueFactory<Inteiros, String>(nome));
//table.getColumns().add(j, col);
table.setItems(data);
table.getColumns().addAll(col);
}
// -------------------------------------------------------------------------
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table);
((Group) scene.getRoot()).getChildren().addAll(vbox);
// -------------------------------------------------------------------------
stage.setScene(scene);
stage.show();
}
}
public class Inteiros {
private SimpleIntegerProperty dividendo; //dividen
private SimpleIntegerProperty divisor; //divisor
private SimpleIntegerProperty quociente; //quotient
private SimpleIntegerProperty resto; //rest
Inteiros(Integer dividendo, Integer divisor, Integer quociente, Integer resto) {
this.dividendo = new SimpleIntegerProperty(dividendo);
this.divisor = new SimpleIntegerProperty(divisor);
this.quociente = new SimpleIntegerProperty(quociente);
this.resto = new SimpleIntegerProperty(resto);
}
public Integer getDividendo() {
return dividendo.get();
}
public void setDividendo(Integer int_num) {
dividendo.set(int_num);
}
public Integer getDivisor() {
return divisor.get();
}
public void setDivisor(Integer int_num) {
divisor.set(int_num);
}
public Integer getQuociente() {
return quociente.get();
}
public void setQuociente(Integer int_num) {
quociente.set(int_num);
}
public Integer resto() {
return resto.get();
}
public void setResto(Integer int_num) {
resto.set(int_num);
}
try this
String[] nome = {"dividendo", "divisor", "quociente", "resto"}
int sizeColumns = 4;
for (int j = 0; j < sizeColumns; j++) {
data.add(new Inteiros(1,2,3,4));
TableColumn col = new TableColumn();
col.setMinWidth(100);
col.setCellValueFactory(new PropertyValueFactory<Inteiros, String>(nome[j]));
table.getColumns().addAll(col);
}
table.setItems(data);
because the value of String nome has to match with the name of the variable

Printing node on multiple pages

I have a table view that can't fit on one page but when I print it only one page gets printed. What should I do so that the rest of the table is printed on other pages?
Sample code below that fills a table view with 50 rows and prints it (I use foxit as a pdf printer, amend as required). The output pdf only contains one page that ends around row 30 although the TableView shows more than 45 rows.
public class FXPrint extends Application {
public static void main(String[] args) { launch(FXPrint.class); }
#Override
public void start(Stage stage) throws Exception {
TableView<String> table = new TableView<>();
for (int i = 0; i < 25; i++) {
TableColumn<String, String> tc = new TableColumn<>("" + i);
int index = i;
tc.setCellValueFactory(param -> {
String s = param.getValue();
if (s.length() <= index) return new SimpleStringProperty();
else return new SimpleStringProperty(s.substring(index, index + 1));
});
table.getColumns().add(tc);
}
for (int i = 0; i < 50; i++) table.getItems().add(i + "sdfghjklrthyjkcasdghasfdsfgdfgsdfggfdg");
Button print = new Button("print");
print.setOnAction(e -> print(table));
VBox box = new VBox(10, table, print);
VBox.setVgrow(table, Priority.ALWAYS);
stage.setScene(new Scene(box));
stage.setWidth(600);
stage.setHeight(1200);
stage.show();
}
public void print(final TableView<?> table) {
Printer printer = Printer.getAllPrinters().stream().filter(p -> p.getName().contains("Foxit")).findAny().get();
PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.PORTRAIT, Printer.MarginType.DEFAULT);
PrinterJob job = PrinterJob.createPrinterJob(printer);
if (job != null) {
job.getJobSettings().setPageLayout(pageLayout);
if (job.printPage(table)) {
job.endJob();
}
}
}
}
You should split your TableView on multiple Nodes according to height of printable area and height of your rows. Then call job.PrintPage for all nodes, and once job.endJob.
Here is my approach for multiple pages printing:
public static List<Node> getLineRecordPages(Collection<LineRecord> lineRecords, PageLayout layout) {
LinkedList<Node> result = new LinkedList<>();
VBox node = null;
double totalHeight = Double.POSITIVE_INFINITY;
for (LineRecord record : lineRecords) {
PrintLineRecordView view = new PrintLineRecordView();
final PrintLineRecordPresenter presenter = (PrintLineRecordPresenter) view.getPresenter();
presenter.bind(record);
final double elementHeight = view.getView().prefHeight(layout.getPrintableWidth());
if (elementHeight + totalHeight > layout.getPrintableHeight()) {
node = new VBox();
node.setMaxWidth(layout.getPrintableWidth());
result.add(node);
totalHeight = 0;
}
totalHeight+=elementHeight;
if (node != null) {
node.getChildren().add(view.getView());
}
}
return result;
}
And actualy sending pages to printing job:
Printer printer = Printer.getDefaultPrinter();
PageLayout pageLayout = printer.getDefaultPageLayout();
PrinterJob printerJob = PrinterJob.createPrinterJob(printer);
final List<Node> pages = Formatter.getLineRecordPages(lineRecords, pageLayout);
final boolean print = printerJob.showPrintDialog(null);
if (print) {
pages.forEach(printerJob::printPage);
printerJob.endJob();
}

javafx-2 tableview implementing custom column resize policy

In my experience CONSTRAINED_RESIZE_POLICY is broken if the TableView contains some fixed width columns unless I am doing something wrong here:
public class JavaFX2Sandbox extends Application
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception
{
StackPane root = new StackPane();
root.autosize();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
configureTable(root);
}
public static class Person
{
public Person(String firstName, String lastName)
{
this.fixedValue = "Dr.";
this.firstName = firstName;
this.lastName = lastName;
}
public String fixedValue;
public String firstName;
public String lastName;
}
private static class CellValueFactory<T> implements Callback<TableColumn.CellDataFeatures<T, Object>, ObservableValue<Object>>
{
private String mFieldName;
public CellValueFactory(String fieldName)
{
mFieldName = fieldName;
}
#Override
public ObservableValue call(TableColumn.CellDataFeatures<T, Object> p)
{
try
{
if (p == null)
{
return new SimpleObjectProperty(null);
}
Object o = p.getValue();
if (o == null)
{
return new SimpleObjectProperty(null);
}
Object fieldVal = o.getClass().getField(mFieldName).get(o);
if (fieldVal == null)
{
return new SimpleObjectProperty(null);
}
return new SimpleObjectProperty(fieldVal);
}
catch (Exception ex)
{
return new SimpleObjectProperty(ex);
}
}
}
private void configureTable(StackPane root)
{
TableView<Person> table = new TableView<>();
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
ArrayList<Person> teamMembers = new ArrayList<>();
teamMembers.add(new Person("John", "Big"));
teamMembers.add(new Person("Frank", "Small"));
TableColumn col0 = new TableColumn("fixed-width");
col0.setResizable(false);
col0.setCellValueFactory(new CellValueFactory("fixedValue"));
TableColumn col1 = new TableColumn("First Name");
col1.setCellValueFactory(new CellValueFactory("firstName"));
TableColumn col2 = new TableColumn("Last Name");
col2.setCellValueFactory(new CellValueFactory("lastName"));
table.getColumns().setAll(col0, col1, col2);
table.setItems(FXCollections.observableList(teamMembers));
root.getChildren().add(table);
}
}
So I started to implement my own resize policy which behaves slightly differently from CONSTRAINED_RESIZE_POLICY but I like mine better :-). It is all okay except for the sum of the widths of the columns do not add up to the width of the TableView.
Here is the implementation of my resize policy class:
static class ColumnResizePolicy implements Callback<TableView.ResizeFeatures, Boolean>
{
double mTVWidth;
#Override
public Boolean call(ResizeFeatures arg0)
{
TableView tv = arg0.getTable();
Double tvWidth = tv.widthProperty().getValue();
if (tvWidth == null || tvWidth <= 0.0)
{
return false;
}
if (mTVWidth != tvWidth && arg0.getColumn() == null)
{
mTVWidth = tvWidth;
int numColsToSize = 0;
double fixedColumnsWidths = 0;
for (TableColumn col : new ArrayList<TableColumn>(tv.getColumns()))
{
if (col.isResizable() && col.isVisible())
{
++numColsToSize;
}
else if (col.isVisible())
{
fixedColumnsWidths += col.getWidth();
}
}
if (numColsToSize == 0)
return TableView.UNCONSTRAINED_RESIZE_POLICY.call(arg0);
TableColumn lastCol = null;
for (TableColumn col : new ArrayList<TableColumn>(tv.getColumns()))
{
if (col.isResizable() && col.isVisible())
{
double newWidth = (tvWidth - fixedColumnsWidths) / numColsToSize;
col.setPrefWidth(newWidth);
lastCol = col;
}
}
if (lastCol != null)
{
lastCol.setPrefWidth(lastCol.getPrefWidth()-2);
}
return true;
}
else
{
return TableView.UNCONSTRAINED_RESIZE_POLICY.call(arg0);
}
}
}
And my question (ironically after this long post) is about number 2 in this line:
lastCol.setPrefWidth(lastCol.getPrefWidth()-2);
I assume that the table width gives back the outer width including the border, hence the difference, but how do I get the inner width?
Try next:
double borderWidth = table.getBoundsInLocal().getWidth() - table.getWidth()
Have you tried getting the width of the place holder node?
I have a problem same https://community.oracle.com/message/12334734#12334734
And this implementing custom column resize policy of you was help me.
Thanks you!
Your code.
if (col.isResizable() && col.isVisible()) {
double newWidth = (tvWidth - fixedColumnsWidths) / numColsToSize;
col.setPrefWidth(newWidth);
lastCol = col;
}
I change to
if (col.isResizable() && col.isVisible()) {
double newWidth = (tvWidth - fixedColumnsWidths)*col.getPercentWidth();
col.setPrefWidth(newWidth);
lastCol = col;
}
With col is
public class PTableColumn<S, T> extends javafx.scene.control.TableColumn<S, T>
And getPercentWidth is
private DoubleProperty percentWidth = new SimpleDoubleProperty(1);

Categories