I'm trying to replace the contents of the CENTER portion of a DockLayoutPanel from a MenuBar. The MenuBar will sit at the North, but "content" (forms, reports, etc) will reside in Center.
I thought I could do it by grabbing the entire DockLayoutPanel from the RootPanel (index 0, since that's the only widget directly attached to it), then somehow remove the current contents of center and insert the new. Unfortunately, getWidget(int index) is non-static, so it's not working.
Can anyone how me with the right way to do this? Non-working code is below:
// snipped package and import details
public class menubar extends Composite {
private static menubarUiBinder uiBinder = GWT.create(menubarUiBinder.class);
interface menubarUiBinder extends UiBinder<Widget, menubar> {
}
#UiField MenuBar applicationMenuBar;
#UiField MenuBar processMenuBar;
#UiField MenuBar reportsMenuBar;
#UiField MenuItem addPowerRequirementCmd;
#UiField MenuItem powerUsageReportCmd;
public menubar() {
initWidget(uiBinder.createAndBindUi(this));
// command to replace whatever is in DockLayoutPanel.CENTER w/ AddPowerRequirement
// FormPanel
addPowerRequirementCmd.setCommand(new Command() {
#Override
public void execute() {
// get DockLayoutPanel from the RootPanel (it's the only widget, should be
// index 0
DockLayoutPanel dlp = (DockLayoutPanel) RootPanel.getWidget(0);
// clear out DockLayoutPanel.CENTER
// insert the FormLayoutPanel into DockLayoutPanel.CENTER
dlp.add(new PowerRequirementForm());
}
});
// command to replace whatever is in DockLayoutPanel.CENTER w/ power usage report
powerUsageReportCmd.setCommand(new Command() {
#Override
public void execute() {
}
});
}
}
Thanks!
Use a ui:field attribute, like you do for the MenuBar, to get a reference to the DockLayoutPanel from UiBinder:
<g:DockLayoutPanel ui:field="dockPanel"/>
and in the class:
#UiField DockLayoutPanel dockPanel;
However, it sounds like you want to have a set of widgets that are shown in the center of the panel depending on application state. A DeckPanel is a better solution for this:
<g:DockLayoutPanel>
<g:center>
<g:DeckPanel ui:field="deck">
<g:FlowPanel>Panel #0</g:FlowPanel>
<g:FlowPanel>Panel #1</g:FlowPanel>
</g:DeckPanel>
</g:center>
</g:DockLayoutPanel>
And then to switch the displayed child of the DeckPanel:
deck.showWidget(1); // Show Panel #1
deck.showWidget(0); // Show panel #0
Related
I am building a GWT application.
In this application I have a number of DataGrid implementations showing data retrieved from the server. In one panel I have a TabLayoutPanel, with a DataGrid on each tab.
I am attempting to lazy-load the DataGrids when the parent tab becomes visible.
Here is the ui.xml:
<g:TabLayoutPanel width="800px" height="450px" barUnit='EM' barHeight='3'>
<g:tab>
<g:header size='7'><b>Volunteer Assignments</b></g:header>
<grid:VolunteerAssignmentGrid/>
</g:tab>
<g:tab>
<g:header size='7'><b>Volunteer Details</b></g:header>
<g:LazyPanel ui:field="lazyDetails">
<grid:VolunteerFieldsGrid/>
</g:LazyPanel>
</g:tab>
</g:TabLayoutPanel>
In the above code, VolunteerAssignmentGrid and VolunteerFieldsGrid are sub-classes of DataGrid.
The VolunteerAssignmentGrid is visible immediately and the data displays OK.
However, the VolunteerFieldsGrid on the next tab does not display at all.
The strange thing is, it is requesting the data at the correct time (when I click on the other tab), and the server response is correct. It's as if the table is not visible.
Any ideas why the second DataGrid is not visible?
EDIT:
The UiBinder class:
public class VolunteerDetailsPanel extends DialogBox {
interface Binder extends UiBinder<Widget, VolunteerDetailsPanel> {}
private static final Binder binder = GWT.create(Binder.class);
#UiField LazyPanel lazyDetails;
private Record volunteerRecord;
private String fullName;
private String volunteerId;
public VolunteerDetailsPanel(Record record) {
this.volunteerRecord = record;
fullName = volunteerRecord.getValue("forename")+" "+volunteerRecord.getValue("surname");
volunteerId = volunteerRecord.getValue("id");
setText(fullName);
}
public void initComponent() {
setWidget(binder.createAndBindUi(this));
}
#UiFactory VolunteerAssignmentGrid createAssignmentGrid() {
return new VolunteerAssignmentGrid(volunteerId, fullName);
}
#UiFactory VolunteerFieldsGrid createFieldsGrid() {
return new VolunteerFieldsGrid(volunteerId);
}
}
As requested, also the VolunteerFieldsGrid class. It extends ListGrid (one of mine, but too long to post here, all my other Grids extend it and are OK), which in turn extends GWT's DataGrid:
public class VolunteerFieldsGrid extends ListGrid {
public VolunteerFieldsGrid(String volunteerId) {
super(100, "name", false);
setWidth("100%");
ListGridColumn<?>[] columns = new ListGridColumn<?>[] {
new FieldNameColumn("Field", "name").width(75),
new TextColumn("Value", "value").width(300)
};
setColumns(columns);
ListGridDataProvider data = ListGridDataProvider.getInstance("field",
"/volunteer/"+volunteerId, "name", false);
setDataProvider(data);
}
}
You have to register a handler for SelectionEvent in the TabLayoutPanel that will call LazyPanel.setVisible(true). Try something like this in UiBinder:
#UiHandler("yourTabPanelUiField")
void onSelectionEvent(SelectionEvent event) {
//for extra functionality check if EventTarget equals the correct tab
lazyDetails.setVisible(true);
}
I am using a GWT HeaderPanel. As a middle element, I am using a DockLayoutPanel as follows:
<g:DockLayoutPanel width="1200px" height="100%">
<g:west size="220">
<g:HTMLPanel styleName="{style.debug}">
something <br />
something <br />
</g:HTMLPanel>
</g:west>
</g:DockLayoutPanel>
The page renders fine but, if the browser window is shrunk vertically, the middle panel goes on top of the footer, which is of course not what you would want with a header panel.
I rather like to have the fixed footer, which is why I am not doing the whole thing using DockLayoutPanel. What am I doing wrong? Thanks!
EDIT: ok, actually, if the window is grown vertically, the middle panel still does not resize
EDIT2: The HeaderPanel is directly in the root panel and looks like this:
<g:HeaderPanel>
<my.shared:Header></my.shared:Header>
<my.shared:Middle></my.shared:Middle>
<my.shared:Footer></my.shared:Footer>
</g:HeaderPanel>
Layout panels 101: HeaderPanel is a RequiresResize panel, so it must either be put into a ProvidesResize panel, such as RootLayoutPanel, (or as the middle panel of a HeaderPanel [1]) or be given an explicit fixed size.
[1] HeaderPanel does not implement ProvidesResize because it only fulfills the contract for its middle panel.
The following approach worked for me. It's based on Zack Linder's advice
Google Web Toolkit ›layout panel problem
(1) Attach a HeaderLayoutPanel to your RootLayoutPanel. The headerLayoutPanel is a class you create that extends HeaderPanel and implements ProvidesResize().
import com.google.gwt.user.client.ui.HeaderPanel;
import com.google.gwt.user.client.ui.ProvidesResize;
import com.google.gwt.user.client.ui.SimpleLayoutPanel;
import com.google.gwt.user.client.ui.Widget;
public class HeaderLayoutPanel extends HeaderPanel implements ProvidesResize {
SimpleLayoutPanel contentPanel;
public HeaderLayoutPanel() {
super();
contentPanel=new SimpleLayoutPanel();
}
#Override
public void setContentWidget(Widget w) {
contentPanel.setSize("100%","100%");
contentPanel.setWidget(w);
super.setContentWidget(contentPanel);
}
public void onResize() {
int w=Window.getClientWidth();
int h=Window.getClientHeight();
super.setPixelSize(w, h);
}
}
(2) Next, instantiate a HeaderLayoutPanel. The header and footer widgets are assigned
a fixed height (e.g. menu bar height), and their width adjusts automatically to the
width of the panel. The center widget should be a ProvidesSize. I used a LayoutPanel.
For example,
public class AppViewer extends Composite implements MyApp.AppDisplay {
private HeaderLayoutPanel allContentsPanel;
MenuBar menuBarTop;
MenuBar menuBarBottom;
LayoutPanel dataPanel;
public AppViewer() {
allContentsPanel = new HeaderLayoutPanel();
menuBarTop = new MenuBar(false);
menuBarBottom = new MenuBar(false);
dataPanel = new LayoutPanel();
menuBarTop.setHeight("30px");
menuBarBottom.setHeight("20px");
allContentsPanel.setHeaderWidget(menuBarTop);
allContentsPanel.setFooterWidget(menuBarBottom);
allContentsPanel.setContentWidget(dataPanel);
initWidget(allContentsPanel);
}
#Override
public void doOnResize() {
allContentsPanel.onResize();
}
}
(3) The center widget (LayoutPanel) will hold the DeckLayoutPanel, which I defines in a
separate Composite (but you can do whatever you want). For example,
public class MyDataView extends Composite implements MyDataPresenter.DataDisplay {
private DockLayoutPanel pnlAllContents;
private HorizontalPanel hpnlButtons;
private HorizontalPanel hpnlToolbar;
private VerticalPanel pnlContent;
public MyView() {
pnlAllContents=new DockLayoutPanel(Unit.PX);
pnlAllContents.setSize("100%", "100%");
initWidget(pnlAllContents);
hpnlToolbar = new HorizontalPanel();
hpnlToolbar.setWidth("100%");
pnlAllContents.addNorth(hpnlToolbar, 30);
hpnlButtons = new HorizontalPanel();
hpnlButtons.setWidth("100%");
pnlAllContents.addSouth(hpnlButtons,20);
pnlContent=new VerticalPanel();
//center widget - takes up the remainder of the space
pnlAllContents.add(pnlContent);
...
}
}
(4) Finally everything gets tied together in the onModuleLoad() class: AppViewer generates
the display which is added to the RootLayoutPanel, and MyDataView generates a display.asWidget()
that is added to the container. For example,
public class MyApp implements EntryPoint,Presenter{
private HasWidgets container=RootLayoutPanel.get();
private static AppDisplay display;
private DataPresenter dataPresenter;
public interface AppDisplay extends Display{
#Override
Widget asWidget();
HasWidgets getContentContainer();
void doOnResize();
}
#Override
public void onModuleLoad() {
display=new AppViewer();
dataPresenter = new DataPresenter();
display.getContentContainer().add(dataPresenter.getDisplay().asWidget());
container.add(display.asWidget());
bind();
}
#Override
public void bind() {
Window.addResizeHandler(new ResizeHandler() {
#Override
public void onResize(ResizeEvent event) {
display.doOnResize();
}
});
}
#Override
public com.midasmed.client.presenter.Display getDisplay() {
return display;
}
}
Hope this helps!
Well, I haven't been able to solve this but, for future visitors: the same can be achieved (minus the problem I couldn't fix) using a DockLayourPanel with a north, center and south components.
i created a dialog box using uiBinder in gwt app, it works fine except it cannot move around. i don't know what's wrong with it, do i have to set caption in order to move it around?
here is my code:
myDialog.ui.xml
<g:HTMLPanel ui:field="_glossaryPanel">
<div class="dialogBox">
<h3>content goes here..</h3>
<p>More content...</p>
</div>
</g:HTMLPanel>
myDialog.java
public class MyDialog extends DialogBox {
private static MyDialogUiBinder uiBinder = GWT.create(MyDialogUiBinder.class);
interface MyDialogUiBinder extends UiBinder<Widget, MyDialog> {
}
public MyDialog() {
setWidget(uiBinder.createAndBindUi(this));
this.setModal(true);
this.setAutoHideEnabled(true);
}
FooterView.java
public class FooterView extends Composite implements FooterPresenter.Display {
interface Binder extends UiBinder<Widget, FooterView> {
}
private static final Binder BINDER = GWT.create(Binder.class);
#UiField
Anchor _glossary;
#UiHandler("_glossary")
public void handleGlossaryClick(ClickEvent event) {
MyDialog mDialog = new MyDialog();
mDialog.setGlassEnabled(true);
mDialog.setAnimationEnabled(true);
mDialog.center();
mDialog.show();
}
See http://gwt.google.com/samples/Showcase/Showcase.html#!CwDialogBox You have to use a DialogBox (not a PopupPanel) to move the thing around.
EDIT:
I tried your code and it worked for me. Have you tried clicking in the border (not content!) to drag the dialog box around?
GWT Dialogs can't be moved around like a desktop window. There was a projected called gwt-windows that would let you do that, but it hasn't been updated in years.
Maybe you could try in your ui.xml file to change the root element type
from HTMLpanel to a FlowPanel
I saw somewhere that was saying something like this. where ? I can't remember :-(
your <div clas="dialogBox"> is, in my opinion, a bit confusing, maybe yould consider renaming to something more personal and less in gwt keywords' like.
Here is the Solution,
VerticalPanel panel;
DialogBox dialogbox;
PopupPanel glass;
VerticalPanel DialogBoxContents;
ClickListener listener;
HTML message;
Button button;
SimplePanel holder;
public void demo()
{
// Create a panel and add it to the screen
panel = new VerticalPanel();
RootPanel.get("demo").add(panel);
panel.setStyleName("table-center");
//
// Create a DialogBox with a button to close it
dialogbox = new DialogBox(false);
dialogbox.setStyleName("demo-DialogBox");
DialogBoxContents = new VerticalPanel();
dialogbox.setText("DialogBox");
message = new HTML("Click 'Close' to close");
message.setStyleName("demo-DialogBox-message");
listener = new ClickListener()
{
public void onClick(Widget sender)
{
dialogbox.hide();
}
};
button = new Button("Close", listener);
holder = new SimplePanel();
holder.add(button);
holder.setStyleName("demo-DialogBox-footer");
DialogBoxContents.add(message);
DialogBoxContents.add(holder);
dialogbox.setWidget(DialogBoxContents);
//
// Add a button to the demo to show the above DialogBox
listener = new ClickListener()
{
public void onClick(Widget sender)
{
dialogbox.center();
}
};
button = new Button("Show DialogBox", listener);
panel.add(button);
}
Check out the DEMO AT http://examples.roughian.com/index.htm#Widgets~DialogBox
"do i have to set caption in order to move it around?"
Yes.
dialogbox.setText("DialogBox");
You may drag only catpion div;
When you drag caption div, whole dialog box will move.
Is there a way to add image or icon inside a GWT TextBox widget?
EDIT: The image is required to have a ClickHandler.
If you are only interested in visually adding an icon , you can add it using css such as :
background-image:url('icon.png');
background-repeat:no-repeat;
UPDATE :
If you need to add events to image, you can bind an image and a textbox in a horizontal panel as in #Sandro Munda's answer. Also another method is to use an absolute panel and css to make the image and the textbox overlap as such :
public class TextBoxWithImage extends Composite {
public TextBoxWithImage() {
AbsolutePanel p = new AbsolutePanel();
p.add(new TextBox());
Image image = new Image("images/down.png");
image.getElement().getStyle().setMarginLeft(-20, Unit.PX);
p.add(image);
image.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
Window.alert("Clicked!");
}
});
initWidget(p);
}
}
Not directly.
You can extend an HorizontalPanel and create your new widget like the ValueSpinner class does (from the Gwt Mosaic project).
ValueSpinner.java
As you can see, the ValueSpinner joins a TextBox and an Image inside a HorizontalPanel to create the widget.
It seems that Panel doesn't inherit from HasClickHandlers and I can't add a clickHandler to DivElement. Is there any way to add the clickHandler to a DIV?
EDIT: The reason I can't use Label as that the DIV I want to be clickable contains other DIV.
By default, Panel doesnt 'sink' the onCLick event. That is, clicking on Panels doesnt actually result into a 'ClickEvent' and hence the handler isnt fired. To use click events with Panel (or for that matter any other Widget) you must first invoke sinkEvents() on it with the appropriate event bits.
For example:
SimplePanel p = new SimplePanel();
p.sinkEvents(Event.ONCLICK);
p.setTitle("Click me");
p.setSize("600px", "600px");
p.addHandler(new ClickHandler(){
#Override
public void onClick(ClickEvent event) {
Window.alert("SimplePanel clicked!");
}
}, ClickEvent.getType());
The above piece of code first 'enables' click events for the SimplePanel using p.sinkEvents(Event.ONCLICK); and then goes on to add the standard ClickHandler onto it. Note that even though SimplePanel doesnt implement HasClickHandlers, you can always add a handler using the addHandler() method.
Use the FocusPanel.
A simple panel that makes its contents focusable, and adds the ability to catch mouse and keyboard events.
public class ClickableDiv extends FlowPanel implements HasClickHandlers {
#Override
public HandlerRegistration addClickHandler(ClickHandler handler) {
return addDomHandler(handler, ClickEvent.getType());
}
}
That should be all you need. addDomHandler will take care of "sinking" the event type for you.