JavaFX 8 node dynamic scaling

I'm trying to implement a scene with a ScrollPane in which the user can drag around a knot and resize it dynamically. I'm moving and scaling with the mouse wheel work as well as a zoom reset.

Here's my question:

I have a problem with the calculations to suit the width of the parent node.

If I Zoom in or out, the width adjustment does not work.

If I change the size of the window after execution of fitWidth() once, the width adjustment does not the second time.

Here is my code as a NBS and how it works...

1 (works) mouse wheel will zoom in and out around the mouse pointer

2 (works) or press left mouse to drag the rectangle autour

3 (work) left, double-click to reset the zoom

4. (does not) double-clicked right to fit the width

My calculations to reposition the rectangle at the top left of the pane and mount it (i.e., resize it upwards or downwards) to the width of the parent are incorrect.

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeType;
import javafx.stage.Stage;
import javafx.util.Duration;

public class ZoomAndPanExample extends Application {

   private ScrollPane scrollPane = new ScrollPane();

   private final DoubleProperty zoomProperty = new SimpleDoubleProperty(1.0d);
   private final DoubleProperty deltaY = new SimpleDoubleProperty(0.0d);

   private final Group group = new Group();

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

   @Override
   public void start(Stage primaryStage) {

  scrollPane.setPannable(true);
  scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
  scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
   AnchorPane.setTopAnchor(scrollPane, 10.0d);
   AnchorPane.setRightAnchor(scrollPane, 10.0d);
   AnchorPane.setBottomAnchor(scrollPane, 10.0d);
   AnchorPane.setLeftAnchor(scrollPane, 10.0d);

   AnchorPane root = new AnchorPane();

   Rectangle rect = new Rectangle(80, 60);

  rect.setStroke(Color.NAVY);
  rect.setFill(Color.NAVY);
  rect.setStrokeType(StrokeType.INSIDE);

  group.getChildren().add(rect);
   // create canvas
   PanAndZoomPane panAndZoomPane = new PanAndZoomPane();
  zoomProperty.bind(panAndZoomPane.myScale);
  deltaY.bind(panAndZoomPane.deltaY);
  panAndZoomPane.getChildren().add(group);

   SceneGestures sceneGestures = new SceneGestures(panAndZoomPane);

  scrollPane.setContent(panAndZoomPane);
  panAndZoomPane.toBack();
  scrollPane.addEventFilter( MouseEvent.MOUSE_CLICKED, sceneGestures.getOnMouseClickedEventHandler());
  scrollPane.addEventFilter( MouseEvent.MOUSE_PRESSED, sceneGestures.getOnMousePressedEventHandler());
  scrollPane.addEventFilter( MouseEvent.MOUSE_DRAGGED, sceneGestures.getOnMouseDraggedEventHandler());
  scrollPane.addEventFilter( ScrollEvent.ANY, sceneGestures.getOnScrollEventHandler());

  root.getChildren().add(scrollPane);
   Scene scene = new Scene(root, 600, 400);
  primaryStage.setScene(scene);
  primaryStage.show();
   }

   class PanAndZoomPane extends Pane {

   public static final double DEFAULT_DELTA = 1.3d;
   DoubleProperty myScale = new SimpleDoubleProperty(1.0);
   public DoubleProperty deltaY = new SimpleDoubleProperty(0.0);
   private Timeline timeline;


   public PanAndZoomPane() {

   this.timeline = new Timeline(60);

   // add scale transform
  scaleXProperty().bind(myScale);
  scaleYProperty().bind(myScale);
   }


   public double getScale() {
   return myScale.get();
   }

   public void setScale( double scale) {
  myScale.set(scale);
   }

   public void setPivot( double x, double y, double scale) {
   // note: pivot value must be untransformed, i. e. without scaling
   // timeline that scales and moves the node
  timeline.getKeyFrames().clear();
  timeline.getKeyFrames().addAll(
   new KeyFrame(Duration.millis(200), new KeyValue(translateXProperty(), getTranslateX() - x)),
   new KeyFrame(Duration.millis(200), new KeyValue(translateYProperty(), getTranslateY() - y)),
   new KeyFrame(Duration.millis(200), new KeyValue(myScale, scale))
   );
  timeline.play();

   }

   /** 
  * !!!! The problem is in this method !!!!
  * 
  * The calculations are incorrect, and result in unpredictable behavior
  *  
  */
   public void fitWidth () {
   double scale = getParent().getLayoutBounds().getMaxX()/getLayoutBounds().getMaxX();
   double oldScale = getScale();

   double f = (scale / oldScale)-1;

   double dx = getTranslateX() - getBoundsInParent().getMinX() - getBoundsInParent().getWidth()/2;
   double dy = getTranslateY() - getBoundsInParent().getMinY() - getBoundsInParent().getHeight()/2;

   double newX = f*dx + getBoundsInParent().getMinX();
   double newY = f*dy + getBoundsInParent().getMinY();

  setPivot(newX, newY, scale);

   }

   public void resetZoom () {
   double scale = 1.0d;

   double x = getTranslateX();
   double y = getTranslateY();

  setPivot(x, y, scale);
   }

   public double getDeltaY() {
   return deltaY.get();
   }
   public void setDeltaY( double dY) {
  deltaY.set(dY);
   }
   }


   /**
  * Mouse drag context used for scene and nodes.
  */
   class DragContext {

   double mouseAnchorX;
   double mouseAnchorY;

   double translateAnchorX;
   double translateAnchorY;

   }

   /**
  * Listeners for making the scene's canvas draggable and zoomable
  */
   public class SceneGestures {

   private DragContext sceneDragContext = new DragContext();

   PanAndZoomPane panAndZoomPane;

   public SceneGestures( PanAndZoomPane canvas) {
   this.panAndZoomPane = canvas;
   }

   public EventHandler<MouseEvent> getOnMouseClickedEventHandler() {
   return onMouseClickedEventHandler;
   }

   public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
   return onMousePressedEventHandler;
   }

   public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
   return onMouseDraggedEventHandler;
   }

   public EventHandler<ScrollEvent> getOnScrollEventHandler() {
   return onScrollEventHandler;
   }

   private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {

   public void handle(MouseEvent event) {

  sceneDragContext.mouseAnchorX = event.getX();
  sceneDragContext.mouseAnchorY = event.getY();

  sceneDragContext.translateAnchorX = panAndZoomPane.getTranslateX();
  sceneDragContext.translateAnchorY = panAndZoomPane.getTranslateY();

   }

   };

   private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
   public void handle(MouseEvent event) {

  panAndZoomPane.setTranslateX(sceneDragContext.translateAnchorX + event.getX() - sceneDragContext.mouseAnchorX);
  panAndZoomPane.setTranslateY(sceneDragContext.translateAnchorY + event.getY() - sceneDragContext.mouseAnchorY);

  event.consume();
   }
   };

   /**
  * Mouse wheel handler: zoom to pivot point
  */
   private EventHandler<ScrollEvent> onScrollEventHandler = new EventHandler<ScrollEvent>() {

   @Override
   public void handle(ScrollEvent event) {

   double delta = PanAndZoomPane.DEFAULT_DELTA;

   double scale = panAndZoomPane.getScale(); // currently we only use Y, same value is used for X
   double oldScale = scale;

  panAndZoomPane.setDeltaY(event.getDeltaY()); 
   if (panAndZoomPane.deltaY.get() < 0) {
  scale /= delta;
   } else {
  scale *= delta;
   }

   double f = (scale / oldScale)-1;

   double dx = (event.getX() - (panAndZoomPane.getBoundsInParent().getWidth()/2 + panAndZoomPane.getBoundsInParent().getMinX()));
   double dy = (event.getY() - (panAndZoomPane.getBoundsInParent().getHeight()/2 + panAndZoomPane.getBoundsInParent().getMinY()));

  panAndZoomPane.setPivot(f*dx, f*dy, scale);

  event.consume();

   }
   };

   /**
  * Mouse click handler
  */
   private EventHandler<MouseEvent> onMouseClickedEventHandler = new EventHandler<MouseEvent>() {

   @Override
   public void handle(MouseEvent event) {
   if (event.getButton().equals(MouseButton.PRIMARY)) {
   if (event.getClickCount() == 2) {
  panAndZoomPane.resetZoom();
   }
   }
   if (event.getButton().equals(MouseButton.SECONDARY)) {
   if (event.getClickCount() == 2) {
  panAndZoomPane.fitWidth();
   }
   }
   }
   };
   }
}

I found the answer. I was looking at the wrong calculations, assuming that it be linked to translation. The real culprit was the calculation of the difference in scale. I just changed this:

double f = (scale / oldScale)-1;

to do this:

double f = scale - oldScale;

in the fitWidth() method, thus producing this...

    public void fitWidth () {
        double scale = getParent().getLayoutBounds().getMaxX()/getLayoutBounds().getMaxX();
        double oldScale = getScale();

        double f = scale - oldScale;

        double dx = getTranslateX() - getBoundsInParent().getMinX() - getBoundsInParent().getWidth()/2;
        double dy = getTranslateY() - getBoundsInParent().getMinY() - getBoundsInParent().getHeight()/2;

        double newX = f*dx + getBoundsInParent().getMinX();
        double newY = f*dy + getBoundsInParent().getMinY();

        setPivot(newX, newY, scale);

    }

Tags: Java

Similar Questions

  • Center a node dynamically in its container

    Hello

    In the application of FX that I'm working, I have to add a label at runtime and Center it in its parent container.
    I can get the width of the parent container node, but the problem is that I can't get the width of the label.
    See the code example below.
    Any help is appreciated.
    Thank you!

    Example code:

    Import javafx.application.Application;
    Import javafx.event.ActionEvent;
    Import javafx.event.EventHandler;
    Import javafx.scene.Scene;
    Import javafx.scene.control.Button;
    Import javafx.scene.control.Label;
    Import javafx.scene.layout.VBox;
    Import javafx.stage.Stage;

    SerializableAttribute public class GetLabelWidthTest extends Application {}
    VBox vb;

    Public Shared Sub main (String [] args) {}
    Launch (args);
    }

    @Override
    public void start (point primaryStage) bird Exception {}
    primaryStage.setTitle ("width of Label test");

    VB = new VBox();

    Button addLabelButton = new Button();
    addLabelButton.setText ("add a label");
    addLabelButton.setOnAction (new EventHandler < ActionEvent > () {}
    @Override
    {} public void handle (ActionEvent event)
    Label = new Sun;
    label.setText ("test label");
    vb.getChildren () .add (label);

    Double width = label.getWidth ();
    System.out.println ("the label width =" + width); still prints 0

    label.setTranslateX ((vb.getWidth () - width) / 2); trying to focus but will not work because the width is 0.
    }
    });

    vb.getChildren () .add (addLabelButton);

    Scene = new scene (vb, 800, 600);
    primaryStage.setScene (scene);
    primaryStage.show ();
    }
    }

    First of all, you can use a StackPane instead of a VBox? Then, the work is done for you.
    Second, the size of a node in the scene graph is not known until it is laid out. If you put your call to getWidth in a Platform.runLater, it will work fine.
    Third, you can listen the widthProperty, then setLayoutX once the width isn't known.

  • Adding new nodes dynamically

    I don't know if I'm missing something really obvious and are looking for examples

    I created a JavaFX 1.3 application that allowed me to draw a map using a palette of images. Click on an image in the palette and it is copied to the plan.

    I'm trying to replicate this in 2.o and find that, after the construction of the node, I can't add new children to it. I added onMousePressedProperty Manager and indeed it fires
    and it calls the function addNode which creates a new ImageView and attempts to add to the visible area... but nothing is visible on the screen. If the addNode code is run from the
    constructor of the target area, then it becomes visible. It never works after that the constructor is run.

    Can you please help me understand how things have changed in what concerns this kind of thing in JavaFx 2.0?

    public void addNode() {
    
            ImageView iv = new ImageView();
    
            Image img = new Image("c:/images/StarPngM.png");
            iv.setImage(img);
            iv.toFront();
            iv.setTranslateX(200);
            iv.setTranslateY(200);
            iv.setVisible(true);
    
            this.getChildren().add(iv);
        }

    1. first of all you need to know what is the main element to be cloned. In your context that the Image object is the main thing to be cloned then pass the ImageObject to your function addNode (Argument) and create a new object ImageView and then embed image passed argument

    This code brand new view Image object each time with image object that is already loaded in memory.

     public void addNode(Image ivp) {
            ImageView iv = new ImageView();
            iv.setImage(ivp.getImage());
            //code stuffs
            getChildren().add(iv);
         }
    

    2. for static image, and then do a static variable to give access to class to take advantage of this image.
    Make sure that the image is loaded either in the constructor or the ImageViewPalette class initialization phase.

    Thank you.
    Narayan

  • Bug in display of the tree when adding nodes dynamically?

    I am building a tree dynamically, child nodes are added only after a user clicks to open a node, and a call is made to see if there are children.

    The control is very sensitive, but after a few clicks, that it is as if an object of the same color that the background appears in the middle of the control tree obscuring nodes beneath it.

    If I click on the empty area at the location where the darkened nodes would fall meet and expand/collapse becoming visible/invisible as they fall under this area or beyond. If I hover over the empty box I see the node highlighting as a strip about 5 pixels wide on the left side.

    Revalidation of the tree redraws not this area. Has anyone seen this before, and how can I fix it?

    The problem disappeared. I think it was a bug is triggered by setting the selected items after I had updated the dataProvider and refreshing the tree.

    I had another question where the selectedItems disappeared after update of the tree. I fixed it by setting using callLater() selectedItems, because put immediately after the update the dataProvider of the tree did not work as long as the selection was lost anyway. callLater to do this fixed the issue of the selection and now apparently also the issue with a section of the tree being overshadowed.

  • TextField dynamically scaling

    Hey, I just created a form of contact with muse but noticed that the TextField doesn't scale when it overflows, but creates instead a scroll bar

    can I set it automatically adapts or having one of these buttons scaling to pull out at the bottom?

    I don't want to just scale the field because it must adapt to the design of the page

    Thanks in advance,

    Joe

    You can try to customize the code exported by adding the character limit setting, there is no way that we can limit the characters in form options.

    Thank you

    Sanjit

  • JavaFX scale canvas

    I would have use a fixed pixel size canvas, which can be resized to fill a window and will increase when the window is resized.

    I use my FXML SceneBuilder.

    My starting point is:

    FXML:

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

    <? import javafx.geometry. *? >

    <? import javafx.scene.image. *? >

    <? import javafx.scene.canvas. *? >

    <? import javafx.scene.shape. *? >

    <? import java.lang. *? >

    <? import java.util? >

    <? import javafx.scene. *? >

    <? import javafx.scene.control. *? >

    <? import javafx.scene.layout. *? >

    "" " < MaxHeight = BorderPane" "-Infinity" maxWidth = "-infinite" minHeight = ""-infinite "minWidth ="-infinite "xmlns =" http://JavaFX.com/JavaFX/8.0.40 "xmlns:fx =" " http://JavaFX.com/fxml/1 "fx:controller =" scalingcanvas. FXMLDocumentController">

    < center >

    < AnchorPane BorderPane.alignment = "CENTER" >

    < children >

    "" < canvas fx:id = "canvas" height = "200,0" width = "200,0" AnchorPane.bottomAnchor = "0.0" AnchorPane.leftAnchor ="0.0" AnchorPane.rightAnchor = "0.0" AnchorPane.topAnchor ="0.0" / >

    < / children >

    < / AnchorPane >

    < /Center >

    < top >

    < label text = 'top' BorderPane.alignment = "CENTER" / > "

    < / top >

    < down >

    < label text = 'bottom' BorderPane.alignment = "CENTER" / > "

    < / background >

    < left >

    < label text = 'left' BorderPane.alignment = "CENTER" / > "

    < / left >

    < right >

    < label text = 'right' BorderPane.alignment = "CENTER" / > "

    < / right >

    < / BorderPane >

    Controller of Java:

    package scalingcanvas;

    import java.net.URL;

    import java.util.ResourceBundle.

    Import javafx.fxml.FXML;

    Import javafx.fxml.Initializable;

    Import javafx.scene.canvas.Canvas;

    Import javafx.scene.canvas.GraphicsContext;

    Import javafx.scene.paint.Color;

    / public class FXMLDocumentController implements {bootable

    @FXML

    private canvas canvas;

    @Override

    Public Sub initialize (URL url, rb ResourceBundle) {}

    System.out.printf("hi\n");

    G2d GraphicsContext = canvas.getGraphicsContext2D ();

    Double w = canvas.getWidth ();

    Double h = canvas.getHeight ();

    g2d.setFill (Color.ALICEBLUE);

    g2d.fillRect (0, 0, w, h);

    g2d.setStroke (Color.Blue);

    g2d.strokeOval (0, 0, w, h);

    g2d.strokeLine (0, 0, w, h);

    g2d.strokeLine (0, h, o, 0);

    }

    }

    Main application:

    package scalingcanvas;

    Import javafx.application.Application;

    Import javafx.fxml.FXMLLoader;

    Import javafx.scene.Parent;

    Import javafx.scene.Scene;

    Import javafx.stage.Stage;

    SerializableAttribute public class ScalePanel extends Application {}

    @Override

    public void start (steps) riser Exception {}

    Mother-root = FXMLLoader.load (getClass () .getResource ("FXMLDocument.fxml"));

    Scene = new Scene (root);

    stage.setScene (scene);

    internship. Show();

    }

    Public Shared Sub main (String [] args) {}

    Launch (args);

    }

    }

    I understand why the existing code is not suitable the canvas when the window is cultivated, but what I need to add to get there?

    Also I need the canvas on the scale to maintain its underlying proportions (as specified by its width in pixels and height) and also to stay centered in the lowest node including the enclosing the proportions of the node is not the same as that of the canvas.

    Any help appreciated gratefully.

    Based on the code I found here I finally found a solution AutoScalingStackPane.

    The AutoScalingStackPane applies a scaling to scale its content to fill or proportions (preserved) to the size of StackPane. I added an AutoScale property that allows you to choose the option scale (NONE, ADAPT, scale).

    If you compile in a jar it can be used (and tested) with SceneBuilder.

    Given that it required only so little of code, I wonder if StackPane this could include scaling functionality directly. It seems that it could be useful and there is no API changes (only the inclusion of the additional AutoScale property)

    Also posted response StackOverflow

    /*
     * Based on http://gillius.org/blog/2013/02/javafx-window-scaling-on-resize.html
    */
    package dsfxcontrols;
    
    import javafx.beans.property.ObjectProperty;
    import javafx.beans.property.SimpleObjectProperty;
    import javafx.scene.Node;
    import javafx.scene.layout.StackPane;
    
    /**
    * A StackPane that scales its contents to fit (preserving aspect ratio),
    * or fill (scaling independently in X and Y) the available area.
    * 

    * Note AutoScalingStackPane applies to the contents a scaling * transformation rather than attempting to resize the contents. *

    * If the contents is a Canvas with pixel dimension 50 by 50, after scaling the * Canvas still will have 50 by 50 pixels and the appearance may be pixelated * (this might be desired if the application is interfacing a camera and the * Canvas needs to match in size the camera's CCD size). *

    * If the content contains FX Controls then these get magnified rather than * resized, that is all text and graphics are scaled (this might be desired for * Point of Sale full screen applications) *

    *

    Known Limitations

    * Rescaling occurs only when the AutoScalingStackPane is resized, it does not * occur automatically if and when the content changes size. * * * @author michaelellis */ public class AutoScalingStackPane extends StackPane { /** * Force scale transformation to be recomputed based on the size of this * AutoScalingStackPane and the size of the contents. */ public void rescale() { if (!getChildren().isEmpty()) { getChildren().forEach((c) -> { double xScale = getWidth() / c.getBoundsInLocal().getWidth(); double yScale = getHeight() / c.getBoundsInLocal().getHeight(); if (autoScale.get() == AutoScale.FILL) { c.setScaleX(xScale); c.setScaleY(yScale); } else if (autoScale.get() == AutoScale.FIT) { double scale = Math.min(xScale, yScale); c.setScaleX(scale); c.setScaleY(scale); } else { c.setScaleX(1d); c.setScaleY(1d); } }); } } private void init() { widthProperty().addListener((b, o, n) -> rescale()); heightProperty().addListener((b, o, n) -> rescale()); } /** * No argument constructor required for Externalizable (need this to work * with SceneBuilder). */ public AutoScalingStackPane() { super(); init(); } /** * Convenience constructor that takes a content Node. * * @param content */ public AutoScalingStackPane(Node content) { super(content); init(); } /** * AutoScale scaling options: * {@link AutoScale#NONE}, {@link AutoScale#FILL}, {@link AutoScale#FIT} */ public enum AutoScale { /** * No scaling - revert to behaviour of StackPane. */ NONE, /** * Independently scaling in x and y so content fills whole region. */ FILL, /** * Scale preserving content aspect ratio and center in available space. */ FIT } // AutoScale Property private ObjectProperty autoScale = new SimpleObjectProperty(this, "autoScale", AutoScale.FIT); /** * AutoScalingStackPane scaling property * * @return AutoScalingStackPane scaling property * @see AutoScale */ public ObjectProperty autoScaleProperty() { return autoScale; } /** * Get AutoScale option * * @return the AutoScale option * @see AutoScale */ public AutoScale getAutoScale() { return autoScale.getValue(); } /** * Set the AutoScale option * * @param newAutoScale * @see AutoScale * */ public void setAutoScale(AutoScale newAutoScale) { autoScale.setValue(newAutoScale); } }
  • How can I avoid a content panel, ScrollPane scaling of being centered?

    I want to create a ScrollPane where I can to scale the content. Think of a simple drawing program that allows you to zoom and zoom out.

    If I create a ScrollPane in SceneBuilder and then drop a few circles in the AnchorPane everything seems good.

    If I then put a scale of 0.5 to AnchorPane scale X and Y of the scale of the AnchorPane gets scaled around its Center leaving

    the space between the left and top of the AnchorPane edge and the edge left and upper pane scrolling bounding.

    The only way to get the AnchorPane so that it is aligned with the upper-left corner of ScrollPane seems to be adding a negative amount

    Translate X and Y of the translation.

    In my application, I would like the user to be able to set the zoom (scale) continuously and also the size of the AnchorPane should be allowed to change

    as add/changes/deletes user content.

    Does this mean that I must continually monitor the AnchorPane properties and the compensation value

    Definition of X and there translating values each time? Or y at - it an easier way to achieve what I want?

    Scene BuilderScreenSnapz001.png

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

    <? import javafx.scene.paint. *? >

    <? import javafx.scene.effect. *? >

    <? import javafx.scene. *? >

    <? import javafx.scene.shape. *? >

    <? import java.lang. *? >

    <? import javafx.scene.control. *? >

    <? import javafx.scene.layout. *? >

    " < fitToHeight ScrollPane ="true"="true"prefHeight ="409,0"prefWidth fitToWidth ="517,0"xmlns:fx =" http://JavaFX.com/fxml/1 "xmlns =" " http://JavaFX.com/JavaFX/8 ">

    < content >

    < AnchorPane = "0.5" scaleX scaleY = "0.5" style = "" background - fx - color: AliceBlue; ">"

    < children >

    < fill circle "#c3cd8d" = "175,0" layoutX = on = RADIUS "136,0" = "100.0" race = 'BLACK' strokeType = 'INTERNAL' / >

    < fill circle = ' #31aeb2d1 ' layoutX '275.0' = on = RADIUS "265.0" = "100.0" race = 'BLACK' strokeType = 'INTERNAL' / >

    < / children > < / AnchorPane >

    < / content >

    < / ScrollPane >

    Found this on the scalability in JavaFX and ScrollPanes - Stack Overflow

    ScrollPane layout calculations are based on the layoutBounds rather than the
    boundsInParent (visual bounds) of the scroll node. If an application wants the
    scrolling to be based on the visual bounds of the node (for scaled content etc.),
    they need to wrap the scroll node in a Group.

    My SceneBuilder now looks like this:

    And the FXML is:

    http://JavaFX.com/fxml/1"xmlns ="http://javafx.com/javafx/8">."

  • How can I create dynamic events for a group/list?

    Hey,.
    ATM I'm programming request a bit where I add items to my center pane.

    Simpyfied I got:

    -Center pane: here are the items that appear on right click in the lower pane. This component must serve something like a playground where you can drag and drop and associate items in the bottom pane
    -Low component: here, I got approximately 180 items which are quite equal. It's smth like a menu of items that you can use. I realized the java classes extended from a parent with v.f. dispute class.

    What I want:
    I want to create an event handler for EACH of the items 'menu' dynamically. Just sth like:
        for (int i = 0; i < basic_menu_list.size(); i++)
        {
          final Element el = hbox_bottom.getChildren().get(i);
          hbox_bottom.getChildren().get(i).setOnMouseClicked(new EventHandler<MouseEvent>()
          {
    
            public void handle(MouseEvent event)
            {
              if (event.isSecondaryButtonDown())
              {
                playground.add(el);
                redrawPlayground();
              }
            }
    
          });
        }
    But as I expected, it does not work...

    Now my question:
    How can I solve this problem? Y at - it no option to listen to all the elements of a group without hard-coding every single listener?

    Thanks for your help,
    Martin

    Hello user,.

    Why you expected you it wouldn't work?
    You have an example with the 'transition' apply on a bunch of circles in the Getting Started with JavaFx (http://download.oracle.com/javafx/2.0/get_started/jfxpub-get_started.htm)

    Here is a class of the basic example...

    import javafx.application.Application;
    
    import javafx.event.EventHandler;
    
    import javafx.scene.Node;
    import javafx.scene.Scene;
    import javafx.scene.control.TextBox;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.Pane;
    import javafx.scene.layout.VBox;
    
    import javafx.stage.Stage;
    
    public class HelloWorld extends Application {
    
        //~ ----------------------------------------------------------------------------------------------------------------
        //~ Methods
        //~ ----------------------------------------------------------------------------------------------------------------
    
        public static void main(String[] args) {
            // Entry point
            Application.launch(args);
        }
    
        @Override
        public void start(Stage mainStage) throws Exception {
    
            Pane pane = new Pane();
            Scene scene = new Scene(pane, 200, 200);
    
            VBox vBox = new VBox();
            TextBox input1 = new TextBox();
            TextBox input2 = new TextBox();
            vBox.getChildren().addAll(input1, input2);
    
            for (Node input : vBox.getChildren()) {
                input.setOnMouseClicked(new EventHandler() {
                        public void handle(MouseEvent event) {
                            System.out.println("test click");
                        }
                    });
            }
    
            pane.getChildren().add(vBox);
            mainStage.setScene(scene);
            mainStage.setVisible(true);
        }
    }
    

    Niculaiu

  • Why stage Builder creates constantly new instances of nodes?

    Hello

    I thought I had a simple idea to create a control that would allow me to recover a part of the behavior of a component of the map.  It's all of the control:

    import javafx.beans.property.BooleanProperty;
    import javafx.beans.property.SimpleBooleanProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.scene.Node;
    import javafx.scene.Parent;
    import javafx.scene.layout.StackPane;
    
    
    public class Card extends StackPane {
        private final BooleanProperty active = new SimpleBooleanProperty();
        public final BooleanProperty activeProperty() {return active;}
        public final boolean isActive() {return active.get();}
        public final void setActive(boolean active) {this.active.set(active);}
    
    
        {
            visibleProperty().bind(active);
            managedProperty().bind(active);
    
    
            active.addListener(new ChangeListener<Boolean>() {
                @Override
                public void changed(ObservableValue<? extends Boolean> observable,
                                    Boolean old,
                                    Boolean active) {
                    System.out.println(toString() + " active changed to: " + active);
                    if(active) {
                        Parent parent = getParent();
                        if(parent != null) {
                            System.out.println("Parent is: " + parent.toString());
                            parent.getChildrenUnmodifiable().forEach(Card.this::deactivateIfCard);
                        }
                        else {
                            System.out.println("Parent is null.");
                        }
                    }
                }
            });
        }
    
    
        private void deactivateIfCard(Node node) {
            if(node != this && node instanceof Card) {
                Card card = (Card) node;
                card.setActive(false);
            }
        }
    }
    

    The idea is simple enough; expand StackPane, add an active property, bind the visible and managed component properties to the property active, and, whenever the active property is changed to true, browse the sibling nodes by disabling brothers and sisters who are also the type of card.

    However, this does not work with the generator from the scene.  While trying to debug, I created an ExtStackPane:

    import javafx.collections.ListChangeListener;
    import javafx.scene.Node;
    import javafx.scene.layout.StackPane;
    
    
    public class ExtStackPane extends StackPane {
        {
            getChildren().addListener((ListChangeListener<Node>) c -> {
                System.out.println("ExtStackPane children change: " + c.toString());
            });
        }
    }
    

    It doesn't save that list change events.  However, I was very surprised by the exit when you work in the generator from the scene.  I added both controls the generator onstage and did the following:

    0) added an ExtStackPane

    (1) added a map to the ExtStackPane

    2) added another card at the ExtStackPane

    (3) adds a label the first card

    (4) added a label to the second card

    5) changed the text of the first label Hello

    6) changed the text of the label of second in the world

    (7) set the first card to active

    (8) the value of the second card active

    I get the following result:

    1)
    ExtStackPane children change: { [Card@5b9067b3] added at 0 }
    
    
    2)
    ExtStackPane children change: { [Card@6b6328bd] added at 0 }
    ExtStackPane children change: { [Card@6aca8cc5] added at 1 }
    
    
    3)
    ExtStackPane children change: { [Card@3b7bc340] added at 0 }
    ExtStackPane children change: { [Card@1879819e] added at 1 }
    
    
    4)
    ExtStackPane children change: { [Card@60ffed67] added at 0 }
    ExtStackPane children change: { [Card@64955a14] added at 1 }
    
    
    5)
    ExtStackPane children change: { [Card@5dc96bc4] added at 0 }
    ExtStackPane children change: { [Card@40667c26] added at 1 }
    
    
    6)
    ExtStackPane children change: { [Card@164770fa] added at 0 }
    ExtStackPane children change: { [Card@7decebbf] added at 1 }
    
    
    7)
    Card$1@f4f4850 active changed to: true
    Parent is null.
    ExtStackPane children change: { [Card@27442c8b] added at 0 }
    ExtStackPane children change: { [Card@643d810e] added at 1 }
    
    
    8)
    Card$1@4877c67b active changed to: true
    Parent is null.
    ExtStackPane children change: { [Card@7e8a473e] added at 0 }
    Card$1@2b4497c1 active changed to: true
    Parent is null.
    ExtStackPane children change: { [Card@5df6c8cc] added at 1 }
    

    This is what things look like in the generator from the scene:

    card-panes.PNG

    The scene generator recreate the entire hierarchy whenever I make a small change?  Here's an app that does the same thing as the manual steps that I performed in the stage Builder:

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.stage.Stage;
    
    
    public class CardApplication extends Application {
        @Override
        public void start(Stage primaryStage) throws Exception {
            ExtStackPane stackPane = new ExtStackPane();
    
    
            // 1
            Card card1 = new Card();
            stackPane.getChildren().add(card1);
    
    
            // 2
            Card card2 = new Card();
            stackPane.getChildren().add(card2);
    
    
            // 3
            Label label1 = new Label();
            card1.getChildren().add(label1);
    
    
            // 4
            Label label2 = new Label();
            card2.getChildren().add(label2);
    
    
            // 5
            label1.setText("Hello");
    
    
            // 6
            label2.setText("World");
    
    
    
    
            primaryStage.setScene(new Scene(stackPane));
            primaryStage.setTitle("Card Application");
            primaryStage.setWidth(600);
            primaryStage.setHeight(400);
            primaryStage.show();
    
    
            // 7
            card1.setActive(true);
    
    
            // 8
            card2.setActive(true);
        }
    }
    

    The output when executing the above is:

    1)
    ExtStackPane children change: { [Card@6dfaa767] added at 0 }
    
    
    2)
    ExtStackPane children change: { [Card@6aa2c411] added at 1 }
    
    
    7)
    Card$1@1abf7511 active changed to: true
    Parent is: ExtStackPane@41993867[styleClass=root]
    
    
    8)
    Card$1@5733cd2 active changed to: true
    Parent is: ExtStackPane@41993867[styleClass=root]
    Card$1@1abf7511 active changed to: false
    

    The behavior is obviously very different than when I work with control in the generator from the scene.  Can someone explain to me that event giving rise to the stage to change the behavior of my map control so much?  My map control breaks some I'm not aware of one or more rules?

    I think you're confused about what makes SceneBuilder.

    SceneBuilder is a design tool, used by the programmer (not the end user) to generate the part of the code that is used to run the application. (Specifically, it generates the FXML code which is analysed by the FXMLLoader to create and configure objects that are usually part of the graphic scene.)

    When you use SceneBuilder to create the code, it generates a model of what the user interface will look like, if the generated FXML should be loaded and displayed. This model is not meant to be an identical vision of what will be the end user, but a help to you, the programmer, to generate the code that you want to.

    So, for example your accordion/TitledPane in the layout of the poster than SceneBuilder, the * selected * titled pane is always expanded. This allows you to drag and drop objects inside and set it up in other ways. If you clear the checkbox "extended" in the properties pane, then it remains extended in the model so that you can continue to configure it. However, this property is not ignored: the State of these boxes is respected in the FXML file that is generated. So when you click on 'save' in SceneBuilder, the fxml generated will contain TitledPane extended element = "true" If the box is checked and expanded = "false" If the check box is cleared. (SceneBuilder will of course also applied the rule that only TitledPane in the accordion can be increased.)

    Similarly, for your control customized, you should be able to implement and SceneBuilder displays the 'active' property in the box. If you disable this property, if active = false, which will be respected in the fxml and when you run the active application will be set to false and so by your liaison, visible is set to false and the component is not displayed. But the comp in (of course) SceneBuilder always displays your component, because it would be extremely difficult for you to configure a component that did not appear in the programming tool.

    In fact, there is no real reason for SceneBuilder create all the objects that you set up at all. He could just trying to figure out what they look like and render a representation of them on a canvas, for example. It's probably much (much) harder than instantiating them and the authors of SceneBuilder apparently chose to write SceneBuilder in a way that re-instantiates the controls several times. But this has absolutely nothing to do with what happens when you run the application and it is no logic at all to compare the two.

  • Strange Exception while moving the mouse over the node Java8

    Hello

    I did a customAnchorPane (extends AnchorPane) who plays the adding and removing of other nodes an animation. I get a strange exception when I move the mouse on some! nodes (not all). The source of the exception seems to be internal.

    I have no idea how to solve this problem.

    Someone at - it an idea?

    I use the Java8

    Exception in thread "Thread of Application JavaFX" java.lang.NullPointerException

    at com.sun.javafx.scene.input.PickResultChooser.processOffer(PickResultChooser.java:183)

    at com.sun.javafx.scene.input.PickResultChooser.offer(PickResultChooser.java:142)

    at javafx.scene.Node.impl_computeIntersects(Node.java:4763)

    at javafx.scene.Node.impl_intersects(Node.java:4730)

    at javafx.scene.Node.impl_pickNodeLocal(Node.java:4660)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2699)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2699)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2699)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2699)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2699)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2699)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2699)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2699)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2699)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2699)

    at javafx.scene.Node.impl_pickNode(Node.java:4695)

    to javafx.scene.Scene$ MouseHandler.pickNode (Scene.java:3798)

    to javafx.scene.Scene$ MouseHandler.access$ 1900 (Scene.java:3384)

    at javafx.scene.Scene.pick(Scene.java:1832)

    to javafx.scene.Scene.access$ 6700 (Scene.java:193)

    to javafx.scene.Scene$ MouseHandler.process (Scene.java:3610)

    to javafx.scene.Scene$ MouseHandler.access$ 1800 (Scene.java:3384)

    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1652)

    to javafx.scene.Scene$ ScenePeerListener.mouseEvent (Scene.java:2443)

    to com.sun.javafx.tk.quantum.GlassViewEventHandler$ MouseEventNotification.run (GlassViewEventHandler.java:314)

    to com.sun.javafx.tk.quantum.GlassViewEventHandler$ MouseEventNotification.run (GlassViewEventHandler.java:243)

    at java.security.AccessController.doPrivileged (Native Method)

    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:345)

    at com.sun.glass.ui.View.handleMouseEvent(View.java:526)

    at com.sun.glass.ui.View.notifyMouse(View.java:898)

    at com.sun.glass.ui.win.WinApplication._runLoop (Native Method)

    to com.sun.glass.ui.win.WinApplication.access$ 300 (WinApplication.java:39)

    to com.sun.glass.ui.win.WinApplication$ $4 1.run(WinApplication.java:112)

    at java.lang.Thread.run(Thread.java:744)

    Can you post a NBS that illustrates the problem?

    If you have a version of Java 8 corresponding to the current source code, it seems that the system attempts to select a node that is not attached to the graphic scene. This could happen in theory (I guess) If you change the chart of scene on the FX Application thread; but it's a blind guess.

  • LineChart change color dynamically

    I have a StackPane with a line chart and a button: I would like to change the color by clicking on a button, that is, from white to black.

    How to get there?

    Thank you.

    import java.util.Set;
    import javafx.application.Application;
    import javafx.event.EventHandler;
    import javafx.scene.Group;
    import javafx.scene.Node;
    import javafx.scene.Scene;
    import javafx.scene.chart.CategoryAxis;
    import javafx.scene.chart.LineChart;
    import javafx.scene.chart.NumberAxis;
    import javafx.scene.chart.XYChart;
    import javafx.scene.control.Button;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
    import static javafx.scene.paint.Color.RED;
    import javafx.stage.Stage;
    
    
    /**
     *
     * @author Alberto
     */
    public class SimpleLineChart extends Application {
        
        @Override
        public void start(Stage primaryStage) {
            
            final NumberAxis xAxis = new NumberAxis();
            final NumberAxis yAxis = new NumberAxis();
        
            final LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
    
            
            XYChart.Series series = new XYChart.Series();
          
            
            series.getData().add(new XYChart.Data(1, 100));
            series.getData().add(new XYChart.Data(2, 200));
            series.getData().add(new XYChart.Data(3, 50));
            series.getData().add(new XYChart.Data(4, 75));
            series.getData().add(new XYChart.Data(5, 110));
            series.getData().add(new XYChart.Data(6, 300));
            series.getData().add(new XYChart.Data(7, 111));
            series.getData().add(new XYChart.Data(8, 30));
            series.getData().add(new XYChart.Data(9, 75));
            series.getData().add(new XYChart.Data(10, 55));
            series.getData().add(new XYChart.Data(11, 225));
            series.getData().add(new XYChart.Data(12, 99));
            
            lineChart.setCreateSymbols(false);
            lineChart.setAlternativeColumnFillVisible(false);
            lineChart.setAlternativeRowFillVisible(false);
            lineChart.setLegendVisible(false);
            lineChart.setAnimated(false);
            lineChart.setVerticalZeroLineVisible(true);
            lineChart.setEffect(null);
        
            lineChart.getData().add(series);
                
            String color = "White";
            String lineColor  = "-fx-stroke: " + color + ";";
            
            
            Set<Node> lineNode = lineChart.lookupAll(".series0");
                for (final Node line : lineNode) {
                    
                    line.setStyle(lineColor);             
                }
            
            
            StackPane sp = new StackPane();
            Button btn = new Button();
            btn.setText("test");
            
            
            btn.setOnMousePressed(new EventHandler<MouseEvent>(){
                @Override
                public void handle(MouseEvent me){
                    System.out.println("prova print");
                }
            });
            
            sp.getChildren().addAll(lineChart, btn);
            
            Scene scene = new Scene(sp, primaryStage.getWidth(), primaryStage.getHeight());
        
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
    
       
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    You already have the code to change the color of the line on the graph and the code to respond to the key (even if you use onAction, not onMousePressed). Just put it together:

    btn.setOnAction(new EventHandler() {
         @Override
         public void handle(ActionEvent event) {
              Set lineNode = lineChart.lookupAll(".series0");
              for (final Node line : lineNode) {
                   line.setStyle("-fx-stroke: black;");
              }
         }
    });
    
  • There is no Node.LayoutZ?  JDK 8.0, even when the API specifies its existing

    OK so I might be confused, but it seems that the provision of a node defined there (X, Y) position as SetX and SetY would swing... However, there is no setLayoutZ... When I goto setTranslateZ it is said

    'javafx.scene.Node '.
    public final void setTranslateZ (double value)
    Sets the value of the translateZ property.
    Description of the property:
    Defines the coordinate Z from the translation that is added to the transformed coordinates of this node. This value will be added to any translation defined by the transformations ObservableList and layoutZ. »


    I guess I could put the Z translation, if necessary, but I'm confused what exactly the point of affecting the translation and layout if they do the same thing... IT seems as if the translation of setting is important for other things himself...


    Remember PositionX, getScreenX, and getSceneX... >)

    what I'm trying to do is set a box 3D x, y and z. Rectangle has x, y, but the box has nothing. Is it because it is too early in construction, or...? That's why I look at you I choose other methods. the only thing that makes sense is exactly the translation.

    Simply use the properties translate for the positioning of objects in 3D at the moment (that's all that you have).

    You may also cross this post to the discussion of possible changes to the api openjfx-dev list (such as adding a layoutZ property, a method to move some who takes z parameters for 3-d shape builders specify the initial values of page layout, etc., coordinates z, x, y, x).

    I don't know if JavaFX will adopt eventually the concept of layout for use in a 3d scene graph, similar to how it works in a 2d scene graph - if it does then the above methods and properties would be desirable, otherwise they will be necessary (and everything should be done by using the coordinates translate only what you need to do today). My feeling is that finally the 3d scene graph will get 3d layout managers, but probably not in JavaFX 8 times (if you do not bring it upwards on openjfx-dev now or newspaper questions about jira, you can be assured that this facility is not available during the period of JavaFX 8).

  • Node.getSize ()?

    Hi all

    My Q is very simple...

    How do I get the size (width / height) to a node?

    I expect that there are: MyNode.getWidth () and MyNode.getHeight ()...
    But they does NOT exist... or equivalent methods.

    It's really ubnormal?

    Thanks for any help...

    The things that extend from region (for example, page layouts and controls) have width and height properties, so you can just do:

    label.getWidth();
    

    The nodes have different types of limits =>
    http://docs.Oracle.com/JavaFX/2/API/JavaFX/scene/node.html#layoutBoundsProperty%28%29
    http://docs.Oracle.com/JavaFX/2/API/JavaFX/scene/node.html#boundsInLocalProperty%28%29
    http://docs.Oracle.com/JavaFX/2/API/JavaFX/scene/node.html#boundsInParentProperty%28%29

    A simple program to illustrate that do this:
    https://gist.github.com/1441960

    In my words:
    -Layout limits: the boundary of the shape.
    -Delimits local: the boundary of the shape and the effect.
    -Limits of Parent: the boundary of the shape, the effects and transformations.

    Once you have the appropriate limits, you can query its width, height and depth.

    For example:

    node.getBoundsInParent().getWidth()
    

    Note that if the node contains something resizable or css stylesheet, you really won't get a proper report to the limits until it was posted on a scene active and a pulse was performed on this subject. Thus, for example, the declared value for boundaries immediately after creating the node may differ from the value declared after that (scene) stage.show has been called. To always be informed of what is the height or width of a node, add a listener to the property of the appropriate limits, for example:

    final DoubleProperty nodeWidth = new SimpleDoubleProperty(node.getWidth());
    node.boundsInParentProperty().addListener(new ChangeListener() {
      @Override public void changed(ObservableValue ov, Bounds oldBounds, Bounds newBounds) {
        nodeWidth.set(newBounds.getWidth());
      }
    });
    

    Aspects of layout and controls have a property of convenience for this already, so you can do things like:

    label.widthProperty().bind(scene.widthProperty());
    

    Then there are things that calculates the preferred, minimum and maximum amounts for the nodes based on a given width or height. For nodes in constant sizes, these will always return the same value for resizable nodes, they can return different values. These should be used when in the subclassed layoutChildren call you create your own composite nodes (i.e. not so often and never if you are a beginner to write JavaFX programs).

    node.minWidth(height)  // minimum width for a given height.
    node.prefWidth(height)
    node.maxWidth(height)
    

    Finally resizable nodes that extend the region as part of layout and controls have the following properties, which you will likely finish by using a little:

    region.minWidthProperty()
    region.prefWidthProperty()
    region.maxWidthProperty()  
    

    For example region.getMaxWidth will return either
    -Region.USE_PREF_SIZE-online maximum width will be the same as the default width.
    -Region.USE_COMPUTED_SIZE-online maximum width will be of what is implemented in the default region.
    -Some absolute value-online the maximum width will be all that a caller has chosen via region.setMaxWidth (value) call.
    -Double.MAX_VALUE-online unlimited maximum width.

    A good layout strategy is not to worry about sizes much at all, instead use resizable controls inside layout managers and set a default size of resizable controls only when you need to.

  • How can I add a context menu to control nodes?

    I want to add a context menu to a rectangle, but currently the popup menu can only be added to control nodes. What is the reason behind this?

    I guess this is same reason that the ToolTip has a static installation for nodes in control - i.e. method for javafx.scene classes as node have a dependency on javafx.control classes.

    Add an eventhandler to your rectangle (e.g. mouseclicked) and call contextMenu.show () in the eventhandler.
    http://docs.Oracle.com/JavaFX/2.0/API/JavaFX/scene/node.html#setOnMouseClicked%28javafx.event.EventHandler%29
    http://docs.Oracle.com/JavaFX/2.0/API/JavaFX/scene/control/ContextMenu.html#show%28javafx.scene.node, %20javafx.geometry.Side,%20double,%20double%29

  • Help understand Node.boundsInLocal, Node.boundsInParent?

    Hi all

    I read the API JavaFX2 to understand the methods getBoundsInLocal() and getBoundsInParent() for a node. I understand the limits object that is returned. I want to better understand the difference between the two methods.

    I read in the API that the getBoundsInLocal() method returns "the rectangular boundaries of this node in the coordinate space local transformed node." Am I correct in thinking that it is primarily the transformations? It would be the height, width, x and are coordinated during initialization?

    The getBoundsInParent() method says "rectangular limits of this node include its transformations.» This includes transformations?

    ---

    My next question is to understand the method of getBoundsInLocal() as it is used in this demonstration. Here is an example of creating custom button written by Eric Bruno (http://www.drdobbs.com/blogs/jvm/229400781).

    In the class ArrowButtonSkin.java, Eric sets height and width of the label. When I run the program I see the value of width is - 1.0 and the height is 0.0. If the control is displayed as a dot on the screen. Is there a reason that the methods below are back-1 and 0? I don't know where I was wrong. It works if I put the values explicitly.

    Double labelWidth = label.getBoundsInLocal () .getWidth ();
    Double labelHeight = label.getHeight ();

    Thank you very much for the help.

    Here is the code:
    Driver.Java
    /*
     * This demo creates a custom Button. See article and explanation at:
     * http://www.drdobbs.com/blogs/jvm/229400781
     */
    package ui.drdobbs;
    
    import javafx.application.Application;
    import javafx.event.EventHandler;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.input.MouseEvent;
    import javafx.stage.Stage;
    
    public class Driver extends Application {
    
        @Override
        public void start(final Stage stage) { 
            
            stage.setTitle("The JavaFX Bank");
            
            // Create the node structure for display
            Group rootNode = new Group();
            Button normalBtn = new Button("Close");
            normalBtn.setTranslateX(140);
            normalBtn.setTranslateY(170);
            
            normalBtn.setOnMouseClicked(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent me) {
                    stage.close();
                }
            });
            
            // Create a directional arrow button to display account information
            ArrowButton accountBtn = new ArrowButton("Accounts");
            accountBtn.setDirection(ArrowButton.RIGHT);
            accountBtn.setTranslateX(125);
            accountBtn.setTranslateY(10);
           
            // Handle arrow button press
            accountBtn.setOnMouseClicked(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent me) {
                    System.out.println("Arrow button pressed");
                }
            });
    
            // Some description text
            Label description = new Label(
                    "Thanks for logging into the\n"
                    + "JavaFX Bank. Click the button\n"
                    + "above to move to the next \n"
                    + "screen, and view your active \n"
                    + "bank accounts.");
            description.setTranslateX(10);
            description.setTranslateY(50);
            
            rootNode.getChildren().add(accountBtn);
            rootNode.getChildren().add(description);
            rootNode.getChildren().add(normalBtn);
            
            Scene scene = new Scene(rootNode, 200, 200);
            stage.setScene(scene);
            stage.show();
        }
        
        public static void main(String[] args) {launch(args);}
        
    }
    ArrowButton.java
    package ui.drdobbs;
    
    import javafx.scene.control.Control;
    import javafx.scene.control.Skin;
    import javafx.scene.input.MouseEvent;
    
    
    public class ArrowButton extends Control implements ArrowButtonInterface {
        private String title = "";
        
        public ArrowButton() {
            this.setSkin(new ArrowButtonSkin(this));
        }
        
        public ArrowButton(String title) {
            this();
            this.title = title;
            ArrowButtonSkin skin = (ArrowButtonSkin)this.getSkin();
            skin.setText(title);
        }
        
        @Override
        public void setText(String text) {
            getSkin(getSkin()).setText(text);
        }
    
        @Override
        public void setOnMouseClicked(MouseEvent eh) {
            getSkin(getSkin()).setOnMouseClicked(eh);
        }
    
        @Override
        public void setDirection(int direction) {
            getSkin(getSkin()).setDirection(direction);
        }
        
        private ArrowButtonSkin getSkin(Skin skin) {
            return (ArrowButtonSkin)skin;
        }
        
    }
    ArrowButtonSkin.java
    package ui.drdobbs;
    
    import javafx.event.EventHandler;
    import javafx.scene.Group;
    import javafx.scene.Node;
    import javafx.scene.control.Label;
    import javafx.scene.control.Skin;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.paint.Color;
    import javafx.scene.paint.CycleMethod;
    import javafx.scene.paint.LinearGradient;
    import javafx.scene.paint.Stop;
    import javafx.scene.shape.*;
    
    public class ArrowButtonSkin implements Skin<ArrowButton>, ArrowButtonInterface {
        
        //Attributes
        static final double ARROW_TIP_WIDTH = 5;
        ArrowButton control;
        String text = "";
        Group rootNode = new Group();
        Label label = null;
        int direction = ArrowButtonInterface.RIGHT;
        EventHandler clientEH = null;
     
        //Constructors
        public ArrowButtonSkin(ArrowButton control) {
            this.control = control;
            draw();
        }
     
        //Methods
        public ArrowButton getControl() {
            return control;
        }
     
        //////////////////////////////////////////////////////////////
     
        private void draw() {
            //Create a label.
            if ( label == null )
                label = new Label(text);
    
            //Set Width Height
            double labelWidth = label.getBoundsInLocal().getWidth();
            double labelHeight = label.getHeight();
            
            System.out.println(labelWidth + ", " + labelHeight);
            label.setTranslateX(2);
            label.setTranslateY(2);
            
            // Create arrow button line path elements
            Path path = new Path();
            MoveTo startPoint = new MoveTo();
            double x = 0.0f;
            double y = 0.0f;
            double controlX;
            double controlY;
            double height = labelHeight;
            startPoint.setX(x);
            startPoint.setY(y);
    
            HLineTo topLine = new HLineTo();
            x += labelWidth;
            topLine.setX(x);
    
            // Top curve
            controlX = x + ARROW_TIP_WIDTH;
            controlY = y;
            x += 10;
            y = height / 2;
            QuadCurveTo quadCurveTop = new QuadCurveTo();
            quadCurveTop.setX(x);
            quadCurveTop.setY(y);
            quadCurveTop.setControlX(controlX);
            quadCurveTop.setControlY(controlY);
    
            // Bottom curve
            controlX = x - ARROW_TIP_WIDTH;
            x -= 10;
            y = height;
            controlY = y;
            QuadCurveTo quadCurveBott = new QuadCurveTo();
            quadCurveBott.setX(x);
            quadCurveBott.setY(y);
            quadCurveBott.setControlX(controlX);
            quadCurveBott.setControlY(controlY);
    
            HLineTo bottomLine = new HLineTo();
            x -= labelWidth;
            bottomLine.setX(x);
    
            VLineTo endLine = new VLineTo();
            endLine.setY(0);
    
            path.getElements().add(startPoint);
            path.getElements().add(topLine);
            path.getElements().add(quadCurveTop);
            path.getElements().add(quadCurveBott);
            path.getElements().add(bottomLine);
            path.getElements().add(endLine);
            
            // Create and set a gradient for the inside of the button
            Stop[] stops = new Stop[] {
                new Stop(0.0, Color.LIGHTGREY),
                new Stop(1.0, Color.SLATEGREY)
            };
            LinearGradient lg =
                new LinearGradient( 0, 0, 0, 1, true, CycleMethod.NO_CYCLE, stops);
            path.setFill(lg);
            
            rootNode.getChildren().setAll(path, label);
                    
            rootNode.setOnMouseClicked(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent me) {
                    // Pass along to client if an event handler was provided
                    if ( clientEH != null )
                        clientEH.handle(me);
                }
            });
        }
     
        //*****************************************
        //Overridden methods from ArrowButtonInterface
        //*****************************************
        /**
         * setText. Method provided by ArrowButtonInterface.
         * @param text 
         */
        @Override
        public void setText(String text) {
            this.text = text;
            label.setText(text);
     
            // update button
            draw();
        }
     
        /**
         * setOnMouseClicked. Method provided by ArrowButtonInterface.
         * @param eh 
         */
        public void setOnMouseClicked(EventHandler eh) {
            clientEH = eh;
        }
     
        /**
         * setDirection. Method provided by ArrowButtonInterface.
         * @param direction 
         */
        @Override
        public void setDirection(int direction) {
            this.direction = direction;
     
            // update button
            draw();
        }
    
        //*****************************************
        //Overridden methods from Control
        //*****************************************
        @Override
        public ArrowButton getSkinnable() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
        @Override
        public void setOnMouseClicked(MouseEvent eh) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
        
        @Override
        public Node getNode() {
            return rootNode;
        }
     
        @Override
        public void dispose() {
        }
    }
    ArrowButtonInterface
    package ui.drdobbs;
    
    import javafx.scene.input.MouseEvent;
    
    public interface ArrowButtonInterface {
        public static final int RIGHT = 1;
        public static final int LEFT = 2;
     
        public void setText(String text);
        public void setOnMouseClicked(MouseEvent eh);
        public void setDirection(int direction); 
    }
    Published by: 927562 on April 13, 2012 13:28

    Published by: 927562 on April 13, 2012 13:33

    You should take a look at this demo:
    https://gist.github.com/1441960
    It shows quite well the differences.
    Michael

Maybe you are looking for

  • iCloud is not finished

    Hi there my iCloud will not save more

  • Cover my 600EX-RT flash LINK is still red in slave mode

    Hi everyone, I hope someone can help me here. I got my Flash Canon & T5i recently, these two works great when the flash is mounted on the camera, but when Iam using the flash in the mood of the slave with the camera the cover link turns red indicatin

  • Problems re - install Windows 7

    I'm trying to reinstall Windows 7 on my desktop using a USB key. I put the BIOS and Boot Menu to start using USB - HDD. Every time the re - install starts and reaches the point where he needs to reboot to continue, since early the process instead of

  • Authorization of NFC?

    I can't find this information anywhere and I don't have BB10 Dev Alpha. I have to specify permissions in the manifest file to be able to take advantage of the features of NFC in my native application?

  • Is it possible to block the hotmail and Skype account?

    Original title: my iphone was stolen can I close my hotmail account 0n this phone my iphone was stolen at the Airport yesterday and opened my hotmail and my Skype can block them to work on the phone