Пользовательское событие в виджете GWT не работает

#java #gwt #vaadin7

#java #gwt #vaadin7

Вопрос:

Я работаю над приложением в Vaadin для своих классов. Мне нужно нарисовать какую-то карту на экране, поэтому я использую gwt-graphics lib. У меня также есть некоторый сервлет, который ожидает запросов. Когда придет какой-то конкретный запрос, вид карты должен быть изменен. Это привело меня к подготовке пользовательского события:

 // class NewModulePositionHandler
package com.example.locator;

import com.google.gwt.event.shared.EventHandler;

public interface NewModulePositionHandler extends EventHandler {
    void onNewModulePosition(NewModulePositionEvent event);
}
  

Ниже приведена реализация моего пользовательского события:

 import com.google.gwt.event.shared.GwtEvent;

public class NewModulePositionEvent extends GwtEvent<NewModulePositionHandler> {
    private static final Type<NewModulePositionHandler> TYPE = new Type<NewModulePositionHandler>();
    private final String m_Color;

    public NewModulePositionEvent(String color) {
        m_Color = color;
    }

    public static Type<NewModulePositionHandler> getType() {
        return TYPE;
    }

    public String getColor() {
        return m_Color;
    }

    @Override
    public com.google.gwt.event.shared.GwtEvent.Type<NewModulePositionHandler> getAssociatedType() {
        // TODO Auto-generated method stub
        return TYPE;
    }

    @Override
    protected void dispatch(NewModulePositionHandler handler) {
        handler.onNewModulePosition(this);
    }

}
  

И пришло время для реализации моего пользовательского виджета:

а) MyComp.java

 import com.google.gwt.event.shared.GwtEvent;

public class NewModulePositionEvent extends GwtEvent<NewModulePositionHandler> {
    private static final Type<NewModulePositionHandler> TYPE = new Type<NewModulePositionHandler>();
    private final String m_Color;

    public NewModulePositionEvent(String color) {
        m_Color = color;
    }

    public static Type<NewModulePositionHandler> getType() {
        return TYPE;
    }

    public String getColor() {
        return m_Color;
    }

    @Override
    public com.google.gwt.event.shared.GwtEvent.Type<NewModulePositionHandler> getAssociatedType() {
        // TODO Auto-generated method stub
        return TYPE;
    }

    @Override
    protected void dispatch(NewModulePositionHandler handler) {
        handler.onNewModulePosition(this);
    }

}
  

б) MyCompClientRpc.java

 import com.vaadin.shared.communication.ClientRpc;

public interface MyCompClientRpc extends ClientRpc {

    // TODO example API
    public void alert(String message);
    public void changeColor(String color);
}
  

c) MyCompConnector.java

 package com.example.locator.widgetset.client.mycomp;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.shared.ui.Connect;
import com.example.locator.MyComp;
import com.example.locator.NewModulePositionEvent;
import com.example.locator.NewModulePositionHandler;
import com.example.locator.widgetset.client.mycomp.MyCompWidget;
import com.example.locator.widgetset.client.mycomp.MyCompServerRpc;
import com.vaadin.client.communication.RpcProxy;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.example.locator.widgetset.client.mycomp.MyCompClientRpc;
import com.example.locator.widgetset.client.mycomp.MyCompState;
import com.vaadin.client.communication.StateChangeEvent;

@Connect(MyComp.class)
public class MyCompConnector extends AbstractComponentConnector {
MyCompServerRpc rpc = RpcProxy
        .create(MyCompServerRpc.class, this);

public MyCompConnector() {
    registerRpc(MyCompClientRpc.class, new MyCompClientRpc() {
        public void alert(String message) {
            // TODO Do something useful
            Window.alert(message);
        }
        public void changeColor(String color) {
            getWidget().InitMap(color);         
        }
    });

    // TODO ServerRpc usage example, do something useful instead
    getWidget().addClickHandler(new ClickHandler() {
        public void onClick(ClickEvent event) {
            final MouseEventDetails mouseDetails = MouseEventDetailsBuilder
                .buildMouseEventDetails(event.getNativeEvent(),
                            getWidget().getElement());
            rpc.clicked(mouseDetails);
        }
    });


    getWidget().addNewModulePositionHandler(new NewModulePositionHandler() {

        public void onNewModulePosition(NewModulePositionEvent event) {
            // TODO Auto-generated method stub
            rpc.newModulePosition(event.getColor());
        }

    });

}

@Override
protected Widget createWidget() {
    return GWT.create(MyCompWidget.class);
}

@Override
public MyCompWidget getWidget() {
    return (MyCompWidget) super.getWidget();
}

@Override
public MyCompState getState() {
    return (MyCompState) super.getState();
}

@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
    super.onStateChanged(stateChangeEvent);

    // TODO do something useful
    final String color = getState().color;
    getWidget().InitMap(color);
}

}
  

d) MyCompServerRpc.java

 package com.example.locator.widgetset.client.mycomp;

import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.communication.ServerRpc;

public interface MyCompServerRpc extends ServerRpc {

    // TODO example API
    public void clicked(MouseEventDetails mouseDetails);
    public void newModulePosition(String color);
}
  

e) MyCompState.java

 package com.example.locator.widgetset.client.mycomp;

public class MyCompState extends com.vaadin.shared.AbstractComponentState {

    // TODO example state
    public String color = "#000000";

}
  

And finally implementation of the widget:

f) MyCompWidget.java

 package com.example.locator.widgetset.client.mycomp;
import org.vaadin.gwtgraphics.client.DrawingArea;
import org.vaadin.gwtgraphics.client.Line;
import org.vaadin.gwtgraphics.client.shape.Circle;
import org.vaadin.gwtgraphics.client.shape.Rectangle;

import com.example.locator.HasNewModulePositionHandlers;
import com.example.locator.NewModulePositionEvent;
import com.example.locator.NewModulePositionHandler;
import com.google.gwt.dev.util.collect.HashMap;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.touch.client.Point;
import com.example.locator.Module;

// TODO extend any GWT Widget


public class MyCompWidget extends DrawingArea implements HasNewModulePositionHandlers {

    public static final String CLASSNAME = "mycomp";
    public static double m_AreaWidth = 64.355;
    public static double m_AreaHeight = 17.385;
    public static int m_PictureWidth;
    public static int m_PictureHeight;
    public static double m_AreaToMapRatio;
    public static double m_RouteWidth = 3.5;
    public static double m_MainRouteCoordinateY = 8.0828;
    public Circle circle;
    //public HashMap<Integer, Module> ModuleMap = new HashMap<Integer, Module>();

    public MyCompWidget(){
        super(640, 320);

        //ModuleMap.put(666, new Module(666, 30.0, 8.08, new Circle((int)TranslateCoordinate(30.0), (int)TranslateCoordinate(8.0), 7)));
        //ModuleMap.put(15, new Module(15, 27.0, 8.08, new Circle((int)TranslateCoordinate(30.0), (int)TranslateCoordinate(8.0), 7)));

        double xRatio = m_AreaWidth / 640;
        double yRatio = m_AreaHeight / 320;
        m_AreaToMapRatio = xRatio > yRatio ? xRatio : yRatio;

        InitMap("#919491");
        setStyleName(CLASSNAME);
    }

    public void InitMap(String color)
    {
        m_PictureWidth  = (int)TranslateCoordinate(m_AreaWidth);
        m_PictureHeight  = (int)TranslateCoordinate(m_AreaHeight);
        Rectangle rectangle = new Rectangle(0, 0, m_PictureWidth, m_PictureHeight);
        rectangle.setFillColor(color);
        add(rectangle);
        Point point1Beg = new Point(0.0, 8.0828);
        Point point1End = new Point(64.355, 8.0838);

        Point point2Beg = new Point(20.2825, 8.0828);
        Point point2End = new Point(20.2825, 17.385);

        Point point3Beg = new Point(59.325, 0.0);
        Point point3End = new Point(59.325, 8.0828);

        point1Beg = TranslatePoint(point1Beg);
        point1End = TranslatePoint(point1End);

        point2Beg = TranslatePoint(point2Beg);
        point2End = TranslatePoint(point2End);

        point3Beg = TranslatePoint(point3Beg);
        point3End = TranslatePoint(point3End);

        Line line1 = new Line((int)point1Beg.getX(), (int)point1Beg.getY(), (int)point1End.getX(), (int)point1End.getY());
        Line line2 = new Line((int)point2Beg.getX(), (int)point2Beg.getY(), (int)point2End.getX(), (int)point2End.getY());
        Line line3 = new Line((int)point3Beg.getX(), (int)point3Beg.getY(), (int)point3End.getX(), (int)point3End.getY());

        line1.setStrokeColor("#FFFFFF");
        line2.setStrokeColor("#FFFFFF");
        line3.setStrokeColor("#FFFFFF");

        line1.setStrokeWidth((int)TranslateCoordinate(m_RouteWidth));
        line2.setStrokeWidth((int)TranslateCoordinate(m_RouteWidth));
        line3.setStrokeWidth((int)TranslateCoordinate(m_RouteWidth));

        add(line1);
        add(line2);
        add(line3);

        DrawWall(TranslateCoordinate(10.0));
        DrawWall(TranslateCoordinate(20.0));
        DrawWall(TranslateCoordinate(30.0));
        DrawWall(TranslateCoordinate(40.0));
        DrawWall(TranslateCoordinate(50.0));
        DrawWall(TranslateCoordinate(60.0));

        DrawDoor(3.0, 3.0);
        DrawDoor(13.0, 3.0);
        DrawDoor(23.0, 3.0);
        DrawDoor(33.0, 3.0);
        DrawDoor(43.0, 3.0);
        DrawDoor(53.0, 3.0);
        circle = new Circle((int)TranslateCoordinate(25.0), (int)TranslateCoordinate(8.0), 15);
        add(circle);
    }

    public void DrawWall(double a_Place)
    {
        Line line = new Line((int)a_Place, 0, (int)a_Place, (int)TranslateCoordinate(m_AreaHeight));
        line.setStrokeColor("#FFFFFF");
        add(line);
    }

    public void DrawDoor(double a_Position, double a_Width)
    {
        double realDoorPositionY = m_MainRouteCoordinateY - (m_RouteWidth / 2);
        int doorPositionYTop = (int)TranslateCoordinate(realDoorPositionY) - 1;
        int doorPositionYBottom = (int)TranslateCoordinate(realDoorPositionY   m_RouteWidth)   1;

        Line line = new Line((int)TranslateCoordinate(a_Position), doorPositionYTop, (int)TranslateCoordinate(a_Position)   (int)TranslateCoordinate(a_Width), doorPositionYTop);
        line.setStrokeColor("#000000");
        line.setStrokeWidth(2);
        add(line);
        Line line2 = new Line((int)TranslateCoordinate(a_Position), doorPositionYBottom, (int)TranslateCoordinate(a_Position)   (int)TranslateCoordinate(a_Width), doorPositionYBottom);
        line2.setStrokeColor("#000000");
        line2.setStrokeWidth(2);
        add(line2);
    }

    public Point TranslatePoint(Point a_Point)
    {
        Point translatedPoint = new Point(TranslateCoordinate(a_Point.getX()), TranslateCoordinate(a_Point.getY()));
        return translatedPoint;
    }

    public double TranslateCoordinate(double a_Coordinate)
    {
        return (a_Coordinate) / (m_AreaToMapRatio);
    }

    public void Move(int id) {
        //ModuleMap.get(id).GetCircle().setX(10   circle.getX());
    }


       public HandlerRegistration addNewModulePositionHandler(
                NewModulePositionHandler handler) {
            return addHandler(handler, NewModulePositionEvent.TYPE);
        }

        private void someMethod() {
            fireEvent(new NewModulePositionEvent("#000000"));
        }
        public void emulateEvent() {
            someMethod();
        }
}
  

g) HasNewModulesPositionHandlers.java

 package com.example.locator;

import com.google.gwt.event.shared.HandlerRegistration;

public interface HasNewModulePositionHandlers {
    // Attention! method returns HandlerRegistration, so that handler can be cancelled
    public HandlerRegistration addNewModulePositionHandler(
            NewModulePositionHandler handler);
}
  

Если я скомпилирую набор виджетов, содержащий MyCompWidget, а затем запущу свое приложение на glassfish, я получу следующее сообщение:

Widgetset ‘com.example.locator.widgetset.LocatorWidgetset’ не содержит реализации для com.example.locator.MyComp. Проверьте сопоставление @Connect его компонентного соединителя, файл описания модуля widgetsets GWT и повторно скомпилируйте свой widgetset. Если вы загрузили пакет надстроек vaadin, вы можете обратиться к инструкциям надстройки.

Если я отключу

   public void addNewModulePositionHandler(
            NewModulePositionHandler handler) {
        handlerManager.addHandler(NewModulePositionEvent.getType(), handler);
        // TODO Auto-generated method stub
    }
  

виджет работает правильно (конечно, я также должен закомментировать эти строки из MyCompConnector):

     getWidget().addNewModulePositionHandler(new NewModulePositionHandler() {

        public void onNewModulePosition(NewModulePositionEvent event) {
            // TODO Auto-generated method stub
            rpc.newModulePosition(event.getColor());
        }

    });
  

Кто-нибудь может сказать мне, в чем проблема? Кажется, что компиляция виджета завершается сбоем, но я не могу найти никакой информации об этом.
Пожалуйста, помогите мне.
Заранее спасибо.

Ответ №1:

Проблема компиляции предельно ясна: компилятор GWT не может выполнить поиск исходного кода для указанного класса Java. Вы добавляете исходные файлы в область компилятора GWT в два этапа:

  1. * .java-файлы должны быть доступны через classpath (компилятор eclipse gwt автоматически включает все исходные папки в classpath)
  2. Вам нужно сообщить GWT, что он должен учитывать ваши пакеты во время компиляции
    • Создать .gwt.xml файл в РОДИТЕЛЬСКОМ пакете (относительно ваших исходных файлов) со следующим содержимым (если ваш пакет pkg1.pkg2.pkg3, то вы должны в пакете pkg1.pkg2 создать файл «Pkg3.gwt.xml «, pkg = «pkg3», по соглашению pkg3 обычно называется «клиент»)
 <module>
    <source path="pkg3" />
</module>
  

!!! Будьте осторожны с буквенными регистрами, по соглашению это правильные имена.

  • Добавьте в свой widgetset.gwt.xml файл «наследует» директиву, подобную этой
 <inherits name="pkg1.pkg2.Pkg3" />
  

!!! Обратите внимание на регистры букв (P — заглавная буква в Pkg3 после имени файла Pkg3.gwt.xml ), .gwt.xml здесь опущено

Тогда, прежде всего, Vaadin использует GWT с определенной изюминкой. Я бы рекомендовал просмотреть образцы пользовательских наборов виджетов. Возможно, вам потребуется понять, как передавать события в компоненты, специфичные для Vaadin, и из них. Ниже я объясню, как предполагается реализовать и использовать событие GWT. Я не эксперт в Vaadin, особенно в сложных темах, таких как настройка наборов виджетов.

Итак, говоря о GWT.

По сути, вам нужно понять только две вещи, чтобы заставить (не-DOM, также известные как безразрядные) события работать в GWT.

  1. Поддержка кода
    • Класс события. NewModulePositionEvent в вашем случае.
    • Интерфейс обработчика событий. NewModulePositionHandler в вашем случае.
    • Функциональный интерфейс (необязательно, но рекомендуется). В вашем случае есть обработчики newmodulepositionhandlers.
  2. Шаблон использования
    • По сути, компонент, который должен запускать событие, должен создать соответствующий объект события и передать его методу fireEvent. Вся логика для вызова необходимого habdler предоставляется EventBus (внутренне)
    • Если вам нужно предоставить API для запуска событий извне (например, метод click () для кнопки), это должно быть сделано путем предоставления специальных методов (не раскрывайте внутренний материал, как именно запускается событие)

События DOM отличаются подробным описанием того, как они создаются (браузером) и отправляются (они должны быть явно включены). В любом случае, все события браузера уже реализованы в GWT из коробки.

Итак, типичные реализации для вышеуказанных элементов: для наглядности я привожу выдержки из нашего производственного кода.

1) Класс события

 public class QuestionClickEvent extends GwtEvent<QuestionClickHandler> {

    public QuestionClickEvent(SScript script, SQuestion question) {
        super();
        this.script = script;
        this.question = question;
    }

    public static final Type<QuestionClickHandler> TYPE = new Type<QuestionClickHandler>();

    // internal event state
    private final SScript script;
    private final SQuestion question;

    @Override
    public Type<QuestionClickHandler> getAssociatedType() {
         return TYPE;
    }

    @Override
    protected void dispatch(QuestionClickHandler handler) {
        handler.onQuestionClicked(this);
    }


    // provide access to internal event state

    public SScript getScript() {
        return script;
    }

    public SQuestion getQuestion() {
        return question;
    }
}
  

2) Интерфейс обработчика

 public interface QuestionClickHandler extends EventHandler {
    public void onQuestionClicked(QuestionClickEvent event);
}
  

3) Интерфейс функции

 public interface HasQuestionClickHandlers {
    // Attention! method returns HandlerRegistration, so that handler can be cancelled
    public HandlerRegistration addQuestionClickHandler(
            QuestionClickHandler handler);
}
  

4) Ваш виджет / компонент

 public class SummaryPanel extends Widget implements HasQuestionClickHandlers {
// blah-blah-blah

        // implement your handler registration method
    @Override
    public HandlerRegistration addQuestionClickHandler(
            QuestionClickHandler handler) {
        return addHandler(handler, QuestionClickEvent.TYPE);
    }

// blah-blah-blah

    private someMethod() {
        // suddenly you realized that you need to to fire your event
        fireEvent(new QuestionClickEvent(script, question));
    }

// sample external API method

    public void emulateEvent() {
        someMethod();
    }
}
  

И, наконец, пример использования:

     SummaryPanel summary = new SummaryPanel();
    summary.addQuestionClickHandler(new QuestionClickHandler() {

        @Override
        public void onQuestionClicked(QuestionClickEvent event) {
            // your reaction goes here
        }
    });
  

Комментарии:

1. Спасибо за ваш ответ. Я применил ваши подсказки к своему коду (я обновил основной пост), но виджет по-прежнему не работает. (Он успешно компилируется без моего события). Я что-то не так понял? Вам нужно больше деталей, чтобы решить мою проблему?