GWT SimplePager : How to change the button images of the pager? - gwt

I want to change the button images of pager (first, last, next, prev, fastforward). I tired using CSS but i haven't been able to achieve it. Any Help or Suggestion would be appreciated.
I am using GWT 2.4.0

You need to extend SimplePager.Resources interface and provide your own images. Then pass on an instance of these resources into the SimplePager constructor:
public interface MyPagerImages extends SimplePager.Resources
{
// Here you can #Override all the methods and place #Source annotation to tell
// SimplePager what image should be loaded as a replacement
// For example here I am replacing the Fast Forward image.
#Override
#Source( "myFastForward.gif" )
ImageResource simplePagerFastForward()
}
then when constructing the SimplePager:
MyPagerImages myImages = GWT.create(MyPagerImages.class);
SimplePager pager = new SimplePager(SimplePager.TextLocation.CENTER,
myImages, true, 1000 /* that's the default */, false);

Related

GWT: How to dynamically load a new image?

I want to fetch an image from a remote server (not my app's server, but I don't think that matters) and display it in an existing Image widget. The existing widget displays its original content, from a ClientBundle ImageResource , OK.
In UiBinder template:
<g:Image ui:field='myImage' resource='{res.anImage}'/>
In code:
#UiField Image myImage;
...
int width = Window.getClientWidth();
int height = Window.getClientHeight();
String url = ...;
myImage.addErrorHandler(new ErrorHandler() {
public void onError(ErrorEvent event) {
Window.alert("Error getting image data: " + event);
}
});
myImage.addLoadHandler(new LoadHandler() {
public void onLoad(LoadEvent event) {
Window.alert("LoadEvent: " + event);
}
});
myImage.setUrlAndVisibleRect(url, 0, 0, width, height);
As far as I can tell setUrlAndVisibleRect is a no-op. FireBug reports no network activity -- no request to the server specified by the URL. What am I overlooking? In my extended thrashing about trying to get this working I have inferred that it may have something to do with myImage not being "logically attached", but I'm not entirely sure what that means and I've no idea how to correct it if that is the problem.
EDIT with SUMMARY of SOLUTION:
My initial hunch was right. Because I had chosen to implement the image code within a second pseudo-widget (...extends Composite) that shared my UiBinder template with the main pseudo-widget that implements most of my app's UI, I got into trouble. I neglected to add this second pseudo-widget to the RootPanel as is normally done in the class that implements EntryPoint. This left my Image widget unattached to the widget chain, because its parent, the second pseudo-widget, was unattached. And an Image widget must be attached to work. What I ended up doing is moving the Image code back into my main app/GUI class, i.e., into the first and now only pseudo-widget and abandoning the special class for the Image code. I did that because it's simpler and the Image code turns out not to be as long as I had originally thought.
Adding image to the DOM is little tricky,the below code which supports all the browsers(setVisibility trick added to support IE also,as It has a different way to image rendering).
I did'nt use setUrlAndVisibleRect before and AFAIK,Image must render to the DOM inorder to resize it.Just try the below codes.
image.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
//Do your operations on image .//resize ..etc
image.getElement().getStyle().setVisibility
(Style.Visibility.Visible);
}
});
image.getElement().getStyle().setVisibility(Style.Visibility.HIDDEN);
RootPanel.get().add(image);
image.setUrl(url);
You are using ClientBundle ImageResource which is compile time. You cannot change it unless you replace the new image with exact name in the exact position of prev one. One of the possible hack which is possible is, place the image in a div with its ID set ( getElement().setId("your ID") ). Once you get you new image you use RootPanel.get("Your Id") and do your job.

How to force GWT to add unique ID to each DOM element?

I am having a GWT app,
I would like to add ID to each element automaticlly
if it's impossible, what would be the fastest way to do it manually?
I am not so sure about performance issues. How would adding a dew ids in a form of 10-20 widgets cause performance loss?
To automagically set debug ids on widgets you need to include following in your module.gwt.xml file.
<!-- Enable debug ID. -->
<inherits name="com.google.gwt.user.Debug"/>
<set-property name="gwt.enableDebugId" value="true"/>
You can create your own Widget class that extends GWT Widget and sets an id to each one:
public class myWidget extends Widget {
public myWidget(String id) {
super();
getElement().setId("id");
}
public void setId(String id) {
// Use this method if you use Ui:Binder
getElement().setId("id");
}
}
You can, obviously, extend other classes instead of Widget if you don't need id on all widgets, like FlowPanel, Button, etc.
If you want to have an element to have an Id always, you can go with ensureDebugId of UI Object class. It make sure that, your element have an Id set before attaching it to the dom.
Yes its Possible :
First way:
Button b = new Button();
DOM.setElementAttribute(b.getElement(), "id", "my-button-id")
Second way :
FlowPanel panel = new FlowPanel();
panel.getElement().setId("my-flowpanel-id");
If you want to do assign all the id's attached to DOM you can do
Iterator<Widget> iterator = RootPanel.get().iterator();
while(iterator.hasNext()) {
Widget w = iterator.next();
w.getElement().setId("id");
}

GWT: TabLayoutPanel with custom tabs does not display correctly

I have a TabLayoutPanel where I am putting custom widgets in for the tabs to be able to display some images next to the text. I originally worked with TabPanel and using custom HTML for the tab text, but custom tab widgets allows me to modify the image on the fly as needed.
My tab widget is essentially a HorizontalPanel, a number of small images, and a line of text. The problem I'm having is that the tab doesn't want to stick to the bottom of the tab bar like normal. The tab is getting positioned at the top of the space reserved for the tab bar, and there's a gap between it and the bottom of the tab bar. I uploaded an image of the problem to http://imgur.com/fkSHd.jpg.
Is there some style that I need to apply to custom widget tabs to make them appear correctly?
In my brief experience, the newer standards mode panels (they all end in "LayoutPanel") don't get along with the older ones (the ones that just end in "Panel"). So you might consider trying a DockLayoutPanel instead of the HorizontalPanel, and it may be more cooperative.
See https://developers.google.com/web-toolkit/doc/latest/DevGuideUiPanels, particularly the section called "What won't work in Standards Mode?":
HorizontalPanel is a bit trickier. In some cases, you can simply
replace it with a DockLayoutPanel, but that requires that you specify
its childrens' widths explicitly. The most common alternative is to
use FlowPanel, and to use the float: left; CSS property on its
children. And of course, you can continue to use HorizontalPanel
itself, as long as you take the caveats above into account.
After a bit more research, I found the answer here: https://groups.google.com/d/msg/google-web-toolkit/mq7BuDaTNgk/wLqPm5MQeicJ. I had to use InlineLabel or InlineHTML widgets instead of normal Label or HTML widgets. I've tested this solution and it does exactly what I want. I pasted the code of the class below for completeness. Note two things here:
The "float" attribute cannot be set on the last element (the InlineLabel) or the incorrect drawing condition occurs again.
The code could be cleaned up a bit further by having the class extend directly from FlowPanel instead of making it a composite containing a FlowPanel.
package com.whatever;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Float;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.InlineLabel;
public class StatusTab extends Composite
{
public interface StatusImages extends ClientBundle
{
public static StatusImages instance = GWT.create(StatusImages.class);
#Source("images/status-green.png")
ImageResource green();
#Source("images/status-red.png")
ImageResource red();
}
private final ImageResource greenImage;
private final ImageResource redImage;
private final FlowPanel flowPanel;
public LinkStatusTab(String text, int numStatuses) {
greenImage = StatusImages.instance.green();
redImage = StatusImages.instance.red();
flowPanel = new FlowPanel();
initWidget(flowPanel);
for (int i = 0; i < numStatuses; i++)
{
Image statusImg = new Image(redImage);
statusImg.getElement().getStyle().setMarginRight(3, Unit.PX);
statusImg.getElement().getStyle().setFloat(Float.LEFT);
flowPanel.add(statusImg);
}
flowPanel.add(new InlineLabel(text));
}
/**
* Sets the image displayed for a specific status entry.
*/
public void setStatus(int which, boolean status)
{
Image image = (Image)flowPanel.getWidget(which);
if (status)
image.setResource(greenImage);
else
image.setResource(redImage);
}
}

Inserting GWT widget into a div element

I'm using a GWT library (gwt-openlayers) which allows me to create a map popup containing arbitrary HTML, similar to Google Maps. I need this HTML to contain a GWT Button widget.
I'm creating some HTML elements on-the-fly like this:
Element outerDiv = DOM.createDiv();
outerDiv.getStyle().setOverflow(Overflow.HIDDEN);
outerDiv.getStyle().setWidth(100, Unit.PCT);
outerDiv.appendChild(new HTML(mapPOI.getHtmlDetails()).getElement());
Button popupButton = new Button("View Property");
popupButton.getElement().getStyle().setFloat(com.google.gwt.dom.client.Style.Float.RIGHT);
outerDiv.appendChild(popupButton.getElement());
Then I'm getting the source HTML for these elements by calling
String src = outerDiv.toString();
and inserting this html into my map marker. Now my map marker displays the content ok, including the button. However, the button won't respond to any events! From what I can gather, this is because the buttons onAttach() method is never being called.
Is there a better way to do this?
Thanks,
Jon
~~~~EDIT~~~~
I'm now trying a new way of doing this, which seems to be the accepted method looking at other similar posts.
First I'm creating my div:
String divId = "popup-" + ref;
String innerHTML = "<div id=\"" +divId + "\"></div>";
Then I'm adding this to my map popup and displaying it (which adds it to the DOM). After the popup has been displayed, I'm getting the Element as follows and trying to wrap a HTMLPanel around it:
Element element = Document.get().getElementById(divId);
HTMLPanel popupHTML = HTMLPanel.wrap(element);
My div element is successfully retrieved. However, HTMLPanel.wrap(element); doesn't complete. The reason for this is that wrap(..) calls RootPanel.detachOnWindowClose(Widget widget), which includes the following assertions:
assert !widgetsToDetach.contains(widget) : "detachOnUnload() called twice "
+ "for the same widget";
assert !isElementChildOfWidget(widget.getElement()) : "A widget that has "
+ "an existing parent widget may not be added to the detach list";
I put some breakpoints in and it seems that the 2nd assertion is failing!
Does anybody have any idea why this might be the case? Should failing this assertion really result in a complete failure of the method (no return)?
Your first approach is good, you just need to register onClick event for your button like this:
DOM.sinkEvents(popupButton.getElement(), Event.ONCLICK);
DOM.setEventListener(popupButton.getElement(), new EventListener() {
#Override
public void onBrowserEvent(Event event) {
//implement the logic after click
}
});
I have checked this, it works 100%!
You might try something like
RootPanel.get("idOfYourMapMarker").add(popupButton);
See RootPanel.get()
Unfortunately, RootPanels are AbsolutePanels which aren't so nice for layout but could work if you just have a simple button to add. You could also try RootLayoutPanel which will give you a LayoutPanel (also not so nice when you just want things to flow). You might end up creating a container widget that does the layout for you, and adding that to the RootPanel.
SimplePanel is a DIV. Perhaps that can be used instead?
You added the element, but you have to keep the hierarchy of the actual GWT Widgets too.
I don't see a clean way to do this, but you could use something like jQuery to grab the button by and ID and add a click handler back to it that would call the original click handler.
private static native void registerEvents(String buttonId, MyClass instance)/*-{
var $ = $wnd.$;
//check click
$('#'+buttonId).live('click', function(e) {
e.preventDefault();
instance.#com.package.MyClass::handleButtonClick(Lcom/google/gwt/event/dom/client/ClickEvent;)(null);
});
}-*/;
Call this registerEvents() either in your onAttach or constructor.
I once had a similar problem. You can use the gwt-openlayer's MapWidget as follows:
private MapWidget createMapWidget() {
final MapOptions defaultMapOptions = new MapOptions();
defaultMapOptions.setDisplayProjection(DEFAULT_PROJECTION);
defaultMapOptions.setNumZoomLevels(TOTAL_ZOOM_LEVELS);
MapWidget mapWidget = new MapWidget(MAP_WIDGET_WIDTH, MAP_WIDGET_HEIGHT, defaultMapOptions);
map = mapWidget.getMap();
return mapWidget;
}
And then add it to any panel be it vertical or horizontal.
MapWidget mapWgt = createMapWidget();
VerticalPanel mainPanel = new VerticalPanel();
mainPanel.add(mapWgt);
...
... add whatever you want
...
You can finally add the created Panel(containing the MapWidget and the gwt widget) to the PopupPanel. Also, you should now be able to add handlers to the gwt button.

Using Google Visualization in GWT 2.0

I'm working on learning GWT (total newb) and have a question regarding the Visualiztion API provided by Google. This page:
http://code.google.com/p/gwt-google-apis/wiki/VisualizationGettingStarted
Describes getting started with a pie chart (which is what I need). However I'm trying to do this in a composite UI using UiBinder. To that end I don't know how to handle the callback correctly that is shown:
public class SimpleViz implements EntryPoint {
public void onModuleLoad() {
// Create a callback to be called when the visualization API
// has been loaded.
Runnable onLoadCallback = new Runnable() {
public void run() {
Panel panel = RootPanel.get();
// Create a pie chart visualization.
PieChart pie = new PieChart(createTable(), createOptions());
pie.addSelectHandler(createSelectHandler(pie));
panel.add(pie);
}
};
// Load the visualization api, passing the onLoadCallback to be called
// when loading is done.
VisualizationUtils.loadVisualizationApi(onLoadCallback, PieChart.PACKAGE);
}
My First assumption is this would go in the UiBinder constructor, correct? Yet this assumes that I want to place the element in the RootLayoutPanel, and I don't. I can't see an elegant and obvious way of placing it in the binder. I submit that even this guess may be wrong. Any ideas from the experts?
EDIT:
I should make clear my attempt:
public GraphPanel() {
initWidget(uiBinder.createAndBindUi(this));
Runnable onLoadCallback = new Runnable() {
public void run() {
//LayoutPanel panel = RootPanel.
// Create a pie chart visualization.
PieChart pie = new PieChart(createPieTable(), createPieOptions());
pie.addSelectHandler(createSelectHandler(pie));
mySelf.getElement().appendChild(pie.getElement()); // .add(pie);
}
};
// Load the visualization api, passing the onLoadCallback to be called
// when loading is done.
VisualizationUtils.loadVisualizationApi(onLoadCallback, PieChart.PACKAGE);
}
When run I get the following in the Composites DIV:
<div class="gwt-viz-container"></div>
But I see no graph using the code from the above page.
EDIT 2:
This link may provide additional information. However, the solution suggested is not optimal since the app then needs to know more about the widget (and if the widget is even there).
http://vaadin.com/forum/-/message_boards/message/97850
EDIT 3:
It shouldn't matter, but just in case, I'm running FF on Linux. Some articles I've read have implied that this is a problem.
EDIT 4:
Adding:
pie.draw(createPieTable(), createPieOptions());
after the append child gets the graph to display. This implies that the ordering of the example is wrong. If so what is the optimum?
It is also important to know that although the GWT JRE Emulation library supports the Runnable interface, it can't really be used for parallel processing in a separate thread, as the code is compiled into JavaScript which in turn runs single-threaded in the browser. Same goes for the synchronized keyword.
I also would recommend doing all preparation logic in the Widget/Composite's constructor but any actual drawing in the onLoad callback, which you need to override. This callback is called when the widget is loaded in the browser document, it is only then that you can perform any page/layout interaction, like enabling/disabling controls or requesting focus.
Either way you suggest would work. If the Visualization API is used by a bunch of different widgets on the page, then it might be simpler to put the loadVisualizationApi call in the EntryPoint class - an example of this is below.
You can write the Composite like so:
public MyPieChartContainer extends Composite {
interface MyUiBinder extends UiBinder<Widget, MyPieChartContainer>;
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
#UiField Panel panel;
public MyPieChartContainer() {
initWidget(uiBinder.createAndBindUi(this));
PieChart pie = new PieChart(createTable(), createOptions());
pie.addSelectHandler(createSelectHandler(pie));
panel.add(pie);
}
}
And then do this in the EntryPoint:
public class SimpleViz implements EntryPoint {
public void onModuleLoad() {
// Create a callback to be called when the visualization API
// has been loaded.
Runnable onLoadCallback = new Runnable() {
public void run() {
Panel panel = RootPanel.get();
MyPieChartContainer myPieChartContainer = new MyPieChartContainer();
panel.add(myPieChartContainer);
}
};
// Load the visualization api, passing the onLoadCallback to be called
// when loading is done.
VisualizationUtils.loadVisualizationApi(onLoadCallback, PieChart.PACKAGE);
}