1
votes

I making a version of Risk in JavaFX. Right now to display the game data I'm using a Grid of Labels that display the information about each territory. I would like to, for now, have mouse click listeners on the labels so I can test the game functions by clicking on them until I have the full game board made. Except when I try to add the listeners in the FXML document I get errors. Right now I'm declaring the labels in the controller, adding them to a collection so I can use a loop to bind each label's textProperty, then adding each to the grid. Then in the FXML is where I'm defining onMouseClicked for each. Here is the controller code:

@FXML
private GridPane tGrid = new GridPane();

@FXML Label label1 = new Label();
@FXML Label label2 = new Label();
@FXML Label label3 = new Label();
@FXML Label label4 = new Label();
@FXML Label label5 = new Label();
@FXML Label label6 = new Label();
@FXML Label label7 = new Label();
@FXML Label label8 = new Label();
@FXML Label label9 = new Label();
@FXML Label label10 = new Label();
@FXML Label label11 = new Label();
@FXML Label label12 = new Label();
@FXML Label label13 = new Label();
@FXML Label label14 = new Label();
@FXML Label label15 = new Label();
@FXML Label label16 = new Label();
@FXML Label label17 = new Label();
@FXML Label label18 = new Label();
@FXML Label label19 = new Label();
@FXML Label label20 = new Label();
@FXML Label label21 = new Label();
@FXML Label label22 = new Label();
@FXML Label label23 = new Label();
@FXML Label label24 = new Label();
@FXML Label label25 = new Label();
@FXML Label label26 = new Label();
@FXML Label label27 = new Label();
@FXML Label label28 = new Label();
@FXML Label label29 = new Label();
@FXML Label label30 = new Label();
@FXML Label label31 = new Label();
@FXML Label label32 = new Label();
@FXML Label label33 = new Label();
@FXML Label label34 = new Label();
@FXML Label label35 = new Label();
@FXML Label label36 = new Label();
@FXML Label label37 = new Label();
@FXML Label label38 = new Label();
@FXML Label label39 = new Label();
@FXML Label label40 = new Label();
@FXML Label label41 = new Label();
@FXML Label label42 = new Label();


@Override
public void initialize(URL url, ResourceBundle rb) {
    anchor.setLeftAnchor(tGrid, 10.0);
    anchor.setRightAnchor(pGrid, 10.0);
    tGrid.setVisible(false);
    pGrid.setVisible(false);
    labels.add(label1);
    labels.add(label2);
    labels.add(label3);
    labels.add(label4);
    labels.add(label5);
    labels.add(label6);
    labels.add(label7);
    labels.add(label8);
    labels.add(label9);
    labels.add(label10);
    labels.add(label11);
    labels.add(label12);
    labels.add(label13);
    labels.add(label14);
    labels.add(label15);
    labels.add(label16);
    labels.add(label17);
    labels.add(label18);
    labels.add(label19);
    labels.add(label20);
    labels.add(label21);
    labels.add(label22);
    labels.add(label23);
    labels.add(label24);
    labels.add(label25);
    labels.add(label26);
    labels.add(label27);
    labels.add(label28);
    labels.add(label29);
    labels.add(label30);
    labels.add(label31);
    labels.add(label32);
    labels.add(label33);
    labels.add(label34);
    labels.add(label35);
    labels.add(label36);
    labels.add(label37);
    labels.add(label38);
    labels.add(label39);
    labels.add(label40);
    labels.add(label41);
    labels.add(label42);
    int k = 0;
    for(int i = 0; i < 6; i++) {
        for(int j = 0; j < game.getContinent(i).getTerritoryNum(); j++) {
            labels.get(k).textProperty().bind(game.getContinent(i).getTerritory(j).getProperty());
            k += 1;
        }//for
    }//for
    for (int i = 0; i < 42; i++) {
        tGrid.add(labels.get(i), 0, i);
    }//for

And here is the FXML code (Except all the labels would have the onMouseClicked):

         <Label fx:id="label1"onMouseClicked="#labelAction" />
            <Label fx:id="label2"/>
            <Label fx:id="label3"/>
            <Label fx:id="label4"/>
            <Label fx:id="label5"/>
            <Label fx:id="label6"/>
            <Label fx:id="label7"/>
            <Label fx:id="label8"/>
            <Label fx:id="label9"/>
            <Label fx:id="label10"/>
            <Label fx:id="label11"/>
            <Label fx:id="label12"/>
            <Label fx:id="label13"/>
            <Label fx:id="label14"/>
            <Label fx:id="label15"/>
            <Label fx:id="label16"/>
            <Label fx:id="label17"/>
            <Label fx:id="label18"/>
            <Label fx:id="label19"/>
            <Label fx:id="label20"/>
            <Label fx:id="label21"/>
            <Label fx:id="label22"/>
            <Label fx:id="label23"/>
            <Label fx:id="label24"/>
            <Label fx:id="label25"/>
            <Label fx:id="label26"/>
            <Label fx:id="label27"/>
            <Label fx:id="label28"/>
            <Label fx:id="label29"/>
            <Label fx:id="label30"/>
            <Label fx:id="label31"/>
            <Label fx:id="label32"/>
            <Label fx:id="label33"/>
            <Label fx:id="label34"/>
            <Label fx:id="label35"/>
            <Label fx:id="label36"/>
            <Label fx:id="label37"/>
            <Label fx:id="label38"/>
            <Label fx:id="label39"/>
            <Label fx:id="label40"/>
            <Label fx:id="label41"/>
            <Label fx:id="label42"/>

And here is the error:

Exception in Application start method
java.lang.reflect.InvocationTargetException
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:497)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
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:497)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$152(LauncherImpl.java:182)
at com.sun.javafx.application.LauncherImpl$$Lambda$50/1343441044.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: javafx.fxml.LoadException:
file:/C:/Users/Brent/Documents/NetBeansProjects/RiskFXML/dist/run1282679996/RiskFXML.jar!/riskfxml/FXML.fxml:34

at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2605)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2547)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2445)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3218)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3179)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3152)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3128)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3108)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3101)
at riskfxml.RiskFXML.start(RiskFXML.java:22)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$159(LauncherImpl.java:863)
at com.sun.javafx.application.LauncherImpl$$Lambda$53/1527242123.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$172(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl$$Lambda$45/355629945.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$170(PlatformImpl.java:295)
at com.sun.javafx.application.PlatformImpl$$Lambda$48/1753953479.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$171(PlatformImpl.java:294)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/1915503092.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda$36/1963387170.run(Unknown Source)
... 1 more
Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[34,38]
Message: Element type "Label" must be followed by either attribute specifications, ">" or "/>".
at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next(XMLStreamReaderImpl.java:601)
at javax.xml.stream.util.StreamReaderDelegate.next(StreamReaderDelegate.java:88)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2517)
... 22 more
Exception running application riskfxml.RiskFXML
Java Result: 1

Update

Ok so I removed all the '= new Label()'s which got rid of the error, cause the problem was by defining them in both the fxml and controller I was trying to add duplicate elements. Now my problem is how do I add the labels to the gridpane in fxml in the same positions as I was when I was doing it in that loop at the bottom of my sample controller code? Is the a way to add them to an arraylist in fxml and just add that? I'm aware that I can just do

<Label fx:id="label1" onMouseClicked="#labelAction" GridPane.columnIndex="0" GridPane.rowIndex="0" />

for each of the labels but there has to be a better way than to hand type and place every single label right? They just need to be in the same column in increasing rows.

1
Can you identify the relevant line (line 34) in the FXML file? This isn't the cause of the error, but you should not initialize @FXML-injected fields (i.e. remove all the = new Label() parts of the statements, and the = new GridPane(). (Also, wouldn't something like this be better in Java code, with a loop, instead of in FXML?) - James_D
There should be a space in <Label fx:id="label1"onMouseClicked="#labelAction" /> - ItachiUchiha
Have you heard of Scene Builder? Try to use it to manipulate your fxml's. It is tool where you can drag and drop components and it creates FXML code for you. - ItachiUchiha

1 Answers

1
votes

I was facing a similar issue to you and solved it in a different way: create a Button on top of the label and assign the opacity to 0.

This way the button does not show up to the end user, but when they click on the label the underlying button picks up the action. Since it is a standard javafx Button, you can just use onAction="#yourAction" and you do not even have to change anything in the Label.

Hope this helps!