I'm creating a composite uibinder widget with a Label and a TextBox.
The intented use is:
<x:XTextBox ui:field="fieldName" label="a caption" >
The text to be put in the box.
</x:XTextBox>
I've found how to catch the label with a custom #UiConstructor constructor, I might add another parameter to the constructor, but I would like to know how to get the text from the xml, just like the GWT tag <g:Label>a caption</g:Label> does.
Any help is greatly appreciated.
I've found a possible implementation by looking at the Label widget source code.
The key point is that the composite widget must implement the HasText interface. so in the declaration and in the body:
public class XTextBox extends Composite implements HasText ...
...
#UiField TextBox textBox;
...
public void setText(String text) {
textBox.setText(text);
}
public String getText() {
return textBox.getText();
}
...
Just put the text into another parameter of your widget and have your #UiConstructor take that parameter. That is:
<x:XTextBox ui:field="fieldName" label="a caption"
text="The text to be put in the box." />
Then your XTextBox.java will have this:
#UiField TextBox textBox;
#UiConstructor XTextBox(String label, String text) {
initWidget(uiBinder.createAndBindUi(this));
textBox.setValue(text);
}
Han is right; HasText is what you need to implement. One thing I found handy is to browse the source if you know a Google widget does something you'd like to do also. e.g.
http://www.google.com/codesearch/p?hl=en#A1edwVHBClQ/user/src/com/google/gwt/user/client/ui/Label.java
Related
Edit
Since no one has responded to my original question I think it is worthwhile adding a description of what I am attempting to accomplish, in addition to the existing description of how I have attempted to achieve my goal:
My objective is to create a DataGrid that will resize according to any change in size of its container. This is not difficult to do, but I have an additional requirement, which is to have Panel widgets above and below the DataGrid; these two Panel widgets will contain widgets that are fixed in size (e.g., a row of buttons or text input widgets). My expectation was that a HeaderPanel would be perfect for this, but this doesn't seem to work (as can be seen in my original question, below). So ... an alternative to my original question ("why doesn't this work") is: what is the best way to implement this requirement?
My original question:
I have a DataGrid in the content area of a HeaderPanel, but the detail lines in the DataGrid are not being displayed (the DataGrid column headings are showing, however). Is there an issue with using a DataGrid in the content area of a HeaderPanel? Or is this a simple misuse of the widgets? I'm adding the HeaderPanel to the RootLayoutPanel, which should provide the necessary resize notification (I think). Here is my UiBinder code:
<ui:UiBinder
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:c='urn:import:com.google.gwt.user.cellview.client'>
<g:HeaderPanel>
<g:SimplePanel/>
<g:ResizeLayoutPanel>
<c:DataGrid ui:field='dataGrid'/>
</g:ResizeLayoutPanel>
<g:HorizontalPanel>
<g:Button
ui:field='addRecordButton'
text='Add Record'/>
<g:Label ui:field='numberOfRecordsLabel'/>
</g:HorizontalPanel>
</g:HeaderPanel>
</ui:UiBinder>
and here is the Java code:
public class TempGWT implements EntryPoint {
#UiField
Button addRecordButton;
#UiField
DataGrid<Record> dataGrid;
#UiField
Label numberOfRecordsLabel;
private ArrayList<Record> _recordList;
interface TempGWTBinder extends UiBinder<Widget, TempGWT> {
}
private static class Record {
private String _field1;
}
#Override
public void onModuleLoad() {
_recordList = new ArrayList<Record>();
TempGWTBinder binder = GWT.create(TempGWTBinder.class);
Widget widget = binder.createAndBindUi(this);
Column<Record, String> field1Column = new Column<Record, String>(new TextInputCell()) {
#Override
public String getValue(final Record record) {
return record._field1;
}
};
dataGrid.addColumn(field1Column, "Field 1");
RootLayoutPanel.get().add(widget);
}
#UiHandler("addRecordButton")
public void onAddRecordButtonClick(final ClickEvent event) {
Record record = new Record();
record._field1 = "Record " + (_recordList.size() + 1);
_recordList.add(record);
dataGrid.setRowData(_recordList);
numberOfRecordsLabel.setText("Records:" + _recordList.size());
}
}
I've attempted to trace the execution and, although I'm not certain, it looks as though the following happens when I change the size of the browser window and the "resize" request is received by the DataGrid (I've skipped some of the "unimportant" methods):
DataGrid#onResize
HeaderPanel#forceLayout
ScrollPanel#onResize
The DataGrid object contains a HeaderPanel, which contains the headings for the DataGrid and a ScrollPanel. I don't know whether this is the key to the problem, but the ScrollPanel in the DataGrid's HeaderPanel contains a DataGrid$TableWidget object, and TableWidget does not implement RequiresResize; the ScrollPanel#onResize method only sends the resize to its child if the child implements RequiresResize.
The Tables and Frames section of the GWT Developer's Guide makes it clear that I just needed to use a width/height of 100% for the DataGrid! Like so:
<c:DataGrid
ui:field='dataGrid'
width='100%'
height='100%'/>
I use a CellTable widget in GWT.
I want to change the font size of every texts contained in the first column. The method addColumnStyleName does not fit my need because it adds the class to the colgroup tag; only partial css is handled on this tag, and I can't change the font attributes of a colgroup (it has no incidence on text).
So, I want to add a class on each td of the first column but cannot find an easy way to do that.
Something like setRowStyles for columns would be fine but it doesn't exist...
Have you got some hint about doing such a thing ?
EDIT: I use GWT 2.3 and not 2.4 (which has the method setCellStyleNames)
It's as easy as calling setCellStyleNames on the Column instance.
I finally get it. But I'm not really happy with that solution. It's a bit verbose for a such simple task. I'm opened to any other suggestion.
The way I achieve it is to create a new cell and a new column :
private class KeyColumn extends Column<SimpleLegendItem, String> {
public KeyColumn() {
super(new KeyCell());
}
#Override
public String getValue(SimpleLegendItem item) {
return item.getKey();
}
}
private class KeyCell extends AbstractCell<String> {
#Override
public void render(com.google.gwt.cell.client.Cell.Context context, String value, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<span class=\"" + tableResources.cellTableStyle().box() + "\">");
sb.appendEscaped(value);
sb.appendHtmlConstant("</span>");
}
}
To simplify the example, I intentionally do not use a template.
Is there any way to SuggestBox to CellTable? Maybe there is another solution then SuggestBox?
I need to get an editable cell with suggestion feature?
I'm using GWT 2.4.
I don't think you can add it directly in. Try using a ClickableTextCell as the cell for that column. Then code your ValueUpdater (which will be called when the cell is clicked) to open up a DialogBox. Put your SuggestBox, and other widgets (OK button, Cancel button, and such), inside that DialogBox. Initialize the SelectionBox with the current contents of the cell. The DialogBox will likely be a DialogBox subclass with extra state data you initialize with the object for that CellTable row as well as the field for that column, so that the OK action knows what field on what object to update with the new contents of the SuggestBox. Essentially it's a popup editor. Not ideal, because users will expect the editor to be embedded in the CellTable, but there are only a few cell editors available (EditTextCell, DatePickerCell, SelectionCell and CheckboxCell, and maybe another variant of text editing), but I've used this technique, and really, it's not too bad.
I ended up using FlexTable instead of CellTable. With FlexTable you may put any widget inside a table cell.
I needed this also and found a solution (under testing, but solong it is working):
I copied the Code from TextInputCell into a new Class SuggestBoxTextInputCell
public class SuggestBoxTextInputCell extends AbstractInputCell<String, SuggestBoxTextInputCell.ViewData> {
MySuggestBox suggestBox;
and added some lines to the onBrowserEvent method:
// Ignore events that don't target the input.
InputElement input = getInputElement(parent);
String eventType = event.getType();
if (BrowserEvents.FOCUS.equals(eventType)) {
TextBox textBox = new MyTextBox(input);
suggestBox = new MySuggestBox(getSuggestOracle(), textBox);
suggestBox.onAttach();
}
Element target = event.getEventTarget().cast();
The classes MySuggestBox and MyTextbox exist only to make the needed constructor and methods public:
private class MyTextBox extends TextBox {
public MyTextBox(Element element) {
super(element);
}
}
private class MySuggestBox extends SuggestBox {
public MySuggestBox(SuggestOracle suggestOracle, TextBox textBox) {
super(suggestOracle, textBox);
}
#Override
public void onAttach() {
super.onAttach();
}
}
getSuggestOracle() only delivers the needed SuggestOracle. Hope someone can use this solution.
I needed this as a solution so I play around with the solution provided by Ande Hofer.
The exact same issue met by Ankit Singla, when the suggestbox is working fine when I press "Enter" key, but not from the "Mouse Click".
I go on further and add-on this onto the solution.
if (BrowserEvents.FOCUS.equals(eventType)) {
...
...
suggestbox.addSelectionHandler(new SelectionHandler<Suggestion>() {
#Override
public void onSelection(SelectionEvent<Suggestion> event) {
Suggestion selectedSuggestion = event.getSelectedItem();
String selectedValue = selectedSuggestion.getReplacementString();
onSuggestSelected(input, selectedValue, valueUpdater);
}
});
suggestbox.onAttach();
}
and a private function
private void onSuggestSelected(Element input, String value,
ValueUpdater<String> valueUpdater) {
input.blur();
suggestbox.onDetach();
if (suggestbox.getSuggestionDisplay().isSuggestionListShowing()) {
((DefaultSuggestionDisplay) suggestbox.getSuggestionDisplay()).hideSuggestions();
}
valueUpdater.update(value);
}
So far so good.
I'm writing a widget with the following markup:
<g:HTMLPanel ui:field="shortcutPanel" styleName="{style.shortcut}">
<g:Image ui:field="shortcutImage"></g:Image>
<span ui:field="shortcutLabel"></span>
</g:HTMLPanel>
So essentially a div that wraps and image and a label. Now, instead of adding the event handlers on the image/span, I'd like an onClick to be associated with the HTMLPanel. My problem however is that gwt tells me that
shortcutPanel doesn't not have an addClickHandler method associated
So I'm assuming the difference is that HTMLPanel doesn't implement HasClickHandlers or something along that line. I'm wondering then what is the standard way to attach a click handler to a Ui element such as an HTMLPanel or even better, is there such a GWT Widget that is essentially a div wrapper that I can easily attach events to with the #UiHandler annotation.
You are probably looking for FocusPanel - it has all the goodies: HasAllFocusHandlers, HasAllKeyHandlers, HasAllMouseHandlers, HasBlurHandlers, HasClickHandlers.... to name a few :) I find it to be the easiest and best way to attach click handlers to a Panel.
I haven't done this before, but you could do the following:
Create a custom class MyPanel that extends HTMLPanel and implements HasClickHandlers
Add the following method in MyPanel.java
public HandlerRegistration addClickHandler(ClickHandler handler) {
return addDomHandler(handler, ClickEvent.getType());
}
Then replace HTMLPanel with MyPanel in your ui.xml and its corresponding Java implementation.
You can always look at the implementation of HTMLTable to get an understanding of how the event propagation works. It's a Panel and implements HasClickHandlers.
If you want to use the #UiHandler annotation to register event handlers for your custom widget, you need to re-implement the addXXHandler methods. The GWT compiler doesn't seem to find those in superclasses. e.g. if you want to use
#UiHandler("myCustomWidget")
public void handleWidgetSelectionChangeEvent(final SelectionEvent<CountryDts> event) {
...
}
and your CustomWidget extends a class for which this is working, you might need to add the HasSelectionHandlers interface explicitly to your class:
public class CustomComboBox<D> extends ComboBox<D> implements HasSelectionHandlers<D> {
#Override
#SuppressWarnings("pmd.UselessOverridingMethod")
public HandlerRegistration addSelectionHandler(final SelectionHandler<D> handler) {
// GWT Compile doesn't recognize method in supertype for UIHandler
return super.addSelectionHandler(handler);
}
...
}
I would like to implement menus (MenuBar, MenuItem) using the declarative approach via UiBinder in GWT 2.0.
I have run into two problems:
Is there a way to add MenuItemSeparators in the .ui.xml file? So
far, I have only managed to put MenuBar- and MenuItem-tags into the
file.
Using #UiHandler, GWT writes the boilerplate code for event
handlers for me. For menus, I need to write commands. How am I
supposed to do this using the UiBinder approach? Is there a command
tag to put in the .ui.xml file? Do I have to write the boilerplate
code for the command handlers myself?
Thanks for thinking about these questions!
I agree, if you try to put a MenuItemSeparator in, it will complain stating only a MenuItem can be a child when GWT tries to create the widget . Since this is not currently supported, I suggest that you request this as a future enhancement to the GWT team.
In the meantime, you can add a separator programmatically and add a command in the following manner:
The XML file:
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:HTMLPanel>
<g:MenuBar ui:field="menuBar">
<g:MenuItem ui:field="helpMenuItem">Help</g:MenuItem>
<g:MenuItem ui:field="aboutMenuItem">About</g:MenuItem>
<g:MenuItem ui:field="siteMapMenuItem">Site Map</g:MenuItem>
</g:MenuBar>
</g:HTMLPanel>
The Java file(s):
public class Menu extends Composite {
...
#UiField MenuBar menuBar;
#UiField MenuItem helpMenuItem;
...
public Menu() {
initWidget(uiBinder.createAndBindUi(this));
// insert a separator
menuBar.insertSeparator(1);
// attach commands to a menu item
helpMenuItem.setCommand(new MenuCommand(HistoryToken.Help));
...
}
public class MenuCommand implements Command {
final HistoryToken historyToken;
public MenuCommand(HistoryToken historyToken) {
this.historyToken = historyToken;
}
#Override
public void execute() {
historyToken.fire();
}
}
public enum HistoryToken {
Help,About,SiteMap;
public void fire(){
History.newItem(this.toString());
}
}
Elsewhere in my code, I implemented a HistoryListener to catch any changes, i.e.
class HistoryManager implements ValueChangeHandler<String> {
// 1. get token
// 2. change it into a HistoryToken
// 3. perform switch statement
// 4. change contents based upon HistoryToken found
...
}
For (1) JavaDoc says:
Use in UiBinder Templates
MenuBar elements in UiBinder template files can have a vertical boolean attribute (which defaults to false), and may have only MenuItem elements as children. MenuItems may contain HTML and MenuBars.
For example:
<g:MenuBar>
<g:MenuItem>Higgledy
<g:MenuBar vertical="true">
<g:MenuItem>able</g:MenuItem>
<g:MenuItem>baker</g:MenuItem>
<g:MenuItem>charlie</g:MenuItem>
</g:MenuBar>
</g:MenuItem>
<g:MenuItem>Piggledy
<g:MenuBar vertical="true">
<g:MenuItem>foo</g:MenuItem>
<g:MenuItem>bar</g:MenuItem>
<g:MenuItem>baz</g:MenuItem>
</g:MenuBar>
</g:MenuItem>
<g:MenuItem><b>Pop!</b>
<g:MenuBar vertical="true">
<g:MenuItem>uno</g:MenuItem>
<g:MenuItem>dos</g:MenuItem>
<g:MenuItem>tres</g:MenuItem>
</g:MenuBar>
</g:MenuItem>
</g:MenuBar>
Taking the hint from the words "only MenuItem elements as children", my guess is that MenuItemSeparators are not supported
Here's an example of my solution to this, which seems to work pretty well with GWT 2.4.0.
UiBinder:
<g:MenuBar vertical='true' ui:field='mainMenu'>
<g:MenuItem ui:field='item1'>Item 1</g:MenuItem>
<g:MenuItem ui:field='item2'>Item 2</g:MenuItem>
<g:MenuItemSeparator />
<g:MenuItem ui:field='sub' enabled='false'>
Submenu
<g:MenuBar vertical='true' ui:field='subMenu' />
</g:MenuItem>
</g:MenuBar>
Java:
#UiField MenuItem item1;
#UiField MenuItem item2;
#UiField MenuBar subMenu;
#UiField MenuItem sub;
...
this.setWidget(uiBinder.createAndBindUi(this));
item1.setCommand(new Command() {
public void execute() {
History.newItem("item1");
}
});
Overall not too bad.
I know this question is OLD, but I keep running across this question in my google searches, so i thought it would be important to note that although i haven't seen it documented anywhere yet, i have been using:
<g:MenuItemSeparator/>
successfully in my uibinder template. The gwt eclipse plugin gives me a red error marker, but the MenuItemSeparator compiles and shows up ok. I'm using gwt 2.1.
Just thought someone might be interested to know.
Unfortunately I haven't seen a solution for #2 yet - but I hope they give us something soon.
It is possible to add a menuItemSeparator in the ui.xml file. Here is an example with separator and submenu from the official GWT-API page.
Well, i think i found a way to implement this. (This is a solution if you want to declare the separator inside the *.ui.xml file. )
HocusView.java
...
#UiField MenuBar menuBar;
#UiField MenuItem item1;
#UiField MenuItem item2;
#UiField MenuItem item3;
#UiField MenuItem item4;
...
private static HocusViewUiBinder uiBinder = GWT.create(HocusViewUiBinder.class);
#UiTemplate("Hocus.ui.xml")
interface HocusViewUiBinder extends UiBinder<Widget, HocusView>{}
public HocusView()
{
initWidget(uiBinder.createAndBindUi(this));
// Attach commands to menu items
menuItem1.setScheduledCommand(cmd_menuItem1);
menuItem2.setScheduledCommand(cmd_menuItem2);
menuItem3.setScheduledCommand(cmd_menuItem3);
menuItem4.setScheduledCommand(cmd_menuItem4);
}
Command cmd_menuItem1= new Command(){
#Override
public void execute() {
Window.alert(" Gifts ");
}
};
Command cmd_menuItem2 = new Command(){
#Override
public void execute() {
Window.alert(" Gifts ");
}
};
Command cmd_menuItem3 = new Command(){
#Override
public void execute() {
Window.alert(" Gifts ");
}
};
Command cmd_menuItem4 = new Command(){
#Override
public void execute() {
Window.alert(" Gifts ");
}
};
});
HocusView.ui.xml
<gwt:MenuBar ui:field="menuBar" >
<gwt:MenuItem ui:field="menuItem1">Search</gwt:MenuItem>
<gwt:MenuItemSeparator></gwt:MenuItemSeparator>
<gwt:MenuItem ui:field="menuItem2">Ingestion</gwt:MenuItem>
<gwt:MenuItemSeparator></gwt:MenuItemSeparator>
<gwt:MenuItem ui:field="menuItem3">Analysis</gwt:MenuItem>
<gwt:MenuItemSeparator></gwt:MenuItemSeparator>
<gwt:MenuItem ui:field="menuItem4">About</gwt:MenuItem>
</gwt:MenuBar>
Its as simple as that.This will add a separator between the menu items.
Cheers!