How to integrate GWT UIBinder with Canvas? - gwt

I am trying to find my way around with the Google Web Toolkit. Right now I am trying to get a Canvas widget up and running.
But I am getting this error and do not understand why:
Compiling module de.kuntze.HelloCanvas
Computing all possible rebind results for 'de.kuntze.client.HelloCanvas.HelloCanvasUiBinder'
Rebinding de.kuntze.client.HelloCanvas.HelloCanvasUiBinder
Invoking generator com.google.gwt.uibinder.rebind.UiBinderGenerator
[ERROR] com.google.gwt.canvas.client.Canvas has no default (zero args) constructor. To fix this, you can define a #UiFactory method on the UiBinder's owner, or annotate a constructor of Canvas with #UiConstructor.
[ERROR] Errors in 'de/kuntze/client/HelloCanvas.java'
[ERROR] Line 14: Failed to resolve 'de.kuntze.client.HelloCanvas.HelloCanvasUiBinder' via deferred binding
[WARN] For the following type(s), generated source was never committed (did you forget to call commit()?)
[WARN] de.kuntze.client.HelloCanvas_HelloCanvasUiBinderImpl
My code looks like this:
The module HelloCanvas.gwt.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.5.1/distro-source/core/src/gwt-module.dtd">
<module>
<inherits name="com.google.gwt.user.User" />
<source path="client"/>
<entry-point class="de.kuntze.client.HelloCanvas"/>
</module>
The UIBinder file HelloCanvas.ui.xml
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<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.canvas.client'>
<ui:style>
</ui:style>
<g:HTMLPanel>
<c:Canvas ui:field="canvas"></c:Canvas>
</g:HTMLPanel>
The Java file HelloCanvas.java
package de.kuntze.client;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
public class HelloCanvas extends Composite implements EntryPoint{
private static HelloCanvasUiBinder uiBinder = GWT
.create(HelloCanvasUiBinder.class);
#UiField Canvas canvas;
interface HelloCanvasUiBinder extends UiBinder<Widget, HelloCanvas> {
}
public HelloCanvas() {
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public void onModuleLoad() {
canvas = Canvas.createIfSupported();
canvas.setWidth("400px");
canvas.setHeight("400px");
canvas.setCoordinateSpaceWidth(400);
canvas.setCoordinateSpaceHeight(400);
RootPanel.get().add(this);
}
}
I bet the answer will be pretty easy but I do not know why I get this error message and why the code does not compile.
Edit:
So after trying the advice below it works. Here comes the edited code which draws a black triangle.
The UIBinder file HelloCanvas.ui.xml including a SimplePanel
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:HTMLPanel>
<g:SimplePanel width="200px" height="200px" ui:field="panel">
</g:SimplePanel>
</g:HTMLPanel>
The edited Java file HelloCanvas.java
package de.kuntze.client;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
public class HelloCanvas extends Composite implements EntryPoint {
private static HelloCanvasUiBinder uiBinder = GWT
.create(HelloCanvasUiBinder.class);
#UiField
SimplePanel panel;
interface HelloCanvasUiBinder extends UiBinder<Widget, HelloCanvas> {
}
public HelloCanvas() {
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public void onModuleLoad() {
Canvas tCanvas = Canvas.createIfSupported();
tCanvas.setWidth("400px");
tCanvas.setHeight("400px");
tCanvas.setCoordinateSpaceWidth(400);
tCanvas.setCoordinateSpaceHeight(400);
Context2d tContext2d = tCanvas.getContext2d();
tContext2d.beginPath();
tContext2d.moveTo(25, 25);
tContext2d.lineTo(105, 25);
tContext2d.lineTo(25, 105);
tContext2d.fill();
panel.add(tCanvas);
RootPanel.get().add(this);
}
}

You cannot create a Canvas with the UI:Binder, because there is no zero-arg constructor, nor a #UIConstructor.
I would suggst to create a warpper (A simplePanel) and within your Wrapper-Code, you can create a Canvas, by calling Canvas.createIfSupported():
The canvas itself is prvided.
#UiField(provided = true)
Canvas canvas;
Before you call binder.createAndBindUi(this); you will have to create the Canvas:
canvas = Canvas.createIfSupported()
I have no simple example, but maybe, this link is helpful:
https://code.google.com/p/gwtgae2011/source/browse/src/main/java/com/googlecode/gwtgae2011/client/main/SketchView.java?r=8e7169e7fbb411f320f99f77dcdb27efa27b727a
You also could use a CanvasElement, like described in this question:
GWT uibinder CanvasElement wont resize when deployed

Related

JavaFX and CDI: How to Inject many Stages

I would like to integrate JavaFX and CDI. There are some good examples over the web about that like these ones:
https://dzone.com/articles/fxml-javafx-powered-cdi-jboss
http://fxapps.blogspot.com.br/2017/10/using-cdi-20-in-javafx-application.html
However, all the examples I have seen don't work in a real world because they are not able to inject more than one Stage (the primaryStage), if they are, I don't know how.
So I would like to know if it's possible in a JavaFX/CDI project to inject more than one Stage (to use in modal windows for example...)
thank's!
You don't need to use CDI to manage the stages: stages themselves simply have a Scene; they do not have any dependencies on any other objects you need to manage. All you need to do is ensure that the FXMLLoader has a controllerFactory that retrieves controller instances from the DI framework.
Here is a quick example (caveat: I have never used CDI/Weld before, so I might not have the optimal way of doing things here).
First, it's probably a good idea to expose a controller factory that gets the appropriate controllers:
package app;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javafx.util.Callback;
#ApplicationScoped
public class CDIControllerFactory implements Callback<Class<?>, Object> {
#Inject
private Instance<Object> instance ;
#Override
public Object call(Class<?> type) {
Object controller = instance.select(type).get();
return controller;
}
}
Here is a model class we want to share with all the controllers. Since we only want one instance, we make it #ApplicationScoped:
package app;
import javax.enterprise.context.ApplicationScoped;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
#ApplicationScoped
public class Model {
private final ObservableList<String> names = FXCollections.observableArrayList();
public ObservableList<String> getNames() {
return names ;
}
public void addName(String name) {
names.add(name);
}
}
The test application will just have a list view (with a list of names) and a button for adding a new name from a dialog. Here is the main controller:
package app;
import java.io.IOException;
import javax.inject.Inject;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class MainController {
#Inject
private Model model ;
#Inject
private CDIControllerFactory controllerFactory ;
#FXML
private ListView<String> listView ;
#FXML
private void initialize() {
listView.setItems(model.getNames());
}
#FXML
private void showAddDialog() throws IOException {
FXMLLoader loader = new FXMLLoader(AddNameController.class.getResource("AddNameDialog.fxml"));
loader.setControllerFactory(controllerFactory);
Scene scene = new Scene(loader.load());
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setScene(scene);
stage.show();
}
}
Note how it uses the controller factory on the FXMLLoader. The stage can just be created "by hand".
Here's the controller for the dialog that is used to add new names. Note how it has a reference to the same model instance, via CDI:
package app;
import javax.enterprise.inject.Default;
import javax.inject.Inject;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
#Default
public class AddNameController {
#Inject
private Model model ;
#FXML
private TextField nameField ;
#FXML
private void submit() {
model.addName(nameField.getText());
close();
}
#FXML
private void close() {
nameField.getScene().getWindow().hide();
}
}
Here are the two FXML files (they are both in the app package: the only real requirement with the way I coded these is that they should be in the same package as their corresponding controller classes).
Main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.MainController">
<center>
<ListView fx:id="listView" />
</center>
<bottom>
<HBox alignment="CENTER">
<padding>
<Insets top="5" right="5" left="5" bottom="5" />
</padding>
<Button text="Add..." onAction="#showAddDialog" />
</HBox>
</bottom>
</BorderPane>
AddNameDialog.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.MainController">
<center>
<ListView fx:id="listView" />
</center>
<bottom>
<HBox alignment="CENTER">
<padding>
<Insets top="5" right="5" left="5" bottom="5" />
</padding>
<Button text="Add..." onAction="#showAddDialog" />
</HBox>
</bottom>
</BorderPane>
Here's the application class:
package app;
import java.io.IOException;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
private Weld weld ;
private WeldContainer container ;
#Override
public void init() {
weld = new Weld();
container = weld.initialize();
}
#Override
public void stop() {
weld.shutdown();
}
#Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader = new FXMLLoader(MainController.class.getResource("Main.fxml"));
loader.setControllerFactory(container.select(CDIControllerFactory.class).get());
Scene scene = new Scene(loader.load(), 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
and of course the CDI configuration class, META-INF/beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>
If you really want to let CDI provide your stages, you can, but I don't really see there's much to gain by it. But, e.g. you can do something like:
package app;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.METHOD,
ElementType.TYPE, ElementType.PARAMETER})
public #interface ModalStage { }
which lets you provide modal and non-modal stages:
package app;
import javax.enterprise.inject.Produces;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class StageProducer {
#Produces
public Stage stage() {
return new Stage();
}
#Produces
#ModalStage
public Stage modalStage() {
Stage stage = stage();
stage.initModality(Modality.APPLICATION_MODAL);
return stage ;
}
}
And then your MainController might look like
public class MainController {
#Inject
private Model model ;
#Inject
private CDIControllerFactory controllerFactory ;
#Inject
#ModalStage
private Stage addNameDialogStage ;
#FXML
private ListView<String> listView ;
#FXML
private void initialize() {
listView.setItems(model.getNames());
}
#FXML
private void showAddDialog() throws IOException {
FXMLLoader loader = new FXMLLoader(AddNameController.class.getResource("AddNameDialog.fxml"));
loader.setControllerFactory(controllerFactory);
Scene scene = new Scene(loader.load());
addNameDialogStage.setScene(scene);
addNameDialogStage.show();
}
}
There are other facilities you could easily build into this, e.g. providing a class for loading FXML from a resource name, which incorporates the controller factory already, etc etc.

UiBinder: Package not found

I tried to import one of my widgets in another ui.xml file.
In eclipse no errors are shown but in (maven) development mode it says:
[ERROR] Package not found: de.s.pp.client.application.projectdetail.overview.subview
The widget that imports:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:ovs='urn:import:de.s.pp.client.application.projectdetail.overview.subview'>
<ovs:ProjectProperties/>
</ui:UiBinder>
ProjectProperties.java:
package de.s.pp.client.application.projectdetail.overview.subview;
import com.google.common.io.Resources;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
public class ProjectProperties extends Composite {
interface MyUiBinder extends UiBinder<Widget, ProjectProperties> {
}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
private Resources resources;
public ProjectProperties() {
super();
initWidget(uiBinder.createAndBindUi(this));
}
public ProjectProperties(Resources resources) {
this();
this.resources = resources;
}
}
ProjectProperties.ui.xml:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:style>
</ui:style>
<g:CaptionPanel width="95%" captionText="Projekteigenschaften">
</g:CaptionPanel>
</ui:UiBinder>
Did you forgot to add jar file, to use the de.s.pp.client.application.projectdetail.overview.subview
The problem was that the absolute path of the file was to long

LazyPanel in GWT (Uibinder)

I want to learn the utility of lazypanel of GWT. I want to use it using Uibinder. I have written the code as below. I want to use the lazy panel for tablayoutpanel.
XML file
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:d="urn:import:com.google.gwt.dom.client"
xmlns:lazy="urn:import:abc.client">
<g:HTMLPanel>
<lazy:Lazy1></lazy:Lazy1>
</g:HTMLPanel>
</ui:UiBinder>
This is the java file associated.
Lazy1.java
package abc.client;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.LazyPanel;
import com.google.gwt.user.client.ui.Widget;
public class Lazy1 extends LazyPanel{
Label label = new Label("Mani");
#Override
protected Widget createWidget() {
return label;
}
}
I am getting the exceptions and error as below:-
13:00:08.222 [ERROR] [abc] Generator 'com.google.gwt.uibinder.rebind.UiBinderGenerator' threw an exception while rebinding 'abc.client.AbcUI.abcUIUiBinder'
java.lang.NullPointerException: null
at com.google.gwt.uibinder.elementparsers.LazyPanelParser.parse(LazyPanelParser.java:40)
at com.google.gwt.uibinder.rebind.UiBinderWriter.parseElementToField(UiBinderWriter.java:934)
at com.google.gwt.uibinder.elementparsers.WidgetInterpreter.interpretElement(WidgetInterpreter.java:88)
at com.google.gwt.uibinder.elementparsers.WidgetInterpreter.interpretElement(WidgetInterpreter.java:34)
at com.google.gwt.uibinder.elementparsers.InterpreterPipe.interpretElement(InterpreterPipe.java:58)
at com.google.gwt.uibinder.rebind.GetInnerHtmlVisitor.visitElement(GetInnerHtmlVisitor.java:45)
at com.google.gwt.uibinder.rebind.ChildWalker.accept(ChildWalker.java:48)
at com.google.gwt.uibinder.rebind.GetInnerHtmlVisitor.getEscapedInnerHtml(GetInnerHtmlVisitor.java:33)
at com.google.gwt.uibinder.rebind.XMLElement.consumeInnerHtml(XMLElement.java:391)
at com.google.gwt.uibinder.rebind.XMLElement.consumeInnerHtml(XMLElement.java:403)
at com.google.gwt.uibinder.elementparsers.HTMLPanelParser.parse(HTMLPanelParser.java:57)
at com.google.gwt.uibinder.rebind.UiBinderWriter.parseElementToField(UiBinderWriter.java:934)
at com.google.gwt.uibinder.rebind.UiBinderParser.parse(UiBinderParser.java:146)
at com.google.gwt.uibinder.rebind.UiBinderWriter.parseDocumentElement(UiBinderWriter.java:1368)
at com.google.gwt.uibinder.rebind.UiBinderWriter.parseDocument(UiBinderWriter.java:1073)
at com.google.gwt.uibinder.rebind.UiBinderGenerator.generateOnce(UiBinderGenerator.java:177)
at com.google.gwt.uibinder.rebind.UiBinderGenerator.generate(UiBinderGenerator.java:129)
at com.google.gwt.core.ext.IncrementalGenerator.generateNonIncrementally(IncrementalGenerator.java:40)
at com.google.gwt.dev.javac.StandardGeneratorContext.runGeneratorIncrementally(StandardGeneratorContext.java:657)
at com.google.gwt.dev.cfg.RuleGenerateWith.realize(RuleGenerateWith.java:41)
at com.google.gwt.dev.shell.StandardRebindOracle$Rebinder.rebind(StandardRebindOracle.java:79)
at com.google.gwt.dev.shell.StandardRebindOracle.rebind(StandardRebindOracle.java:276)
at com.google.gwt.dev.shell.ShellModuleSpaceHost.rebind(ShellModuleSpaceHost.java:141)
at com.google.gwt.dev.shell.ModuleSpace.rebind(ModuleSpace.java:595)
at com.google.gwt.dev.shell.ModuleSpace.rebindAndCreate(ModuleSpace.java:465)
at com.google.gwt.dev.shell.GWTBridgeImpl.create(GWTBridgeImpl.java:49)
at com.google.gwt.core.shared.GWT.create(GWT.java:57)
at com.google.gwt.core.client.GWT.create(GWT.java:85)
at abc.client.AbcUI.<clinit>(AbcUI.java:12)
at abc.client.ABC.onModuleLoad(ABC.java:10)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.google.gwt.dev.shell.ModuleSpace.onLoad(ModuleSpace.java:406)
at com.google.gwt.dev.shell.OophmSessionHandler.loadModule(OophmSessionHandler.java:200)
at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:526)
at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:364)
at java.lang.Thread.run(Thread.java:662)
ABC.java
package abc.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
public class ABC implements EntryPoint {
public void onModuleLoad() {
RootPanel.get().add(new AbcUI());
}
}
AbcUi.java
package abc.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.LazyPanel;
public class AbcUI extends Composite {
interface abcUIUiBinder extends UiBinder<HTMLPanel, AbcUI> {}
private static abcUIUiBinder uiBinder = GWT.create(abcUIUiBinder.class);
public AbcUI() {
initWidget(uiBinder.createAndBindUi(this));
}
}
According to this you have this error if you do not have an #UiField annotation for the LazyPanel. So I would try the following:
For the UiBinder XML file:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:d="urn:import:com.google.gwt.dom.client"
xmlns:lazy="urn:import:abc.client">
<g:HTMLPanel>
<lazy:Lazy1 ui:field="myLazy1"/>
</g:HTMLPanel>
</ui:UiBinder>
For your AbcUi.java file:
package abc.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.LazyPanel;
public class AbcUI extends Composite {
interface abcUIUiBinder extends UiBinder<HTMLPanel, AbcUI> {}
private static abcUIUiBinder uiBinder = GWT.create(abcUIUiBinder.class);
#UiField
Lazy1 myLazy1;
public AbcUI() {
initWidget(uiBinder.createAndBindUi(this));
}
}

GWT Compiler Error: Missing Interface Methods on Subclass (PlayN HTML)

Disclaimer: I'm new to GWT/PlayN, so this might be an obvious mistake that I'm making.
When I have a basic (starter) PlayN project, my BlahGame class method implements the Game interface, which requires three methods: init, paint, and update. The starter class looks something like:
public class BlahGame implements Game {
public void init() { ... }
public void paint(float alpha) { ... }
public void update(float alpha) { ... }
}
I created a BaseGame class to implement game, like so:
public class BaseGame implements Game {
public void init() { ... }
public void paint(float alpha) { ... }
public void update(float alpha) { ... }
}
My main game class then became a sublass of BaseGame like so:
public class BlahGame extends BaseGame {
public void init() { ... base.init(); ... }
}
Everything compiles and works from Java. But when I try to GWT-compile the HTML version of my game, I get this error:
com.google.gwt.dev.jjs.InternalCompilerException: Failed to get JNode
at com.google.gwt.dev.jjs.impl.TypeMap.get(TypeMap.java:140)
at com.google.gwt.dev.jjs.impl.TypeMap.get(TypeMap.java:71)
at com.google.gwt.dev.jjs.impl.BuildTypeMap.getType(BuildTypeMap.java:730)
...
[ERROR] <no source info>: public class com.deengames.BaseGame
extends java.lang.Object
implements : playn.core.Game
/* methods */
public void <init>()
public void init()
[unresolved] public void paint(float)
[unresolved] public void update(float)
[unresolved] public int updateRate()
I'm not sure what I'm missing here. Is it that some GWT classes need to be updated? Or is it something else? I had expected the HTML vesrion to compile since the Java version compiles; the signatures of the classes shouldn't change from subclassing.
Edit: I'm using a brand new, boilerplate PlayN project. In the class, if I extend the base class AND implement the interface, it still doesn't compile; only removing the base class extension works.
This is your problem right here:
[ERROR] <no source info>: public class com.deengames.BaseGame
You have put code in the top-level package com.deengames. I bet that your GWT module file is also in that same package directory, probably something like com/deengames/MyGame.gwt.xml. The GWT module file has to specify sub-package directories for all code that GWT will see.
When you generate a project using the PlayN Maven archetype, it has this structure:
core/src/main/java/com/foozle/core/Barzle.java
core/src/main/java/com/foozle/resources/images/bg.png
html/src/main/java/com/foozle/Barzle.gwt.xml
html/src/main/java/com/foozle/html/BarzleHtml.java
All of the game code is in the com.foozle.core package and the resources are in the com.foozle.resources package. If you look at the generated Barzle.gwt.xml file you will see:
<module rename-to='barzle'>
<inherits name='playn.PlayN'/>
<source path='core'/>
<source path='html'/>
<public path="resources" />
<entry-point class='com.foozle.html.BarzleHtml'/>
</module>
The two <source> lines explicitly add the com.foozle.core and com.foozle.html sub-packages to the GWT project. Anything that is not explicitly listed in this GWT module file will be ignored by GWT. Due to the way GWT specifies these packages, it is not possible to add the top-level package to your GWT project. You cannot use:
<source path=""/>
or:
<source path="."/>
You have to put all of your code in sub-packages that are explicitly enumerated in your GWT module file.
I presume there is an issue with the BlahGame.gwt.xml file inclusions. Make sure all the directories are included in that file, as sources. The structure should be similar to:
<module rename-to='blah'>
<inherits name='playn.PlayN' />
<source path='core'/>
<source path='common'/>
... etc ...
<source path='html'/>
<public path="resources" />
<entry-point class='full.namespace.BlahGameHtml' />
</module>
Additionally, your BlahGameHtml.java class should look something like:
public class BlahGameHtml extends HtmlGame
{
#Override
public void start()
{
HtmlAssetManager assets = HtmlPlatform.register().assetManager();
assets.setPathPrefix("blah/");
PlayN.run(new BlahGame());
}
}

GWT: Getting a Reference to a DockLayoutPanel from a MenuBar

I am a newbie trying to use a MenuBar to swap the displayed panel in a DeckPanel.
I have 2 classes and 2 associated uibinder XML files:
ApplicationUi.java
ApplicationUi.ui.xml
ApplicationMenu.java
ApplicationMenu.ui.xml
In ApplicationUi.java and the UI XML, the root is bound to a DockLayoutPanel. The ApplicationMenu is meant to be in the North section of the DockLayoutPanel. The MenuBar options will affect the DeckPanel in the Center section.
In ApplicationMenu, how can I get a reference to the DeckPanel so I can call showWidget() to swap the displayed panel?
Also, since I'm a newb, any suggestions or reviews of this code are welcome. I've done the best I can on Google, but alot of what I'm looking for doesn't seem to be out there.
(This is a followup to Replace GWT DockLayoutPanel Contents).
Source:
ApplicationUi.java
import org.jason.datacenter.client.forms.NewRequirementForm;
public class ApplicationUi extends Composite {
private static final Binder binder = GWT.create(Binder.class);
interface Binder extends UiBinder<Widget, ApplicationUi> {
}
#UiField DockLayoutPanel dlp;
#UiField VerticalSplitPanel headerPanel;
#UiField DeckPanel deckPanel;
public ApplicationUi() {
initWidget(binder.createAndBindUi(this));
// add the NewRequirementForm to the deckpanel as index #0
deckPanel.add(new NewRequirementForm());
}
public void switchDeck(int newIndex) {
deckPanel.showWidget(newIndex);
}
}
ApplicationUi.ui.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:style>
.panel {
background-color: ivory;
}
</ui:style>
<g:DockLayoutPanel ui:field="dlp">
<g:north size="800">
<g:VerticalSplitPanel ui:field="headerPanel">
</g:VerticalSplitPanel>
</g:north>
<g:center>
<g:DeckPanel ui:field="deckPanel" />
</g:center>
</g:DockLayoutPanel>
</ui:UiBinder>
ApplicationMenu.java:
public class ApplicationMenu extends Composite {
private static final Binder binder = GWT.create(Binder.class);
interface Binder extends UiBinder<Widget, ApplicationMenu> {
}
#UiField MenuBar applicationMenu;
#UiField MenuItem mitmNewPower;
public ApplicationMenu() {
initWidget(binder.createAndBindUi(this));
mitmNewPower.setCommand(new Command() {
#Override
public void execute() {
RootLayoutPanel rlp = RootLayoutPanel.get();
DockLayoutPanel dlp = (DockLayoutPanel) rlp.getWidget(0);
}
});
}
}
ApplicationMenu.ui.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:style>
.panel {
background-color: ivory;
}
</ui:style>
<g:MenuBar ui:field="applicationMenu">
<g:MenuItem>
Process
<g:MenuBar>
<g:MenuItem ui:field="mitmNewPower" />
</g:MenuBar>
</g:MenuItem>
</g:MenuBar>
</ui:UiBinder>
One way you could do this would be to use an EventBus. Create an event type and have your ApplicationMenu fire an event of that type when a menu item gets clicked. The ApplicationUi object can subscribe to that event and respond to it by updating the contents of the DeckPanel. This avoids the menu object needing to know about the DeckPanel at all.