I tried this code:
public class OwnFlowPanel extends FlowPanel implements HasClickHandlers{
public HandlerRegistration addClickHandler(ClickHandler handler) {
return addDomHandler(handler, ClickEvent.getType());
}
}
and then I used this in another class:
OwnFlowPanel panel = new OwnFlowPanel();
panel.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
Window.alert("Clicked on object id: "+id);
}
});
This didn't work :(
Nevermind! I restarted Eclipse's server and it works now :-P
You could also just put the FlowPanel into a FocusPanel (call setWidget()).
Related
Simple Question:
Verification (1) passes.
Verification (2) does not. Why? How to fix it?
Test
#Test
public void test() {
System.out.println("test");
EventBus eb = mock(EventBus.class);
MyWidget.View v = mock(MyWidget.View.class);
GreetingServiceAsync s = mock(GreetingServiceAsync.class);
HasClickHandlers button = mock(HasClickHandlers.class);
when(v.getButton()).thenReturn(button);
new MyWidget(eb, v, s);
button.fireEvent(mock(ClickEvent.class));
verify(button).addClickHandler(any(ClickHandler.class)); (1)
verify(v).alert(anyString()); (2)
}
Widget
#Inject
public MyWidget(EventBus eventBus, View view, GreetingServiceAsync service){
this.view = view;
this.service = service;
bindView();
bindEventBus();
}
private void bindView(){
view.getButton().addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
view.alert("test");
}
});
}
because button is a mock, so calling fireEvent on it doesn't actually fire the event; and onClick is never called on the view.
Because Button was mocked out and there is no implementation telling it what to do when fireEvent is called. See the line:
HasClickHandlers button = mock(HasClickHandlers.class);
...
button.fireEvent(mock(ClickEvent.class));
As David Wallace said, you are mocking the button. It does lose all its abilities.
you could fix this by making a ArgumentCatptor
ArgumentCaptor<ClickHandler> captor = ArgumentCaptor.forClass(ClickHandler.class);
Then manually fire the function of the event by using:
captor.getValue().onClick(null);
This will fake the call that should have been made by the button.
If your class only has one button or one catcher for a specific event you can make it extend the ClickHandler class. Then you can just call the onClick of your class.
That is what I did:
public class ClickableElement implements HasClickHandlers{
ClickHandler ch;
#Override
public void fireEvent(GwtEvent<?> event) {
ch.onClick((ClickEvent) event);
}
#Override
public HandlerRegistration addClickHandler(ClickHandler handler) {
this.ch = handler;
return null;
}
};
I'm trying to get up to speed on using GWT Activities and Places. I'm testing with some source code originally found on this good blog post.
I'm finding the Handlers that get added during bind() never seem to removed. My little understanding of the Activity javadoc had me thinking they should get automagically removed by the time the Activity's onStop() method is invoked.
All event handlers it registered will have been removed before this
method is called.
But each time I click a button the corresponding handler is called n+1 times.
What am I missing? Please let me know if there is more info I can provide.
Here's a relevant snippet from the code:
public class ContactsActivity extends AbstractActivity {
private List<ContactDetails> contactDetails;
private final ContactsServiceAsync rpcService;
private final EventBus eventBus;
private final IContactsViewDisplay display;
private PlaceController placeController;
public interface IContactsViewDisplay {
HasClickHandlers getAddButton();
HasClickHandlers getDeleteButton();
HasClickHandlers getList();
void setData(List<String> data);
int getClickedRow(ClickEvent event);
List<Integer> getSelectedRows();
Widget asWidget();
}
public ContactsActivity(ClientFactory factory) {
GWT.log("ContactActivity: constructor");
this.rpcService = factory.getContactServiceRPC();
this.eventBus = factory.getEventBus();
this.display = factory.getContactsView();
this.placeController = factory.getPlaceController();
}
#Override
public void start(AcceptsOneWidget container, EventBus eventBus) {
GWT.log("ContactActivity: start()");
bind();
container.setWidget(display.asWidget());
fetchContactDetails();
}
public void bind() {
GWT.log("ContactActivity: bind()");
display.getAddButton().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
GWT.log("Add button clicked");
ContactsActivity.this.placeController.goTo(new NewContactPlace(""));
}
});
display.getDeleteButton().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
GWT.log("ContactActivity: Delete button clicked");
deleteSelectedContacts();
}
});
display.getList().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
GWT.log("ContactActivity: List clicked");
int selectedRow = display.getClickedRow(event);
if (selectedRow >= 0) {
String id = contactDetails.get(selectedRow).getId();
ContactsActivity.this.placeController.goTo(new EditContactPlace(id));
}
}
});
}
Events registered via. the EventBus passed to AbstractActivity#start() will be unregistered by the time onStop() is called. The event handlers registered in the above bind() method, however, are not registered via the EventBus and are not visible to the abstract base class. You need to unregister them yourself:
public class ContactsActivity extends AbstractActivity {
private List<HandlerRegistration> registrations = new ArrayList();
private void bind() {
registrations.add(display.getAddButton().
addClickHandler(new ClickHandler() { ... }));
registrations.add(display.getDeleteButton().
addClickHandler(new ClickHandler() { ... }));
registrations.add(display.getList().
addClickHandler(new ClickHandler() { ... }));
}
#Override
public void onStop() {
for (HandlerRegistration registration : registrations) {
registration.removeHandler();
}
registrations.clear();
}
}
I found it best to handle registration in the view - make it responsible for only keeping one click hander active for each button.
Instead of:
class View {
Button commitButton;
public HasClickHandlers getCommit () {return commitButton;}
}
..and link to this in the Activity:
view.getCommit.addClickHandler(new Clickhandler()...
Do this in the View:
class View {
private Button commitButton;
private HandlerRegistration commitRegistration = null;
public void setCommitHandler (ClickHandler c) {
commitRegistraion != null ? commitRegistration.removeRegistration ();
commitRegistration = commitButton.addClickHandler (c);
}
}
And the Activity:
view.setCommitHandler (new ClickHandler () ...
Hope that helps.
I trying to pass a parameter in the placerequest to a presenter that will be a popup, but, the i receive empty parameters in the popup presenter.. am i forgot anything?
AddProjetoPresenter
public class AddProjetoPresenter extends Presenter<AddProjetoPresenter.AddProjetoView, AddProjetoPresenter.AddProjetoProxy>
{
#ProxyCodeSplit
#NameToken(NameTokens.addproj)
public interface AddProjetoProxy extends ProxyPlace<AddProjetoPresenter>
{
}
public interface AddProjetoView extends View
{
HasValue<String> getNome();
HasValue<Date> getDtInicio();
HasValue<Date> getDtFim();
HasClickHandlers getAddRequisitos();
HasClickHandlers getAddStakeholders();
HasClickHandlers getBtCancelar();
HasClickHandlers getBtSalvar();
}
private final DispatchAsync dispatch;
private final PlaceManager placeManager;
private Projeto projeto;
#Inject
public AddProjetoPresenter(final EventBus eventBus, final AddProjetoView view, final AddProjetoProxy proxy, final DispatchAsync dispatch,
final PlaceManager placeManager)
{
super(eventBus, view, proxy);
this.dispatch = dispatch;
this.placeManager = placeManager;
}
#Override
protected void revealInParent()
{
RevealContentEvent.fire(this, MainPresenter.TYPE_SetMainContent, this);
}
#Override
protected void onBind()
{
super.onBind();
getView().getBtSalvar().addClickHandler(new ClickHandler()
{
#Override
public void onClick(ClickEvent event)
{
}
});
getView().getAddRequisitos().addClickHandler(new ClickHandler()
{
#Override
public void onClick(ClickEvent event)
{
PlaceRequest pr = new PlaceRequest(NameTokens.addreq);
pr.with("oi", "oiiiii"); // HERE
placeManager.revealPlace(pr, false);
}
});
}
}
AddRequisitoPresenter
public class AddRequisitoPresenter extends Presenter<AddRequisitoPresenter.AddRequisitoView, AddRequisitoPresenter.AddRequisitoProxy>
{
#ProxyCodeSplit
#NameToken(NameTokens.addreq)
public interface AddRequisitoProxy extends ProxyPlace<AddRequisitoPresenter>
{
}
public interface AddRequisitoView extends PopupView
{
DialogBox getDialog();
}
private final DispatchAsync dispatcher;
private Projeto projeto;
#Inject
public AddRequisitoPresenter(final EventBus eventBus, final AddRequisitoView view, final AddRequisitoProxy proxy, final DispatchAsync dispatcher)
{
super(eventBus, view, proxy);
this.dispatcher = dispatcher;
}
#Override
public void prepareFromRequest(PlaceRequest request)
{
super.prepareFromRequest(request);
getView().getDialog().setText(request.getParameterNames().size() + ""); //SIZE IS ZERO!!
}
#Override
protected void onBind()
{
super.onBind();
}
#Override
protected void revealInParent()
{
RevealRootPopupContentEvent.fire(this, this);
}
}
I think ai doing something wrong...
thanks in advance.
From what I understood in the wiki, a popup can't be a place, and it needs a parent presenter.
I see two obvious problems here :
Your second presenter (the popup) should implement PresenterWidget, not Presenter
You can't display a popup by calling placeManager.revealPlace(), because a popup is not a place. Instead, you have to apply one of the two methods explained in the wiki (addToPopupSlot() or RevealRootPopupContentEvent.fire(), both called from the parent).
I'm trying to bind a GWT view with its presentation layer, but it doesn't seem to be doing anything.
It's a Spring Roo GWT generated project and I'm trying to use the scaffold given as far as possible.
The view is a simple button (R.ui.xml) and the rest of the view is defined in R.java:
public class R extends Composite implements RPresenter.Display {
interface MyUiBinder extends UiBinder<Widget, R> {}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
#UiField Button myButton;
private ClickHandler buttonClickHandler = null;
public R(){
initWidget(uiBinder.createAndBindUi(this));
}
#UiHandler("myButton")
void onButtonClick(ClickEvent event){
GWT.log('Button clicked');
if (buttonClickHandler != null){
GWT.log("buttonClickHandler event triggered");
buttonClickHandler.onClick(event);
}
}
#Override
public void setButtonClickHandler(ClickHandler buttonClickHandler) {
GWT.log("setButtonClickHandler");
this.buttonClickHandler = buttonClickHandler;
}
}
The presenter:
public class RPresenter {
public interface Display extends IsWidget {
void setButtonClickHandler(ClickHandler buttonClickHandler);
}
private final Display display;
private final EventBus eventBus;
#Inject
public RPresenter(EventBus eventBus, Display display){
this.display = display;
this.eventBus = eventBus;
bind();
}
private void bind(){
display.setButtonClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
GWT.log("onClick event triggered");
}
});
}
public void go(HasWidgets container){
container.add(display.asWidget());
}
}
And for my GIN module I use the generated ScaffoldModule in the ...client.scaffold.ioc package:
public class ScaffoldModule extends AbstractGinModule {
#Override
protected void configure() {
GWT.log("ScaffoldModule configure");
bind(EventBus.class).to(SimpleEventBus.class).in(Singleton.class);
bind(ApplicationRequestFactory.class).toProvider(RequestFactoryProvider.class).in(Singleton.class);
bind(PlaceController.class).toProvider(PlaceControllerProvider.class).in(Singleton.class);
//bind(RPresenter.Display.class).to(R.class).in(Singleton.class);
bind(RPresenter.Display.class).to(R.class);
}
static class PlaceControllerProvider implements Provider<PlaceController> {
private final EventBus eventBus;
#Inject
public PlaceControllerProvider(EventBus eventBus) {
this.eventBus = eventBus;
}
public PlaceController get() {
return new PlaceController(eventBus);
}
}
static class RequestFactoryProvider implements Provider<ApplicationRequestFactory> {
private final EventBus eventBus;
#Inject
public RequestFactoryProvider(EventBus eventBus) {
this.eventBus = eventBus;
}
public ApplicationRequestFactory get() {
ApplicationRequestFactory requestFactory = GWT.create(ApplicationRequestFactory.class);
requestFactory.initialize(eventBus);
return requestFactory;
}
}
}
In the GWT development mode console, the "ScaffoldModule configure" never displays, yet the generated scaffold seems to binding just fine as the events get passed along from component to component without a hitch, unless the binding is magically happening somewhere else and that is dead code.
When I put my bind(RPresenter.Display.class).to(R.class) in, it doesn't seem to do the binding. The only output I get in the GWT console is "Button clicked" which is called in the view and then nothing further. I'm clearly missing something, any ideas?
The call to GWT.log() will not output anything from an AbstractGinModule - classes that extend AbstractGinModule (ScaffoldModule in your situation) are used by gin at compile time to decide which concrete implementations to use for injected interfaces. From the rest of your description (i.e. that the UI shows up in the application) it appears that your dependency injection is working correctly.
I have a gwt VerticalPanel class that i need to handel KeyDown events for it.
the method i used to implement keyboard handler in my class is:
i add :
this.sinkEvents(Event.ONKEYDOWN);
to constructor
then i override method onBrowserEvent() to handle key down event.
#Override
public void onBrowserEvent(Event event) {
// TODO Auto-generated method stub
super.onBrowserEvent(event);
int type = DOM.eventGetType(event);
switch (type) {
case Event.ONKEYDOWN:
//call method to handle this keydown event
onKeyDownEvent(event);
break;
default:
return;
}
}
however this method doesn’t work for this VerticalPanel class.no KeyDown Event is fired when i press a key!
there are specific gwt widgets that support KeyDownHandler like Button etc..VerticalPanel is not one of them..so we need a work around to register a KeyDownHandler on a class extending VerticalPanel.
can you suggest an idea or hint?
thanks
You could create a Composite that wrappes a FocusPanel and a VerticalPanel. This way you can catch all key events provided the FocusPanel is focused. Simply delegate the needed methods to the panels:
public void onModuleLoad() {
ExtendedVerticalPanel panel = new ExtendedVerticalPanel();
panel.add(new Label("some content"));
panel.addKeyDownHandler(new KeyDownHandler() {
#Override
public void onKeyDown(KeyDownEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
Window.alert("enter hit");
}
}
});
RootPanel.get().add(panel);
}
private class ExtendedVerticalPanel extends Composite implements HasWidgets, HasAllKeyHandlers {
private VerticalPanel fVerticalPanel;
private FocusPanel fFocusPanel;
public ExtendedVerticalPanel() {
fVerticalPanel = new VerticalPanel();
fFocusPanel = new FocusPanel();
fFocusPanel.setWidget(fVerticalPanel);
initWidget(fFocusPanel);
}
#Override
public void add(Widget w) {
fVerticalPanel.add(w);
}
#Override
public void clear() {
fVerticalPanel.clear();
}
#Override
public Iterator<Widget> iterator() {
return fVerticalPanel.iterator();
}
#Override
public boolean remove(Widget w) {
return fVerticalPanel.remove(w);
}
#Override
public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
return fFocusPanel.addKeyUpHandler(handler);
}
#Override
public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
return fFocusPanel.addKeyDownHandler(handler);
}
#Override
public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
return fFocusPanel.addKeyPressHandler(handler);
}
}
UPDATE
Your question on how to prevent the browser from scrolling when the arrow keys are pressed. Here a small example that works for me:
public void onModuleLoad() {
ExtendedVerticalPanel panel = new ExtendedVerticalPanel();
// make panel reeeeaally big
panel.setHeight("3000px");
panel.add(new TextBox());
panel.addKeyDownHandler(new KeyDownHandler() {
#Override
public void onKeyDown(KeyDownEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_DOWN) {
Window.alert("down hit");
event.preventDefault();
}
}
});
RootPanel.get().add(panel);
}
Add the handlers you need and call preventDefault() on the events the browser must not take care of.