I have a JavaFx TableView with each Row having a column with a delete button which when clicked should delete the TableRow, as well as the corresponding entries in the H2 database via Hibernate.
So far I'm not getting anything. Nothing happens on button click. Not even if I manually assign the item Primary Key like so:
NewBeautifulKiwi toDelete = (NewBeautifulKiwi) session.get(NewBeautifulKiwi.class, 97);
Please help me make this work; the button click to delete the TableRow it belongs to as well as the Database items populating that particular TableRow. So far nothing happens at all on ButtonClick.
Thank you in advance.
Ps.
The buttons also get printed where the columns are empty. It would also help if you helped me solve this and only have Buttons on Rows with data
The Class Extract:
public class HomeController implements Initializable {
#FXML
public static TableView<NewBeautifulKiwi> KIWI_TABLE;
#FXML
private TableColumn<NewBeautifulKiwi, Object> KiwiAction;
// Initializes the controller class.
#Override
public void initialize(URL url, ResourceBundle rb) {
KiwiAction.setCellValueFactory(new PropertyValueFactory<NewBeautifulKiwi, Object>("KiwiAction"));
KiwiAction.setCellFactory(new Callback<TableColumn<NewBeautifulKiwi, Object>, TableCell<NewBeautifulKiwi, Object>>() {
#Override
public TableCell<NewBeautifulKiwi, Object> call(TableColumn<NewBeautifulKiwi, Object> param) {
final Button button;
Image image = new Image(getClass().getResourceAsStream("/MediaTools/Error.png"));
final ImageView imageView = new ImageView();
imageView.setFitHeight(16);
imageView.setFitWidth(16);
imageView.setImage(image);
button = new Button("", imageView);
final TableCell<NewBeautifulKiwi, Object> cell = new TableCell<NewBeautifulKiwi, Object>() {
#Override
public void updateItem(Object item, boolean empty) {
if (item != null) {
super.updateItem(item, empty);
final VBox vbox = new VBox(0);
button.setAlignment(Pos.CENTER);
button.maxWidth(32);
button.getStyleClass().add("deleteButton");
final TableCell<NewBeautifulKiwi, Object> c = this;
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
TableRow tableRow = c.getTableRow();
NewBeautifulKiwi item = (NewBeautifulKiwi) tableRow.getTableView().getItems().get(tableRow.getIndex());
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
NewBeautifulKiwi toDelete = (NewBeautifulKiwi) session.get(NewBeautifulKiwi.class, item);
session.delete(toDelete);
session.getTransaction().commit();
session.flush();
session.close();
System.out.println("Deleted");
}
});
vbox.getChildren().add(button);
setGraphic(vbox);
}
}
};
cell.setGraphic(button);
return cell;
}
});
});
Kiwi.setCellValueFactory(new PropertyValueFactory<NewBeautifulKiwi, String>("Kiwi"));
}
I have created a SSCCE to help with deletion of row data with a button. Please have a look at the following code :
TableViewDeleteSample
Related
I have a TableView where the last column is an "Action" column, containing a custom ActionBox object, with buttons for several actions. To add behaviour to this ActionBox, I need to pass a Data object to it. However, I don't know how to reference the object.
class TableViewWithActionColumn() {
#FXML TableColumn<Data, Void> actionColumn;
public TableViewWithActionColumn() {
// Code for loading custom component...
}
#FXML
public void initialize() {
populateActionColumn();
}
private void populateActionColumn() {
Callback<TableColumn<Data, Void>, TableCell<Data, Void>> cellFactory = new Callback<TableColumn<Data, Void>, TableCell<Data, Void>>() {
#Override
public TableCell<Data, Void> call(final TableColumn<Data, Void> param) {
return new TableCell<Data, Void>() {
private final ActionBox actionBox = new ActionBox();
#Override
public void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
setGraphic(actionBox);
}
}
};
}
};
actionColumn.setCellFactory(cellFactory);
}
}
I assumed that the reference to the object was in Void item, so I tried replacing all occurrences of Void with Data, and doing setGraphic(new ActionBox(item));, but this led to a NullPointerException, so I suppose that's not the right way to do it. So, how do I reference row's data in CellFactory context?
TableCell has a getTableRow() method, that gives you a reference to the TableRow that contains the cell. The TableRow is itself a cell implementation, so you can call its getItem() method to get the data represented by the row.
In context (and removing all the unnecessary boilerplate from your code):
private void populateActionColumn() {
actionColumn.setCellFactory(col -> new TableCell<Data, Void>() {
private final ActionBox actionBox = new ActionBox();
#Override
public void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
Data rowData = getTableRow().getItem();
// ... something like: actionBox.setData(rowData) ;
setGraphic(actionBox);
}
}
});
}
I have a JavaFX TableView populated with many TableColumns, one of which is matImageColumn. The code for it looks like:
matImageColumn.setCellFactory(new Callback<TableColumn<CustomObject, ImageView>, TableCell<CustomObject, ImageView>>() {
#Override
public TableCell call(final TableColumn<CustomObject, ImageView> param) {
final TableCell<CustomObject, ImageView> cell = new TableCell<CustomObject, ImageView>() {
ImageView img = new ImageView();
#Override
public void updateItem(ImageView item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
setText(null);
} else {
CustomObject co = getTableView().getItems().get(getIndex());
img = co.getImageViewOfMat();
setGraphic(img);
setText(null);
}
}
};
return cell;
}
});
Now as it is, I am looking to include a click event on my imageview but I am clueless from where to start.Can you show me possible solutions to this issue? Thanks in advance.
I am using a JavaFX tableview that has 5 columns (Data Type of Column): Task Id (int), Task Name (String), Task Description (String), Status (String) and Remark (String). Now, I am loading the data from a database that has the same columns and what I'm trying to do is when the user clicks on the task status column in the software the column cell changes to a Combobox (String) but the list of statuses that are displayed in the Combobox should be different depending on the selected item that the user is trying to edit (aka the status of the task)
I have tried creating a new cellFactory in the OnEdit of the column and I have also tried to override the update item method and using a boolean variable I would set whether to set the graphic to a Combobox or not
myStatusColumn.setOnEditStart(new EventHandler<TableColumn.CellEditEvent<Task, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Task, String> event) {
try {
dataBeingEdited = true;
Task task = myTasksTable.getSelectionModel().getSelectedItem();
statuses = Login.dbHandler.getStatuses(task.getTaskTypeID());
myStatusColumn.setCellFactory(new Callback<TableColumn<Task, String>, TableCell<Task, String>>() {
#Override
public TableCell<Task, String> call(TableColumn<Task, String> param) {
return new TableCell<Task,String>(){
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if(empty)
setGraphic(null);
else
{
if(dataBeingEdited)
{
ComboBox<String> comboBox = new ComboBox<>(statuses);
setGraphic(comboBox);
}
}
}
};
}
});
} catch (SQLException e) {
e.printStackTrace();
}
}
});
I expect the output to be a Combobox when I double click on the status column but I am not getting a Combobox to appear and when I get
so far I have not found a way to directly use the ComboBoxTableCell class but what I did is redesigned my own using the CellFactory. What I did was before returning the Cell created in the CellFactory I set an onMouseClickedListner that will check for a double click and when the user double clicks I would get the selected item from the table and set the graphic to be a Combobox with values that depend on the row selected and the column clicked
and then I set an onKeyPressedListener that will change the item selected and then refresh the table and update the database
myStatusColumn.setCellFactory(new Callback<TableColumn<Task, String>, TableCell<Task, String>>() {
#Override
public TableCell<Task, String> call(TableColumn<Task, String> param) {
ComboBox<String> box = new ComboBox<>();
TableCell<Task, String> cell = new TableCell<Task, String>() {
#Override
protected void updateItem(String item, boolean empty) {
if (empty)
setGraphic(null);
else {
setEditable(false);
setText(item);
}
}
};
cell.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if(event.getButton().equals(MouseButton.PRIMARY))
{
Task task = myTasksTable.getSelectionModel().getSelectedItem();
if(task!=null)
box.setItems(FXCollections.observableArrayList(task.getStatuses()));
cell.setEditable(true);
}
if(event.getClickCount()==2 && cell.isEditable() ) {
box.getSelectionModel().select(0);
cell.setText(null);
cell.setGraphic(box);
}
}
});
cell.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if(event.getCode().equals(KeyCode.ENTER))
{
try {
TaskLog taskLog = (TaskLog) myTasksTable.getSelectionModel().getSelectedItem();
if(taskLog != null) {
taskLog.setStatues(box.getSelectionModel().getSelectedItem());
taskLog.setStatuesID(Login.dbHandler.getStatusID(taskLog.getStatues()));
System.out.println(taskLog.getStatues());
Login.dbHandler.addNewTaskLog(taskLog);
cell.setEditable(false);
myTasksTable.refresh();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
});
return cell;
}
});
I have created a cellList :
I want to add a clickhandler when user clicks on button "Send"
Please Help. FieldUpdater should work if user clicks on "Send" button.
Here is the code :
final String imageHtml =AbstractImagePrototype.create(images.contact()).getHTML();
// first make a list of HasCell type - MyClass is the type of object being displayed in the CellList (could be String for simple labels)
List<HasCell<contactinfo, ?>> hasCells = new ArrayList<HasCell<contactinfo, ?>>();
hasCells.add(new HasCell<contactinfo, String>()
{
public ButtonCell cell = new ButtonCell();
public Cell<String> getCell()
{
return cell;
}
#Override
public String getValue(contactinfo object)
{
return "Send";
}
#Override
public FieldUpdater<contactinfo, String> getFieldUpdater() {
FieldUpdater< contactinfo, String > updater= new FieldUpdater<contactinfo, String>() {
#Override
public void update(int index, contactinfo object, String value) {
Window.alert("You clicked "+object.getName());
}
};
return updater;
}
}
);
// now construct the actual composite cell using the list (hasCells)
Cell<contactinfo> myClassCell = new CompositeCell<contactinfo>(hasCells)
{
#Override
public void render(Context context, contactinfo value, SafeHtmlBuilder sb)
{
sb.appendHtmlConstant("<table><tbody><tr>");
super.render(context, value, sb);
sb.appendHtmlConstant("</tr></tbody></table>");
}
#Override
protected Element getContainerElement(Element parent)
{
// Return the first TR element in the table.
return parent.getFirstChildElement().getFirstChildElement();
}
#Override
protected <X> void render(Context context, contactinfo contactinfo, SafeHtmlBuilder sb, HasCell<contactinfo, X> hasCell)
{
this renders each of the cells inside the composite cell in a new table cell
// Value can be null, so do a null check..
if (contactinfo == null) {
return;
}
sb.appendHtmlConstant("<table>");
// Add the contact image.
sb.appendHtmlConstant("<tr><td rowspan='3'>");
sb.appendHtmlConstant(imageHtml);
sb.appendHtmlConstant("</td>");
// Add the name and address.
sb.appendHtmlConstant("<td style='font-size:95%;'>");
if(contactinfo.getName()!=null)
sb.appendEscaped(contactinfo.getName());
sb.appendHtmlConstant("</td></tr><tr><td>");
if(contactinfo.getAddress()!=null)
sb.appendEscaped(contactinfo.getRemarks());
sb.appendHtmlConstant("</td>");
Cell<X> cell = hasCell.getCell();
sb.appendHtmlConstant("<td>");
cell.render(context, hasCell.getValue(contactinfo), sb);
sb.appendHtmlConstant("</td></tr></table>");
}
};
// then make the actual cellList, passing the composite cell
cellList =new CellList<contactinfo>(myClassCell,KEY_PROVIDER);
// Add a selection model so we m select cells.
singleselectionModel = new SingleSelectionModel<contactinfo>(
KEY_PROVIDER);
cellList.setSelectionModel(singleselectionModel);
singleselectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
}
});
Also, I do not see in code any piece that handles event. Did you read through http://www.gwtproject.org/doc/latest/DevGuideUiCustomCells.html#cell-onBrowserEvent
Have you tried the code sample provided by GWT - http://gwt.googleusercontent.com/samples/Showcase/Showcase.html#!CwCellSampler . Browse the "Source Code" !!!
If you have not read already then you should start here # DevGuideUiCustomCells
I have a form with a checkbox column.
ArrayList<MyObject> myObjectsList = // Load from database ...
ArrayList<MyObject> selectedObjects = new ArrayList<MyObject>();
Form form = new Form("my-form");
CheckGroup<MyObject> myObjectGroup = new CheckGroup<MyObject>("object-check-group", new AbstractReadOnlyModel() {
#Override
public Object getObject() {
return selectedObjects;
}
});
WebMarkupContainer container = new WebMarkupContainer("table-container");
DataView dataView = new DataView("table-body", new ListDataProvider<MyObject>(myObjectsList)) {
public void populateItem(final Item item) {
final MyObject myObject = (MyObject) item.getModelObject();
item.add(new Check("check-box", item.getModel())); // Checkbox for each item
// And a couple more columns
}
};
container.add(dataView);
group.add(container);
form.add(group);
add(form);
Now what I would want is to update a form whenever the number of selected objects change :
item.add(new Check("check-box", item.getModel()).add(new AjaxEventBehavior("onclick") {
#Override
protected void onEvent(AjaxRequestTarget target) {
selectedObjects = (ArrayList<MyGroup>) myObjectGroup.getModelObject(); // this does not work sadly :(
// Update form elements
}
}));
Is there an easy way to achieve this with Wicket??
Add a AjaxFormChoiceComponentUpdatingBehavior to your checkgroup. The ajax will trigger everytime a check in your group is clicked.
myObjectGroup.add(new AjaxFormChoiceComponentUpdatingBehavior()
{
#Override
protected void onUpdate(AjaxRequestTarget target)
{
//update form elements
}
});