JavaFX - добавление изображения в GridPane вручную - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть следующие настройки

enter image description here

Три крестики-нолики в JavaFx являются сетками.

Я пытаюсь очень простым способом добавить ImageView к узлу сетки, чтобы указать, является ли это x или o.

Код, с которым я делаю это.

private void handleNewGameAction(ActionEvent event) throws IOException {

        FXMLLoader fxmlloader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));

        GridPane pane = (GridPane)fxmlloader.getNamespace().get("topGrid");

        Image image = new Image("x.png");
        pane.add(new ImageView(image), 0, 0);

    }

Я получаю ошибку

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
    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.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    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:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.control.MenuItem.fire(MenuItem.java:462)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1405)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$343(ContextMenuContent.java:1358)
    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.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$MouseHandler.process(Scene.java:3757)
    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:394)
    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$353(GlassViewEventHandler.java:432)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
    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$147(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)
Caused by: 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:498)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1769)
    ... 43 more
Caused by: java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found
    at javafx.scene.image.Image.validateUrl(Image.java:1118)
    at javafx.scene.image.Image.<init>(Image.java:620)
    at pkg3dtictactoe.FXMLDocumentController.handleNewGameAction(FXMLDocumentController.java:40)
    ... 53 more
Caused by: java.lang.IllegalArgumentException: Invalid URL or resource not found
    at javafx.scene.image.Image.validateUrl(Image.java:1110)
    ... 55 more

Я действительно в растерянности, и я смотрю на переполнение стека и вижу ответы, которые выглядят точно так же, как я написал, но я все еще получаю ошибку выше.

1 Ответ

0 голосов
/ 06 сентября 2018

Во-первых, чтобы ответить на непосредственную проблему, конечная причина ошибки определяется трассировкой стека:

Caused by: java.lang.IllegalArgumentException: Invalid URL or resource not found
    at javafx.scene.image.Image.validateUrl(Image.java:1110)
    ... 55 more

Это означает, что URL ("x.png"), который вы даете конструктору Image, недействителен. Либо вы использовали неправильный путь, либо ресурс находится не там, где вы думаете. В комментариях вы упоминаете, что ваш файл изображения находится в том же каталоге, что и ваши .java файлы. Если вы используете Maven или Gradle, для ресурсов по умолчанию используется src/main/resourcessrc/main/java для *.java файлов). Если это чистый JavaBX-проект NetBeans (который может использовать Ant?), Я не знаю, куда должны идти ресурсы. Посмотрите, есть ли каталог, предназначенный для ресурсов, и, если он есть, переместите туда все файлы ресурсов.

В вашем коде есть пара ошибок:

private void handleNewGameAction(ActionEvent event) throws IOException {

    FXMLLoader fxmlloader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));

    GridPane pane = (GridPane)fxmlloader.getNamespace().get("topGrid");

    Image image = new Image("x.png");
    pane.add(new ImageView(image), 0, 0);

}

Первый выпуск посвящен fxmlloader.getNamespace().get("topGrid"). Вы звоните по этому номеру только что созданного FXMLLoader и еще не звонили load(). Результат этого вызова всегда будет null, потому что FXMLLoader на самом деле еще ничего не создавал.

Вторая, и, на мой взгляд, более крупная проблема связана с тем, что вы создаете новую GridPane каждый раз, когда вызывается этот метод. Этот новый GridPane никогда не добавляется ни к одному Scene, и поэтому графический интерфейс никогда не будет обновляться. И чтобы быть ясным, GridPane, который вы извлекаете в методе , не тот, который уже отображается . И когда метод завершается, GridPane выпадает из области видимости и подвергается сборке мусора.

Поскольку вы создаете игровую доску, вам необходимо загружать доску только один раз (или, может быть, один раз за игру). После этого вы используете загруженную доску для добавления изображений в. Вы должны использовать класс контроллера, связанный с файлом FXML.

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;

public class Controller {

  @FXML 
  private GridPane topGrid;

  @FXML
  private void handleAction(ActionEvent event) {
    topGrid.add(new ImageView(/*image*/), 0, 0);
    event.consume();
  }

}

Чтобы связать контроллер с файлом FXML, вы должны использовать или атрибут fx:controller в файле или , который вы будете использовать FXMLLoader.setController(Object) перед вызовом метода load() экземпляра , Чтобы получить контроллер, вы можете использовать FXMLLoader.getController() после вызова load.

Чтобы узнать больше о FXML в JavaFX, см. Введение в FXML .

...