Background
Using JavaFX, I render a TableView and a Button side by side.
The Table contains a number of entries which are more then the Table size. Hence TableView automatically shows a scrollbar for scrolling down.
The Problem
I want to scroll down the table by using the button. So pressing the button, scroll down the table by 5 entries. I found the scrollTo() method, which would be sufficient for the task, but I need an index to scroll to. Which I do not have, as far as I understand there is no "getfirstvisibleindex" method (or something similar, you get the idea).
How can a determine the table row index to scroll to?
Edit
Thanks everyone for helping me out. For the sake of completeness I post "my" final solution as well, which is based/copied on the link provided below, Link1 and Link2. The following method is implemented as part of an extented version of TableView and will be called by a button. (Side Node: I am not sure if the check for the end is reached cased is really necessary.)
public void scrollbartest(){
TableViewSkin skin = (TableViewSkin) getSkin();
VirtualFlow vf = null;
ObservableList<Node> kids = skin.getChildren();
if (kids != null && !kids.isEmpty())
{
vf = (VirtualFlow)kids.get(1);
}
if (vf == null) { return; }
if (vf.getFirstVisibleCell() == null) { return; }
int first = vf.getFirstVisibleCell().getIndex();
int last = vf.getLastVisibleCell().getIndex();
int numberofrows = this.getItems().size();
if(last != numberofrows-1){
this.scrollTo(first+1);
}
}
I'm using the tableview tutorial as an example: http://docs.oracle.com/javafx/2/ui_controls/table-view.htm
The TableView is backed by an observable list of some object type you define. In the tutorial, they use:
final ObservableList<Person> data = FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com")
);
Along with the line:
table.setItems(data);
The data list object has a size method which would be useful for your case. In your button action, you could look up the size of the list and set the scrollTo() index 5 positions forward. Just keep track of what the starting index is outside of the button action definition.
Related
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.
In JavaFX is it at all possible to fill a ComboBox with items read from a file? Basically, I have a list of all the street names in a country and I want to display them within my ComboBox as options. Thanks.
Edit:
Finally found some time to actually tackle however I got stuck when it came to loading the array into the combobox. Any help?
This is the method which reads from the file:
private String ReadTownsAndCities(String[] choice){
List<String> list = new ArrayList<>();
String s;
FileReader fr;
BufferedReader br;
try{
fr = new FileReader("TownsAndCities.txt");
br = new BufferedReader(fr);
while((s = br.readLine()) !=null){
list.add(s);
}
choice = list.toArray(new String[list.size()]);
fr.close();
}catch(FileNotFoundException exc){
System.out.println("Cannot open input file.");
}catch(IOException exc){
System.out.println("Error reading file");
}
Now I need to load it into this combobox:
//locality combo box
localityCombo = new ComboBox<>();
//localityCombo.getItems().addAll();
grid.add(localityCombo, 1,11);
Depends on what format does the file have. If it contains many lines and each line is a street name, i would read the file line by line with a WHILE-Loop and for each iteration create a new Item in your ComboBox.
So, I'm trying to delete the highlighted row in TableView in my program.
I've looked at loads of tutorials online, but really can't get my head around this.
I have followed the example from CodeMakery, which is in Eclipse, but I'm unable to get it to work on IntelliJ (because of some apparent JDK problems?)
This is the code from CodeMakery:
private void handleDeletePerson() {
int selectedIndex = personTable.getSelectionModel().getSelectedIndex();
if (selectedIndex >= 0) {
personTable.getItems().remove(selectedIndex);
} else {
// Nothing selected.
Alert alert = new Alert(AlertType.WARNING);
alert.initOwner(mainApp.getPrimaryStage());
alert.setTitle("No Selection");
alert.setHeaderText("No Person Selected");
alert.setContentText("Please select a person in the table.");
alert.showAndWait();
}
}
Could you please help me understand how to make selected row get deleted?
just add at the beginning of this method personTable.setEditable(true). Should work now.
since my code is quite long, I'll try to only describe the issue first to see if someone has faced it before.
I have a TableView that i populate with various objects which works just fine. I created a context menu so whenever I right-click an Item i can edit certain columns. Everything works fine but when i maximize the window, I cant select any Items anymore by clicking on them.
Has anyone faced that issue before?
Thx for the help!
edit:
I added some lines of code. Im using Java 1.8.
anchorPane = new AnchorPane();
anchorPane.setMaxWidth(550.0);
tabPane = new TabPane();
tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
tabPane.setTabMinHeight(22.0);
tabPane.setPrefWidth(this.navigationWidth);
homeTableView = new TableView<Player>();
homeTableView.setEditable(true);
homeTableView.setContextMenu(homeContextMenu);
List<Player> test= mainWindow.getHomeTeamPlayer();
ObservableList<Player> homeTeamPlayer = FXCollections.observableArrayList(test);
homeTableView.setItems(homeTeamPlayer);
homeTableView.setContextMenu(homeContextMenu);
Field[] fields = Player.class.getDeclaredFields();
for(Field field: fields){
// Get column information from Metadata
ColumnMetadata columnMetadata = field.getAnnotation(ColumnMetadata.class);
if(!columnMetadata.showInTable()) continue;
TableColumn<Player, String> HomeCol = new TableColumn<>(columnMetadata.displayTitle());
HomeCol.setCellValueFactory(new PropertyValueFactory<>(field.getName()));
if(columnMetadata.isEditable()){
HomeCol.setEditable(true);
}
homeTableView.getColumns().add(HomeCol);
}
homeTab = addTab("homename", homeTableView);
AnchorPane.setRightAnchor(tabPane, 0.0);
AnchorPane.setLeftAnchor(tabPane, 0.0);
AnchorPane.setTopAnchor(tabPane, 0.0);
AnchorPane.setBottomAnchor(tabPane, 0.0);
anchorPane.getChildren().addAll(tabPane);
public Tab addTab(String name, TableView tableView){
Tab tab = new Tab();
tab.setText(name);
tab.setContent(tableView);
tabPane.getTabs().addAll(tab);
return tab;
}
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.