Search code examples
scrolljavafxmenubarpaneborderpane

JavaFx, how to add menuBar and drawingPane


I'an busy with some demo, drawing some lines in a scroll window. So far so good, but now it's possible to draw lines on the menuBar, which should not be possible of course. See code below. Please help!

This is what happens:

See output here

The wrong code:

package Example12a;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

public class Example12a extends Application {

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

    private Line curLine;

    @Override
    public void start(Stage stage) throws Exception {
        Pane drawingPane = new Pane();
        BorderPane theBorderPane = new BorderPane();

        drawingPane.setPrefSize(800, 800);
        drawingPane.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);

        MenuBar menuBar = new MenuBar();
        // --- Menu File
        Menu menuFile = new Menu("File");
        MenuItem add = new MenuItem("Save");
        add.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                System.out.println("Save");
            }
        }); 
        menuFile.getItems().addAll(add);
        //yOffset = (int)menuBar.getHeight();        
        Menu menuEdit = new Menu("Edit");
        Menu menuView = new Menu("View");
        menuBar.getMenus().addAll(menuFile, menuEdit, menuView);
        theBorderPane.setTop(menuBar);

        ScrollPane scrollPane = new ScrollPane(theBorderPane);
        scrollPane.setPrefSize(300, 300);
        scrollPane.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
        scrollPane.setFitToWidth(true);
        scrollPane.setFitToHeight(true);
        scrollPane.setStyle("-fx-focus-color: transparent;");

        theBorderPane.setOnMousePressed(event -> {
            if (!event.isPrimaryButtonDown()) {
                return;
            }

            curLine = new Line(
                event.getX(), event.getY(), 
                event.getX(), event.getY()
            );
            theBorderPane.getChildren().add(curLine);
        });

        theBorderPane.setOnMouseDragged(event -> {
            if (!event.isPrimaryButtonDown()) {
                return;
            }

            if (curLine == null) {
                return;
            }

            curLine.setEndX(event.getX());
            curLine.setEndY(event.getY());

            double mx = Math.max(curLine.getStartX(), curLine.getEndX());
            double my = Math.max(curLine.getStartY(), curLine.getEndY());

            if (mx > theBorderPane.getMinWidth()) {
                theBorderPane.setMinWidth(mx);
            }

            if (my > theBorderPane.getMinHeight()) {
                theBorderPane.setMinHeight(my);
            }
        });

        theBorderPane.setOnMouseReleased(event -> curLine = null);

        theBorderPane.setCenter(drawingPane);
        Scene scene = new Scene(scrollPane);
        stage.setMinWidth(100);
        stage.setMinHeight(100);
        stage.setScene(scene);

        stage.show();
    }
}

Solution

  • Fixed your layout.

    What i did was:

    The BorderPane is now your root Pane.

    The ScrollPane is the center of the BorderPane and its content is the drawingPane.

    The MenuBar is still the the Top of the BorderPane.

    I also changed the Mouse Events from borderPane to drawingPane and the lines are added to the drawingPane instead of the borderPane.

    So its working fine.

    import javafx.application.Application;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Scene;
    import javafx.scene.control.Menu;
    import javafx.scene.control.MenuBar;
    import javafx.scene.control.MenuItem;
    import javafx.scene.control.ScrollPane;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.Pane;
    import javafx.scene.shape.Line;
    import javafx.stage.Stage;
    
    public class Example12a extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        private Line curLine;
    
        @Override
        public void start(Stage stage) throws Exception {
            Pane drawingPane = new Pane();
            BorderPane theBorderPane = new BorderPane();
    
            drawingPane.setPrefSize(800, 800);
            drawingPane.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
    
            MenuBar menuBar = new MenuBar();
            // --- Menu File
            Menu menuFile = new Menu("File");
            MenuItem add = new MenuItem("Save");
            add.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent t) {
                    System.out.println("Save");
                }
            }); 
            menuFile.getItems().addAll(add);
            //yOffset = (int)menuBar.getHeight();        
            Menu menuEdit = new Menu("Edit");
            Menu menuView = new Menu("View");
            menuBar.getMenus().addAll(menuFile, menuEdit, menuView);
            theBorderPane.setTop(menuBar);
    
            ScrollPane scrollPane = new ScrollPane(drawingPane);
            scrollPane.setPrefSize(300, 300);
            scrollPane.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
            scrollPane.setFitToWidth(true);
            scrollPane.setFitToHeight(true);
            scrollPane.setStyle("-fx-focus-color: transparent;");
    
            drawingPane.setOnMousePressed(event -> {
                if (!event.isPrimaryButtonDown()) {
                    return;
                }
    
                curLine = new Line(
                    event.getX(), event.getY(), 
                    event.getX(), event.getY()
                );
                drawingPane.getChildren().add(curLine);
            });
    
            drawingPane.setOnMouseDragged(event -> {
                if (!event.isPrimaryButtonDown()) {
                    return;
                }
    
                if (curLine == null) {
                    return;
                }
    
                curLine.setEndX(event.getX());
                curLine.setEndY(event.getY());
    
                double mx = Math.max(curLine.getStartX(), curLine.getEndX());
                double my = Math.max(curLine.getStartY(), curLine.getEndY());
    
                if (mx > drawingPane.getMinWidth()) {
                    drawingPane.setMinWidth(mx);
                }
    
                if (my > drawingPane.getMinHeight()) {
                    drawingPane.setMinHeight(my);
                }
            });
    
            theBorderPane.setOnMouseReleased(event -> curLine = null);
    
            theBorderPane.setCenter(scrollPane);
            Scene scene = new Scene(theBorderPane);
            stage.setMinWidth(100);
            stage.setMinHeight(100);
            stage.setScene(scene);
    
            stage.show();
        }
    }
    

    enter image description here

    Note:

    if your trying to make a Drawing Programm I would prevere to Render all Lines in a Canvas instead of using the Line class. The Canvas is much faster with many Lines.