I have an application that I am building that has a table in it, I'm not using a tableview to build this table because I need each row to be able to expand similar to an accordion. I was able to achieve what I need by using a timeline and looping through the data and building each row (its kind of crude right now since I'm still working with dummy data eventually it will be a list iterator and not just a for loop) but I'm not happy with how its done. There are a lot of default values that will never change so I don't really need to set them in my worker class every time, I decided to just add them to the object class that I put together. So basically, at a high level it looks something like this:
for (int i = 0; i < 30; i++) {
RowBuilder builder = new RowBuilder(tableBox, i);
try {
builder.run();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I'm passing it the parent which is a VBox - tableBox, then I'm passing the count for later use.
Inside the RowBuilder I'm getting a new instance of the object DashboardRow which has all the defaults set in it, then I'm setting the data for each row and returning the DashboardRow.
Here is an example of a getter setting values in the DashboardRow
public HBox getMainRow() {
mainRow.setAlignment(Pos.CENTER_LEFT);
mainRow.setPrefHeight(60);
mainRow.setMinHeight(60);
mainRow.setMaxHeight(60);
mainRow.setPrefWidth(-1);
mainRow.setStyle("-fx-background-color:#FFFFFF;");
return mainRow;
}
Inside the DashboardRow class I have a ton of new objects being created for every element I need in the row. There are 21 for each row, mostly VBox, HBox and StackPane to build the actual row, the rest are just labels and buttons.
This is what is looks like so far. Opened and closed states.
Is there a better way to dynamically build things like this in javafx? I'm basically pulling data from a database and looping through that data to populate a row.
I can't comment but it may be an answer anyway. Why can't you use the setGraphic method of a custom table cell and put the accordion node in a table. setGraphic takes any kind of node.
It sounds simpler than what you're doing.
I just tried it out with the Oracle sample and it works great.
I added
Callback<TableColumn<Person, String>, TableCell<Person, String>> accCellFactory
= new Callback<TableColumn<Person, String>, TableCell<Person, String>>() {
#Override
public TableCell call(TableColumn p) {
TitledPane t1 = new TitledPane("T1", new Button("B1"));
TitledPane t2 = new TitledPane("T2", new Button("B2"));
TitledPane t3 = new TitledPane("T3", new Button("B3"));
Accordion accordion = new Accordion();
accordion.getPanes().addAll(t1, t2, t3);
TableCell tc = new TableCell();
tc.setGraphic(accordion);
return tc;
}
};
and changed this line firstNameCol.setCellFactory(accCellFactory);
and I get
Of course you might want something other than buttons but I just copied the Accordion sample from the javadoc.
Related
so I am using JavFX to create a form that stores all the answers in a csv file. I need to create a dropdown menu that allows the users to select an option, which is then recorded in the csv file. I have tried a lot of different options, however I think comboBox is the best option.
I have no problem creating the ComboBox, I only run into problems when it comes to the method to get the value of the box.
Can someone help me find a solution, or suggest what another JavaFX menu I can use?
This is the code I have right now:
public VBox setFamiliar(){
Button button = new Button();
button.setOnAction(e -> toString());
familiarComboBox = new ComboBox<>();
familiarVBox = new VBox();
familiarComboBox.getItems().addAll("Irmão", "Irmã", "Avó", "Avô", "Tio", "Tia", "Pai", "Mãe");
familiarVBox.getChildren().add(familiarComboBox);
familiarVBox.getChildren().add(button);
return familiarVBox;
}
Here I set the ComboBox, this part doesnt seem to have a problem because it appears and I can select an item. I created a separate void toString() method that sets the value of a variable to the current selected item
public void toString(ActionEvent e){
familiar = familiarComboBox.getSelectionModel().getSelectedItem().toString();
}
The problem is then in the get method to get the value that was selected.
public String getIrmao(){
if(familiar.equals("Irmão")){
return "2";
}
return "0";
I also tried to do familiarComboBox.getSelectionModel().getSelectedItem().equals(), and other variations of this combination.
If I understand your requirement -- that when a user makes a choice from the "Familiar" combo box, a value should be written immediately to a CSV file -- you don't need the getIrmao() method. You simply write the value out in the action which you are calling toString(...) (not a good choice of names), but which we will rename to handleFamiliarChange(...).
Now the method becomes
public void handleFamiliarChange(ActionEvent e){
final String familiar =
familiarComboBox.getSelectionModel().getSelectedItem().toString();
FileUtils.writeToCsvFile(familiar.equals("Irmão") ? 2 : 0);
}
where FileUtils.writeToCsvFile(...) is a method that does the file writing. Note that FileUtils is a class you have created to separate out file handling concerns -- your JavaFX view class should only concern itself with views.
i have used the following code for the button
natTable.addOverlayPainter(new NatTableBorderOverlayPainter());
Composite panel = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 5;
layout.marginWidth = 8;
panel.setLayout(layout);
GridDataFactory.fillDefaults().grab(true, true).applyTo(panel);
Composite gridPanel = new Composite(panel, SWT.NONE);
gridPanel.setLayout(layout);
GridDataFactory.fillDefaults().grab(true, true).applyTo(gridPanel);
Composite buttonPanel = new Composite(panel, SWT.NONE);
buttonPanel.setLayout(new RowLayout());
GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonPanel);
Button addButton = new Button(gridPanel, SWT.PUSH);
addButton.setText("Export");
addButton.setSize(1, 1);
addButton.setLocation(450, 150);
addButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
natTable.doCommand(new ExportCommand(natTable
.getConfigRegistry(), null, editable));
natTable.updateResize();
}
but at the end i am getting this as a result
https://imgur.com/EFcPaqo
Your layout is broken. Probably because the NatTable instance is not created on one of your Composites. But hard to tell without seeing the creation of it.
Either have a look at Understanding layouts in SWT or even check the NatTable examples PrintExample that shows exactly the same. There you can see that NatTable is created on the gridPanel.
I've a couple of copied elements in an observablelist which I use for copy/paste operations in a TableView. The name of the table is cpTable (copy and paste Table) for storing copied elements and to paste elements that are stored in the table. After each paste operation I want to clear the contents of cpTable before I copy other selected items with Ctrl+C.
But I always get the error:
JavaFX Application Thread" java.lang.UnsupportedOperationException:
Not supported.
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.remove(ReadOnlyUnbackedObservableList.java:246)
Here is my pseudocode:
if (cpTable !=null) {
//first, get all copied items for removing all elements
ObservableList<String> copiedItems = cpTable.getItems();
int size = copiedItems.size();
// remove all elements
for(int i=0;i<size;i++) {
copiedItems.remove(i);
}
cpTable.setItems(copiedItems); //clear cpTable by setting an empty list
}
This is a method that copies the contents of selected items and puts it in a cpTable
public TableView<String> copySelectionToClipboard(TableView<String> table) {
ObservableList<String> data = table.getSelectionModel().getSelectedItems();
TableView<String> tmp = new TableView<>();
tmp.setItems(data);
return tmp;
}
When Ctrl+C is pressed the following line puts all copied items in a cpTable:
cpTable = copySelectionToClipboard( (TableView<String>) keyEvent.getSource());
As mentioned I want to clear all cpTable contents immediately after pasting
the items in a table.
Just clear your Observable List. It looks like you should use copiedItems.clear();
That should clear your table.
As James_D already mentioned, you haven't cleared exactly what's the point.
If you want to delete selected items from a table, you need to delete them from the table item list itself and not from the selection model.
A possible solution looks like this:
TableView<String> table = new TableView<>();
ObservableList<String> tableItems = table.getItems();
// needs multirowselection is set to true
ObservableList<String> readOnlyItems = table.getSelectionModel().getSelectedItems();
// removes all selected elements for the table
readOnlyItems.stream().forEach((item) -> {
tableItems.remove(item);
});
// clear the selection
table.getSelectionModel().clearSelection();
Update
This method get's an TableView, calls it's selection model to get all selected items. And then you add the data to a new TableView. And there is the problem! It's an unmodifiable read only list that you attached to your new table. First make it modifiable, like in the code below:
public TableView<String> copySelectionToClipboard(TableView<String> table) {
ObservableList<String> readOnlyData = table.getSelectionModel().getSelectedItems();
ObservableList<String> writableData = FXCollections.<String>observableArrayList(readOnlyData);
TableView<String> tmp = new TableView<>();
tmp.setItems(writableData);
return tmp;
The next problem is in your call to this method. You call it with a TableView<CsvData> and with a TableView<String> as your method needs. If CsvData is a subtype of String, than you have to change your method signature to TableView<? extends String>
If you are trying to clear all the items from your tableView and want just an empty tableView. You can use this:
myTableView.getItems().clear();
This basically gets all the items from your table view which is nothing but just the observable list now it performs clear operations to remove all the items in tableView.
Assuming you mean
table.getSelectionModel().getSelectedItems()
(since the selection model has no getItems() method), according to the Javadocs, this returns a read-only list. Thus attempting to modify the list will throw an UnsupportedOperationException.
To clear the selection, do
table.getSelectionModel().clearSelection();
(And similarly, if you want to manipulate the selection in any other way, you use methods on the selection model, rather than on the list.)
I have a simple JavaFX app that allows the user to query a database and see the data in a table.
I'd like to allow the user to be able to click a table cell and copy text from that cell to the clipboard with the standard clipboard key stroke: ctrl-c for Win/Linux or cmd-c for Mac. FYI, the text entry controls support basic copy/paste by default.
I'm using the standard javafx.scene.control.TableView class. Is there a simple way to enable cell copy? I did some searches and I see other people create custom menu commands... I don't want to create a custom menu, I just want basic keyboard copy to work with single cells.
I'm using single selection mode, but I can change to something else if need be:
TableView<Document> tableView = new TableView<Document>();
tableView.getSelectionModel().setCellSelectionEnabled(true);
tableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
You just have to create a listener in the scene, something like:
scene.getAccelerators()
.put(new KeyCodeCombination(KeyCode.C, KeyCombination.CONTROL_ANY), new Runnable() {
#Override
public void run() {
int row = table.getSelectionModel().getSelectedIndex();
DataRow tmp = table.getItems().get(row);
final Clipboard clipboard = Clipboard.getSystemClipboard();
final ClipboardContent content = new ClipboardContent();
if(table.getSelectionModel().isSelected(row, numColumn)){
System.out.println(tmp.getNumSlices());
content.putString(tmp.getNumSlices().toString());
}
else{
System.out.println(tmp.getSelected());
content.putString(tmp.getSelected());
}
clipboard.setContent(content);
}
});
For a complete example, you can download it at the gist.
I recommended that you review this post, work for me
http://respostas.guj.com.br/47439-habilitar-copypaste-tableview-funcionando-duvida-editar-funcionalidade
The author use an aditional util java class for enable the cell content copy from a tableView
because I don't really know the sollution.
Lets say i have a TableView that holds info about product: description, quantity and the price. Also have a label that shows a sum of prices (times quantity) of all products from a table. Now i want to be notified about any changes that took affect on this component like changes in existing rows or addition of a new one. Is there any listener or sth similar to achieve it?
Usually you construct a TableView by passing an ObservableList to it. Something like this:
TableView myTable = new TableView<>(myObservableList);
ObservableList<ClassOfTheObjectsInTheList> myObservableList = FXCollections.FXCollections.observableArrayList(anyNoneObservableCollection);
TableView<ClassOfTheObjectsInTheList> myTable = new TableView<>(myObservableList);
You can add a ListChangeListener to any ObservableList at will by doing:
myObservableList.addListener(new ListChangeListener<ClassOfObjectsInTheList>(){
#Override
public void onChanged(javafx.collections.ListChangeListener.Change<? extends ClassOfObjectsInTheList> pChange) {
while(pChange.next()) {
// Do your changes here
}
}
});