how to create a focusable widget - gwt

i have created my own gwt widgets that consist of a TextLabel and an image.
I need that this widget be focusable. I extend this widget from the interface hasFocusHandler, focusable and blurhandler. Nothing is working. I am receiving neither focus nor blur event when i click on or outside of the widget. What should I do?
My code:
public class MyWidget extends ComplexPanel implements HasFocusHandlers, HasBlurHandlers, HasClickHandlers, Focusable{
private Icon icon = new Icon();
private TextNode text = new TextNode("");
private static final FocusImpl impl = FocusImpl.getFocusImplForWidget();
protected static FocusImpl getFocusImpl() {
return impl;
}
public HandlerRegistration addClickHandler(ClickHandler handler) {
return addDomHandler(handler, ClickEvent.getType());
}
#Override
public HandlerRegistration addBlurHandler(BlurHandler handler) {
return addDomHandler(handler,BlurEvent.getType());
}
#Override
public HandlerRegistration addFocusHandler(FocusHandler handler) {
return addDomHandler(handler, FocusEvent.getType());
}
#Override
public void onBrowserEvent(Event event) {
switch (DOM.eventGetType(event)) {
case Event.ONCLICK:
if (isEnabled()) {
super.onBrowserEvent(event);
}
break;
default:
super.onBrowserEvent(event);
break;
}
}
public int getTabIndex() {
return impl.getTabIndex(getElement());
}
#Override
public void setAccessKey(char key) {
DOM.setElementProperty(getElement(), "accessKey", "" + key);
}
#Override
public void setFocus(boolean focused) {
if (focused) {
impl.focus(getElement());
} else {
impl.blur(getElement());
}
}
#Override
public void setTabIndex(int index) {
impl.setTabIndex(getElement(), index);
}
#Override
protected void onAttach() {
super.onAttach();
int tabIndex = getTabIndex();
if (-1 == tabIndex) {
setTabIndex(0);
}
}
}
My implementation is not working (I am not receiving the onFocus call, when i click on the myWidget)
mywidget.addFocusHandler(new FocusHandler()
{
#Override
public void onFocus(FocusEvent event) {
//DO SOMETHING
}
});

We should have more information, because I miss some code, for example, where do you attach the Icon and TextNode to the DOM?
I have done one example and it works for me. Look:
#UiField Label labelText;
public MyWidget(String text) {
super();
//That is the key. Attach the widgets to the dom
setElement(uiBinder.createAndBindUi(this).getElement());
labelText.setText(text);
}
Also instead of having my internal widgets declared in the class, I have created a UiBinder class. Basically:
<!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>
</ui:style>
<g:FlowPanel>
<g:Label ui:field="labelText">
</g:Label>
</g:FlowPanel>
</ui:UiBinder>
In that case you can attach your widgets to the Panel quicker and easier. and in the constructor do only a setElement().
If you have any doubt, just ask!

Related

GWT 2.5.1: dynamic required field indicator

What would be a better approach for displaying a dynamic required field indicator (in my case, display a '*' next to the field IF it is empty, hide it if the user type something, display it again if the user clears the input field) ?
The indicator is called requiredFieldHighlight in the code below.
MyValueBoxEditorDecorator.java
public class MyValueBoxEditorDecorator<T> extends Composite implements HasEditorErrors<T>,
IsEditor<ValueBoxEditor<T>>
{
interface Binder extends UiBinder<Widget, MyValueBoxEditorDecorator<?>>
{
Binder BINDER = GWT.create(Binder.class);
}
#UiField
DivElement label;
#UiField
SimplePanel contents;
#UiField
DivElement requiredFieldHighlight;
#UiField
DivElement errorLabel;
private ValueBoxEditor<T> editor;
private ValueBoxBase<T> valueBox;
/**
* Constructs a ValueBoxEditorDecorator.
*/
#UiConstructor
public MyValueBoxEditorDecorator()
{
initWidget(Binder.BINDER.createAndBindUi(this));
}
public MyValueBoxEditorDecorator(int dummy)
{
this();
valueBox = (ValueBoxBase<T>) new TextBoxTest(requiredFieldHighlight);
this.editor = valueBox.asEditor();
valueBox.addValueChangeHandler(new ValueChangeHandler<T>()
{
#Override
public void onValueChange(ValueChangeEvent<T> event)
{
MyValueBoxEditorDecorator.this.onValueChange();
}
});
contents.add(valueBox);
MyValueBoxEditorDecorator.this.onValueChange();
}
private void onValueChange()
{
T value = editor.getValue();
if (value == null)
{
requiredFieldHighlight.getStyle().setDisplay(Style.Display.INLINE_BLOCK);
return;
}
else
{
requiredFieldHighlight.getStyle().setDisplay(Style.Display.NONE);
}
}
public ValueBoxEditor<T> asEditor()
{
return editor;
}
public void setEditor(ValueBoxEditor<T> editor)
{
this.editor = editor;
}
#UiChild(limit = 1, tagname = "valuebox")
public void setValueBox(ValueBoxBase<T> widget)
{
contents.add(widget);
setEditor(widget.asEditor());
}
#Override
public void showErrors(List<EditorError> errors)
{
// this manages the content of my errorLabel UiField
}
}
UiBinder file:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:style src="common.css" />
<g:HTMLPanel width="100%">
<div ui:field="label" class="{style.label}"/>
<g:SimplePanel ui:field="contents" stylePrimaryName="{style.contents}" />
<div class="{style.errorLabel}" ui:field="errorLabel" />
<div class="{style.errorLabel} {style.requiredFieldHighlight}" ui:field="requiredFieldHighlight">*</div>
</g:HTMLPanel>
</ui:UiBinder>
The issue with my approach is that onValueChange() will not be called when my screen is initialized (before the user interacts with this widget), although I need the MyValueBoxEditorDecorator to update the status of its 'requiredFieldHighlight' !
This is why I created that TextBoxTest class. I simply pass it a reference to the indicator DivElement object and overload setText+setValue.
TextBoxTest.java
public class TextBoxTest extends TextBox
{
#Override
public void setText(String text)
{
super.setText(text);
updateRequiredFieldHighlight(text);
}
private final DivElement requiredFieldHighlight;
public TextBoxTest(DivElement requiredFieldHighlight)
{
super();
this.requiredFieldHighlight = requiredFieldHighlight;
}
private void updateRequiredFieldHighlight(String withValue)
{
if (withValue != null && !withValue.isEmpty())
{
requiredFieldHighlight.getStyle().setDisplay(Style.Display.NONE);
}
else
{
requiredFieldHighlight.getStyle().setDisplay(Style.Display.INLINE_BLOCK);
}
}
#Override
public void setValue(String value, boolean fireEvents)
{
super.setValue(value, fireEvents);
updateRequiredFieldHighlight(value);
}
}
I have several problems with that approach. First, it creates a dependency to another specific class of mine (TextBoxTest), and second, it does not really work properly because setText() is not automagically called by GWT when I clear the contents of the text field using the GUI ! In other words for the indicator to work properly, I need BOTH to overload setText+setValue in the TextBoxTest class and have to ValueChangeHandler added to my MyValueBoxEditorDecorator object. Why ? (and where would be the right event / place to handle a text change ?)
20150629 update: actually setValue() IS called when my screen is initialized. My valueChangeHandler is not triggered, 'though, due to GWT internals (I think due to setValue() provided without a fireEvents flag calling fireEvents overload with a False fireEvent flag).

GWT Custom header with a TextBox (TextInputCell) in my CellTable -> How to override onBrowserEvent?

I would like to use a custom header with a TextBox (TextInputCell) in my CellTable.
I found this example and tried to adapt it:
GWT 2: how can I add Button to the CellTable's header?
public static class BtnHeader extends Header<String>{
public BtnHeader(ButtonCell cell) {
super(cell);
}
#Override
public void onBrowserEvent(Context context, Element elem, NativeEvent nativeEvent)
{
int eventType = Event.as(nativeEvent).getTypeInt();
if (eventType == Event.ONCLICK)
{
nativeEvent.preventDefault();
updateHeader();
}
}
#Override
public String getValue() {
return "Click!";
}
protected void updateHeader() {
// TODO to redefine in a defiant class
}
}
And in your code:
tnHeader header = new BtnHeader(new ButtonCell()){
#Override
protected void updateHeader(){
// Actions when clicking button
}
cTable.addColumn(column, header);
How can I adapt this to my use case ?
I tried the following:
public class TextBoxHeader extends Header<String> {
private String myCaption;
public TextBoxHeader(TextInputCell cell, String caption) {
super(cell);
myCaption = caption;
}
#Override
public String getValue() {
// TODO Auto-generated method stub
return myCaption;
}
protected void updateHeader() {
// TODO to redefine in a defiant class
}
}
The whole part with the onBrowserEvent is missing. How to implement it ?
The documentation (http://www.gwtproject.org/javadoc/latest/com/google/gwt/cell/client/TextInputCell.html) shows that onBrowserEvent is not protected. What to do now ?
Cheers,
Tim
Ok I found the solution. Instead of extending Header, I used a TextInputCell and put it in the Header. I then added a ValueUpdater to the header and I could react to the changes in the input field.
TextInputCell cell = new TextInputCell("Program");
com.google.gwt.user.cellview.client.Header<String> header = new com.google.gwt.user.cellview.client.Header<String>(cell) {
#Override
public String getValue() {
// TODO Auto-generated method stub
return "";
}
};
header.setUpdater(new ValueUpdater<String>() {
#Override
public void update(String value) {
}
});
Cheers,
Tim

Clear SuggestBox on blur in GWT

I have a SuggestionBox in GWT. Is there a way to clear it when it blurs (unless the user made a selection, in which case an action should happen)?
Add a BlurHandler:
suggestionBox.getValueBox().addBlurHandler(new BlurHandler() {
#Override
public void onBlur(BlurEvent event) {
// your code goes here
}
});
Try this one using ValueChangeHandler:
Note: ValueChange event has same behavior as Blue event but it is fired only if value is changed in SuggestBox.
class MyMultiWordSuggestOracle extends MultiWordSuggestOracle {
private Set<String> values = new HashSet<String>();
#Override
public void add(String value) {
super.add(value);
values.add(value);
}
#Override
public void clear(){
super.clear();
values.clear();
}
public boolean contains(String value) {
return values.contains(value);
}
}
You code:
final MyMultiWordSuggestOracle oracle = new MyMultiWordSuggestOracle();
oracle.add("A");
oracle.add("AB");
oracle.add("BCD");
oracle.add("BCDE");
final SuggestBox suggestionBox = new SuggestBox(oracle);
suggestionBox.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
if (!oracle.contains(event.getValue())) {
suggestionBox.setValue("");
}
}
});

Getting header column names in Cell table on click in GWT

I am using Cell Table of GWT 2.2 version. I want to get the name of the header column on which I have clicked. I didn't get any click event on the same.
Is there any work around by which I can accomplish my task.
Something like this? ;)
public class CellTableExample implements EntryPoint, ClickHandler {
private static class SomeEntity {
/* ... */
}
private static class ClickableTextHeader extends TextHeader {
private ClickHandler handler;
public ClickableTextHeader(String text, ClickHandler handler) {
super(text);
this.handler = handler;
}
#Override
public void onBrowserEvent(Context context, final Element elem,
final NativeEvent event) {
//maybe hijack click event
if(handler != null) {
if(Event.ONCLICK == Event.getTypeInt(event.getType())) {
handler.onClick(new ClickEvent() {
{
setNativeEvent(event);
setRelativeElement(elem);
setSource(ClickableTextHeader.this);
}
});
}
}
//default dom event handler
super.onBrowserEvent(context, elem, event);
}
}
CellTable<SomeEntity> cellTable;
TextColumn<SomeEntity> firstColumn;
TextColumn<SomeEntity> secondColumn;
TextColumn<SomeEntity> thirdColumn;
#Override
public void onModuleLoad() {
/* somehow init columns - it's not the point for this example */
cellTable.addColumn(firstColumn, new ClickableTextHeader("First column header", this));
cellTable.addColumn(secondColumn, new ClickableTextHeader("Second column header", this));
cellTable.addColumn(thirdColumn, new ClickableTextHeader("Third column header", this));
}
#Override
public void onClick(ClickEvent event) {
ClickableTextHeader source = (ClickableTextHeader) event.getSource();
Window.alert(source.getValue());
}
}
Hijacking event could look simpler if we used "simple listener interface" - i just wanted to be "semanticaly compliant with out-of-the-box Handlers" :)

CellList backed with ListDataProvider does not get redrawn on list change

I'm working on a project with GWT 2.1 and mvp4g. In a view, I'm using
a CellList backed with a ListDataProvider. If I pass a List with data to the constructor
when instantiating the ListDataProvider, the CellList shows this data.
The problem is that afterthat, the CellList never gets redrawn
whenever I change the list within the ListDataProvider. I don't know what I am
doing wrong or if I missing something.
Here is the code:
The UIBinder xml file:
<g:DockLayoutPanel unit="PX">
<g:west size="300">
<g:VerticalPanel styleName='{style.leftPanel}' spacing="8">
<g:Label>Expositores</g:Label>
<g:ScrollPanel addStyleNames='{style.exhibitorList}' width="250px" height="600px">
<c:CellList ui:field="exhibitorList" />
</g:ScrollPanel>
<g:Button ui:field="editExhibitorButton" addStyleNames='{style.button}'>Editar</g:Button>
</g:VerticalPanel>
</g:west>
...
The View class:
public class ExhibitorsAdminView extends Composite implements
ExhibitorsAdminPresenter.IExhibitorsAdminView {
interface Binder extends UiBinder<Widget, ExhibitorsAdminView> {}
private static final Binder binder = GWT.create( Binder.class );
private static class ExhibitorCell extends AbstractCell<Exhibitor> {
#Override
public void render(Cell.Context context, Exhibitor exhibitor,
SafeHtmlBuilder sb) {
if (exhibitor != null) {
sb.appendEscaped(exhibitor.getName());
}
}
}
private ListDataProvider<Exhibitor> exhibitorsDataProvider;
private SingleSelectionModel<Exhibitor> exhibitorsSelectionModel;
#UiField( provided = true )
CellList<Exhibitor> exhibitorList;
#UiField
Button editExhibitorButton;
// #UiField(provided = true)
// CellTable<Object> moduleList = new CellTable<Object>();
public ExhibitorsAdminView() {
exhibitorsSelectionModel = new
SingleSelectionModel<Exhibitor>(Exhibitor.KEY_PROVIDER);
exhibitorList = new CellList<Exhibitor>(new ExhibitorCell(),
Exhibitor.KEY_PROVIDER);
exhibitorList.setSelectionModel(exhibitorsSelectionModel);
exhibitorsDataProvider = new
ListDataProvider<Exhibitor>(getExhibitors());
exhibitorsDataProvider.addDataDisplay(exhibitorList);
exhibitorList.setPageSize(exhibitorsDataProvider.getList().size());
initWidget( binder.createAndBindUi( this ) );
}
public SingleSelectionModel<Exhibitor> getExhibitorsSelectionModel()
{
return exhibitorsSelectionModel;
}
public ListDataProvider<Exhibitor> getExhibitorsDataProvider() {
return exhibitorsDataProvider;
}
private List<Exhibitor> getExhibitors() {
List<Exhibitor> exhibitors = new ArrayList<Exhibitor>();
for (int i = 0; i < 10; i++) {
exhibitors.add(new Exhibitor(i, "aaaaaaaaaaaaaaa"));
}
return exhibitors;
}
public HasClickHandlers getEditExhibitorButton() {
return editExhibitorButton;
}
}
The presenter class:
#Presenter(view = ExhibitorsAdminView.class)
public class ExhibitorsAdminPresenter extends
BasePresenter<ExhibitorsAdminPresenter.IExhibitorsAdminView,
ExhibitorsEventBus> {
public interface IExhibitorsAdminView {
SingleSelectionModel<Exhibitor> getExhibitorsSelectionModel();
ListDataProvider<Exhibitor> getExhibitorsDataProvider();
HasClickHandlers getEditExhibitorButton();
}
private DispatchAsync dispatch = null;
#Inject
public ExhibitorsAdminPresenter(final DispatchAsync dispatch) {
this.dispatch = dispatch;
}
#Override
public void bind() {
getView().getExhibitorsSelectionModel().addSelectionChangeHandler(
new SelectionChangeEvent.Handler() {
public void onSelectionChange(SelectionChangeEvent event) {
Exhibitor selected =
getView().getExhibitorsSelectionModel().getSelectedObject();
if (selected != null) {
Window.alert("You selected: " + selected.getName());
}
}
});
getView().getEditExhibitorButton().addClickHandler(
new ClickHandler() {
public void onClick(ClickEvent event) {
}
});
}
public void onGoToExhibitorsAdmin() {
}
public void onLoadExhibitors() {
dispatch.execute(new GetExhibitors(), new
AsyncCallback<GetExhibitorsResult>() {
public void onSuccess(GetExhibitorsResult result) {
getView().getExhibitorsDataProvider().setList(
result.getExhibitors());
getView().getExhibitorsDataProvider().refresh();
}
public void onFailure(Throwable caught) {
GWT.log("error executing command ", caught);
}
});
}
}
Thanks.
I solved it. I'm sorry, it was an issue related with mvp4g. I was doing something wrong that was causing to have to different instances of the view where the CellList was placed. The update operations I was doing on the list of the ListDataProvider were being done on the view instance that wasn't being shown.
You have to manipulate the list by getting it first of your provider like provider.getList().add(...). See How to add or remove a single element from/to CellList? for a minimal example.
Just call exhibitorsDataProvider.refresh() after all operations with underlying list.