2016-04-21 84 views
0

我遇到了问题,部分解决了问题,但我对另一个(更好的)解决方案感到好奇。 我想要一个填充整个窗口并调整窗口大小的画布。JavaFX可调整大小的画布问题

选项1(部分解决方案):

根据该:https://dlemmermann.wordpress.com/2014/04/10/javafx-tip-1-resizable-canvas/ 和此:How to make canvas Resizable in javaFX? 我已经创建(复制)的类:

public class ResizableCanvas extends Canvas { 

    public ResizableCanvas() { 
     widthProperty().addListener(evt -> draw()); 
     heightProperty().addListener(evt -> draw()); 
    } 

    private void draw() { 
     double width = getWidth(); 
     double height = getHeight(); 

     GraphicsContext gc = getGraphicsContext2D(); 
     gc.clearRect(0, 0, width, height); 

     gc.setStroke(Color.RED); 
     gc.strokeLine(0, 0, width, height); 
     gc.strokeLine(0, height, width, 0); 
    } 

    @Override 
    public boolean isResizable() { 
     return true; 
    } 

    @Override 
    public double prefWidth(double height) { 
     return getWidth(); 
    } 

    @Override 
    public double prefHeight(double width) { 
     return getHeight(); 
    } 
} 

和我放入下列内容添加到我的ViewField.fxml文件中:

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.canvas.Canvas?> 
<?import javafx.scene.layout.StackPane?> 
<?import blahblahblah.ResizableCanvas?> 

<StackPane fx:id="pane" minHeight="500.0" minWidth="500.0" style="-fx-background-color: white; -fx-border-color: black;" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="blahblahblah.ViewFieldController"> 
    <children> 
     <ResizableCanvas fx:id="resizableCanvas" /> 
    </children> 
</StackPane> 

我的控制器(附于本FXML文件)ViewFieldController.java:

import javafx.beans.property.ReadOnlyDoubleProperty; 
import javafx.fxml.FXML; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.layout.StackPane; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

public class ViewFieldController { 

    private Stage dialogStage; 

    @FXML 
    private StackPane pane; 

    @FXML 
    private ResizableCanvas resizableCanvas; 

    @FXML 
    private void initialize() { 

     GraphicsContext gc = resizableCanvas.getGraphicsContext2D(); 

     ReadOnlyDoubleProperty widthProperty = pane.widthProperty(); 
     ReadOnlyDoubleProperty heightProperty = pane.heightProperty(); 
     resizableCanvas.widthProperty().bind(widthProperty); 
     resizableCanvas.heightProperty().bind(heightProperty); 

     drawArea(gc); 
    } 

    public void setDialogStage(Stage dialogStage) { 
     this.dialogStage = dialogStage; 
    } 

    private void drawArea(GraphicsContext gc) { 

     gc.setStroke(Color.BLACK); 
     gc.setLineWidth(1); 
     gc.strokeLine(0, 0, resizableCanvas.getWidth(), resizableCanvas.getHeight()); 
     gc.strokeLine(0, resizableCanvas.getHeight(), resizableCanvas.getWidth(), 0); 
    } 

} 

窗户被从主控制器MainApp.java加载:

public class MainApp extends Application { 

public static void main(String[] args) { 
    launch(args); 
} 
//... 

public void showViewField() { 
    try { 
     FXMLLoader loader = new FXMLLoader(); 
     loader.setLocation(MainApp.class.getResource("view/ViewField.fxml")); 
     StackPane pane = (StackPane) loader.load(); 

     Stage stage = new Stage(); 
     stage.setTitle("View Field"); 
     Scene scene = new Scene(pane); 
     stage.setScene(scene); 

     ViewFieldController controller = loader.getController(); 
     controller.setDialogStage(stage); 

     stage.show(); 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

} 

此解决方案( “大X” 出现在画布上,感谢drawArea()方法)。 这个解决方案的问题放置ResisableCanvas类到FXML文件后,我无法用任何SceneBuilder更多关于这个文件,因为我得到以下异常:

java.io.IOException: javafx.fxml.LoadException: 
... 

    at com.oracle.javafx.scenebuilder.kit.fxom.FXOMLoader.load(FXOMLoader.java:92) 
    at com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.<init>(FXOMDocument.java:82) 
    at com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.<init>(FXOMDocument.java:97) 
    at com.oracle.javafx.scenebuilder.kit.editor.EditorController.updateFxomDocument(EditorController.java:2384) 
    at com.oracle.javafx.scenebuilder.kit.editor.EditorController.setFxmlTextAndLocation(EditorController.java:664) 
    at com.oracle.javafx.scenebuilder.app.DocumentWindowController.loadFromFile(DocumentWindowController.java:381) 
    at com.oracle.javafx.scenebuilder.app.SceneBuilderApp.performOpenFiles(SceneBuilderApp.java:554) 
    at com.oracle.javafx.scenebuilder.app.SceneBuilderApp.handleOpenFilesAction(SceneBuilderApp.java:424) 
    at com.oracle.javafx.scenebuilder.app.SceneBuilderApp.handleLaunch(SceneBuilderApp.java:403) 
    at com.oracle.javafx.scenebuilder.app.AppPlatform.requestStartGeneric(AppPlatform.java:139) 
    at com.oracle.javafx.scenebuilder.app.AppPlatform.requestStart(AppPlatform.java:106) 
    at com.oracle.javafx.scenebuilder.app.SceneBuilderApp.start(SceneBuilderApp.java:353) 
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$163(LauncherImpl.java:863) 
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$176(PlatformImpl.java:326) 
    at com.sun.javafx.application.PlatformImpl.lambda$null$174(PlatformImpl.java:295) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$175(PlatformImpl.java:294) 
    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$149(WinApplication.java:191) 
    at java.lang.Thread.run(Thread.java:745) 
Caused by: javafx.fxml.LoadException: 
... 

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601) 
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2848) 
    at javafx.fxml.FXMLLoader.processImport(FXMLLoader.java:2692) 
    at javafx.fxml.FXMLLoader.processProcessingInstruction(FXMLLoader.java:2661) 
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2517) 
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2425) 
    at com.oracle.javafx.scenebuilder.kit.fxom.FXOMLoader.load(FXOMLoader.java:89) 
    ... 20 more 
Caused by: java.lang.ClassNotFoundException: blahblahblah.ResizableCanvas 
    at java.lang.ClassLoader.findClass(ClassLoader.java:530) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) 
    at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2916) 
    at javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2905) 
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2846) 
    ... 25 more 

选项2(部分解决方案) :

我的第二个解决方案使用相同的ResizableCanvas类,但没有FXML文件或控制器类。

public class MainApp extends Application { 

    //... 

    public void showViewField2() { 

     ResizableCanvas canvas = new ResizableCanvas(); 
     StackPane pane = new StackPane(); 
     pane.getChildren().add(canvas); 

     Stage stage = new Stage(); 
     stage.setTitle("View Field"); 
     Scene scene = new Scene(pane); 
     stage.setScene(scene); 

     canvas.widthProperty().bind(pane.widthProperty()); 
     canvas.heightProperty().bind(pane.heightProperty()); 

     stage.show(); 
    } 

} 

此解决方案太(大X是目前在屏幕上),但同样的问题出现在这里: 我不能ScreenBuilder但不同的原因打开FXML文件(也就是在不FXML文件所有)。

选项3(我原来的解决方案,不工作)

我已经取代了ViewField.fxml的ResizableCanvas类原始Canvas类文件:

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.canvas.Canvas?> 
<?import javafx.scene.layout.StackPane?> 

<StackPane fx:id="pane" minHeight="500.0" minWidth="500.0" style="-fx-background-color: white; -fx-border-color: black;" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="blahblahblah.ViewFieldController"> 
    <children> 
     <Canvas fx:id="regularCanvas" /> 
    </children> 
</StackPane> 

我ViewFieldController.java看起来像这样:

import javafx.beans.property.ReadOnlyDoubleProperty; 
import javafx.fxml.FXML; 
import javafx.scene.canvas.Canvas; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.layout.StackPane; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

public class ViewFieldController { 

    private Stage dialogStage; 

    @FXML 
    private StackPane pane; 

    @FXML 
    private Canvas regularCanvas; 

    @FXML 
    private void initialize() { 

     GraphicsContext gc = regularCanvas.getGraphicsContext2D(); 

     ReadOnlyDoubleProperty widthProperty = pane.widthProperty(); 
     ReadOnlyDoubleProperty heightProperty = pane.heightProperty(); 
     regularCanvas.widthProperty().bind(widthProperty); 
     regularCanvas.heightProperty().bind(heightProperty); 

     drawArea(gc); 
    } 

    public void setDialogStage(Stage dialogStage) { 
     this.dialogStage = dialogStage; 
    } 

    private void drawArea(GraphicsContext gc) { 

     gc.setStroke(Color.BLACK); 
     gc.setLineWidth(1); 
     gc.strokeLine(0, 0, regularCanvas.getWidth(), regularCanvas.getHeight()); 
     gc.strokeLine(0, regularCanvas.getHeight(), regularCanvas.getWidth(), 0); 
    } 

} 

但是屏幕在这里是空的。画布上没有绘制“大X”。 如果我调整窗口大小,我不知道画布是否调整大小,但可以将FXML文件加载到SceneBuilder中以便进一步工作..

如果我给出一些高度和宽度到画布(结果是相同的)。

<StackPane fx:id="pane" minHeight="500.0" minWidth="500.0" style="-fx-background-color: white; -fx-border-color: black;" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="blahblahblah.ViewFieldController"> 
    <children> 
     <Canvas fx:id="regularCanvas" height="300.0" width="300.0" /> 
    </children> 
</StackPane> 

我的问题是:

  1. 为什么 “大X” 不会出现INT第三呢?
  2. 我应该怎样做第三个案例?
  3. 有没有其他解决方案能解决我的问题?
  4. 为什么我在第一种情况下得到异常?
  5. 为什么在SceneBuilder中“适合父母”画布是不可能的?
  6. 为什么在SceneBuilder中禁用“可抵抗”选项?

回答

1

通过将自定义画布绑定到jar文件并将其导入场景生成器库,您可以使选项1与Scene Builder一起工作。例如,参见this question

选项3不起作用,因为您只从initialize()方法中调用drawArea()。此时,画布不是Scene的一部分,并且肯定不会显示在窗口中;因此没有进行布局,因此没有宽度和高度。您可以通过向宽度和高度添加侦听器并在更改时重新绘制来修复此选项,如同在选项1中所做的那样:

@FXML 
private void initialize() { 

    GraphicsContext gc = regularCanvas.getGraphicsContext2D(); 

    ReadOnlyDoubleProperty widthProperty = pane.widthProperty(); 
    ReadOnlyDoubleProperty heightProperty = pane.heightProperty(); 
    regularCanvas.widthProperty().bind(widthProperty); 
    regularCanvas.heightProperty().bind(heightProperty); 

    regularCanvas.widthProperty().addListener((obs, oldWidth, newWidth) -> drawArea(gc)); 
    regularCanvas.heightProperty().addListener((obs, oldHeight, newHeight) -> drawArea(gc)); 

    drawArea(gc); 
}