Juri Strumpflohner
Juri Strumpflohner Juri is a full stack developer and tech lead with a special passion for the web and frontend development. He creates online videos for Egghead.io, writes articles on his blog and for tech magazines, speaks at conferences and holds training workshops. Juri is also a recognized Google Developer Expert in Web Technologies

GWT Button with image AND text

2 min read

GWT just provides the basic widgets like check boxes, hyperlinks, buttons etc...and leave the more complex ones to the developer or to 3rd party providers. For instance they don't have lists. Another thing which quite surprised me, their implementation of a button doesn't allow to have images AND text at the same time although a lot of Google products have it (Wave, GDocs, Gmail...).

With GWT buttons you have mainly two possibilities, using Button or PushButton. The first is just the standard one while the latter allows to assign an image which is passed in its constructor. But also the PushButton doesn't allow to have both, image AND text visualized...which somehow seems to be a use case which is quite requested. A search on the web brought me to the GWT's JavaDoc describing a CustomButton widget which can be used like this:
<g:PushButton ui:field='pushButton' enabled='true'>
<g:upFace>
<b>click me</b>
</g:upFace>
<g:upHoveringFace>
<b>Click ME!</b>
</g:upHoveringFace>
<g:downFace image='{res.save}' />
</g:PushButton>

But also this kind of implementation doesn't allow you to have an image and text declaration...* uff *.

So after that, similar as for the Hyperlink, I decided to implement one by myself. The implementation wasn't that difficult after all. Here's the source code:
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Image;

public class CustomButton extends Button {
private String text;

public CustomButton(){
super();
}

public void setResource(ImageResource imageResource){
Image img = new Image(imageResource);
String definedStyles = img.getElement().getAttribute("style");
img.getElement().setAttribute("style", definedStyles + "; vertical-align:middle;");
DOM.insertBefore(getElement(), img.getElement(), DOM.getFirstChild(getElement()));
}

@Override
public void setText(String text) {
this.text = text;
Element span = DOM.createElement("span");
span.setInnerText(text);
span.setAttribute("style", "padding-left:3px; vertical-align:middle;");

DOM.insertChild(getElement(), span, 0);
}

@Override
public String getText() {
return this.text;
}
}
The according usage with the GWT UiBinder is the following:
...
<!-- Declaration of your ImageBundle -->
<ui:with field="res" type="com.sample.client.IDevbookImageBundle" />
...
<d:CustomButton ui:field="buttonSave" text="Save" resource="{res.save}"></d:CustomButton>
Pretty simple, isn't it? And it doesn't alter the button's behavior rather than adding the image. Some explanations might be needed as for instance you may wonder why I've overridden the setText(String), getText() of the standard Button widget. This was needed in order to wrap the text inside a span element which I can then identify when adding the image in order to position the image before the text. This has the drawback that a definition like
...
<d:CustomButton ui:field="buttonSave"resource="{res.save}">Save</d:CustomButton>
...won't work.

Moreover this widget may be enhanced by making it more configurable like adding the image after the text etc. I've also hard-coded some styles as you see in order to make the widget easier to use. The final outcome:

Questions? Thoughts? Hit me up on Twitter
comments powered by Disqus