combo box autocomplete - gwt

Is there anyway to have the autocomplete for a combo box to start from anywhere in the text, let me give you an example. If I have someone named john smith in the combobox if I start with the letter 'j' it pulls up john smith but less say I want to start with the letter 's' to search for his last name, is that possible, if so does anyone have code or a link to code that does this.

Have you looked at SuggestBox? The MultiWordSuggestOracle that feeds the data to the suggest box seems to do exactly what you want - see the javadocs for usage and examples.
Update: Here's a rather nice example of customizing GWT's SuggestBox to look like the one on Facebook: http://raibledesigns.com/rd/entry/creating_a_facebook_style_autocomplete Be sure to follow all the links in that tutorial, as they contain a lot of info about using the SuggestBox.

I been have any problems with AdvancedComboBoxExample sencha
http://www.sencha.com/examples/#ExamplePlace:advancedcombobox
I found in this link http://www.sencha.com/forum/showthread.php?222543-CRTL-C-triggers-a-reload-of-data-in-Combobox the response for my problem.
I had to make some adjustments to my code. Below is the code for those who need it.
ComboBox ajax without paging:
import com.extjs.gxt.ui.client.data.*;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.List;
import java.util.Map;
public class AjaxComboBox<T extends ModelData> extends ComboBox<T> {
public AjaxComboBox() {
}
public interface GetDataCallback<T> {
void getData(String query, AsyncCallback<List<T>> dataCallback);
}
public AjaxComboBox(final String displayField, final int minChars, final GetDataCallback<T> getDataCallback) {
final RpcProxy<ListLoadResult<T>> proxy = new RpcProxy<ListLoadResult<T>>() {
#Override
protected void load(final Object loadConfig, final AsyncCallback<ListLoadResult<T>> callback) {
ListLoadConfig load = (ListLoadConfig) loadConfig;
final Map<String, Object> properties = load.getProperties();
getDataCallback.getData((String) properties.get("query"), new AsyncCallback<List<T>>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(List<T> result) {
callback.onSuccess(new BaseListLoadResult<T>(result));
}
});
}
};
final BaseListLoader<ListLoadResult<T>> loader = new BaseListLoader<ListLoadResult<T>>(proxy);
final ListStore<T> store = new ListStore<T>(loader);
setFieldLabel(displayField);
setStore(store);
setHideTrigger(true);
setMinChars(minChars);
setWidth(300);
}
}
ComboBox lazy with paging
import com.extjs.gxt.ui.client.data.*;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.Map;
public class ComboBoxLazy<T extends ModelData> extends ComboBox<T> {
public interface GetPagingDataCallback<T> {
void getData(String query, PagingLoadConfig loadConfig,
AsyncCallback<PagingLoadResult<T>> dataCallback);
}
public ComboBoxLazy(final String displayField, final int minChars,
final GetPagingDataCallback<T> getDataCallback) {
final RpcProxy<PagingLoadResult<T>> proxy = new RpcProxy<PagingLoadResult<T>>() {
#Override
protected void load(Object loadConfig,
final AsyncCallback<PagingLoadResult<T>> callback) {
final Map<String, Object> properties = ((PagingLoadConfig) loadConfig).getProperties();
getDataCallback.getData((String) properties.get("query"),
((PagingLoadConfig) loadConfig),
new AsyncCallback<PagingLoadResult<T>>() {
#Override
public void onSuccess(
final PagingLoadResult<T> result) {
callback.onSuccess(result);
}
#Override
public void onFailure(Throwable caught) {
callback.onFailure(caught);
}
});
}
};
ModelReader reader = new ModelReader();
final BasePagingLoader<PagingLoadResult<T>> loader = new BasePagingLoader<PagingLoadResult<T>>(
proxy, reader);
loader.addListener(Loader.BeforeLoad, new Listener<LoadEvent>() {
public void handleEvent(LoadEvent be) {
be.<ModelData>getConfig().set("start",
be.<ModelData>getConfig().get("offset"));
}
});
setFieldLabel(displayField);
final ListStore<T> store = new ListStore<T>(loader);
setStore(store);
setHideTrigger(true);
setMinChars(minChars);
setPageSize(10);
setWidth(300);
}
}
Class Test
import br.ueg.escala.client.view.ConversorBeanModel;
import com.extjs.gxt.ui.client.data.*;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.VerticalPanel;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.List;
public class ComboBoxTest extends LayoutContainer {
#Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
criarComboBox();
criarComboBoxLazy();
}
private void criarComboBox() {
final AjaxComboBox<BeanModel> combo = new AjaxComboBox<BeanModel>("name", 3, new AjaxComboBox.GetDataCallback<BeanModel>() {
public void getData(String query, final AsyncCallback<List<BeanModel>> dataCallback) {
servico.loadLike(query, new AsyncCallback<List<Person>>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(List<Person> result) {
List<BeanModel> dados = ConversorBeanModel.getListBeanModel(result);
dataCallback.onSuccess(dados);
}
});
}
});
combo.addSelectionChangedListener(new SelectionChangedListener<BeanModel>() {
#Override
public void selectionChanged(SelectionChangedEvent<BeanModel> se) {
BeanModel bm = combo.getView().getSelectionModel().getSelectedItem();
Person p = bm.getBean();
combo.setValue(bm);
try {
combo.setValue(bm);
combo.setRawValue(p.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
});
combo.setItemSelector("div.search-item");
combo.setTemplate(getTemplate());
addText("Any text");
add(combo);
}
private void criarComboBoxLazy() {
String field = "name";
final ComboBoxLazy<BeanModel> comboLazy = new ComboBoxLazy<BeanModel>(field, 3, new ComboBoxLazy.GetPagingDataCallback<BeanModel>() {
public void getData(String query, PagingLoadConfig loadConfig, final AsyncCallback<PagingLoadResult<BeanModel>> dataCallback) {
final PagingLoadConfig load = (PagingLoadConfig) loadConfig;
servico.loadLike(load, new Person(), "name", query, new AsyncCallback<List>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(List result) {
PagingLoadResult<BeanModel> dados = ConversorBeanModel.getPagingLoadResultBeanModel(result, load);
dataCallback.onSuccess(dados);
}
});
}
});
comboLazy.addSelectionChangedListener(new SelectionChangedListener<BeanModel>() {
#Override
public void selectionChanged(SelectionChangedEvent<BeanModel> se) {
BeanModel bm = comboLazy.getView().getSelectionModel().getSelectedItem();
Person p = bm.getBean();
comboLazy.setValue(bm);
try {
comboLazy.setValue(bm);
comboLazy.setRawValue(p.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
});
comboLazy.setItemSelector("div.search-item");
comboLazy.setTemplate(getTemplate());
VerticalPanel vp2 = new VerticalPanel();
vp2.setSpacing(10);
vp2.addText("<span class='text'><b>Combo lazy</span>");
vp2.add(comboLazy);
add(vp2);
}
private native String getTemplate() /*-{
return [ '<tpl for="."><div class="search-item">',
' <h3> <span> Name:</span> <span style="font-weight:normal;">{name}</span> ',
' <span> - Last name:</span> <span style="font-weight: normal">{lastName}</span></h3>', '</div></tpl>'].join("");
}-*/;
}
Application.css:
.searchItem {
font: normal 11px tahoma, arial, helvetica, sans-serif;
padding: 3px 10px 3px 10px;
white-space: normal;
color: #555;
}
.searchItem h3 {
display: block;
font: inherit;
font-weight: bold;
color: #222;
}
.searchItem h3 span {
float: right;
font-weight: normal;
margin: 0 0 5px 5px;
width: 100px;
display: block;
clear: none;
}
Code server
public List loadLike(PagingLoadConfig config, Person classe, String field, String query) {
List<Person> list = null;
try {
List listEntity = genericoBC.loadLike(config.getOffset(), config.getLimit(), field, query, classe.getClass());
list = clone(listEntity);
final int totalCount = genericoBC.contarRegistros(classe.getClass());
config.setLimit(totalCount);
} catch (Exception e) {
tratarExcecao("", e);
}
return list;
}
public List<Person> loadLike(String query) {
List<Person> list = null;
try {
List<Person> listEntity = genericoBC.loadLike(query);
list = clone(listEntity);
} catch (Exception e) {
tratarExcecao("Error:genericoBC.loadLike(query)", e);
}
return list;
}

Override the method boolean isFiltered(ModelData record, String property) of the ListStore of the combobox.The method body will be following:
if (filterBeginsWith != null && property != null) {
Object o = record.get(property);
if (o != null) {
if (!o.toString().toLowerCase().contains(filterBeginsWith.toLowerCase())) {
return true;
}
}
}
if (filters != null) {
for (StoreFilter filter : filters) {
boolean result = filter.select(this, record, record, property);
if (!result) {
return true;
}
}
}
return false;

This is for GXT 3.0.
First, create an instance of the overridden ListStore class like this:
public static class MyListStore extends ListStore<Course>{
private String userText="";
public MyListStore(ModelKeyProvider<Course> k){
super(k);
}
#Override
protected boolean isFilteredOut(Course item) {
boolean result = false;
if(item.getTitle()!=null &&
!item.getTitle().toUpperCase().contains(userText.toUpperCase())){
result = true;
}
return result;
}
public void setUserText(String t){ userText = t; }
}
In this case, I had a Course model class that had the course title (a string) as the label provider for the combobox. So in your overridden class, do similar: use your specific model (the type of this instance of the combobox) in place of 'Course' in the code above.
Next, create an instance of this store for use by the combobox:
private MyListStore courses ;
Next, make sure you initialize the combobox appropriately with this. In my case, I used uibinder, so my initializer is this:
#UiFactory
ListStore<Course> createListStore() {
courses = new MyListStore(courseProps.key());
return courses;
}
The relevant uibinder snippets:
<ui:with type="com.sencha.gxt.data.shared.LabelProvider" field="titles"/>
<ui:with type="com.sencha.gxt.data.shared.ListStore" field="courses"/>
...
<form:ComboBox ui:field="classTitle" store="{courses}" labelProvider="{titles}"
allowBlank="false" forceSelection="true" triggerAction="ALL" width="200" />
Of course, the linkage into your bound java class:
#UiField ComboBox<Course> classTitle;
And, finally, make sure you handle the keyup event from the combobox input:
classTitle.addKeyUpHandler(new KeyUpHandler(){
#Override
public void onKeyUp(KeyUpEvent event) {
courses.setUserText(classTitle.getText());
}
});
This worked perfectly (first time!).

Related

ListView validate edit and prevent commit

I'm using an editable ListView containing Patterns.
The user can see and edit the regexs in the list, and I'd like to validate whether the regex is syntactically correct before committing the value (and give feedback like a red border to the user).
Is there a way to do so?
patternList.setCellFactory(TextFieldListCell.forListView(new StringConverter<Pattern>() {
#Override
public String toString(Pattern pattern) {
return pattern.toString();
}
#Override
public Pattern fromString(String string) {
try {
return Pattern.compile(string);
} catch (PatternSyntaxException e) {
return null;
}
}
}));
patternList.setOnEditCommit(e -> {
if (e.getNewValue() == null) {
// TODO pattern syntax error, prevent commit and stay in edit mode
} else {
patternList.getItems().set(e.getIndex(), e.getNewValue());
}
});
I would do this by creating a TableCell implementation. E.g.:
import java.util.function.Predicate;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.css.PseudoClass;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
public class ValidatingEditingCell<S> extends TableCell<S, String> {
private final TextField textField ;
private static final PseudoClass INVALID = PseudoClass.getPseudoClass("invalid");
private BooleanProperty valid = new SimpleBooleanProperty();
public ValidatingEditingCell(Predicate<String> validator) {
this.textField = new TextField();
valid.bind(Bindings.createBooleanBinding(() -> textField.getText() != null && validator.test(textField.getText()),
textField.textProperty()));
valid.addListener((obs, wasValid, isValid) -> {
pseudoClassStateChanged(INVALID, ! isValid);
});
pseudoClassStateChanged(INVALID, ! valid.get());
textField.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
if (e.getCode() == KeyCode.ENTER && valid.get()) {
commitEdit(textField.getText());
}
if (e.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
});
setGraphic(textField);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? null : item);
textField.setText(empty ? null : item);
setContentDisplay(isEditing() ? ContentDisplay.GRAPHIC_ONLY : ContentDisplay.TEXT_ONLY);
}
#Override
public void cancelEdit() {
super.cancelEdit();
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
#Override
public void commitEdit(String newValue) {
super.commitEdit(newValue);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
#Override
public void startEdit() {
super.startEdit();
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
textField.selectAll();
textField.requestFocus();
}
}
This takes a predicate as an argument; the predicate returns true for valid text and false for invalid text. It sets a CSS pseudoclass on the cell, so you can use CSS to style the text field (or cell itself, if needed).
Here's a simple example which validates three different columns differently:
import java.util.function.Function;
import java.util.function.Predicate;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class ValidatingTableExample extends Application {
private static <S> TableColumn<S, String> column(String title, Function<S, StringProperty> property,
Predicate<String> validator) {
TableColumn<S, String> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
col.setCellFactory(tc -> new ValidatingEditingCell<>(validator));
col.setPrefWidth(150);
return col ;
}
#Override
public void start(Stage primaryStage) {
TableView<Address> table = new TableView<>();
table.setEditable(true);
table.getColumns().add(column("City", Address::cityProperty, s -> ! s.isEmpty()));
table.getColumns().add(column("State", Address::stateProperty, s -> s.length()==2));
table.getColumns().add(column("Zip", Address::zipProperty, s -> s.matches("\\d{5}")));
Button newAddress = new Button("Add");
newAddress.setOnAction(e -> {
table.getItems().add(new Address("City", "State", "Zip"));
});
Button debug = new Button("Debug");
debug.setOnAction(e ->
table.getItems().stream()
.map(address -> String.format("%s, %s %s", address.getCity(), address.getState(), address.getZip()))
.forEach(System.out::println));
HBox buttons = new HBox(5, newAddress, debug);
buttons.setAlignment(Pos.CENTER);
buttons.setPadding(new Insets(5));
BorderPane root = new BorderPane(table, null, null, buttons, null);
Scene scene = new Scene(root, 600, 600);
scene.getStylesheets().add(getClass().getResource("validating-cell.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Address {
private final StringProperty city = new SimpleStringProperty();
private final StringProperty state = new SimpleStringProperty();
private final StringProperty zip = new SimpleStringProperty();
public Address(String city, String state, String zip) {
setCity(city);
setState(state);
setZip(zip);
}
public final StringProperty cityProperty() {
return this.city;
}
public final String getCity() {
return this.cityProperty().get();
}
public final void setCity(final String city) {
this.cityProperty().set(city);
}
public final StringProperty stateProperty() {
return this.state;
}
public final String getState() {
return this.stateProperty().get();
}
public final void setState(final String state) {
this.stateProperty().set(state);
}
public final StringProperty zipProperty() {
return this.zip;
}
public final String getZip() {
return this.zipProperty().get();
}
public final void setZip(final String zip) {
this.zipProperty().set(zip);
}
}
public static void main(String[] args) {
launch(args);
}
}
and some sample CSS:
.table-cell:invalid .text-field {
-fx-focus-color: red ;
-fx-control-inner-background: #ffc0c0 ;
-fx-accent: red ;
}
I finally found a way, by overriding the commitEdit() method of TextFieldListCell:
patternList.setCellFactory(l -> new TextFieldListCell<Pattern>(new StringConverter<Pattern>() {
#Override
public String toString(Pattern pattern) {
return pattern.toString();
}
#Override
public Pattern fromString(String string) {
try {
return Pattern.compile(string);
} catch (PatternSyntaxException e) {
return null;
}
}
}) {
#Override
public void commitEdit(Pattern pattern) {
if (!isEditing()) return;
PseudoClass errorClass = PseudoClass.getPseudoClass("error");
pseudoClassStateChanged(errorClass, pattern == null);
if (pattern != null) {
super.commitEdit(pattern);
}
}
});
patternList.setOnEditCommit(e -> patternList.getItems().set(e.getIndex(), e.getNewValue()));

Dynamic styling with IceFaces: how can I change the color of the outputText at the time of rendering?

I'm new to ICEFaces and I have to maintain someone else's code. I'm working on a web chat where the user can send and receive messages. I would like the messages to have different colors depending on whether they were sent by the user or by someone else.
I currently have the following code in my xhtml file:
<h:dataTable id="history" value="#{chatBean.messages}" var="message" border="0" align="left" style="width: 100%" >
<h:column width="590" height="25" align="left" valign="bottom" >
<h:outputText value="#{message}" styleClass="#{chatBean.messageColor}" />
</h:column>
</h:dataTable>
This shows all messages sent and received, but all with the same color, even though the messageColor property of the chat bean changes: I did an experiment and appended the result of getMessageColor() at the end of each message and it does change, but the text is still rendered in the same color.
The CSS has the following classes (among others):
.class1
{
color:#818181;
width: 100%;
font-size: 15px;
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
}
.class2
{
color:#00657c;
width: 100%;
font-size: 15px;
font-family: Arial, Helvetica, sans-serif;
font-weight: bold;
}
Here's the code for the ChatBean class:
#ManagedBean(name = "chatBean")
#SessionScoped
public class ChatBean implements Serializable {
private static final long serialVersionUID = -12636320254821872L;
private static final String PUSH_GROUP = "chatPage";
private PortableRenderer renderer;
private String message;
private String lastMessageSent = "";
private Date lastMessageTime = new Date();
private String isDown = "false";
private List<String> messages = new ArrayList<String>();
private String buttonDisabled = "true";
private String buttonCancelDisabled = "true";
private String pollDisabled = "false";
private String id = "";
private ChatClient chat;
private Timer timer = new Timer();
private String messageColor;
public class ChatThread extends Thread implements Serializable {
private static final long serialVersionUID = -7636532554421738019L;
private Map<String, String> data;
private String mail;
public ChatThread(final Map<String, String> data, final String mail) {
this.data = data;
this.mail = mail;
}
#Override
public void run() {
chat = new ChatClient(new ChatClient.Event() {
#Override
public void handle(String msg) {
if(msg != null && msg.length() > 0)
pushMessage(msg);
}
#Override
public void agentConnected(String msg) {
buttonDisabled = "false";
buttonCancelDisabled = "false";
pushMessage(msg);
}
#Override
public void agentDisconnected(String msg) {
buttonDisabled = "true";
pushMessage(msg);
try {
timer.cancel();
} catch (Exception e) {
e.printStackTrace();
}
}
});
chat.login(mail, data);
chat.join(mail, data.get("partner"), data.get("business"));
timer.scheduleAtFixedRate(new RefreshTimerTask(), 0, 1000);
}
}
public class RefreshTimerTask extends TimerTask implements Serializable {
private static final long serialVersionUID = 1852678537009150141L;
public void run() {
chat.refresh();
}
}
public ChatBean() {
if(getSession() != null) {
id = getSession().getId();
PushRenderer.addCurrentSession(PUSH_GROUP + id);
renderer = PushRenderer.getPortableRenderer();
setMessageColor("class1");
Log.getLogger().debug("New chat bean.");
if(getData().containsKey("login_chat")) {
ChatThread chat = new ChatThread(getData(), getSessionAttribute(GenesysSingleton.getInstance().getConfigApp().getDisplayName(), "<mail>"));
chat.start();
}
}
}
private void pushMessage(String msg) {
if(msg != null && !msg.isEmpty()) {
ChatBean.this.isDown = "true";
messages.add(msg);//Acá se puede acceder a textColor.
try {
PushRenderer.render(PUSH_GROUP + id);
} catch (Exception e) {
renderer.render(PUSH_GROUP + id);
}
setMessageColor("class1");
}
}
private String getSessionAttribute(String key, String ref) {
Object value = getSession().getAttribute(key);
return value != null ? value.toString() : ref;
}
private Map<String, String> getData() {
Map<String, String> data = new HashMap<String, String>();
HttpSession session = getSession();
#SuppressWarnings("rawtypes")
Enumeration enums = session.getAttributeNames();
while(enums.hasMoreElements()) {
String key = enums.nextElement().toString();
if(!"com.sun.faces.application.view.activeViewMaps".equals(key)
&& !"com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap".equals(key)
&& !"javax.faces.request.charset".equals(key))
data.put(key, session.getAttribute(key).toString());
}
return data;
}
public void sendMessage(ActionEvent event) {
sendMessage();
}
protected synchronized void sendMessage() {
if (message != null && !message.trim().isEmpty()){
Date now = new Date();
//No permito mandar el mismo mensaje 2 veces seguidas en un intervalo menor a un segundo.
message = message.trim();
if (message.equals(lastMessageSent)&&(now.getTime()<(1000+lastMessageTime.getTime()))){
message = null;
}
else{
setMessageColor("class2");
lastMessageSent = message;
message = null;
lastMessageTime = new Date();
chat.refresh(lastMessageSent);
}
}
}
public String disconnect() {
pollDisabled = "true";
return "login";
}
public void sendClose(ActionEvent event) {
}
public void receiveMessage() {
}
#PreDestroy
public void destroy() {
buttonDisabled = "true";
try {
//pushMessage(SISTEMA_3);
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
};
System.out.println(id + "- ssssssss");
try {
timer.cancel();
} catch (Exception e) {
}
chat.logout();
chat.close();
}
private HttpSession getSession() {
return (HttpSession) getContext().getSession(false);
}
private ExternalContext getContext() {
return getFacesContext().getExternalContext();
}
private FacesContext getFacesContext() {
return FacesContext.getCurrentInstance();
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getButtonDisabled() {
return buttonDisabled;
}
public void setButtonDisabled(String buttonDisabled) {
this.buttonDisabled = buttonDisabled;
}
public List<String> getMessages() {
try {
JavascriptContext.addJavascriptCall(getFacesContext(), "document.getElementById('scrollDataTable').scrollIntoView();");
} catch (Exception e) {
e.printStackTrace();
}
return messages;
}
public void setMessages(List<String> messages) {
this.messages = messages;
}
public String getPollDisabled() {
return pollDisabled;
}
public void setPollDisabled(String pollDisabled) {
this.pollDisabled = pollDisabled;
}
public String getButtonCancelDisabled() {
return buttonCancelDisabled;
}
public void setButtonCancelDisabled(String buttonCancelDisabled) {
this.buttonCancelDisabled = buttonCancelDisabled;
}
public String getIsDown() {
return isDown;
}
public void setIsDown(String isDown) {
this.isDown = isDown;
}
public String getMessageColor() {
return messageColor;
}
public void setMessageColor(String textColor) {
this.messageColor = textColor;
}
}
All help will be appreciated. Thank you in advance.
One possible way which I have changed css dynamically depending on a bean property is through using the styleClass attribute of the <h:outputText>.
In your css file define two varying classes such as
.class1
{
color:red; //Put your colour here (#818181)
}
.class2
{
color:green; //Put your colour here (#00657c)
}
Then in your java bean code you could declare a String field with getters and setters such as
private String messageColor;
Then in your code where you do
setTextColor(COLOR_AGENTE);
You can change this to the class which you would like to change the text to such as:
setMessageColor("class1");
Then on your <h:outputText> attach
styleClass="#{chatBean.messageColor}"
This should hopefully work;
Due to my original suggestion not working, you could try this.
Remove private String messageColor; from you chatBean and the getters/setters along with any calls to setMessageColor("class1");.
But keep the two classes in your css.
Now declare a boolean property with getters and setters in your chatBean:
private boolean colourAgente;
Declare a method:
public String setColor() {
if (colourAgente) {
return "class1";
} else {
return "class2";
}
}
Then in your xhtml change the styleClass attribute to:
styleClass="#{chatBean.setColor()}"
Finally, in your java code change:
setMessageColor("class1");
to either colourAgente = true; or colourAgente=false; depending on what colour you want to set.
I finally did it, but I had to use an ugly JavaScript workaround. That is, I'm now running this script every time the chat is refreshed:
function updateColors(){
var username = document.getElementById("form:username").value;
if (username.length > 0){
var x = document.getElementsByClassName("class1");
if (x != null){
for (i = 0; i < x.length; i++){
if (x[i].innerHTML.indexOf(username) === 0){
x[i].className = "class2";
}
}
}
}
}
Anyway, thanks for your help, LiamWilson94. I still don't know what part of the code I'm working with makes it so that your answers don't work, but you have given me a lot of insight which helped me arrive to this "solution", and I have learnt a few things about IceFaces in the process.
OK, I have found a better solution.
I created a TextModel class:
import java.io.Serializable;
public class TextModel implements Serializable {
private static final long serialVersionUID = -8470475291191399871L;
private String text;
private String clase;
public TextModel() {
}
public TextModel(String text, String clase) {
this.text = text;
this.clase = clase;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getClase() {
return clase;
}
public void setClase(String clase) {
this.clase = clase;
}
public String toString() {
return text;
}
}
Then I changed messages in ChatBean from List to List, and changed the following functions in ChatBean.java:
private void pushMessage(String msg) {
if(msg != null && !msg.isEmpty()) {
ChatBean.this.isDown = "true";
messages.add(new TextModel(msg,clase));
try {
PushRenderer.render(PUSH_GROUP + id);
} catch (Exception e) {
renderer.render(PUSH_GROUP + id);
}
clase = "class1";
}
}
protected synchronized void sendMessage() {
if (message != null && !message.trim().isEmpty()){
Date now = new Date();
message = message.trim();
if (message.equals(lastMessageSent)&&(now.getTime()<(1000+lastMessageTime.getTime()))){
message = null;
}
else{
clase = "class2";
lastMessageSent = message;
message = null;
lastMessageTime = new Date();
chat.refresh(lastMessageSent);
}
}
}
Where clase is either "class1" or "class2" (could be neater, but it works for now, I can always make it neater later).
Finally, on chat.xhtml, I changed the outputtext tag to:
<h:outputText value="#{message.text}" styleClass="#{message.clase}" />
That's it. No more messy JavaScript patches.
The trick was making the class a property of the message itself rather than the ChatBean.
I hope this helps someone else in the future.

Javafx Combobox list index set to -1 when executing combobox.get(someobject)

I have a combo box that is populated with the following ObservableList:
final ObservableList<SimplePerson> persons = FXCollections.observableArrayList(
new SimplePerson("Jacob", 1),
new SimplePerson("Isabella", 2),
new SimplePerson("Ethan", 3),
new SimplePerson("Emma", 4),
new SimplePerson("Michael", 5)
);
The combobox's selected index will be set to -1, the combobox's textbox will be populated with "Michael", and the "Michael" item in the drop down list will not be selected when I run
setValue(new SimplePerson("Michael",5))
Here is some example code (SSCCE)
import javafx.application.Application;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.property.IntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
import javafx.util.StringConverter;
import javafx.util.Callback;
import javafx.scene.control.ListView;
import javafx.scene.control.ListCell;
public class ComboBoxDemo extends Application {
public class SimplePerson {
private StringProperty name;
private IntegerProperty id;
private String somethingElse;
public SimplePerson(String name, Integer id) {
setName(name);
setId(id);
}
public final void setName(String value) {
nameProperty().set(value);
}
public final void setId(Integer id) {
idProperty().set(id);
}
public String getName() {
return nameProperty().get();
}
public int getId() {
return idProperty().get();
}
public StringProperty nameProperty() {
if (name == null) {
name = new SimpleStringProperty(this, "name");
}
return name;
}
public IntegerProperty idProperty() {
if (id == null) {
id = new SimpleIntegerProperty(this, "id");
}
return id;
}
#Override
public String toString() {
return name.get();
}
}
final ObservableList<SimplePerson> persons = FXCollections.observableArrayList(
new SimplePerson("Jacob", 1),
new SimplePerson("Isabella", 2),
new SimplePerson("Ethan", 3),
new SimplePerson("Emma", 4),
new SimplePerson("Michael", 5)
);
#Override
public void start(Stage stage) throws Exception {
final ComboBox<SimplePerson> cb = new ComboBox<>();
final ComboBox<String> cb2 = new ComboBox<>();
cb.setItems(persons);
cb.setEditable(true);
cb.setConverter(new StringConverter<SimplePerson>() {
#Override
public String toString(SimplePerson p) {
if (p != null) {
System.out.println("Looking up toString " + p.getName());
return p.getName();
} else {
System.out.println("Looking up toString null");
return "";
}
}
#Override
public SimplePerson fromString(String name) {
if (cb.getValue() != null) {
((SimplePerson) cb.getValue()).setName(name);
cb.show();
System.out.println("Here I am" + ((SimplePerson) cb.getValue()).getName());
return (SimplePerson) cb.getValue();
}
System.out.println("Returning null");
return null;
}
});
stage.setScene(new Scene(cb));
stage.show();
cb.setCellFactory(new Callback<ListView<SimplePerson>, ListCell<SimplePerson>>() {
#Override
public ListCell<SimplePerson> call(ListView<SimplePerson> l) {
return new ListCell<SimplePerson>() {
#Override
protected void updateItem(SimplePerson item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
System.out.println("I'm null");
} else {
System.out.println("Go get them " + item.getName());
setText(item.getName());
}
}
};
}
});
cb.setValue(new SimplePerson("Michael", 5));
System.out.println(cb.getSelectionModel().getSelectedIndex());
System.out.println(cb.getValue().getName());
}
public static void main(String[] args) {
launch(args);
}
}
The drop down list will select the right item when the ObservableList contains Strings
ObservableList<String>
You are passing a new Object to setValue() into the ComboBox. The Michael that is displayed when the ComboBox pops up is not same as the Michael in the dropdown.
If you pass cb.setValue(new SimplePerson("xyz", 5)); then the ComboBox will show the initially selected item as xyz, where xyz is not in the List of Person.
To set the exact object, you need to fetch them from their original reference, which in your case is the ObservableList<SimplePerson> persons. To fetch Michael, we use its index :
cb.setValue(persons.get(4));

GWT : Simple Chat Application for multiple-tab

Sorry for my too long question. I am totally a newbie on GWT and I have still less experiences.I would like to create simple chat application using GWT.
I found for a link simple java chat application using java+servlet+jsp from this. I refrenced it and converted to GWT compactable codes. (I deployed it on http://gwt-chatting-test.appspot.com using GAE). I believe my codes may have plenty of weak points and security holes but I have less experience to handle them .(If you found , pls correct me kindfully).
I would like to describe full of my codes. I used servlet 2.4 , GWT 2.5 ,UI Binder and other required libs.
1) . For Login page
Index.ui.xml
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:d="urn:import:com.google.gwt.dom.client">
<ui:style>
.important {
font-weight: bold;
}
.lblUserName {
margin-right: 3px;
}
</ui:style>
<g:HTMLPanel>
<center>
<g:HorizontalPanel>
<g:Label ui:field="lblUserName" text="User Name : " styleName="{style.lblUserName}"/><g:TextBox height="15px" ui:field="txtUserName"/>
<g:Button styleName="{style.important}" text="Login" ui:field="btnLogin" />
</g:HorizontalPanel>
</center>
</g:HTMLPanel>
Index.java
public class Index extends Composite {
interface IndexUiBinder extends UiBinder<Widget, Index> {}
private static IndexUiBinder uiBinder = GWT.create(IndexUiBinder.class);
#UiField Button btnLogin;
#UiField TextBox txtUserName;
private ChatServiceAsync chatService = GWT.create(ChatService.class);
public Index() {
initWidget(uiBinder.createAndBindUi(this));
}
#UiHandler("btnLogin")
void onClick(ClickEvent e) {
login();
}
#UiHandler("txtUserName")
void onKeyDown(KeyDownEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
if (txtUserName.getText().trim().length() == 0) {
Window.alert("Enter your name for chat-room !");
}
else {
login();
}
}
}
private void login() {
AsyncCallback<String> callback = new AsyncCallback<String>() {
#Override
public void onSuccess(String result) {
RootPanel.get().clear();
RootPanel.get().add(new Chat());
}
#Override
public void onFailure(Throwable caught) {
System.err.println(caught.getMessage());
}
};
chatService.login(txtUserName.getText(), callback);
}
}
2) . For Chatting Page
Chat.ui.xml
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:style>
.main {
height: 420px;
border: 1px solid silver;
padding: 2px;
width: 620px;
margin-bottom: 5px;
}
.txtInputMsg {
margin-right: 3px;
width : 560px;
height :25px;
}
</ui:style>
<g:HTMLPanel>
<center>
<g:VerticalPanel>
<g:ScrollPanel styleName="{style.main}" height="420px" width="620px" ui:field="pnlMain">
<g:VerticalPanel ui:field="pnlMessage"/>
</g:ScrollPanel>
<g:HorizontalPanel ><g:TextBox styleName="{style.txtInputMsg}" ui:field="txtInputMsg"/><g:Button ui:field="btnLogout" text="Logout"/></g:HorizontalPanel>
</g:VerticalPanel>
</center>
</g:HTMLPanel>
Chat.java
public class Chat extends Composite {
public interface MessageTemlate extends SafeHtmlTemplates {
#Template("<div class =\"{2}\"><div class = \"msgTitle\"> {0}</div><div class=\"msgDescription\">{1}</div></div>")
SafeHtml getFormattedMessage(String name, SafeHtml message, String backgroundColor);
#Template("<div class =\"loginInform\"><span class=\"userName\">{0}</span> has been joined to this conversation !</div>")
SafeHtml notifyLoginUser(String userName);
#Template("<div class =\"logoutInform\"><span class=\"userName\">{0}</span> has been left from this conversation !</div>")
SafeHtml notifyLogoutUser(String userName);
}
private static ChatUiBinder uiBinder = GWT.create(ChatUiBinder.class);
#UiField TextBox txtInputMsg;
#UiField ScrollPanel pnlMain;
#UiField VerticalPanel pnlMessage;
#UiField Button btnLogout;
private static final XMLHttpRequest request = XMLHttpRequest.create();
private static final MessageTemlate TEMPLATES = GWT.create(MessageTemlate.class);
private ChatServiceAsync chatService = GWT.create(ChatService.class);
private String loginUser;
private Timer timer;
interface ChatUiBinder extends UiBinder<Widget, Chat> {}
public Chat() {
initWidget(uiBinder.createAndBindUi(this));
pnlMessage.getElement().setAttribute("style", "width:100%");
initLoginUserName();
request.open("post", URL.encode(GWT.getModuleBaseURL()
+ "chat.do?action=login&time='" + new Date().getTime() + ""));
request.send(null);
}
#UiHandler("txtInputMsg")
void sendMessage(KeyDownEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
if (txtInputMsg.getText().trim().length() > 0) {
SafeHtml message = SafeHtmlUtils.fromTrustedString(txtInputMsg.getText());
request.open("post", URL.encode(GWT.getModuleBaseURL()
+ "chat.do?action=send&msg=" + message.asString() + "&time='" + new Date().getTime() + ""));
txtInputMsg.setText("");
pnlMessage.add(new HTML(TEMPLATES.getFormattedMessage(loginUser, message, "myMessage")));
pnlMain.scrollToBottom();
txtInputMsg.setFocus(true);
request.send(null);
}
}
}
#UiHandler("btnLogout")
void logout(ClickEvent e) {
boolean confirm = Window.confirm("Are you sure you want to logout now ?");
if (confirm) {
timer.cancel();
request.open("post", URL.encode(GWT.getModuleBaseURL()
+ "chat.do?action=logout&time='" + new Date().getTime() + ""));
request.send(null);
AsyncCallback<String> callback = new AsyncCallback<String>() {
#Override
public void onSuccess(String result) {
RootPanel.get().clear();
RootPanel.get().add(new Index());
}
#Override
public void onFailure(Throwable caught) {
System.err.println(caught.getMessage());
}
};
chatService.logOut(loginUser, callback);
}
}
private void initChatListener() {
timer = new Timer() {
#Override
public void run() {
request.open("post", URL.encode(GWT.getModuleBaseURL()
+ "chat.do?action=get&time='"
+ new Date().getTime() + ""));
request.send(null);
request.setOnReadyStateChange(new ReadyStateChangeHandler() {
#Override
public void onReadyStateChange(XMLHttpRequest xhr) {
if (xhr.getReadyState() == 4) {
if (xhr.getStatus() == 200 && xhr.getResponseText().trim().length() > 1) {
HTML html = new HTML(xhr.getResponseText().trim());
JSONValue value = JSONParser.parseLenient(html.getText());
JSONWrapper json = new JSONWrapper(value);
for (int i = 0; i < json.getValue().isArray().size(); i++) {
String[] chatData = json.get(i).getValue().toString()
.replaceAll("\"", "").split(":");
if (chatData.length >= 3) {
if (chatData[2].equals("login")) {
pnlMessage.add(new HTML(TEMPLATES.notifyLoginUser(chatData[0])));
}
else {
pnlMessage.add(new HTML(TEMPLATES.notifyLogoutUser(chatData[0])));
}
}
else {
pnlMessage.add(new HTML(TEMPLATES.getFormattedMessage(chatData[0],
SafeHtmlUtils.fromTrustedString(chatData[1]), "receivedMessage")
.asString()));
}
pnlMain.scrollToBottom();
}
}
}
}
});
}
};
timer.scheduleRepeating(1000);
}
private void initLoginUserName() {
AsyncCallback<String> callback = new AsyncCallback<String>() {
#Override
public void onSuccess(String result) {
loginUser = result;
if (loginUser == null) {
Window.alert("You need to login !");
RootPanel.get().clear();
RootPanel.get().add(new Index());
}
else {
initChatListener();
}
}
#Override
public void onFailure(Throwable caught) {
System.err.println(caught.getMessage());
}
};
chatService.getUsername(callback);
}
}
3) . Service and ServiceAsync for RPC
ChatService.java
#RemoteServiceRelativePath("chatService")
public interface ChatService extends RemoteService {
String login(String userName);
String getUsername();
String logOut(String username);
}
ChatServiceAsync.java
public interface ChatServiceAsync {
void login(String userName, AsyncCallback<String> callback);
void getUsername(AsyncCallback<String> callback);
void logOut(String username, AsyncCallback<String> callback);
}
4) . Server side control
ChatServiceImpl.java
#SuppressWarnings("serial")
public class ChatServiceImpl extends RemoteServiceServlet implements ChatService {
public String login(final String userName) {
String newUserName = userName;
HttpSession httpSession = getThreadLocalRequest().getSession();
Map<String, List<String>> chat = ChatSupport.getChattingUsers();
synchronized (chat) {
// prevent userName conflict
int i = 1;
while (chat.containsKey(newUserName)) {
++i;
newUserName = userName + "(" + i + ")";
}
chat.put(newUserName, new ArrayList<String>());
}
httpSession.setAttribute("UID", newUserName);
return "LOGIN_SUCCESS";
}
public String logOut(String username) {
// remove the mapping of user name
ChatSupport.getChattingUsers().remove(username);
getThreadLocalRequest().getSession().invalidate();
return "LOGOUT_SUCCESS";
}
public String getUsername() {
// check if there is a HTTP session setup.
HttpSession httpSession = getThreadLocalRequest().getSession(false);
if (httpSession == null) {
return null;
}
// return the user name
return (String) httpSession.getAttribute("UID");
}
}
ChatSupport.java
#SuppressWarnings("serial")
public class ChatSupport extends HttpServlet {
// message map, mapping user UID with a message list
private static Map<String, List<String>> users = new HashMap<String, List<String>>();
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String action = req.getParameter("action");
if ("login".equals(action)) {
String userName = (String) req.getSession().getAttribute("UID");
for (String key : users.keySet()) {
if (!key.equals(userName)) {
synchronized (users.get(key)) {
users.get(key).add(userName + "::login");
}
}
}
}
else if ("logout".equals(action)) {
String userName = (String) req.getSession().getAttribute("UID");
for (String key : users.keySet()) {
if (!key.equals(userName)) {
synchronized (users.get(key)) {
users.get(key).add(userName + "::logout");
}
}
}
}
// send message
else if ("send".equals(action)) {
// get param with UTF-8 enconding
String msg = new String(req.getParameter("msg").getBytes("ISO-8859-1"), "UTF-8");
String userName = (String) req.getSession().getAttribute("UID");
for (String key : users.keySet()) {
if (!key.equals(userName)) {
synchronized (users.get(key)) {
// put message to any other user's msg list
users.get(key).add(userName + ":" + msg);
}
}
}
}
else if ("get".equals(action)) { // get message
String userName = (String) req.getSession().getAttribute("UID");
if (userName == null) resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
List<String> messages = users.get(userName);
synchronized (messages) {
if (messages.size() > 0) {
// for UTF-8 chars
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
JSONArray result = new JSONArray();
// add all msg to json array and clear list
while (messages.size() > 0) {
result.add(messages.remove(0));
}
out.println(result);
out.close();
}
}
}
}
public static Map<String, List<String>> getChattingUsers() {
return users;
}
}
5) . My gwt.xml
....
<module rename-to='testing'>
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.google.gwt.user.theme.clean.Clean'/>
<inherits name="com.google.gwt.http.HTTP" />
<inherits name="com.google.gwt.json.JSON" />
<inherits name="com.pathf.gwt.util.json.jsonwrapper" />
<entry-point class='test.client.TestingEntry'/>
<source path='client'/><source path='shared'/>
</module>
6) . Servlet configurations at web.xml
<servlet>
<servlet-name>chatServlet</servlet-name>
<servlet-class>test.server.ChatServiceImpl</servlet-class>
</servlet>
<servlet>
<servlet-name>ChatServlet</servlet-name>
<servlet-class>test.server.ChatSupport</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ChatServlet</servlet-name>
<url-pattern>/testing/chat.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>chatServlet</servlet-name>
<url-pattern>/testing/chatService</url-pattern>
My program was run properly on multiple browsers but can't work on same broswer. I can't run this program by using same brower with multi-tabs. I think I am using same session and I need to create new session for every login. But I have no idea how to create it. From How to get multiple session in single browser , that may causes security problems and I shouldn't. But currently I forgot about securtiy issues.
So , How can I do for multiple-tab browser supports ?

JavaFX TableView with Custom Cell Datepicker "OnEditCommit" is not invoked

Hi everyone !!
I'm working with JavaFX and the JDK 8.
I got a TableView filled by a database with the use of a JavaFX POJO Class "Inputs". I've implemented TexField cells, ComboBoxes cells and Checkbox cells succesfully.
But I am not able to make it working with DatePicker Control: the event on the "setOnEditComit" is never invoked...
Hre is my code:
Declarations for TableColumn:
#FXML
private TableColumn<Inputs,LocalDate> colDate = new TableColumn<Inputs,LocalDate>();
[...]
colDate.setCellValueFactory(
new PropertyValueFactory<Inputs,LocalDate>("localdate"));
Callback<TableColumn<Inputs, LocalDate>, TableCell<Inputs, LocalDate>> dateCellFactory =
new Callback<TableColumn<Inputs, LocalDate>, TableCell<Inputs, LocalDate>>() {
public TableCell call(TableColumn p) {
return new EditingDatePickerCell();
}
};
[...]
colDate.setOnEditCommit(
new EventHandler<CellEditEvent<Inputs, LocalDate>>() {
#Override
public void handle(CellEditEvent<Inputs, LocalDate> event) {
System.out.println("EVENT!!!!");
((Inputs) event.getTableView().getItems().get(
event.getTablePosition().getRow())
).setDatePicker(event.getNewValue());
}
}
);
With these JavaFX POJO Objects declarations:
public ObjectProperty<LocalDate> localdate;
[...]
this.localdate = new SimpleObjectProperty<LocalDate>(localdate);
[...]
public LocalDate getDatePicker() {
return localdate.getValue();
}
[...]
public void setDatePicker(LocalDate value) {
System.out.println("EVENT!!!!");
localdate.setValue(value);
}
[...]
public ObjectProperty<LocalDate> localdateProperty() {
return localdate;
}
EditingDatePickerCell class:
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import com.desktop.newapp.utils.Inputs;
public class EditingDatePickerCell <Inputs, LocalDate> extends TableCell<Inputs, LocalDate> {
#Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createDatePicker();
setText(null);
setGraphic(datePicker);
datePicker.requestFocus();
}
}
#Override
public void cancelEdit() {
super.cancelEdit();
datePicker.setValue((java.time.LocalDate) getItem());
setGraphic(null);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
private DatePicker datePicker;
public EditingDatePickerCell() {
if (datePicker == null) {
createDatePicker();
}
setGraphic(datePicker);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
Platform.runLater(new Runnable() {
#Override
public void run() {
datePicker.requestFocus();
}
});
}
#Override
public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (datePicker != null && item != null) {
datePicker.setValue((java.time.LocalDate) getLocalDate());
commitEdit(getLocalDate());
}
setGraphic(datePicker);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
private void createDatePicker() {
datePicker = new DatePicker();
datePicker.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
setGraphic(datePicker);
datePicker.addEventFilter(KeyEvent.KEY_PRESSED,new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(getLocalDate());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
} else if (t.getCode() == KeyCode.TAB) {
commitEdit(getLocalDate());;
}
}
});
setAlignment(Pos.CENTER);
}
private LocalDate getLocalDate() {
return getItem();
///return datePicker.getValue() != null ? datePicker.getValue() : getItem();
}
}
I've been Googling a lot and I didn't find any correct implementation of the Java8 DatePicker Editing capabilities in a JavaFX TableView. Any help would be very appreciate !!
Without Stackoverflow I'll never could done the quarter of the whole job so long life to Stackoverflow !!
Regards.
You need to put the table in editing mode (for the current row) when the user interacts with the picker. That can be achieved with an onShowingHandler like this (example is also with a color picker):
this.colorPicker.setOnShowing(event -> {
final TableView<T> tableView = getTableView();
tableView.getSelectionModel().select(getTableRow().getIndex());
tableView.edit(tableView.getSelectionModel().getSelectedIndex(), column);
});
then watch the valueProperty of the picker like this:
this.colorPicker.valueProperty().addListener((observable, oldValue, newValue) -> {
if(isEditing()) {
commitEdit(newValue);
}
});
For more explanation have a look at my blog post: Custom editor components in JavaFX TableCells.
Full Class:
public class ColorTableCell<T> extends TableCell<T, Color> {
private final ColorPicker colorPicker;
public ColorTableCell(TableColumn<T, Color> column) {
this.colorPicker = new ColorPicker();
this.colorPicker.editableProperty().bind(column.editableProperty());
this.colorPicker.disableProperty().bind(column.editableProperty().not());
this.colorPicker.setOnShowing(event -> {
final TableView<T> tableView = getTableView();
tableView.getSelectionModel().select(getTableRow().getIndex());
tableView.edit(tableView.getSelectionModel().getSelectedIndex(), column);
});
this.colorPicker.valueProperty().addListener((observable, oldValue, newValue) -> {
if(isEditing()) {
commitEdit(newValue);
}
});
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
protected void updateItem(Color item, boolean empty) {
super.updateItem(item, empty);
setText(null);
if(empty) {
setGraphic(null);
} else {
this.colorPicker.setValue(item);
this.setGraphic(this.colorPicker);
}
}
}
I was having the same issues but i ended up solving it with this post. JavaFX8 – Render a DatePicker Cell in a TableView.
The outcome is illustrated in the image below.
Your Model object is a bit strange. The setDatePicker and getDatePicker methods should be called setLocaldate and getLocaldate, to be consistent with the localdateProperty() method and (possibly importantly) the parameter passed to the PropertyValueFactory.
I don't think that would cause the problem you observe, though, and I can't see what else is wrong.
This example works for me.
Have a look and see if you can see what I did that's different...
here is a datapicker cell edit when pressing tab key and go to the next cell
datePicker.setOnKeyPressed /EventHandler doesnot work with tab
datePicker.EventFilter get called twice
to work arround this you need to add a listner to tableview cell and get date text as string and cast it to localdate
addEventFilter to TableCell deduction object is a sample
=> addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler() {...}
public class DatePickerCell extends TableCell<Deduction, LocalDate> {
private DatePicker datePicker;
private TableColumn column;
// private TableCell cell;
public DatePickerCell(TableColumn column) { //
super();
this.column = column;
this.datePicker = new DatePicker(getDate());
}
#Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createDatePicker();
setText(null);
setGraphic(datePicker);
Platform.runLater(new Runnable() {
#Override
public void run() {
datePicker.requestFocus();
}
});
//Platform.runLater(datePicker::requestFocus);
}
}
#Override
public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
// SimpleDateFormat smp = new SimpleDateFormat("dd/MM/yyyy");
/* if (null == this.datePicker) {
System.out.println("datePicker is NULL");
}*/ //TO be reviewed
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (datePicker != null) {
datePicker.setValue(getItem());
}
setText(null);
setGraphic(datePicker);
} else {
setText(getItem().toString());
setGraphic(null);
}
}
}
private LocalDate getDate() {
return getItem() == null ? LocalDate.now() : getItem();
}
private void createDatePicker() {
this.datePicker = new DatePicker(getDate());
datePicker.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
this.datePicker.editableProperty().bind(column.editableProperty());
this.datePicker.disableProperty().bind(column.editableProperty().not());
this.datePicker.setOnShowing(event -> {
final TableView tableView = getTableView();
tableView.getSelectionModel().select(getTableRow().getIndex());
tableView.edit(tableView.getSelectionModel().getSelectedIndex(), column);
});
datePicker.setOnAction((e) -> {
commitEdit(datePicker.getValue());
TableColumn nextColumn = getNextColumn(true);
if (nextColumn != null) {
getTableView().edit(getTableRow().getIndex(),
nextColumn);
}
});
datePicker.focusedProperty().addListener(
new ChangeListener<Boolean>() {
#Override
public void changed(
ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2) {
if (!arg2) {
commitEdit(datePicker.getValue());
}
}
});
datePicker.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
// System.out.println("setOnKeyPressed datapicker get value ...." + t.getCode());
/* if (t.getCode() == KeyCode.ENTER) {
commitEdit(datePicker.getValue());
System.out.println("Enter datapicker get value " + datePicker.getValue());
} else */if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
} else if (t.getCode() == KeyCode.ENTER){
commitEdit(datePicker.getValue());
// System.out.println("Tab datapicker get value " + datePicker.getValue());
TableColumn nextColumn = getNextColumn(!t.isShiftDown());
// System.out.println("nextColumn datapicker get value " + nextColumn.getId());
if (nextColumn != null) {
getTableView().edit(getTableRow().getIndex(),
nextColumn);
}
}
}
});
addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.TAB) {
commitEdit(LocalDate.parse(datePicker.getEditor().getText(), DateTimeFormatter.ofPattern("dd/MM/yyyy")));
TableColumn nextColumn = getNextColumn(true);
if (nextColumn != null) {
getTableView().edit(getTableRow().getIndex(),
nextColumn);
}
}
}
});
//
// // setAlignment(Pos.CENTER);
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().toString());
setGraphic(null);
}
public DatePicker getDatePicker() {
return datePicker;
}
public void setDatePicker(DatePicker datePicker) {
this.datePicker = datePicker;
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
private TableColumn<Deduction, ?> getNextColumn(boolean forward) {
List<TableColumn<Deduction, ?>> columns = new ArrayList<>();
for (TableColumn<Deduction, ?> column : getTableView().getColumns()) {
columns.addAll(getLeaves(column));
}
// There is no other column that supports editing.
if (columns.size() < 2) {
return null;
}
int currentIndex = columns.indexOf(getTableColumn());
int nextIndex = currentIndex;
if (forward) {
nextIndex++;
if (nextIndex > columns.size() - 1) {
nextIndex = 0;
}
} else {
nextIndex--;
if (nextIndex < 0) {
nextIndex = columns.size() - 1;
}
}
return columns.get(nextIndex);
}
private List<TableColumn<Deduction, ?>> getLeaves(
TableColumn<Deduction, ?> root) {
List<TableColumn<Deduction, ?>> columns = new ArrayList<>();
if (root.getColumns().isEmpty()) {
// We only want the leaves that are editable.
if (root.isEditable()) {
columns.add(root);
}
return columns;
} else {
for (TableColumn<Deduction, ?> column : root.getColumns()) {
columns.addAll(getLeaves(column));
}
return columns;
}
}
}
in your class with the tableview
Callback cellFactoryDate
= new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
return new DatePickerCell(p);//DatePickerTest(p) //DatePickerTest2 //EditingCellDate
}
};
dateColumn.setCellValueFactory(new PropertyValueFactory<>("date"));
// dateColumn.setCellFactory(cellFactoryTest);//cellFactoryDate
dateColumn.setCellFactory(cellFactoryDate);
dateColumn.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Deduction, LocalDate>>() {
#Override
public void handle(TableColumn.CellEditEvent<Deduction, LocalDate> t) {
((Deduction) t.getTableView().getItems().get(
t.getTablePosition().getRow())).setDate(t.getNewValue());
}
}
);
Here is a solution acceptable for all custom controls; this example use a ColorPicker control:
So finnaly I deal it like that: on the events of the controls I get back the POJO objects in use by the "((Inputs)getTableView().getItems().get(getTableRow().getIndex()" and I update similary like is it done in the OnEditCommit method...
So for me it's look like this (update the color):
((Inputs) getTableView().getItems().get(
getTableRow().getIndex())
).setColor(cp.getValue());
Here is example with ColorPickerCell
:
public class ColorPickerTableCell<Inputs> extends TableCell<Inputs, Color>{
private ColorPicker cp;
public ColorPickerTableCell(){
cp = new ColorPicker();
cp.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
commitEdit(cp.getValue());
updateItem(cp.getValue(), isEmpty());
((Inputs) getTableView().getItems().get(
getTableRow().getIndex())
).setColor(cp.getValue());
}
});
setGraphic(cp);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setEditable(true);
}
#Override
protected void updateItem(Color item, boolean empty) {
super.updateItem(item, empty);
cp.setVisible(!empty);
this.setItem(item);
cp.setValue(item);
}
}
With this simple JavaFX's POJO:
public ObjectProperty<Color> color = new SimpleObjectProperty<Color>();
this.color = new SimpleObjectProperty(color);
public ObjectProperty<Color> colorProperty() {
return color;
}
public void setColor(Color color2) {
color.set(color2);
}
I do not know if it's a good way to achive that but it worked for me... Note that the JavaFX's POJO is only accessible within an "ActionEvent" request (combobox, datepicker, colorpicker, etc..)
Regards,