How to set the initial message for SWT Combo - swt

SWT Text has a method called setMessage which can be used with SWT.SEARCH to put an initial faded-out message in the text box.
Can something similar be done with SWT Combo? It seems it does not have the setMessage() method, so it seems like some other trick needs to be applied here.

You are right, the Combo does not have regular API to set a message like the text widget does.
You could try to use a PaintListener to draw the message text while the Combo text is empty.
combo.addPaintListener( new PaintListener() {
#Override
public void paintControl( PaintEvent event ) {
if( combo.getText().isEmpty() ) {
int x = ...; // indent some pixels
int y = ...; // center vertically
event.gc.drawText( "enter something", x, y );
}
}
} );
In addition, you would need several listeners that redraw the Combo after its native appearance was updated.
combo.addListener( SWT.Modify, event -> combo.redraw() );
A modify listener is certainly required to show/hide the message but there are probably more listeners necessary to redraw the message when it is invalidated. This answer may give further hints which events are necessary to capture: How to display a hint message in an SWT StyledText
Note, however, that drawing onto controls other than Canvas is unsupported and may not work on all platforms.

A simpler alternative to the paint listener that worked for my purposes involves programatically setting the text and text color using a FocusListener. Here is an example:
final String placeholder = "Placeholder";
combo.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY));
combo.setText(placeholder);
combo.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
String text = combo.getText();
if(text.isEmpty()) {
combo.setText(placeholder);
combo.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY));
}
}
#Override
public void focusGained(FocusEvent e) {
String text = combo.getText();
if(text.equals(placeholder)) {
combo.setText("");
combo.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
}
}
});

Related

Layout update GWT

I use RPC calls to connect to mySql and bring text data from there.
My page is defined as split Layout.
my problem is that I don't know how to update the main layout with different text.
if i use the clear() method it will remove all the layout !
"p" is the splitLayout.
RPC:
rpcService.getChapterTxt(selectedBook,bookChapters[selectedBook],
new AsyncCallback<List<BibleTxt>>(){
public void onFailure(Throwable caught)
{
Window.alert("Failed getting Chapter");
}
public void onSuccess(List<BibleTxt> result)
{
int i = 0 ;
String verseText ="";
//Label verseLabel = new Label();
PPanel chapterPar = new PPanel();
HTML page= new HTML(verseText);
for(i=0;i<result.size();i++)
{
verseText = result.get(i).getVerseText();
//verseLabel.setText(verseText);
page.setText(page.getText() + verseText);
}
chapterPar.add(page);
//p.clear();
p.add(chapterPar); // adds the main layout
}
});
Why you don't reuse the text component changing its content text instead of continuously detaching/attaching elements to the widget hierarchy. That way should perform better and cause less problems.

GWT adding widget to Column Header

I want to customize my cell table's column header. I have to include support for sorting and filtering. I want to have images for both actions. When the user clicks on the sort image, it will toggle (based on ascending / descending order sort ) and the table sorts based on the icon clicked. I am currenty doing this with some messy HTML manipulation , in the onBrowserEvent of my custom header cell. Could someone tell me how I could use GWT's ToggleButton here?
Thanks.
You can't use GWT Widget in Cell Table.
But, you can use a custom Cell for the header.
public class ButtonHeader extends Header<String> {
private String text;
/**
* Construct a new TextHeader.
*
* #param text the header text as a String
*/
public ButtonHeader(String text) {
super(new ButtonCell());
this.text = text;
setUpdater(new ValueUpdater<String>() {
#Override
public void update(String value) {
//When the button is press
}
});
}
#Override
public String getValue() {
return text;
}
}
You can change this for use an other Cell for your usage.
For a (not-so) complete documentation on custom cells check this link.
You WILL have to override onBrowserEvent(), even if it's clumsy, since you can't use a GWT widget in a cell but you can render it. Yet, it'll lose all it's event handling capabilities.
(from this post) Widgets are never attached to the DOM. They exist to be manipulated in memory and then have their HTML extracted and pushed into the DOM. Events from the Widgets, therefore, are not handled. Cell events ARE handled.
So you could just use widget.getElement.getInnerHTML() to render the widget you want in your header (a toggle button or anything else). Despite having this option at hand, my advice would be to use your own SafeHtmlTemplates instead of using getInnerHTML().

Adding Arbitrary Text Beside Tabs with GWT's TabLayoutPanel

Currently, I have a TabLayoutPanel with a few tabs, inside of each tab is a set of breadcrumbs. I would like to be able to display my breadcrumbs right next to the tabs (inside the TabBar itself). I haven't yet seen any instance of someone having done this, and I'm beginning to believe I might end up rewriting their TabLayoutPanel class myself and implementing that where needed, but obviously I'd rather not go that route unless there's no alternative.
Anyone have any guidance on this?
Just came across the same problem. Here are most of the relevent code snippets. I added a Unicode arrow when the tab was selected, and removed it when the tab was deselected.
private final String htmlStr ="\u25bb";
private String getTabTitle(String html){
// Designed to work for this example input.
//If you pass a different string you will need to do different matching.
if(html.indexOf("\u25bb") < 0)
return html;
else
return html.substring(html.indexOf("\u25bb")+1);
}
#Override
public void onBeforeSelection(BeforeSelectionEvent<Integer> event) {
if(!getSelectedIndex().equals(event.getItem())) {
notifyCurrentTabOfClosing();
selectedIndex = event.getItem();
String tabtitle = getTabTitle(getTabBar().getTabHTML(selectedIndex));
getTabBar().setTabHTML(selectedIndex, htmlStr+tabtitle);
}
}
}
public void selectTab(Widget widget) {
int widgetIndex = getWidgetIndex(widget);
selectTab(widgetIndex);
String tabtitle = getTabTitle(getTabBar().getTabHTML(widgetIndex));
getTabBar().setTabHTML(widgetIndex, htmlStr+tabtitle);
}

GWT CellBrowser- how to always show all values?

GWT's CellBrowser is a great way of presenting dynamic data.
However when the browser contains more rows than some (seemingly) arbitrary maximum, it offers a "Show More" label that the user can click to fetch the unseen rows.
How can I disable this behavior, and force it to always show every row?
There are several ways of getting rid of the "Show More" (which you can combine):
In your TreeViewModel, in your NodeInfo's setDisplay or in the DataProvider your give to the DefaultNodeInfo, in onRangeChange: overwrite the display's visible range to the size of your data.
Extend CellBrowser and override its createPager method to return null. It won't change the list's page size though, but you can set it to some very high value there too.
The below CellBrowser removes the "Show More" text plus loads all available elements without paging.
public class ShowAllElementsCellBrowser extends CellBrowser {
public ShowAllElementsCellBrowser(TreeViewModel viewModel, CellBrowser.Resources resources) {
super(viewModel, null, resources);
}
#Override
protected <C> Widget createPager(HasData<C> display) {
PageSizePager pager = new PageSizePager(Integer.MAX_VALUE);
// removes the text "Show More" during loading
display.setRowCount(0);
// increase the visible range so that no one ever needs to page
display.setVisibleRange(0, Integer.MAX_VALUE);
pager.setDisplay(display);
return pager;
}
}
I found a valid and simple solution in setting page size to the CellBrowser's builder.
Hope this will help.
CellBrowser.Builder<AClass> cellBuilder = new CellBrowser.Builder<AClass>(myModel, null);
cellBuilder.pageSize(Integer.MAX_VALUE);
cellBrowser = cellBuilder.build();
The easiest way to do this is by using the:
cellTree.setDefaultNodeSize(Integer.MAX_VALUE);
method on your Cell Tree. You must do this before you begin expanding the tree.
My workaround is to navigate through elements of treeview dom to get "show more" element with
public static List<Element> findElements(Element element) {
ArrayList<Element> result = new ArrayList<Element>();
findShowMore(result, element); return result; }
private static void findShowMore(ArrayList res, Element element) {
String c;
if (element == null) { return; }
if (element.getInnerText().equals("Show more")) { res.add(element);
}
for (int i = 0; i < DOM.getChildCount(element); i++) { Element
child = DOM.getChild(element, i); findShowMore(res, child); } }
and than use:
if (show) { element.getStyle().clearDisplay(); } else {
element.getStyle().setDisplay(Display.NONE); }

How to group gwt composite widgets change events as one change event

If i have a GWT composite widget with three text boxes like for SSN, and i need to fire change event only when focus is lost from the widget as a whole, not from individual text boxes how to go about doing that?
If you want just the event when your whole widget loses focus (not the text boxes), then make the top level of your widget be a FocusPanel, and expose the events that it gives you.
You need to implement the Observer Pattern on your composite, and trigger a new notification everytime:
the focus is lost on a specific text box AND
the focus was not transferred to any of the other text boxes.
Couldn't you use a timer? On lost focus from a text box, start a 5ms (or something small) timer that when it hits, will check focus on all 3 TextBox instances. If none have focus, then you manually notify your observers. If one has focus, do nothing.
Put this in your Composite class:
private Map<Widget, Boolean> m_hasFocus = new HashMap<Widget, Boolean>();
And then add this to each one of your TextBox instances:
new FocusListener() {
public void onFocus(Widget sender) {
m_hasFocus.put(sender, Boolean.TRUE);
}
public void onLostFocus(Widget sender) {
m_hasFocus.put(sender, Boolean.FALSE);
new Timer() {
public void run() {
for (Boolean bool : m_hasFocus.values()) {
if (bool) { return; }
}
notifyObservers();
}
};
}
};