B4J Question Pass Node as event parameter type mismatch

warwound

Expert
Licensed User
I'm adding a GridPane to my form using a layout file created in the SceneBuilder.
I have working java code that detects a click on a child Node of the GridPane and decided to make a simple library wrapper:

B4X:
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4j.objects.NodeWrapper;
import anywheresoftware.b4j.objects.PaneWrapper;

@BA.Author("Martin Pearman")
@BA.Events(values={
     "MouseClicked(Node1 As Node)"
})
@BA.ShortName("GridPane")
@BA.Version(0.01f)
public class GridPane extends PaneWrapper<javafx.scene.layout.GridPane> {

   public void Initialize(final BA ba, String EventName, final javafx.scene.layout.GridPane GridPane1){
     final String subName=new StringBuilder(EventName).append("_MouseClicked").toString().toLowerCase(BA.cul);
     boolean subNameExists=ba.subExists(subName);
     if(subNameExists){
       GridPane1.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>(){
         @Override
         public void handle(MouseEvent mouseEvent) {
    for(javafx.scene.Node childNode:GridPane1.getChildren()){
       if(childNode.getBoundsInParent().contains(mouseEvent.getSceneX(), mouseEvent.getSceneY())){
         
         NodeWrapper<javafx.scene.Node> nodeWrapper=new NodeWrapper<javafx.scene.Node>();
         nodeWrapper.setObject(childNode);
         
     ba.raiseEvent(GridPane1, subName, nodeWrapper);   //   try passing a NodeWrapper
     

     //   ba.raiseEvent(GridPane1, subName, childNode);   //   try passing the java fx Node
  break;
  }
    }
         }
       });
     }
     setObject(GridPane1);
   }
}

My b4j code is:

B4X:
Sub Process_Globals
   Type T99ButtonTag(Number As Int)
   
   Private NUM_COLS As Int=8
   Private NUM_ROWS As Int=12
   
   Private BottomButtonsPane As Pane
   Private BrowseJPGButton As Button
   Private fx As JFX
   Private MainForm As Form
   Private RightButtonsPane As Pane
   Private T99Buttons As List
   Private T99ButtonsPane As Pane
   Private ToggleFlagButton As Button
   Private ToggleGridButton As Button
   Private ToggleMaskButton As Button
End Sub

Sub AppStart (Form1 As Form, Args() As String)
   T99Buttons.Initialize
   
   MainForm=Form1
   MainForm.RootPane.LoadLayout("Main")
   MainForm.Title="pageBuilder™ v2"
   T99ButtonsPane.Style="-fx-background-image: url('http://www.drawingsofleonardo.org/images/vitruvian.jpg'); -fx-background-size: stretch;"
   MainForm.Show
   
   
   For Each Label1 As Label In T99ButtonsPane
     Dim T99ButtonTag1 As T99ButtonTag
     T99ButtonTag1.Initialize
     T99ButtonTag1.Number=Label1.Text
     Label1.Tag=T99ButtonTag1
     T99Buttons.Add(Label1)
   Next
   
   ' here i use my library wrapper which adds a click event listener to my GridPane
   Dim GridPane1 As GridPane
   GridPane1.Initialize("T99ButtonsPane", T99ButtonsPane)
   
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
   Return True
End Sub

Sub GetT99ButtonTag(Label1 As Label) As T99ButtonTag
   Dim T99ButtonTag1 As T99ButtonTag=Label1.Tag
   Return T99ButtonTag1
End Sub

Sub MainForm_Resize (Width As Double, Height As Double)
   '   Log("MainForm_Resize")
   T99ButtonsPane.PrefHeight=Height-64
   T99ButtonsPane.PrefWidth=Width-256
   ScaleUIToFit
End Sub

Sub ScaleUIToFit
   Dim T99ButtonsPaneHeight As Double=T99ButtonsPane.Height
   Dim T99ButtonsPaneWidth As Double=T99ButtonsPane.Width
   
   
   BottomButtonsPane.Top=T99ButtonsPane.Height+10
   BottomButtonsPane.PrefWidth=T99ButtonsPane.Width
End Sub

'   this is the line where the type mismatch occurs
Sub T99ButtonsPane_MouseClicked(Node1 As Node)
   Log("T99ButtonsPane_MouseClicked")
   Dim Label1 As Label=Node1
   Dim T99ButtonTag1 As T99ButtonTag=GetT99ButtonTag(Label1)
   Log(T99ButtonTag1.Number)
End Sub

Passing a NodeWrapper as the parameter in my wrapper code results in this exception when a node (a Label) in my GridPane is clicked:

Waiting for debugger to connect...
Program started.
imagineear.pagebuilder.main:_t99buttonspane_mouseclicked, [(Label) Label@78dfad39[styleClass=label t99button]'32']
Error occurred on line: 77
java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:612)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:226)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:159)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:79)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:92)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:70)
at imagineear.api.scene.layout.GridPane$1.handle(GridPane.java:31)
at imagineear.api.scene.layout.GridPane$1.handle(GridPane.java:1)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$ClickGenerator.postProcess(Scene.java:3470)
at javafx.scene.Scene$ClickGenerator.access$8100(Scene.java:3398)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3766)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:417)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:748)
Error occurred on line: 77
java.lang.NullPointerException
at anywheresoftware.b4a.shell.Shell.runGoodChain(Shell.java:358)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:169)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:159)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:79)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:92)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:70)
at anywheresoftware.b4j.objects.NodeWrapper$1.handle(NodeWrapper.java:89)
at anywheresoftware.b4j.objects.NodeWrapper$1.handle(NodeWrapper.java:1)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$ClickGenerator.postProcess(Scene.java:3470)
at javafx.scene.Scene$ClickGenerator.access$8100(Scene.java:3398)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3766)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:417)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:748)

I get the same exception when passing a javafx Node as the parameter.

Can anyone see what i'm doing wrong?
It's been a long while sinc ei used b4j and i suspect the error is something simple...
 

warwound

Expert
Licensed User
The app i'm working on needs to display a grid of 8 x 12 on top of a JPG image.
Each of those grid squares (96 in total) need to be clickable.

We have an existing version of the app that uses 96 imageviews and the code is a mess.
My task is to update the app so that it supports resizing of the main form window - the current version does not.

So a GridPane is the perfect solution.
I set a JPG as the GridPane background and then add 96 Labels.
The GridPane handles resizing of the background image and Labels for me - makes the code far simpler.

I just need to know how to pass a Node from my library code to my b4j code...
 
Upvote 0

warwound

Expert
Licensed User
It should be ConcreteNodeWrapper.

Well that didn't work - i still got the type mismatch exceptions.
I then changed my event annotation to:

B4X:
MouseClicked(Node1 As Object)

Now my b4j event sub worked BUT then failed.
A click resulted in the desired sub executing successfully followed immediately by the sub being called again and this time a type mismatch exception - MouseEvent cannot be cast to Label.

A Log statement in my library GridPane click handler was executed just once on each GridPane click.
Then it hit me...

b4j adds it's own MouseClicked (EventData As MouseEvent) listener to my GridPane when my Scenebuilder layout is loaded.
My library then adds it's MouseClicked(Node1 As Node) listener.

A click on my GridPane causes both listeners to be executed - once with a matching method signature and once with a non-matching event signature!

All fixed now.
 
Upvote 0
Top