JavaFx 2.0 Layouts

Hello

In JavaFx 1.3, the behavior of nodes to its parent, or shrinkage, size etc., could be changed through its layoutInfo property.

How can this be achieved in Javafx 2.0?

I noticed the default behavior of this aspect is different from some nodes to others, for example, the page layouts grow by default. So, if a want my layout of the scene to be a StackPane that contains a GridPane centered with other stuff, I can't do this because the inner pane will grow to fit the whole scene.

PS: do not use only the GridPane and the setAlignment (Pos.CENTER); because it will still technically be the size of the stage, and I wouldn't be able to paint by css as a Center Panel.

PS2: there should be a new category called JavaFX 2.0 or something.

Thank you...

In the end the size of a resizable node (region, WebView control) will depend on two things:
(1) there are preferences own pref/mini/maxi size
(2) the sizing of its parent policy

(2) you must consult the documentation for the component layout, but for example, a FlowPane will resize itself still nodes to their preferred sizes, while a StackPane will attempt to resize its children to fill its area (up to a limit of maximum size of the child). Which means the size of a default node MAX has everything to do with how it is resized. It has attempted to set the default size values max based on how you would usually controls behave for the implementation:

All aspects of page layout and most of the controls have a size max unlimited, which means that a StackPane them will expand. Exceptions:
-Label, Hyperlink, cursor, buttons, ProgressBar returns pref size max (so they stretch by default)
-Menu bar, TextBox back pref for max height (width is unlimited)
-Separator, toolbar, scroll bar are unlimited in their orientation, but attached to the pref dimension in the other

If you don't want a GridPane to be stretched beyond its preferred size, tighten it just:

gridpane.setMaxSize (Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);

If you want to than the width of a button to be flexible:

button.setMaxWidth (Double.MAX_VALUE);

We did have all the classes to return a max boundless for 'coherence' (so they would behave the same in each pane layout), but we discovered that causes the opposite frustration - you constantly set the max value when you don't want something to grow. So, we tried to give reasonable default values, knowing that sometimes you will have to replace them.

Published by: aim on June 23, 2011 20:58

Tags: Java

Similar Questions

  • Page layout can take the scale into consideration?

    What I read and experimentation little that I've done, it seems that the scale (and other transformations) on a node do not affect its layout. For example, if I set scaleX = 2 on a knot and put it in a HBox, the HBox does not give the knot twice as much space as it would otherwise.

    In WPF, there are separate notions of a RenderTransform and LayoutTransform a; for the latter, containers take the transformation into account during installation on the node. Is there something comparable for JFX, or the transformations here are really only for the stuff of animation?

    Use that I have in mind designs display to a fixed size components and then scaling to fit various places I put them. This is different from the automatic growth/shrinkage in that the main components of layout are good, as all would scale proportionally - sizes of fonts, line weights, etc.

    As best as I can tell, if I want to apply a scale transformation to a component and arranged it properly, I would need the component that is currently scaling to lie to his mother on his size, which looks awkward. Are there better approaches?

    Amy Fowler JavaFX 2.0 presentation layout is the only semi-complete treatment of JavaFX concerns of layout on the web and essential viewing for anyone who is developing JavaFX (you will simply understand why certain things happen as they do without him)-online http://www.parleys.com/#st=5&id=2734&sl=46

    The answers to your questions are in two minutes slides 46 and 48 of the presentation.

    The quick answer is that if you want to layout transforms, effects, etc. into account, then wrap the node to be arranged in a group.

    Example of presentation of Amy:

    Rectangle rect = new Rectangle(10, 10, 100, 100);
    rect.setEffect(new DropShadow());
    layoutRegion.getChildren().add(new Group(rect));
    

    Note the node wrapping in a group to get the limits of effect taken into account during the pass of layout.

    The relevant API that provides the information you are looking for is http://docs.oracle.com/javafx/2.0/api/javafx/scene/Node.html#boundsInParentProperty "rectangular boundaries of this node include its transformations."

    Try running the following demos to help understand how the system works https://gist.github.com/1441960 and https://gist.github.com/1442298 limits

    Page layout is the part the more delicate the development of JavaFX IMO, followed by Threading and deployment.

  • JavaFX 2.0 (questions lebel)

    Hi all!
    Sorry for bugging you with this problem, but I'm completely stuck on it :|: I am trying to build a javafx 2.0 background application. 5 minutes in the project and I have no idea how to do to move the button I just create another place on the stage. I give up on it and continue to read the javafx 2.0 tutorial where I fall on the side of the lable. (Here's where it get rough) After research and reflection and deduct a bit, I discovered that I have to use "import javafx.scene.control.Label;" at the beginning of my code that I can use lables. (just to let you know my level) And my questions are: I don't see the text that I put in the label; I don't know how to use an image with this label. (whence this bloody image resident tried to find the folder of the image tag used for 1 hour without result). Here is my code:



    package simple.app;

    Import javafx.application.Application;
    Import javafx.event.ActionEvent;
    Import javafx.event.EventHandler;
    Import javafx.scene.Group;
    Import javafx.scene.Scene;
    Import javafx.scene.control.Label;
    Import javafx.scene.control.Button;
    Import javafx.stage.Stage;
    Import javafx.animation.KeyFrame;
    Import javafx.animation.KeyValue;
    Import javafx.animation.Timeline;
    Import javafx.util.Duration;
    Import javafx.scene.text.Font;
    Import javafx.scene.effect.Reflection;


    SerializableAttribute public class SimpleApp extends Application {}


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

    @Override
    {} public void start (point primaryStage)
    primaryStage.setTitle ("the application");
    Root of group = new Group();
    Scene = new scene (root, 640, 480);
    Button = new Button();
    button.setText ("OK");
    button.setFont (new do ("Tahoma", 24));
    button.setEffect (new Reflection());

    final timeline timeline = new Timeline();
    timeline.setCycleCount (Timeline.INDEFINITE);
    timeline.setAutoReverse (true);
    final KeyValue kv new KeyValue = (button.opacityProperty (), 0);
    last keyframe kf = new KeyFrame (Duration.millis (0), kv);
    timeline.getKeyFrames () .add (kf).
    Timeline.Play ();
    root.getChildren () .add (button);
    Image image = new Image (getClass ().getResourceAsStream("2.jpg"));
    Label label1 = new Label ("Karina", new ImageView (image));
    Label1.setGraphic (new ImageView (image));


    primaryStage.setScene (scene);

    primaryStage.show ();
    }
    }

    The errors I get when running:

    Compiling 1 source file for C:\Users\I3lue\Documents\NetBeansProjects\simple app\build\classes
    C:\Users\I3lue\Documents\NetBeansProjects\simple app\src\simple\app\SimpleApp.java:53: cannot find symbol
    symbol: the class picture
    location: simple.app.SimpleApp of the class
    Image image = new Image (getClass ().getResourceAsStream("2.jpg"));
    C:\Users\I3lue\Documents\NetBeansProjects\simple app\src\simple\app\SimpleApp.java:53: cannot find symbol
    symbol: the class picture
    location: simple.app.SimpleApp of the class
    Image image = new Image (getClass ().getResourceAsStream("2.jpg"));
    C:\Users\I3lue\Documents\NetBeansProjects\simple app\src\simple\app\SimpleApp.java:54: cannot find symbol
    symbol: class ImageView
    location: simple.app.SimpleApp of the class
    Label label1 = new Label ("Karina", new ImageView (image));
    C:\Users\I3lue\Documents\NetBeansProjects\simple app\src\simple\app\SimpleApp.java:55: cannot find symbol
    symbol: class ImageView
    location: simple.app.SimpleApp of the class
    Label1.setGraphic (new ImageView (image));
    C:\Users\I3lue\Documents\NetBeansProjects\simple app\src\simple\app\SimpleApp.java:56: cannot find symbol
    symbol: variable color
    location: simple.app.SimpleApp of the class
    Label1.setTextFill (Color.Web ("#0076 a 3"));
    5 errors
    C:\Users\I3lue\Documents\NetBeansProjects\simple app\nbproject\build-impl.xml:639: the following error occurred during the execution of this line:
    C:\Users\I3lue\Documents\NetBeansProjects\simple app\nbproject\build-impl.xml:314: Compile; See the error output of the compiler for details.
    BUILD FAILED (total time: 1 second)

    And yes I tried to google the location on disk of the label image and I searched for a more complete tutorial explaining everything from absolute ground for me, but I became more confused after reading that I found...

    Hello

    When the validation code in the forum, please wrap it in the {code} tags according to the https://forums.oracle.com/forums/ann.jspa?annID=1622 is easier to read.

    You have some problems with your code, but you're getting there. First of all, you need to 'import' of each class that you use in your code, it's standard Java. The error that you included was because you are missing the following imports:

    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.paint.Color;
    

    If you use a good IDE should highlight those errors for you and help that set you including imports according to the needs. I use [url http://www.jetbrains.com/idea/] IntelliJ IDEA, [url http://www.eclipse.org/downloads/] Eclipse is very popular and very good, and [http://netbeans.org/ url] NetBeans seems to be popular with the JavaFX developers.

    In order to move the button around you can either use a [url http://download.oracle.com/javafx/2.0/layout/jfxpub-layout.htm] layout for that system to position the button compared to other nodes on the screen, or, since you're using a group like the layout, you can set the x, y of simply do the following :

    button.setLayoutX(100);
    button.setLayoutY(100);
    

    The reason why you don't see your label is that currently you create, but you do not actually Add to the scene at all.

    For the button you currently do the following:

    root.getChildren().add(button);
    

    This is what adds your button to the stage and makes it visible. You must do the same for your label:

    root.getChildren().add(label);
    

    Once you do this, you should see your text label and I hope that your image. The way you load your image is correct and it will look 2 '.jpg' in your 'classpath' in the same package as your application (i.e. simple.app). I recommend you put a "/" in front of your name of the image (i.e. use ' / 2.jpg ') then he's looking for in the root of your classpath. There are many good articles on the use of the classpath in Java, is not specific to JavaFX, but Java just in general.

    Note that because you use 'group' that available to your parent, the button and the label will be drawn ontop each other. Experiment with different configurations of [url http://download.oracle.com/javafx/2.0/layout/jfxpub-layout.htm] for alternatives.

    Finally, the code for your animation is close enough, but you have set a duration of 0 milliseconds and set it to repeat forever. Basically your button goes from the visible to the invisible each 0ms, which is pretty useless and at best will give you a flicker of odd look. Try to use something more like 2000 millis (e.g. 2 seconds), which will make your button fade in entrance and exit every 2 seconds. A little more sensitive.

    You can really help you try to group your code a bit and keep clean. Personally, I'd go with something in addition to the following:

    package simple.app;
    
    import javafx.animation.KeyFrame;
    import javafx.animation.KeyValue;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.effect.Reflection;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.paint.Color;
    import javafx.scene.text.Font;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    public class TestApp extends Application
    {
        public static void main(String[] args)
        {
            Application.launch(args);
        }
    
        public void start(Stage primaryStage)
        {
            Group root = new Group();
    
            // create a button and add it to the root
            Button button = new Button();
            button.setText("OK");
            button.setFont(new Font("Tahoma", 24));
            button.setEffect(new Reflection());
            button.setLayoutX(100);
            button.setLayoutY(100);
            root.getChildren().add(button);
    
            // animate the button to fade in and out
            final Timeline timeline = new Timeline();
            timeline.setCycleCount(Timeline.INDEFINITE);
            timeline.setAutoReverse(true);
            final KeyValue kv = new KeyValue(button.opacityProperty(), 0);
            final KeyFrame kf = new KeyFrame(Duration.millis(2000), kv);
            timeline.getKeyFrames().add(kf);
            timeline.play();
    
            // create a label and add it to the root
            Image image = new Image(getClass().getResourceAsStream("/2.jpg"));
            Label label1 = new Label("asdsad", new ImageView(image));
            // label1.setGraphic(new ImageView(image)); <- this line is not needed, the line above is enough
            label1.setTextFill(Color.web("#0076a3"));
            root.getChildren().add(label1);
    
            // show the scene in the stage (i.e. window)
            Scene scene = new Scene(root, 640, 480);
            primaryStage.setScene(scene);
            primaryStage.setTitle("The App");
            primaryStage.show();
        }
    }
    

    Hope that helps,
    zonski

    Did you find this answer useful? If so, please mark it as 'Correct' or 'useful '.

  • JFX fxml: cellfactory customized for lifted CheckBoxTableCell of exception

    Hello

    I am creating a plant cell customized for inserting a CheckBoxTableCell in a TableView by fxml. But its gives me an exception as described below.
    The cell factory class, I created and the fxml is also put below

    If anyone can help?

    SEVERE: javafx.scene.control.Control property impl_processCSS - fx-skin has not been defined in the CSS for the TableRow [id = null, styleClass = cells indexed table row-cells]
    SEVERE: javafx.scene.control.Control loadSkinClass could not load the skin ' string [bean: TableRow [id = null, styleClass = cells indexed table row-cells], name: skinClassName, value: com.sun.javafx.scene.control.skin.TableRowSkin] "for the TableRow control [id = null, styleClass = cells indexed table row-cells]
    java.lang.ClassCastException: javafx.scene.control.cell.CheckBoxTableCell$ 1 cannot be cast to javafx.scene.control.TableCell
    at com.sun.javafx.scene.control.skin.TableRowSkin.recreateCells(TableRowSkin.java:224)
    to com.sun.javafx.scene.control.skin.TableRowSkin. < init > (TableRowSkin.java:87)
    at sun.reflect.GeneratedConstructorAccessor1.newInstance (unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    at javafx.scene.control.Control.loadSkinClass(Control.java:992)
    at javafx.scene.control.Control.access$ 500 (Control.java:71)
    to javafx.scene.control.Control$ 12.invalidated(Control.java:920)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:127)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:161)
    at com.sun.javafx.css.StyleableStringProperty.set(StyleableStringProperty.java:71)
    to javafx.scene.control.Control$ 12.set(Control.java:912)
    at com.sun.javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:59)
    at com.sun.javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:31)
    at com.sun.javafx.css.StyleableProperty.set(StyleableProperty.java:70)
    at com.sun.javafx.css.StyleHelper.transitionToState(StyleHelper.java:902)
    at javafx.scene.Node.impl_processCSS(Node.java:7415)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1146)
    at javafx.scene.control.Control.impl_processCSS(Control.java:1102)
    at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1598)
    at com.sun.javafx.scene.control.skin.VirtualFlow.addTrailingCells(VirtualFlow.java:1114)
    at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1007)
    at javafx.scene.Parent.layout(Parent.java:1018)
    at javafx.scene.Parent.layout(Parent.java:1028)
    at javafx.scene.Parent.layout(Parent.java:1028)
    at javafx.scene.Parent.layout(Parent.java:1028)
    at javafx.scene.Scene.layoutDirtyRoots(Scene.java:513)
    at javafx.scene.Scene.doLayoutPass(Scene.java:484)
    at javafx.scene.Scene.preferredSize(Scene.java:1485)
    at javafx.scene.Scene.impl_preferredSize(Scene.java:1512)
    to javafx.stage.Window$ 10.invalidated(Window.java:719)
    at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:127)
    at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:161)
    at javafx.stage.Window.setShowing(Window.java:782)
    at javafx.stage.Window.show(Window.java:797)
    at javafx.stage.Stage.show(Stage.java:229)
    to fxmltableview. FXMLTableView.start (FXMLTableView.java:49)
    to com.sun.javafx.application.LauncherImpl$ 5.run(LauncherImpl.java:319)
    to com.sun.javafx.application.PlatformImpl$ 5.run(PlatformImpl.java:206)
    to com.sun.javafx.application.PlatformImpl$ 4.run(PlatformImpl.java:173)
    at com.sun.glass.ui.win.WinApplication._runLoop (Native Method)
    in com.sun.glass.ui.win.WinApplication.access$ 100 (WinApplication.java:29)
    to com.sun.glass.ui.win.WinApplication$ $3 1.run(WinApplication.java:73)
    at java.lang.Thread.run(Thread.java:722)

    Cell factory

    /**
    *
    */
    package view.components;

    Import javafx.scene.control.TableCell;
    Import javafx.scene.control.TableColumn;
    Import javafx.scene.control.cell.CheckBoxTableCell;
    Import javafx.util.Callback;

    public class CheckBoxCellFactory < S, T >
    implements the callback < < S, Boolean >, TableColumn reminder < < S, Boolean >, TableColumn TableCell < S, Boolean > > > {}

    call the public recall < < S, Boolean >, TableColumn TableCell < S, Boolean > > (TableColumn < S, Boolean > paramAnonymousTableColumn) {}
    Return CheckBoxTableCell.forTableColumn (paramAnonymousTableColumn);
    }


    }



    FXML


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

    <? import java.lang. *? >
    <? import java.net. *? >
    <? import java.util? >
    <? import javafx.util. *? >
    <? import javafx.collections. *? >
    <? import javafx.geometry. *? >
    <? import javafx.scene.control. *? >
    <? import javafx.scene.control.cell. *? >
    <? import javafx.scene.layout. *? >
    <? import javafx.scene.paint. *? >
    <? import javafx.scene.text. *? >
    <? Import model.*? >
    <? import the model. DummyTableValues? >
    <? scenebuilder classpath element... / bin? >
    <? import view.components.CheckBoxCellFactory? >

    < ScrollPane id = "scrollPane" fx:id = "scrollPane" minHeight = "275.0" minWidth = '771.0' prefHeight = '275.0' prefWidth = "771.0" xmlns:fx = "http://javafx.com/fxml" >
    < content >
    < TableView id = 'configTable' fx:id = 'configTable"minHeight ="1000.0"minWidth ="1000.0"prefHeight ="1000.0"prefWidth ="1000.0">
    < columns >
    < TableColumn id = "col1" fx:id = "col1" prefWidth = "75.0" text = "Change/Remove" >
    < cellValueFactory >
    < PropertyValueFactory property = 'value3' / >
    < / cellValueFactory >
    < cellFactory >
    < CheckBoxCellFactory > < / CheckBoxCellFactory >
    < / cellFactory >
    < / TableColumn >
    < prefWidth TableColumn = "75.0" text = "Item number" >
    < cellValueFactory >
    < Property PropertyValueFactory = "Value1" / >
    < / cellValueFactory >
    < / TableColumn >
    < prefWidth TableColumn = "75.0" text = "Item Desc" >
    < cellValueFactory >
    < PropertyValueFactory property = "Value2" / >
    < / cellValueFactory >
    < / TableColumn >
    < / columns >
    elements <>
    < FXCollections fx:factory = "observableArrayList" >
    < DummyTableValues value1 = value2 "Jacob1" = "Smith1" / >
    < DummyTableValues value1 = value2 "Jacob2" = "Smith2" / >
    < DummyTableValues value1 = value2 "Jacob3" = "Smith3" / >
    < / FXCollections >
    < / object >
    < / TableView >
    < / content >
    < / ScrollPane >



    package model;

    Import javafx.beans.property.SimpleBooleanProperty;
    Import javafx.beans.property.SimpleStringProperty;


    public class DummyTableValues {}
    private SimpleStringProperty value1 = new SimpleStringProperty ("initial1");
    private SimpleStringProperty value2 = new SimpleStringProperty ("initial2");
    private SimpleBooleanProperty value3 = new SimpleBooleanProperty (false);
    public void setValue1 (String value1) {}
    This.value1.set (value1);
    }

    public void setValue2 (String value2) {}
    This.Value2.Set (value2);
    }

    public String getValue1() {}
    Return value1.get ();
    }

    public String getValue2() {}
    Return value2.get ();
    }

    public boolean isValue3() {}
    Return value3.getValue ();
    }

    public void setValue3 (boolean value3) {}
    This.value3.SetValue (value3);
    }

    }

    My old code will not work: the fx:factory can be used to provide a factory No.-arg method.

    The only way I can see to make it work is to do something like

    package view.components;
    
    import javafx.scene.control.TableCell;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.cell.CheckBoxTableCell;
    import javafx.util.Callback;
    
    public class CheckBoxCellFactory
    implements Callback, Callback, TableCell>> {
    
      public Callback, TableCell> call(TableColumn paramAnonymousTableColumn) {
        return CheckBoxTableCell.forTableColumn(paramAnonymousTableColumn).call(paramAnonymousTableColumn);
      }
    }
    

    It called CheckBoxTableCell.forTableColumn (...) whenever he needs a new table cell. If you did this in Java, rather than FXML, you'd

    col1.setCellFactory(CheckBoxTableCell.forTableColumn(col1));
    

    who creates the cell factory only once. I don't think it's a problem, but in this case, you could do something more sophisticated in your CheckBoxCellFactory. (Perhaps to set a property of 'column', that you can set from the FXML and then set a private reminder that is bound to the column property, assigning the result of CheckBoxTableCell.forTableColumn (...) when the column property.)

  • Dinamic Panel

    Hi guys I am Diego. I need help, look, I am applying and I know how to do a dinamic Panel. I think about how to do a rezisable Panel.
    Well I hope someone help me.

    1 use the built-in layout components that are appropriate for your application. All these aspects of page layout can be resized.
    2. do not use groups and when you create a scene like those who are not resizable.
    3. do not set a size and width of the stage and it will automatically resize itself.
    4. If you need the user to be able to scroll the contents of a component autour, wrap it in a ScrollPane.
    5. If you need to express lines for the size of the pane, use the Max/setMin/PrefWidth functions.

    Read this: http://docs.oracle.com/javafx/2.0/layout/builtin_layouts.htm#CHDGHCDG

  • TilePane in fxml

    Hi all

    I want to reproduce in the fxml a TilePane showed code in this tutorial:

    http://docs.Oracle.com/JavaFX/2.0/layout/builtin_layouts.htm
    -> Example 1-7 creates a horizontal mosaic component that produced the same layout, shown in Figure 1-10.

    In fact, my markup is as follows:
    <TilePane hgap="4" vgap="4" prefColumns="2" >
        <children>
            <Button text="Search">
                <graphic>
                    <ImageView>
                        <image>
                            <Image url="@Search.png"/>
                        </image>
                    </ImageView>
                </graphic>
            </Button> 
            <Button text="Tools">
                <graphic>
                    <ImageView>
                        <image>
                            <Image url="@Tools.png"/>
                        </image>
                    </ImageView>
                </graphic>
            </Button> 
        </children>
    </TilePane>
    I get the error message is:

    Unable to resolve type for ImageView

    The structure of button above works for me on the toolbar (set in fxml as FlowPane). Comparing with the code in the tutorial (example 1-7) I don't see the reason for the error to come. I have not really buttons, I need however manage onClicked event of each tile. I tried to replace the button with only the ImageView, but show the same error.

    have you added import for javafx.scene.image.ImageView?

  • NullPointerException in TableCell.java

    I get the error below on a regular basis, but I can't quite identify where in my own code, the problem is, as it seems to come from the rendering thread. This is sort of related to the clearing and then repopulate a TableView.

    If it is an unknown issue, I'll try to create a reproducible simple example.

    GRAVE: javafx.scene.control.Control loadSkinClass cannot load skin "com.sun.javafx.scene.control.skin.TableRowSkin" for the TableRow control [id = null, styleClass = cells indexed table row-cells]
    java.lang.NullPointerException
    at javafx.scene.control.TableCell.updateItem(TableCell.java:475)
    to javafx.scene.control.TableCell.access$ 000 (TableCell.java:44)
    to javafx.scene.control.TableCell$ 1.invalidated(TableCell.java:76)
    to com.sun.javafx.binding.ExpressionHelper$ SingleInvalidation.fireValueChangedEvent (ExpressionHelper.java:140)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:64)
    to javafx.beans.property.ReadOnlyIntegerWrapper$ ReadOnlyPropertyImpl.fireValueChangedEvent (ReadOnlyIntegerWrapper.java:154)
    at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:120)
    at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:89)
    at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:122)
    at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:91)
    at com.sun.javafx.scene.control.skin.TableRowSkin.updateCells(TableRowSkin.java:224)
    to com.sun.javafx.scene.control.skin.TableRowSkin. < init > (TableRowSkin.java:67)
    at sun.reflect.GeneratedConstructorAccessor5.newInstance (unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at javafx.scene.control.Control.loadSkinClass(Control.java:896)
    at javafx.scene.control.Control.impl_cssSet(Control.java:974)
    at javafx.scene.control.Labeled.impl_cssSet(Labeled.java:604)
    at javafx.scene.Node.impl_cssSet(Node.java:6320)
    at com.sun.javafx.css.StyleHelper.transitionToState(StyleHelper.java:711)
    at javafx.scene.Node.impl_processCSS(Node.java:6194)
    at javafx.scene.Parent.impl_processCSS(Parent.java:965)
    at javafx.scene.control.Control.impl_processCSS(Control.java:1002)
    at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1367)
    at com.sun.javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1270)
    at com.sun.javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1293)
    to com.sun.javafx.scene.control.skin.VirtualFlow$ 3.run(VirtualFlow.java:442)
    to com.sun.javafx.scene.control.skin.VirtualFlow$ 3.run(VirtualFlow.java:440)
    at com.sun.javafx.scene.control.skin.PositionMapper.computeViewportOffset(PositionMapper.java:122)
    at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:827)
    at javafx.scene.Parent.layout(Parent.java:900)
    at javafx.scene.Scene.layoutDirtyRoots(Scene.java:451)
    at javafx.scene.Scene.doLayoutPass(Scene.java:424)
    to javafx.scene.Scene.access$ 2800 (Scene.java:132)
    to javafx.scene.Scene$ ScenePulseListener.pulse (Scene.java:1750)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:292)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:398)
    to com.sun.javafx.tk.quantum.QuantumToolkit$ 10.run(QuantumToolkit.java:330)
    at com.sun.glass.ui.win.WinApplication._runLoop (Native Method)
    in com.sun.glass.ui.win.WinApplication.access$ 100 (WinApplication.java:29)
    to com.sun.glass.ui.win.WinApplication$ $2 1.run(WinApplication.java:62)
    at java.lang.Thread.run(Thread.java:662)

    SEVERE: javafx.scene.control.Control property impl_processCSS - fx-skin has not been defined in the CSS for the TableRow [id = null, styleClass = cells indexed table row-cells]
    GRAVE: javafx.scene.control.Control loadSkinClass cannot load skin "com.sun.javafx.scene.control.skin.TableRowSkin" for the TableRow control [id = null, styleClass = cells indexed table row-cells]
    java.lang.NullPointerException
    at javafx.scene.control.TableCell.updateItem(TableCell.java:475)
    to javafx.scene.control.TableCell.access$ 000 (TableCell.java:44)
    to javafx.scene.control.TableCell$ 1.invalidated(TableCell.java:76)
    to com.sun.javafx.binding.ExpressionHelper$ SingleInvalidation.fireValueChangedEvent (ExpressionHelper.java:140)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:64)
    to javafx.beans.property.ReadOnlyIntegerWrapper$ ReadOnlyPropertyImpl.fireValueChangedEvent (ReadOnlyIntegerWrapper.java:154)
    at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:120)
    at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:89)
    at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:122)
    at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:91)
    at com.sun.javafx.scene.control.skin.TableRowSkin.updateCells(TableRowSkin.java:224)
    to com.sun.javafx.scene.control.skin.TableRowSkin. < init > (TableRowSkin.java:67)
    at sun.reflect.GeneratedConstructorAccessor5.newInstance (unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at javafx.scene.control.Control.loadSkinClass(Control.java:896)
    at javafx.scene.control.Control.impl_cssSet(Control.java:974)
    at javafx.scene.control.Labeled.impl_cssSet(Labeled.java:604)
    at javafx.scene.Node.impl_cssSet(Node.java:6320)
    at com.sun.javafx.css.StyleHelper.transitionToState(StyleHelper.java:711)
    at javafx.scene.Node.impl_processCSS(Node.java:6194)
    at javafx.scene.Parent.impl_processCSS(Parent.java:965)
    at javafx.scene.control.Control.impl_processCSS(Control.java:1002)
    at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1367)
    at com.sun.javafx.scene.control.skin.VirtualFlow.addLeadingCells(VirtualFlow.java:875)
    at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:831)
    at javafx.scene.Parent.layout(Parent.java:900)
    at javafx.scene.Scene.layoutDirtyRoots(Scene.java:451)
    at javafx.scene.Scene.doLayoutPass(Scene.java:424)
    to javafx.scene.Scene.access$ 2800 (Scene.java:132)
    to javafx.scene.Scene$ ScenePulseListener.pulse (Scene.java:1750)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:292)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:398)
    to com.sun.javafx.tk.quantum.QuantumToolkit$ 10.run(QuantumToolkit.java:330)
    at com.sun.glass.ui.win.WinApplication._runLoop (Native Method)
    in com.sun.glass.ui.win.WinApplication.access$ 100 (WinApplication.java:29)
    to com.sun.glass.ui.win.WinApplication$ $2 1.run(WinApplication.java:62)
    at java.lang.Thread.run(Thread.java:662)

    So, I have to get my accusations against CSS (in this case). Sorry CSS.

    The problem is how you work with your ObservableLists. The intention of design with these is that you must create the observable list only once and then just add/remove for her. That's what makes observable - if you keep newing/remove you lose that aspect and can also break things (as you saw).

    As most of the UI components, the TableView actually creates its observable 'elements' list itself and expects that this list is ever changing and always exist. Only its content can change. You are passing in a new list and then nothing for her and is to confuse the TableView (well actually looks like is to confuse the CSS rendering engine, resulting in ever more misleading stack trace). What you need to do is just 'get' the list items and who handle instead.

    Try this piece of code instead of the fuse, you have:

    groupsView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener>() {
        public void changed(ObservableValue> ov, List oldGroup, List newGroup) {
            personsView.getItems().clear();
            if (newGroup != null) {
                personsView.getItems().addAll(newGroup);
            }
        }
    });
    

    There may be other instances in your code (I don't look through it all in detail), but this correction should be your avalanche go :)

    Title of general comment also, if you actually create your own observable collections use the FXCollections support, easier methods.

  • Combination of JavaFX FXML layout

    Hi everyone)) recently I started using javafx and I wonder if there a way to combine the FXML provisions without Java code, like insert smaller layout in larger? (Thanks in advance))

    Is

    
    

    what you're looking for? Documentation here.

  • Custom layout of JavaFX nodes

    I'm developing an application for which it is necessary to nodes available in addition to the other (or on top of the other etc..). However, this provision is only an IPO and the user is able to move these nodes arbitrarily. How does correctly in JavaFX? I'll explain my problem with a simplified example:

    Guess I have 2 rectangles and want to place rect2 right of rect1.

    // create first rectangle at position x= 5, y=5 
    rect1
    = rectangle(5,5);
    // create second rectangle to the right of rect1
    rect2
    = rectangle(5+rect1.width(), 5);

    In this scenario JavaFX has not yet determined the width of rect1, and there will be zero. Intuitively, I would make a call that allows JavaFX rect1 and thus determine its width and then add rect2. See the following example:

    // create first rectangle at position x= 5, y=5 
    rect1
    = rectangle(5,5);
    // let JavaFX draw rect1 (width will be calculated and set)
    draw
    ();
    // create second rectangle to the right of rect1
    rect2
    = rectangle(5+rect1.width(), 5);

    Unfortunately, I have not found a method that does what I want. My current solution appealed to the Platform.runLater (), but this does not work properly all the time. If my interpretation of the links is correct, the links also are not appropriate for this problem. I want only to provision initially nodes, so I have to remove the link after the initial layout (or do rect2 would move if rect1 is moved).

    Thanks in advance for any help.

    Custom presentations are generally made subclassing region, the substitution of layoutChildren() and calculations of page layout based on the prefWidth and the prefHeight of the child nodes.  Best place to understand this for example is by examining the source code of JavaFX , as I've never seen a tutorial on the subject.

    A round, you can use that may or may not be suitable for you, is to use the layout panels for the default page layout, then use translate the properties to allow the user to the default layout components, the translation in this way you can avoid the creation of a custom layout component.

    Another way to do is to use a base pane as the layout container that is not automatic on her children, add children to the pane in the constructor of the component.  Layout() and applyCss() use children to measure children if necessary in order to determine the appropriate size.

  • Write the component layout customized JavaFX 2.0

    Hello

    How to write custom layout pane? What important methods of the parent class of component are?
    Are there examples in Internet?

    Thank you


    Makrem

    Hello

    Here is simple example how to do it. At the end of the post are a few links that should help you.

    package jfx2betatest;
    
    import javafx.collections.ObservableList;
    import javafx.geometry.HPos;
    import javafx.geometry.VPos;
    import javafx.scene.Node;
    import javafx.scene.layout.Region;
    
    public class DiagonalPane extends Region {
    
        // to be simple
        // u can add some methods to add nodes remove nodes etc
        @Override
        public ObservableList getChildren() {
            return super.getChildren();
        }
    
        @Override
        protected double computePrefWidth(double height) {
            // here calculate prefWidth
            // include padding
            return super.computePrefWidth(height);
        }
    
        @Override
        protected double computePrefHeight(double width) {
            // here calculate prefHeight
            // include padding and other stuff
            return super.computePrefHeight(width);
        }
    
        @Override
        protected void layoutChildren() {
            int i = 0;
            for (Node node : getChildren()) {
                layoutInArea(node, i, i, getWidth(), getHeight(), 0.0d, HPos.LEFT, VPos.TOP);
                i += 40;
            }
        }
    }
    

    Main class:

    package jfx2betatest;
    
    import javafx.application.Application;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Rectangle;
    import javafx.stage.Stage;
    
    public class TestDiagonalPane extends Application {
    
        private Scene scene;
        private Group root;
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            Application.launch(TestDiagonalPane.class, args);
        }
    
        @Override
        public void start(Stage primaryStage) throws Exception {
    
            root = new Group();
    
            DiagonalPane dp = new DiagonalPane();
            for (int i = 0; i < 10; i++) {
                Rectangle rect = new Rectangle(50, 50, Color.BLUE);
                rect.setStroke(Color.RED);
                rect.setStrokeWidth(2);
                dp.getChildren().add(rect);
            }
    
            root.getChildren().add(dp);
            scene = new Scene(root, 500, 500);
            primaryStage.setScene(scene);
            primaryStage.setTitle("DiagonalPane Test");
            primaryStage.centerOnScreen();
            primaryStage.setVisible(true);
        }
    }
    

    There are also positionInArea methods in the class of the region.
    Maybe someone will after more complex example.

    Links that may help you:

    http://download.Oracle.com/JavaFX/1.3/tutorials/flowers/layoutContainers.html
    http://download.Oracle.com/JavaFX/2.0/API/JavaFX/scene/layout/region.html-> see more implement custom layout section.

    It will be useful.

  • Transparent edges on the buttons? JavaFX (CSS)

    I would be grateful if someone could share how to get rid of the button edges, or at least they are transparent in .css (using JavaFX). Im trying to recreate the Windows 10 calculator

    The following code does not work

    button {}

    -fx-background-RADIUS: 0;

    -fx-border-color: transparent;

    }


    Thank you!

    You should look at modena.css, you can find it inside the jfxrt.jar of your JRE installation.

    Import javafx.application.Application;
    Import javafx.geometry.Insets;
    Import javafx.scene.Scene;
    Import javafx.scene.control.Button;
    Import javafx.scene.layout.StackPane;
    Import javafx.stage.Stage;

    SerializableAttribute public class boutonAfficher extends Application {}

    @Override
    public void start (final stage) bird Exception {}

    Button = new Button ("Button");
    Presentation of StackPane = new StackPane (button);
    layout.setPadding (new Insets (10));
    button.setStyle)

    "shadow - fx - highlight-color: transparent;" + / / If you do not want evidence of 3d effect.
    "- fx - outside-border: transparent;" + / / If you do not want a border of the button.
    "inner - fx - border: transparent;" + / / If you do not want a border of the button.
    "focus - fx - color: transparent;" + / / If you do not want a focus ring.
    "- fx - faint-focus-color: transparent;" + / / If you do not want a focus ring.
    "base - fx -: palegreen;" + / / If you want a shady button gradient which lightens the overview and go on armament.
    "body - fx - color: palegreen;" + / / instead of - fx-Basic, if you want a flat shaded button which do not alleviate the hover and pounce on armament.
    "police - fx - size: 80px;"
    );

    stage.setScene (new Scene (layout));
    internship. Show();
    }

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

    Launch (args);
    }

    }

  • The ball in javafx graphics

    I'm working on a project where I need to use a graphic of the ball. Are there any card ball already developed?  Can you please share whatever it is? Or at least the idea of creating graphics custom, so that I can create my own?
    Thanks in advance.

    Bullet_Graph_Example.svg.png

    Here's a quick and dirty implementation. It has not been completely tested and there are probably a lot of things to improve:

    package test;
    
    import java.util.stream.IntStream;
    import javafx.beans.InvalidationListener;
    import javafx.beans.property.DoubleProperty;
    import javafx.beans.property.ReadOnlyListProperty;
    import javafx.beans.property.ReadOnlyListWrapper;
    import javafx.beans.property.ReadOnlyObjectProperty;
    import javafx.beans.property.ReadOnlyObjectWrapper;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.beans.property.StringProperty;
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener.Change;
    import javafx.collections.ObservableList;
    import javafx.css.PseudoClass;
    import javafx.geometry.HPos;
    import javafx.geometry.Insets;
    import javafx.geometry.Orientation;
    import javafx.geometry.Side;
    import javafx.geometry.VPos;
    import javafx.scene.Group;
    import javafx.scene.chart.NumberAxis;
    import javafx.scene.chart.ValueAxis;
    import javafx.scene.control.Tooltip;
    import javafx.scene.layout.Region;
    import javafx.scene.text.Text;
    import javafx.scene.text.TextFlow;
    
    /**
    * Quick and dirty implementation of a bullet chart.
    * @author Fabrice Bouyé
    */
    public class BulletGraph extends Region {
    
        private static final PseudoClass VERTICAL_PSEUDO_CLASS = PseudoClass.getPseudoClass("vertical"); // NOI18N.
        private static final String USER_AGENT_STYLE_SHEET = "BulletChart.css"; // NOI18N.
    
        private final NumberAxis axis = new NumberAxis(0d, 100d, 25d);
        private final Region performanceMeasureMarker = new Region();
        private final Region comparativeMeasureMarker = new Region();
        private final Group quantitativeScaleGroup = new Group();
        protected final Region plotArea = new Region() {
            {
                getChildren().add(quantitativeScaleGroup);
                getChildren().add(performanceMeasureMarker);
                getChildren().add(comparativeMeasureMarker);
            }
    
            @Override
            protected void layoutChildren() {
                layoutPlotChildren();
            }
        };
        private final Text titleLabel = new Text();
        private final Text descriptionLabel = new Text();
        private final TextFlow titleFlow = new TextFlow(titleLabel, new Text("\n"), descriptionLabel); // NOI18N.
        private final Tooltip performanceMeasureTip = new Tooltip();
        private final Tooltip comparativeMeasureTip = new Tooltip();
    
        /**
        * Creates a new instance.
        */
        public BulletGraph() {
            super();
            setId("bulletChart"); // NOI18N.
            getStyleClass().add("bullet-chart"); // NOI18N.
            //
            setMinSize(USE_PREF_SIZE, USE_PREF_SIZE);
            //
            axis.setSide(Side.BOTTOM);
            getChildren().add(axis);
            //
            performanceMeasureMarker.getStyleClass().add("performance-measure-marker"); // NOI18N.
            performanceMeasureTip.textProperty().bind(performanceMeasureProperty().asString());
            Tooltip.install(performanceMeasureMarker, performanceMeasureTip);
            //
            comparativeMeasureMarker.getStyleClass().add("comparative-measure-marker"); // NOI18N.
            comparativeMeasureTip.textProperty().bind(comparativeMeasureProperty().asString());
            Tooltip.install(comparativeMeasureMarker, comparativeMeasureTip);
            //
            plotArea.getStyleClass().add("plot-area"); // NOI18N.
            getChildren().add(plotArea);
            //
            getChildren().add(titleFlow);
            titleFlow.getStyleClass().add("title-flow"); // NOI18N.
            titleLabel.textProperty().bind(titleProperty());
            titleLabel.getStyleClass().add("title"); // NOI18N.
            descriptionLabel.textProperty().bind(descriptionProperty());
            descriptionLabel.getStyleClass().add("description"); // NOI18N.
            //
            axis.lowerBoundProperty().addListener(layoutRequestListener);
            axis.upperBoundProperty().addListener(layoutRequestListener);
            comparativeMeasureProperty().addListener(layoutRequestListener);
            performanceMeasureProperty().addListener(layoutRequestListener);
            orientationProperty().addListener(layoutRequestListener);
            titleProperty().addListener(layoutRequestListener);
            descriptionProperty().addListener(layoutRequestListener);
            titleAxisGapProperty().addListener(layoutRequestListener);
            getQuantitativeScale().addListener((Change change) -> {
                resetQuantitativeShapes();
                prepareForLayout();
            });
            //
            resetQuantitativeShapes();
            prepareForLayout();
        }
    
        @Override
        public String getUserAgentStylesheet() {
            return getClass().getResource(USER_AGENT_STYLE_SHEET).toExternalForm();
        }
    
        /**
        * Called when values are invalidated.
        * 
    Call for a relayout. */ private final InvalidationListener layoutRequestListener = observable -> prepareForLayout(); private void resetQuantitativeShapes() { // Clear old shapes. quantitativeScaleGroup.getChildren().clear(); // Create new ones. IntStream.range(0, quantitativeScale.size()) .forEach(index -> { Region region = new Region(); final String style = String.format("quantitative-scale%d", index + 1); // NOI18N. region.getStyleClass().add(style); quantitativeScaleGroup.getChildren().add(region); }); } private void prepareForLayout() { final Orientation orientation = getOrientation(); final boolean isVertical = orientation == Orientation.VERTICAL; pseudoClassStateChanged(VERTICAL_PSEUDO_CLASS, isVertical); axis.setSide(isVertical ? Side.LEFT : Side.BOTTOM); if (!maxWidthProperty().isBound()) { setMaxWidth(isVertical ? USE_PREF_SIZE : Double.MAX_VALUE); } if (!maxHeightProperty().isBound()) { setMaxHeight(isVertical ? Double.MAX_VALUE : USE_PREF_SIZE); } requestLayout(); } @Override protected void layoutChildren() { super.layoutChildren(); final double width = getWidth(); final double height = getHeight(); final Insets insets = getInsets(); final double areaX = insets.getLeft(); final double areaY = insets.getTop(); final double areaW = Math.max(0, width - (insets.getLeft() + insets.getRight())); final double areaH = Math.max(0, height - (insets.getTop() + insets.getBottom())); layoutChartChildren(areaX, areaY, areaW, areaH); } /** * Layout chart in given area. * @param areaX Area's X coordinate. * @param areaY Area's Y coordinate. * @param areaW Area's width. * @param areaH Area's height. */ protected void layoutChartChildren(double areaX, double areaY, double areaW, double areaH) { final Orientation orientation = getOrientation(); final double titleAxisGap = Math.max(0, getTitleAxisGap()); switch (orientation) { case VERTICAL: { final double titleW = Math.min(areaW, titleFlow.getWidth()); final double titleH = titleFlow.prefHeight(titleW); final double titleY = areaY; final double axisX = areaX; final double axisY = titleY + titleH + titleAxisGap; final double axisW = axis.getWidth(); final double axisH = areaH - axisY; layoutInArea(axis, axisX, axisY, axisW, axisH, 0, HPos.LEFT, VPos.TOP); final double plotChildrenX = axisX + axisW; final double plotChildrenY = axisY; final double plotChildrenW = areaW - axisW; final double plotChildrenH = axisH; layoutInArea(plotArea, plotChildrenX, plotChildrenY, plotChildrenW, plotChildrenH, 0, HPos.LEFT, VPos.TOP); final double titleX = plotChildrenX + (plotChildrenW - titleW) / 2; layoutInArea(titleFlow, titleX, titleY, titleW, titleH, 0, HPos.LEFT, VPos.TOP); } break; case HORIZONTAL: default: { final double titleW = Math.min(areaW / 2, titleFlow.getWidth()); final double titleH = titleFlow.prefHeight(titleW); final double titleX = areaX; final double titleY = areaY + (areaH - titleH) / 2; layoutInArea(titleFlow, titleX, titleY, titleW, titleH, 0, HPos.LEFT, VPos.TOP); final double axisX = titleX + titleW + titleAxisGap; final double axisW = areaW - axisX; final double axisH = axis.getHeight(); final double axisY = areaY + areaH - axisH; layoutInArea(axis, axisX, axisY, axisW, axisH, 0, HPos.LEFT, VPos.TOP); final double plotChildrenX = axisX; final double plotChildrenY = areaY; final double plotChildrenW = axisW; final double plotChildrenH = areaH - axisH; layoutInArea(plotArea, plotChildrenX, plotChildrenY, plotChildrenW, plotChildrenH, 0, HPos.LEFT, VPos.TOP); } } layoutPlotChildren(); } /** * Layout plot children in plot area. */ protected void layoutPlotChildren() { final Orientation orientation = getOrientation(); final double width = plotArea.getWidth(); final double height = plotArea.getHeight(); final double lowerBound = axis.getLowerBound(); final double upperBound = axis.getUpperBound(); final double performanceMeasure = getPerformanceMeasure(); final double comparativeMeasure = getComparativeMeasure(); switch (orientation) { case VERTICAL: { IntStream.range(0, quantitativeScale.size()) .forEach(index -> { final Region region = (Region) quantitativeScaleGroup.getChildren().get(index); double stop = quantitativeScale.get(index); double previousStop = (index == 0) ? 0 : quantitativeScale.get(index - 1); double w = width; double h = height * (stop - previousStop); double x = 0; double y = height - height * stop; region.relocate(x, y); region.setMinSize(w, h); // layoutInArea(region, x, y, w, h, 0, HPos.LEFT, VPos.TOP); }); double performanceW = performanceMeasureMarker.getWidth(); double performanceH = height * (performanceMeasure - lowerBound) / (upperBound - lowerBound); double performanceX = (width - performanceW) / 2; double performanceY = height - performanceH; layoutInArea(performanceMeasureMarker, performanceX, performanceY, performanceW, performanceH, 0, HPos.LEFT, VPos.TOP); double comparativeW = comparativeMeasureMarker.getWidth(); double comparativeH = comparativeMeasureMarker.getHeight(); double comparativeX = (width - comparativeW) / 2; double comparativeY = height - height * (comparativeMeasure - lowerBound) / (upperBound - lowerBound) - comparativeH / 2; layoutInArea(comparativeMeasureMarker, comparativeX, comparativeY, comparativeW, comparativeH, 0, HPos.LEFT, VPos.TOP); } break; case HORIZONTAL: default: { IntStream.range(0, quantitativeScale.size()) .forEach(index -> { final Region region = (Region) quantitativeScaleGroup.getChildren().get(index); double stop = quantitativeScale.get(index); double previousStop = (index == 0) ? 0 : quantitativeScale.get(index - 1); double w = width * (stop - previousStop); double h = height; double x = width * previousStop; double y = 0; region.relocate(x, y); region.setMinSize(w, h); // layoutInArea(region, x, y, w, h, 0, HPos.LEFT, VPos.TOP); }); double performanceW = width * (performanceMeasure - lowerBound) / (upperBound - lowerBound); double performanceH = performanceMeasureMarker.getHeight(); double performanceX = 0; double performanceY = (height - performanceH) / 2; layoutInArea(performanceMeasureMarker, performanceX, performanceY, performanceW, performanceH, 0, HPos.LEFT, VPos.TOP); double comparativeW = comparativeMeasureMarker.getWidth(); double comparativeH = comparativeMeasureMarker.getHeight(); double comparativeX = width * (comparativeMeasure - lowerBound) / (upperBound - lowerBound) - comparativeW / 2; double comparativeY = (height - comparativeH) / 2; layoutInArea(comparativeMeasureMarker, comparativeX, comparativeY, comparativeW, comparativeH, 0, HPos.LEFT, VPos.TOP); } } } public ValueAxis getAxis() { return axis; } private final DoubleProperty comparativeMeasure = new SimpleDoubleProperty(this, "comparativeMeasure", 0); // NOI18N. public final double getComparativeMeasure() { return comparativeMeasure.get(); } public final void setComparativeMeasure(double value) { comparativeMeasure.set(value); } public final DoubleProperty comparativeMeasureProperty() { return comparativeMeasure; } private final DoubleProperty performanceMeasure = new SimpleDoubleProperty(this, "performanceMeasure", 0); // NOI18N. public final double getPerformanceMeasure() { return performanceMeasure.get(); } public final void setPerformanceMeasure(double value) { performanceMeasure.set(value); } public final DoubleProperty performanceMeasureProperty() { return performanceMeasure; } private final ReadOnlyObjectWrapper orientation = new ReadOnlyObjectWrapper<>(this, "orientation", Orientation.HORIZONTAL); // NOI18N. public final Orientation getOrientation() { return orientation.get(); } public final void setOrientation(Orientation value) { Orientation v = (value == null) ? Orientation.HORIZONTAL : value; orientation.set(v); } public final ReadOnlyObjectProperty orientationProperty() { return orientation.getReadOnlyProperty(); } private final StringProperty title = new SimpleStringProperty(this, "title", null); // NOI18N. public final String getTitle() { return title.get(); } public final void setTitle(String value) { title.set(value); } public final StringProperty titleProperty() { return title; } private final StringProperty description = new SimpleStringProperty(this, "description", null); // NOI18N. public final String getDescription() { return description.get(); } public final void setDescription(String value) { description.set(value); } public final StringProperty descriptionProperty() { return description; } private final DoubleProperty titleAxisGap = new SimpleDoubleProperty(this, "titleAxisGap", 6); // NOI18N. public final double getTitleAxisGap() { return titleAxisGap.get(); } public final void setTitleAxisGap(double value) { titleAxisGap.set(value); } public final DoubleProperty titleAxisGapProperty() { return titleAxisGap; } private final ReadOnlyListWrapper quantitativeScale = new ReadOnlyListWrapper<>(this, "quantitativeScale", FXCollections.observableArrayList(0.75, 0.90, 1.0)); // NOI18N. public final ObservableList getQuantitativeScale() { return quantitativeScale.get(); } public final ReadOnlyListProperty quantitativeScaleProperty() { return quantitativeScale.getReadOnlyProperty(); } }

    The default CSS (place it in the same package as the control):

    .bullet-chart {
        /*-fx-border-color: red;*/
        -fx-pref-width: 250px;
        -fx-pref-height: 60px;
        -fx-padding: 3px 8px 3px 3px;
    }
    .bullet-chart:vertical {
        -fx-pref-width: 80px;
        -fx-pre-height: 250px;
        -fx-padding: 3px 10px 6px 3px;
    }
    .bullet-chart .title-flow {
        /*-fx-border-color: purple;*/
        -fx-text-alignment: right;
    }
    .bullet-chart:vertical .title-flow {
        -fx-text-alignment: center;
    }
    .bullet-chart .title {
        -fx-font-weight: bold;
    }
    .bullet-chart .description {
        -fx-font-size: 0.85em;
    }
    .bullet-chart .axis {
        /*-fx-border-color: green;*/
    }
    .bullet-chart .plot-area {
        /*-fx-border-color: blue;*/
        -quantitative-color: darkgray;
    }
    .bullet-chart .quantitative-scale1 {
        -fx-background-color: -quantitative-color;
    }
    .bullet-chart .quantitative-scale2 {
        -fx-background-color: derive(-quantitative-color, 30%);
    }
    .bullet-chart .quantitative-scale3 {
        -fx-background-color: derive(-quantitative-color, 66%);
    }
    .bullet-chart .performance-measure-marker {
        -fx-background-color: black;
        -fx-padding: 5px 0px 5px 0px;
    }
    .bullet-chart:vertical .performance-measure-marker {
        -fx-padding: 0px 5px 0px 5px;
    }
    .bullet-chart .comparative-measure-marker {
        -fx-background-color: black;
        -fx-padding: 10px 1.5px 10px 1.5px;
    }
    .bullet-chart:vertical .comparative-measure-marker {
        -fx-padding: 1.5px 10px 1.5px 10px;
    }
    

    The test application:

    package test;
    
    import javafx.application.Application;
    import javafx.geometry.Orientation;
    import javafx.scene.Scene;
    import javafx.scene.control.SplitPane;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    /**
    * Test program.
    * @author Fabrice Bouyé
    */
    public class Main extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            final BulletGraph bulletChart1 = new BulletGraph();
            bulletChart1.setTitle("Example 1");
            bulletChart1.setDescription("Horizontal");
            bulletChart1.setPerformanceMeasure(65);
            bulletChart1.setComparativeMeasure(80);
            final BulletGraph bulletChart2 = new BulletGraph();
            bulletChart2.setTitle("Example 2");
            bulletChart2.setDescription("Vertical");
            bulletChart2.setOrientation(Orientation.VERTICAL);
            bulletChart2.setPerformanceMeasure(65);
            bulletChart2.setComparativeMeasure(80);
            final SplitPane root = new SplitPane();
            root.getItems().add(new StackPane(bulletChart1));
            root.getItems().add(new StackPane(bulletChart2));
            final Scene scene = new Scene(root, 600, 600);
            primaryStage.setTitle("Test Bullet Graph");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        /**
        * Program entry point.
        * @param args the command line arguments
        */
        public static void main(String[] args) {
            launch(args);
        }
    
    }
    
  • 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); } }
  • 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);
    
        }
    
  • Improve the performance of processing image javaFx

    Hello

    I'm working on Image processing with javaFx. I think my code isn't effective favorite (with pictures HD, refresh is very slow). Because I am doing a 'for' on each pixel of my image every time I have to refresh it. But I don't know how else to do.

    So I need help to improve the performance of my treatment.

    This is my code:

    import javafx.application.Application;
    import jvafx.beans.InvalidationListener;
    import javafx.beans.Observable;
    import javafx.beans.property.DoubleProperty;
    import javafx.scene.Scene;
    import javafx.scene.control.ScrollPane;
    import javafx.scene.control.Slider;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.image.PixelReader;
    import javafx.scene.image.PixelWriter;
    import javafx.scene.image.WritableImage;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.paint.Color;
    import javafx.stage.Stage;
        
    public class Example extends Application {
    
        private Image src;
        private WritableImage dest;
        private int width;
        private int height;
         int value = 0;
    
        @Override
        public void start(Stage stage) {
            AnchorPane root = new AnchorPane();
            initImage(root);
            Scene scene = new Scene(root);
            stage.setTitle("Demo processing");
            stage.setResizable(false);
            stage.setScene(scene);
            stage.show();
        }
    
        private void initImage(AnchorPane root) {
            src = new Image(
                    "http://mikecann.co.uk/wp-content/uploads/2009/12/ScreenHunter_02-Dec.-10-19.41-1024x484.jpg");
            width = (int) src.getWidth();
            height = (int) src.getHeight();
            root.setPrefSize(800, 800 + 50);
            ScrollPane scrollPane = new ScrollPane();
            scrollPane.setPrefHeight(600);
            scrollPane.setPrefWidth(1000);
            dest = new WritableImage(width, height);
            ImageView destView = new ImageView(dest);
    
            scrollPane.setContent(destView);
    
            root.getChildren().add(scrollPane);
            AnchorPane.setTopAnchor(scrollPane, 0.0);
    
            Slider slider = new Slider(0, 255, 1);
            slider.setPrefSize(800, 50);
            slider.setShowTickLabels(true);
            slider.setShowTickMarks(true);
            slider.setSnapToTicks(true);
            slider.setMajorTickUnit(1.0);
            slider.setMinorTickCount(0);
            slider.setLayoutY(700);
            slider.valueProperty().addListener(new InvalidationListener() {
                @Override
                public void invalidated(Observable o) {
                    value = (int) ((DoubleProperty) o).get();
                    color();
                }
            });
            root.getChildren().add(slider);
            color();
        }
    
        private void color() {
            PixelReader reader = src.getPixelReader();
            PixelWriter writer = dest.getPixelWriter();
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    Color color = reader.getColor(x, y);
                    double red = (double) value * x * y / (width * height) / 255;
                    double green = color.getGreen();
                    double blue = (double) value * ((width * height) - x * y)
                            / (width * height) / 255;
                        writer.setColor(x, y, Color.color(red, green, blue));
                    }
                }
            }
    
            public static void main(String[] args) {
                launch(args);
            }
        }
    

    And that's with full HD picture:

                src = new Image(
                    "http://www.freedomwallpaper.com//nature-wallpaper-hd/hd_sunshine_hd.jpg");
    

    As you change each pixel independently, there really is no other way than to use a loop through the pixels. Working directly with the pixel data, rather than use setColor and getColor (...) (...) seems to give some performance enhancements. And there are some general performance enhancements, you can use (reorder the loops, calculate the value used repeatedly, etc.). The performance of this version seems acceptable on my system:

    import javafx.application.Application;
    import javafx.beans.InvalidationListener;
    import javafx.beans.Observable;
    import javafx.beans.property.DoubleProperty;
    import javafx.scene.Scene;
    import javafx.scene.control.ScrollPane;
    import javafx.scene.control.Slider;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.image.PixelFormat;
    import javafx.scene.image.PixelWriter;
    import javafx.scene.image.WritableImage;
    import javafx.scene.layout.AnchorPane;
    import javafx.stage.Stage; 
    
    public class ImageProcessingExample extends Application { 
    
        @Override
        public void start(Stage stage) {
            AnchorPane root = new AnchorPane();
            initImage(root);
            Scene scene = new Scene(root);
            stage.setTitle("Demo processing");
            stage.setResizable(false);
            stage.setScene(scene);
            stage.show();
        }
        private void initImage(AnchorPane root) {
    //        Image src = new Image(
    //                "http://mikecann.co.uk/wp-content/uploads/2009/12/ScreenHunter_02-Dec.-10-19.41-1024x484.jpg");
            Image src = new Image(
                    "http://www.freedomwallpaper.com//nature-wallpaper-hd/hd_sunshine_hd.jpg");
            int width = (int) src.getWidth();
            int height = (int) src.getHeight(); 
    
            int[] srcPixels = new int[width*height];
    
            src.getPixelReader().getPixels(0, 0, width, height, PixelFormat.getIntArgbPreInstance(), srcPixels, 0, width);
    
            root.setPrefSize(800, 800 + 50);
            ScrollPane scrollPane = new ScrollPane();
            scrollPane.setPrefHeight(600);
            scrollPane.setPrefWidth(1000);
            WritableImage dest = new WritableImage(width, height);
            PixelWriter pixWriter = dest.getPixelWriter();
    
            ImageView destView = new ImageView(dest);
            scrollPane.setContent(destView);
            root.getChildren().add(scrollPane);
            AnchorPane.setTopAnchor(scrollPane, 0.0);
            Slider slider = new Slider(0, 255, 1);
            slider.setPrefSize(800, 50);
            slider.setShowTickLabels(true);
            slider.setShowTickMarks(true);
            slider.setSnapToTicks(true);
            slider.setMajorTickUnit(1.0);
            slider.setMinorTickCount(0);
            slider.setLayoutY(700);
            slider.valueProperty().addListener(new InvalidationListener() {
                @Override
                public void invalidated(Observable o) {
                    int value = (int) ((DoubleProperty) o).get();
                    color(srcPixels, pixWriter, value, width ,height);
                }
            });
            root.getChildren().add(slider);
            color(srcPixels, pixWriter, 0, width, height);
        }
        private void color(int[] srcPixels, PixelWriter pixWriter, int value, int width, int height) {
            final int area = width * height ;
            final int[] writerPixels = new int[area];
    
            final int a = 0xff00_0000;
            final int greenMask = 0xff00;
    
            for (int y = 0; y < height; y++) {
                final int depthOffset = y * width ;
                for (int x = 0; x < width; x++) {
                    final int xy = x * y;
    final int index = x + depthOffset ;
                    final int red = value * xy  / area ;
                    final int green = srcPixels[index] & greenMask ;
                    final int blue = value * (area - xy)  / area ;
                    writerPixels[index] = a | red << 16 | green | blue ;
                }
            }
            pixWriter.setPixels(0, 0, width, height, PixelFormat.getIntArgbInstance(), writerPixels, 0, width);
        }
            public static void main(String[] args) {
                launch(args);
            }
        } 
    

Maybe you are looking for