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
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 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 a CheckListView which is displaying a list of custom objects. I am trying to implement a select all/ select none option however the list View is not changing. The checkboxes only change if clicked
pendingUsers_listView.setCellFactory(new Callback<ListView<User>, javafx.scene.control.ListCell<User>>() {
#Override
public ListCell<User> call(ListView<User> listView) {
return new PendingUserCell();
}
});
Custom Cell:
public class PendingUserCell extends CheckBoxListCell<User> {
PendingUserCell() {
this.setSelectedStateCallback(new Callback<User, ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(User param) {
return new SimpleBooleanProperty(param.isApproved());
}
});
}
#Override
public void updateItem(User u, boolean empty) {
super.updateItem(u, empty);
if (empty) {
this.setText(null);
} else {
this.setText(u.getFullName() + " ( " + u.getEmail() + " )");
}
}
}
These are the functions responsible for the action
public void handleSelectAll() {
this.pendingUsers_listView.getCheckModel().checkAll();
this.pendingUsers_listView.refresh();
}
public void handleSelectNone() {
this.pendingUsers_listView.getCheckModel().clearChecks();
this.pendingUsers_listView.refresh();
}
here is the solution:
I have a Model class, that holds the information about the items in the ListView, i put there a name, that is displayed in the lisview, and a boolean property that holds the checked/unchecked value like this:
public class Model {
private StringProperty name;
private BooleanProperty selected;
public Model(String name, Boolean selected) {
this.name = new SimpleStringProperty(name);
this.selected = new SimpleBooleanProperty(selected);
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public boolean isSelected() {
return selected.get();
}
public BooleanProperty selectedProperty() {
return selected;
}
}
Then I made a custom StringConverter to convert Model to String for displaying the text in listView like this:
public class ModelConverter extends StringConverter<Model> {
#Override public String toString(Model object) {
return object.getName();
}
#Override public Model fromString(String string) {
return null;
}
}
Then in the controller I added some items to the listView and i put as first element Select All, and a listener for it. So if you check it all items became checked, if you uncheck it you all became unchecked. Here is the code:
public class TestController implements Initializable {
#FXML
private ObservableList<Model> data = FXCollections.observableArrayList();
#FXML
private ListView<Model> listView;
#Override
public void initialize(URL location, ResourceBundle resources) {
listView.setItems(data);
listView.setCellFactory(factory -> new CustomListCell(Model::selectedProperty, new ModelConverter()));
data.addAll(new Model("Select All", false), new Model("Apple", false), new Model("Orange", false),
new Model("Peach", false));
data.get(0).selectedProperty().addListener(
(observable, oldValue, newValue) -> data.forEach(item -> item.selectedProperty().set(newValue)));
}
}
So I made as simple as it can be, by using one item from the listView, but you can use many ways to select all select none, for example defining two separate checkboxes outside of listView, or a togglebutton or something else that you want, the important is to add a listener to the respective component that you want to use it for select all select none, then everything became easy I think.
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
}
});
How do I add a click handler to an ImageCell?
This is what I have:
ImageCell btn= new ImageCell();
Column<Contact,String> column = new Column<Contact,String>(btn)
{
#Override
public String getValue(Contact c)
{
return c.imageLocation;
}
};
column.setFieldUpdater(new FieldUpdater<Contact,String>()
{
public void update(int index, Contact c, String value)
{
Window.alert("clicked");
}
});
This works as well.
// clickable imageresource cell
public class ClickableImageResourceCell extends AbstractCell<ImageResource> {
private static ImageResourceRenderer renderer;
public ClickableImageResourceCell () {
super(BrowserEvents.CLICK);
if (renderer == null) {
renderer = new ImageResourceRenderer();
}
}
#Override
public void onBrowserEvent(Context context, final Element parent, ImageResource value, NativeEvent event,
ValueUpdater<ImageResource> valueUpdater) {
super.onBrowserEvent(context, parent, value, event, valueUpdater);
if (BrowserEvents.CLICK.equals(event.getType())) {
onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
#Override
public void render(com.google.gwt.cell.client.Cell.Context context,
ImageResource value, final SafeHtmlBuilder sb) {
sb.append(renderer.render(value));
}
#Override
protected void onEnterKeyDown(Context context, Element parent, ImageResource value, NativeEvent event,
ValueUpdater<ImageResource> valueUpdater) {
if (valueUpdater != null) {
valueUpdater.update(value);
}
}
}
Maybe this helps: Adding clickHandler to row in CellTable in GWT?. It's not a clickhandler on the cell, but on the cell table (or list). which is more efficient.
I resolved this issue by creating my own ButtonCell class. Following is my code:
import com.google.gwt.cell.client.AbstractSafeHtmlCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.text.shared.SafeHtmlRenderer;
import com.google.gwt.text.shared.SimpleSafeHtmlRenderer;
/**
* A {#link Cell} used to render a button.
*/
public class ClickImage extends AbstractSafeHtmlCell<String> {
/**
* Construct a new ButtonCell that will use a {#link SimpleSafeHtmlRenderer}.
*/
private String bgImage="";
public ClickImage()
{
this(SimpleSafeHtmlRenderer.getInstance());
}
public ClickImage(String bgImage)
{
this(SimpleSafeHtmlRenderer.getInstance());
this.bgImage=bgImage;
}
public String getBgImage()
{
return bgImage;
}
public void setBgImage(String bgImage)
{
this.bgImage = bgImage;
}
/**
* Construct a new ButtonCell that will use a given {#link SafeHtmlRenderer}.
*
* #param renderer a {#link SafeHtmlRenderer SafeHtmlRenderer<String>} instance
*/
public ClickImage(SafeHtmlRenderer<String> renderer) {
super(renderer, "click", "keydown");
}
#Override
public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("click".equals(event.getType())) {
onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
#Override
public void render(Context context, SafeHtml data, SafeHtmlBuilder sb)
{
String img=getBgImage();
String disableButton="";
if(img.equals("transparentButton"))
{
disableButton = "disabled=\"disabled\"";
}
sb.appendHtmlConstant("<button class=\""+img+"\" type=\"button\" "+disableButton+" tabindex=\"-1\">");
if (data != null) {
sb.append(data);
}
sb.appendHtmlConstant("</button>");
}
#Override
protected void onEnterKeyDown(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
if (valueUpdater != null) {
valueUpdater.update(value);
}
}
}
So I used a button to show the image. I used css to make the background color for the button to be transparent and also, I'm passing the link to the image as a parameter to the constructor when the button is being created, that way I can create different clickable images. This worked for me!
addButtonCell("resources/ui/images/download.png", "Download", "download");
private void addButtonCell(final String imageSrc, String columnName, final String action)
{
ActionCell<AttachmentDTO> imageButtonCell = new ActionCell<AttachmentDTO>("", new Delegate<AttachmentDTO>()
{
#Override
public void execute(final AttachmentDTO object)
{
if(action.equalsIgnoreCase("download"))
{
download(object);
}
else
{
eventBus.fireEvent(new ImgButtonClickEvent(object));
}
}
})
{
#Override
public void render(Context context, AttachmentDTO value, SafeHtmlBuilder sb)
{
Image icon = new Image(imageSrc);
SafeHtmlBuilder builder = new SafeHtmlBuilder();
builder.appendHtmlConstant(icon.toString());
sb.append(builder.toSafeHtml());
}
};
final Column<AttachmentDTO, AttachmentDTO> column = new Column<AttachmentDTO, AttachmentDTO>(imageButtonCell)
{
#Override
public AttachmentDTO getValue(AttachmentDTO object)
{
return object;
}
};
cellTable.addColumn(column, columnName);
column.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
cellTable.setColumnWidth(column, "80px");
}