IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaFX Discussion :

Problème de redimention d'image


Sujet :

JavaFX

  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2020
    Messages : 11
    Par défaut Problème de redimention d'image
    Bonjour, je développe une applicaion de visioneuse, et je souhaiterai pouvoir zoomer sur l'image affichée ainsi que de pouvoir me déplacer dedans... Mon problème est quand lorsque j'utilise le zoom, ça redimentionne ma Région au lieux de mon image.. Je vous joint quelques captures d'écran pour vous expliquer :
    Nom : 1.JPG
Affichages : 1014
Taille : 89,5 Ko
    L'image qui est affichée au début.
    Nom : 2.JPG
Affichages : 972
Taille : 65,3 Ko
    L'image une fois que j'ai zoomé
    Nom : 3.JPG
Affichages : 980
Taille : 66,6 Ko
    L'image une fois que j'ai dézoomé.

    Le déplacement dans l'image fonctionne mais le zoom je souhaiterai que la zone de l'image reste fixe et que ce soit l'image qui se zoom et pas l'inverse.

    J'utilise javaFx, j'ai un fichier FXML qui contient pour la zone d'image, un Pane, qui lui comprend une région et une imageView.

    Mon code qui gère le zoom :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    visioneusePrincipal.setImage(image);
                    final Rectangle2D viewport = new Rectangle2D(0, 0, 0, 0);
                    visioneusePrincipal.setViewport(viewport);
                    visioneusePrincipal.setOnMousePressed(this::handleMousePressed);
                    visioneusePrincipal.setOnMouseDragged(this::handleMouseDragged);
                    visioneusePrincipal.setOnScroll(this::handleZoom);
                    visioneusePrincipal.getTransforms().add(scale);
                    Platform.runLater(() -> {
                        mapArea.widthProperty().addListener(this::mapAreaSizeChanged);
                        mapArea.heightProperty().addListener(this::mapAreaSizeChanged);
                    });
    Et les fonctions :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
     
     private void handleMousePressed(MouseEvent e) {
            startX = e.getX();
            startY = e.getY();
        }
     
        private void handleMouseDragged(MouseEvent e) {
     
            double draggedDistanceX = startX - e.getX();
            double draggedDistanceY = startY - e.getY();
     
            startX = e.getX();
            startY = e.getY();
     
            double viewWidth = mapArea.getWidth() * 1 / zoom;
            double viewHeight = mapArea.getHeight() * 1 / zoom;
     
            final Rectangle2D viewport = visioneusePrincipal.getViewport();
            double curMinX = viewport.getMinX();
            double curMinY = viewport.getMinY();
     
            double newMinX = curMinX + draggedDistanceX;
            double newMinY = curMinY + draggedDistanceY;
            newMinX = clamp(newMinX, 0, Math.max(0, visioneusePrincipal.getImage().getWidth() - viewWidth));
            newMinY = clamp(newMinY, 0, Math.max(0, visioneusePrincipal.getImage().getHeight() - viewHeight));
            visioneusePrincipal.setViewport(new Rectangle2D(newMinX, newMinY, viewWidth, viewHeight));
            System.out.printf("%f x %f \t %f x %f%n", newMinX, newMinY, visioneusePrincipal.getImage().getWidth(), visioneusePrincipal.getImage().getHeight());
        }
     
        double clamp(double min, double value, double max) {
            double result = Math.max(min, value);
            result = Math.min(result, max);
            return result;
        }
     
        private void mapAreaSizeChanged(Observable o) {
            double viewWidth = mapArea.getWidth() * 1 / zoom;
            double viewHeight = mapArea.getHeight() * 1 / zoom;
            final Rectangle2D viewport = visioneusePrincipal.getViewport();
            if (viewport.getWidth() != viewWidth || viewport.getHeight() != viewHeight) {
                double newMinX = viewport.getMinX();
                double newMinY = viewport.getMinY();
                newMinX = clamp(newMinX, 0, Math.max(0, visioneusePrincipal.getImage().getWidth() - viewWidth));
                newMinY = clamp(newMinY, 0, Math.max(0, visioneusePrincipal.getImage().getHeight() - viewHeight));
                visioneusePrincipal.setViewport(new Rectangle2D(newMinX, newMinY, viewWidth, viewHeight));
            }
        }
     
        private double zoom = 1.0;
        private Scale scale = new Scale(zoom, zoom);
        private static final double MIN_ZOOM = 0.5;
        private static final double MAX_ZOOM = 2.0;
     
        private void handleZoom(ScrollEvent event) {
            double delta = event.getDeltaY();
            double newZoom = zoom;
            if (delta < 0) {
                newZoom /= 2;
            }
            if (delta > 0) {
                newZoom *= 2;
            }
            newZoom = clamp(MIN_ZOOM, newZoom, MAX_ZOOM);
            if (newZoom == zoom) {
                return;
            }
            zoom = newZoom;
            System.out.printf("Zoom: %f%n", zoom);
            scale.setX(zoom);
            scale.setY(zoom);
            double viewWidth = mapArea.getWidth() * 1 / zoom;
            double viewHeight = mapArea.getHeight() * 1 / zoom;
            final Rectangle2D viewport = visioneusePrincipal.getViewport();
            if (viewport.getWidth() != viewWidth || viewport.getHeight() != viewHeight) {
                double newMinX = viewport.getMinX();
                double newMinY = viewport.getMinY();
                newMinX = clamp(newMinX, 0, Math.max(0, visioneusePrincipal.getImage().getWidth() - viewWidth));
                newMinY = clamp(newMinY, 0, Math.max(0, visioneusePrincipal.getImage().getHeight() - viewHeight));
                visioneusePrincipal.setViewport(new Rectangle2D(newMinX, newMinY, viewWidth, viewHeight));
            }
        }
    Merci beaucoup !

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Ca serait bien d'avoir le FXML.
    Pour ce que j'en vois tu utilises une transformation de zoom (variable scale() sur setTransform()). Pourquoi ne pas tout simplement ne pas utiliser les fitWidth et fitHeight de ton ImageView ?
    Et question conne mais pourquoi ne pas utiliser un ScrollPane ?
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2020
    Messages : 11
    Par défaut
    Citation Envoyé par bouye Voir le message
    Et question conne mais pourquoi ne pas utiliser un ScrollPane ?
    Bonjour déjà merci de ta réponse. Pour ce qui est du ScrollPane, tu parles pour se déplacer dans l'image ? Parce que si c'est le cas le déplacement du click plus déplacement dans l'image est fonctionnel.

    Citation Envoyé par bouye Voir le message
    Pour ce que j'en vois tu utilises une transformation de zoom (variable scale() sur setTransform()). Pourquoi ne pas tout simplement ne pas utiliser les fitWidth et fitHeight de ton ImageView ?
    Je ne sais pas, je débute avec javaFx et j'ai fais des recherches sur internet et je suis tombé sur cette méthode que j'ai essayé d'appliquer dans mon cas. Peux-tu m'en dire plus sur ses 2 méthodes s'il te plait ?

    Citation Envoyé par bouye Voir le message
    Ca serait bien d'avoir le FXML.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    <?xml version="1.0" encoding="UTF-8"?>
     
    <?import javafx.scene.control.Button?>
    <?import javafx.scene.control.TextField?>
    <?import javafx.scene.control.TreeView?>
    <?import javafx.scene.image.Image?>
    <?import javafx.scene.image.ImageView?>
    <?import javafx.scene.layout.AnchorPane?>
    <?import javafx.scene.layout.Pane?>
    <?import javafx.scene.layout.Region?>
     
    <AnchorPane prefHeight="750.0" prefWidth="1300.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="historia.visioneuse.controler.VisioneuseController">
       <children>
          <ImageView id="blason" fitHeight="150.0" fitWidth="200.0" layoutX="1145.0" layoutY="79.0" pickOnBounds="true" preserveRatio="true">
             <image>
                <Image url="@../../../img/blason.jpg" />
             </image>
          </ImageView>
          <TreeView fx:id="selectionTreeView" layoutX="27.0" layoutY="14.0" prefHeight="600.0" prefWidth="200.0" AnchorPane.leftAnchor="15.0" AnchorPane.topAnchor="50.0" />
          <Pane layoutX="300.0" prefHeight="40.0" prefWidth="700.0" AnchorPane.leftAnchor="300.0" AnchorPane.rightAnchor="300.0" AnchorPane.topAnchor="0.0">
             <children>
                <Button layoutX="14.0" layoutY="5.0" mnemonicParsing="false" prefHeight="30.0" prefWidth="117.0" text="Rechercher" />
                <TextField alignment="CENTER" layoutX="161.0" layoutY="5.0" prefHeight="30.0" prefWidth="499.0" promptText="Votre recherche..." />
             </children>
          </Pane>
          <Pane layoutX="1144.0" layoutY="361.0" prefHeight="182.0" prefWidth="122.0">
             <children>
                <Button mnemonicParsing="false" onAction="#handleHelpButton" prefHeight="26.0" prefWidth="122.0" text="Aide" />
                <Button layoutY="38.0" mnemonicParsing="false" onAction="#handleConfig" prefHeight="26.0" prefWidth="122.0" text="Configuration" />
                <Button accessibleHelp="Bonjour" accessibleText="Test" layoutY="81.0" mnemonicParsing="false" onAction="#handleAcceuil" prefHeight="26.0" prefWidth="122.0" text="Accueil" />
                <Button layoutY="118.0" mnemonicParsing="false" prefHeight="26.0" prefWidth="122.0" text="Sauvegarde" />
                <Button layoutY="156.0" mnemonicParsing="false" onAction="#handleFermerSession" prefHeight="26.0" prefWidth="122.0" text="Fermer session" />
             </children>
          </Pane>
          <Pane layoutX="376.0" layoutY="50.0" prefHeight="40.0" prefWidth="548.0">
             <children>
                <Button layoutY="8.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="130.0" text="Marquer cette page" />
                <Button layoutX="140.0" layoutY="8.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="130.0" text="Ajouter mention" />
                <Button layoutX="276.0" layoutY="8.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="130.0" text="Imprimer / Envoyer" />
                <Button layoutX="412.0" layoutY="8.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="130.0" text="Plein écran" />
             </children>
          </Pane>
          <Pane id="BouttonNavigation" layoutX="550.0" layoutY="734.0" prefHeight="30.0" prefWidth="200.0">
             <children>
                <Button maxWidth="200.0" mnemonicParsing="false" onAction="#PreviewButton" prefHeight="25.0" prefWidth="92.0" />
                <Button layoutX="100.0" maxWidth="200.0" mnemonicParsing="false" onAction="#NextButton" prefHeight="25.0" prefWidth="92.0" />
             </children>
          </Pane>
          <Pane fx:id="zoneImage" layoutX="310.0" layoutY="10.0" prefHeight="622.0" prefWidth="838.0" AnchorPane.leftAnchor="276.0" AnchorPane.topAnchor="90.0">
             <children>
                <Region fx:id="mapArea" prefHeight="622.0" prefWidth="838.0" />
                <ImageView fx:id="visioneusePrincipal" fitHeight="622.0" fitWidth="838.0" pickOnBounds="true" preserveRatio="true" />
             </children>
          </Pane>
       </children>
    </AnchorPane>
    Merci beaoucoup

  4. #4
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Pas que pour les déplacements, le ScrollPane offre un espace de clip de la vue via son viewport qui est géré automatiquement; une zone de clip ce qui manque dans ton code.

    Ton ImageView nommée visioneusePrincipal devrait être placée dans un conteneur parent qui devrait disposer d'un rectangle de clip pour l’empêcher de se redimensionner lorsque tu appliques des mises a l’échelle sur visioneusePrincipal.

    ImageView dispose des propriétés fitWidth et fitHeight pour adapter l'image visionnée a de nouvelle dimensions d'affichage ce qui permet en général d’éviter de faire une mise a l’échelle (soit via la propriété scale, soit via une transformation comme toi) sur le nœud.

    Donc en gros tu dois avoir :

    • image - l'Image a afficher.
    • visioneusePrincipal - l'ImageView, le controle qui affiche l'image.
    • viewport - un Rectangle définissant la vue c-a-d la zone de l'image a afficher dans visioneusePrincipal.
    • le conteneur parent qui doit afficher visioneusePrincipal.
    • clip - un Rectangle qui va restreindre le contenu affiche dans le parent. Les dimensions de ce clip doivent donc correspondre aux dimensions logiques du parent (c-a-d l'espace qu'il est sensé occupe a l’écran).



    Après c'est pour une première approche. Y a moyen de combiner le viewport et le clip au niveau de visioneusePrincipal mais ça demande plus de réflexion et de calculs.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  5. #5
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2020
    Messages : 11
    Par défaut
    Citation Envoyé par bouye Voir le message
    Pas que pour les déplacements, le ScrollPane offre un espace de clip de la vue via son viewport qui est géré automatiquement; une zone de clip ce qui manque dans ton code.
    Mais du coup il y aura des barres de scroll non ? Je veux éviter ça justement.

    Citation Envoyé par bouye Voir le message
    Ton ImageView nommée visioneusePrincipal devrait être placée dans un conteneur parent qui devrait disposer d'un rectangle de clip pour l’empêcher de se redimensionner lorsque tu appliques des mises a l’échelle sur visioneusePrincipal.
    Un région n'est pas la même chose ?

    Citation Envoyé par bouye Voir le message
    ImageView dispose des propriétés fitWidth et fitHeight pour adapter l'image visionnée a de nouvelle dimensions d'affichage ce qui permet en général d’éviter de faire une mise a l’échelle (soit via la propriété scale, soit via une transformation comme toi) sur le nœud.
    Juste avec ses deux propriétés un zoom fonctionnerai ? (:

    Citation Envoyé par bouye Voir le message
    Donc en gros tu dois avoir :

    • image - l'Image a afficher.
    • visioneusePrincipal - l'ImageView, le controle qui affiche l'image.
    • viewport - un Rectangle définissant la vue c-a-d la zone de l'image a afficher dans visioneusePrincipal.
    • le conteneur parent qui doit afficher visioneusePrincipal.
    • clip - un Rectangle qui va restreindre le contenu affiche dans le parent. Les dimensions de ce clip doivent donc correspondre aux dimensions logiques du parent (c-a-d l'espace qu'il est sensé occupe a l’écran).
    Le viewport et le clip sont des élément FXML ? Car je ne trouve pas réelement leurs provenance..

    J'ai essayé de me renseigner en vain aujourd'hui. Je n'ai toujours pas réussi à faire ce fichu zoom. Je suis souvent tomber sur l'utilsiation d'une Region mais ne fonctionne toujours pas malgré mes nombreux essais..

    PS : Je suis désolé je débute seulement et j'ai pas forcément toutes les conaissances nécéssaires.

  6. #6
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Citation Envoyé par Ouisticrabe Voir le message
    Mais du coup il y aura des barres de scroll non ? Je veux éviter ça justement.
    l'affichage des barres de scroll est gerable via les policy :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
    scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);

    Citation Envoyé par Ouisticrabe Voir le message
    Un région n'est pas la même chose ?
    Une region c'est un noeud basique dans lequel il faut tout faire a mano y compris la mise en page.


    Citation Envoyé par Ouisticrabe Voir le message
    Juste avec ses deux propriétés un zoom fonctionnerai ? (:
    Elles sont un peu faites pour... Et si tu faisais un petit programme de test a cote pour voir comment ca marche ? C'est comme ca qu'on apprend.

    Citation Envoyé par Ouisticrabe Voir le message
    Le viewport et le clip sont des élément FXML ? Car je ne trouve pas réelement leurs provenance..
    Le viewport (le tien) provient de ton code...
    Le clip est une propriété standard donc oui tu peux le définir dans le FXML même s'il faudra faire de la manipulation pour le mettre aux bonnes tailles dans le contrôleur.

    Citation Envoyé par Ouisticrabe Voir le message
    J'ai essayé de me renseigner en vain aujourd'hui. Je n'ai toujours pas réussi à faire ce fichu zoom. Je suis souvent tomber sur l'utilsiation d'une Region mais ne fonctionne toujours pas malgré mes nombreux essais..
    Region c'est un noeud basique (c'est l'equivalent d'un simple <div> en HTML donc faut tout programmer soit meme, ce qui rend la chose moins abordable quand on debute du coup.

    Citation Envoyé par Ouisticrabe Voir le message
    PS : Je suis désolé je débute seulement et j'ai pas forcément toutes les conaissances nécéssaires.
    C'est pas bien grave, il fait bien commencer un jour...
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  7. #7
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Voici un exemple rapide permettant de tester les 3 principales méthodes de zoom :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    package image.zoom;
     
    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.scene.Scene;
    import javafx.scene.control.ScrollPane;
    import javafx.scene.control.Slider;
    import javafx.scene.control.SplitPane;
    import javafx.scene.control.ToolBar;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.Priority;
    import javafx.scene.layout.VBox;
    import javafx.scene.transform.Scale;
    import javafx.stage.Stage;
     
    import java.util.Arrays;
    import java.util.stream.IntStream;
     
    public final class Main extends Application {
        public static void main(final String... args) {
            launch(args);
        }
     
        private Image image;
     
        @Override
        public void init() throws Exception {
            image = new Image(getClass().getResource("100102eau2.jpg").toExternalForm());
        }
     
        @Override
        public void start(final Stage stage) throws Exception {
            final var zoomSlider = new Slider();
            zoomSlider.setMin(1);
            zoomSlider.setMax(10);
            zoomSlider.setBlockIncrement(1);
            zoomSlider.setMajorTickUnit(1);
            zoomSlider.setMinorTickCount(0);
            zoomSlider.setSnapToTicks(true);
            zoomSlider.setShowTickMarks(true);
            zoomSlider.setShowTickLabels(true);
            final var toolBar = new ToolBar();
            toolBar.getItems().add(zoomSlider);
            //
            final var splitPane = new SplitPane();
            VBox.setVgrow(splitPane, Priority.ALWAYS);
            final var imageViews = IntStream.range(0, 4)
                    .mapToObj(index -> {
                        final var imageView = new ImageView(image);
                        imageView.setSmooth(false);
                        return imageView;
                    })
                    .toArray(ImageView[]::new);
            final var scaleTransform = new Scale();
            scaleTransform.setX(1);
            scaleTransform.setY(1);
            imageViews[3].getTransforms().add(scaleTransform);
            Arrays.stream(imageViews)
                    .forEach(imageView -> {
                        final var scrollPane = new ScrollPane();
                        scrollPane.setContent(imageView);
                        scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
                        scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
                        splitPane.getItems().add(scrollPane);
                    });
            final var root = new VBox();
            root.setFillWidth(true);
            root.getChildren().addAll(toolBar, splitPane);
            final var scene = new Scene(root, 800, 600);
            stage.setScene(scene);
            stage.setTitle("Test");
            stage.show();
            Platform.runLater(() -> splitPane.setDividerPositions(0.25, 0.5, 0.75));
            zoomSlider.valueProperty().addListener((observable, oldValue, newValue) -> {
                final int zoom = newValue.intValue();
                final int imgWidth = (int) image.getWidth();
                final int imgHeight = (int) image.getHeight();
                // Centre de la mise a l'echelle en (0,0)
                // Le scroll pane fonctionne car la taille logique de l'image view a changee.
                imageViews[1].setFitWidth(imgWidth * zoom);
                imageViews[1].setFitHeight(imgHeight * zoom);
                // Centre de la mise a l'echelle au milieu du controle donc on compense par une translation.
                // Le scroll pane semble paume sur la dimension horizontale.
                imageViews[2].setTranslateX(imgWidth * (zoom - 1) / 2);
                imageViews[2].setTranslateY(imgHeight * (zoom - 1) / 2);
                imageViews[2].setScaleX(zoom);
                imageViews[2].setScaleY(zoom);
                // Par defaut la transformation se fait autour de (0, 0)
                // Le scroll pane semble aussi paume sur la dimension horizontale.
                scaleTransform.setX(zoom);
                scaleTransform.setY(zoom);
            });
        }
    }
    Ici le ScrollPane répond toujours au scroll mais pas au pan donc effectivement avoir un control perso pour le faire peut etre un plus.

    J'avais lu qq part qu'ils avaient enfin mis ce qu'il fallait pour éviter le blur lors des redimensionnements de mise a l'echelle des bitmaps dans des versions recentes... que neni... ca donne toujours autant une bouille de pixels flous quelquel soit la methode de mise a l'echelle utilisee.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  8. #8
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Un exemple rapide pour montrer ce a quoi sert le clip :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    package image.pan;
     
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.CheckBox;
    import javafx.scene.control.ToolBar;
    import javafx.scene.image.Image;
    import javafx.scene.layout.Priority;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
     
    public final class Main extends Application {
        public static void main(final String... args) {
            launch(args);
        }
     
        private Image image;
     
        @Override
        public void init() throws Exception {
            image = new Image(getClass().getResource("100102eau2.jpg").toExternalForm());
        }
     
        @Override
        public void start(final Stage stage) throws Exception {
            final var imagePanView = new ImagePanView(image);
            VBox.setVgrow(imagePanView, Priority.ALWAYS);
            final var clipImageCheck = new CheckBox("Clip");
            clipImageCheck.selectedProperty().bindBidirectional(imagePanView.clipImageProperty());
            final var toolBar = new ToolBar();
            toolBar.getItems().addAll(clipImageCheck);
            final var root = new VBox();
            root.setFillWidth(true);
            root.getChildren().addAll(toolBar, imagePanView);
            final var scene = new Scene(root, 800, 600);
            stage.setScene(scene);
            stage.setTitle("Test");
            stage.show();
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    package image.pan;
     
    import javafx.beans.property.BooleanProperty;
    import javafx.beans.property.ObjectProperty;
    import javafx.beans.property.SimpleBooleanProperty;
    import javafx.beans.property.SimpleObjectProperty;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.Region;
    import javafx.scene.shape.Rectangle;
     
    final class ImagePanView extends Region {
        private final Rectangle clip = new Rectangle();
        private final ImageView content = new ImageView();
        private final Region viewport = new Region() {
            {
                getChildren().add(content);
            }
     
            @Override
            protected void layoutChildren() {
                content.resizeRelocate(0, 0, getWidth(), getHeight());
            }
        };
     
        public ImagePanView() {
            this(null);
        }
     
        public ImagePanView(final Image image) {
            super();
            setId("imagePanView");
            getStyleClass().add("image-pan-view");
            viewport.setId("viewport");
            viewport.getStyleClass().add("viewport");
            content.setId("content");
            content.getStyleClass().add("content");
            // Debug.
            setStyle("-fx-padding: 50px; -fx-border-color: red; -fx-background-color: cornflowerblue;");
            viewport.setStyle("-fx-background-color: #00000088; -fx-border-color: yellow; -fx-border-width: 5px");
            //
            content.imageProperty().bind(imageProperty());
            viewport.setClip(clip);
            getChildren().addAll(viewport);
            clipImageProperty().addListener((observable, oldValue, newValue) -> viewport.setClip(newValue ? clip : null));
            setImage(image);
        }
     
        @Override
        protected void layoutChildren() {
            super.layoutChildren();
            final double width = getWidth();
            final double height = getHeight();
            final var insets = getInsets(); // padding.
            //
            final double viewPortX = insets.getLeft();
            final double viewPortY = insets.getTop();
            final double viewPortW = Math.max(0, width - (insets.getLeft() + insets.getRight()));
            final double viewPortH = Math.max(0, height - (insets.getTop() + insets.getBottom()));
            viewport.resizeRelocate(viewPortX, viewPortY, viewPortW, viewPortH);
            clip.setWidth(viewPortW);
            clip.setHeight(viewPortH);
        }
     
        private final ObjectProperty<Image> image = new SimpleObjectProperty<>(this, "image");
     
        public final Image getImage() {
            return image.get();
        }
     
        public void setImage(final Image value) {
            image.set(value);
        }
     
        public ObjectProperty<Image> imageProperty() {
            return image;
        }
     
        private final BooleanProperty clipImage = new SimpleBooleanProperty(this, "clipImage", true);
     
        public final BooleanProperty clipImageProperty() {
            return clipImage;
        }
    }
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  9. #9
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2020
    Messages : 11
    Par défaut
    Je m'en vais essayer tout ça et comprendre les exemples que tu m'a donné.

    J'ai juste une question sur le code expliquant le clip, dans la class ImagePanView :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    private final Rectangle clip = new Rectangle();
        private final ImageView content = new ImageView();
        private final Region viewport = new Region() {
            {
                getChildren().add(content);
            }
     
            @Override
            protected void layoutChildren() {
                content.resizeRelocate(0, 0, getWidth(), getHeight());
            }
        };
    Etant donné que mon viewport et mon content sont dans mon fichier FXML, les commandes getChlidren().add(..) vont me provoquer une erreur je suppose ?

    Et cette même commande récupère la liste des enfants du parent, mais dans ton code, le parent (c'est le stage je me trompe ?) c'est n'est pas le même que dans mon fichier FXML je me trompe ?

    Et puis je n'ai pas besoin de d'ajouter cette ligne au vu de mon architecture FXML :
    Nom : aa.JPG
Affichages : 889
Taille : 20,1 Ko

    Je m'en vais décortiquer petit à petit le code que tu m'a donné, je te remercie.

  10. #10
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Ici, je ne voulais pas alourdir la chose en devant gérer un FXML avec son chargement et son contrôleur, mon but était de rester sur ces exemples très simples. Le clip sert a cacher tout ce qui dépasse, ce dont tu peux te rendre compte en cochant/décochant la case clip dans l'UI de test.

    En passant par le FXML il t'est impossible de faire certaines actions telles que par exemple surcharger layoutChildren(). Or il faut surcharger cette méthode pour redimensionner correctement le clip ou encore repositionner l'ImageView (si jamais il y a besoin de le faire). FXML prend en charge les contrôles perso donc par exemple il est tout a fait possible d'inclure mon ImagePanView du second test dans un FXML où il fera office en quelques sorte de "boite noire" / composant prêt à l'emploi.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  11. #11
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2020
    Messages : 11
    Par défaut
    Citation Envoyé par bouye Voir le message
    En passant par le FXML il t'est impossible de faire certaines actions telles que par exemple surcharger layoutChildren(). Or il faut surcharger cette méthode pour redimensionner correctement le clip ou encore repositionner l'ImageView (si jamais il y a besoin de le faire). FXML prend en charge les contrôles perso donc par exemple il est tout a fait possible d'inclure mon ImagePanView du second test dans un FXML où il fera office en quelques sorte de "boite noire" / composant prêt à l'emploi.
    Je me suis renseigner sur la facon d'inclure un UI perso, mais malheureusement ça ne fonctionne pas.. J'utilise scene builder. J'ai donc créer un fichier jar avec la classe ImagePaneView, que j'ai essayer d'inmporter dans scene builder afin d'avoir mon composant perso mais il me dit que dans ma classe je n'ai pas de composant
    Nom : scb.JPG
Affichages : 889
Taille : 41,2 Ko

    Malgré de nombreuses recherche je n'ai pas trouvé d'où ça provenais.. Je pense que ça viens de mon jar au moment ou je le fait.

    Pour créer mon jar, (je suis sous eclipse) je fait Export>JAR file>, je donne le nom de mon jar.

  12. #12
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Tu peux directement utiliser n'importe quelle classe qui est dans le ClassPath dans du FXML (pas essayé depuis la modularisation par contre, j'imagine qu'il faudra exporter le package et le rendre disponible à javafx.fxml). Par contre pour SceneBuilder c'est une autre histoire, il faut exporter ton composant dans un JAR standalone (idem pas essayé depuis la modularisation) ; et il te faut respecter les normes de nommage habituelles des beans et de JavaFX au niveau des noms des getter, setters et propriété. Il faut aussi probablement fournir un fichier bean info annexe pour avoir les descriptions additionnelles qui vont bien.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  13. #13
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2020
    Messages : 11
    Par défaut
    J'ai abandonné l'idée de pouvoir l'utiliser avec SceneBuilder, j'essaie de le mettre directement dans mon fxml mais en vain, malgré des heures de test et de recherches sur comment utiliser mon propre composant (surcharge d'un composant existant.. Ici une région) mais ça ne fonctionne toujours pas..

    J'ai ajouté dans mon code fxml :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <?import historia.visioneuse.utils.ImagePaneView?>
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <ImagePaneView fx:id="zoneImage" layoutX="246.0" layoutY="94.0" prefHeight="622.0" prefWidth="838.0" />
    Mais lorsque j'éssaie de le récupérer avec : private ImagePaneView zoneImage; j'ai l'erreur comme quoi ImagePaneView cannot be resolved to a type.

    Citation Envoyé par bouye Voir le message
    j'imagine qu'il faudra exporter le package et le rendre disponible à javafx.fxml
    Je pense c'est ce qui manque pour que le code plus haut fonctionne mais peux-tu expliquer la démarche je galère vraiment..

  14. #14
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Commence deja par déclarer la classe en public, si ce n'est pas deja fait histoire qu'elle soit accessible au reste du monde.

    Ensuite, aucun soucis pour moi:

    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <?xml version="1.0" encoding="UTF-8"?>
     
    <?import java.lang.*?>
    <?import java.util.*?>
    <?import javafx.scene.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
     
    <?import test.image.pan.ImagePanView?>
    <VBox xmlns="http://javafx.com/javafx"
          xmlns:fx="http://javafx.com/fxml"
          fx:controller="test.image.pan.fxml.TestController"
          prefHeight="400.0" prefWidth="600.0">
        <children>
            <ToolBar fx:id="toolBar"></ToolBar>
            <ImagePanView fx:id="imagePanView" VBox.vgrow="ALWAYS"/>
        </children>
    </VBox>


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    package test.image.pan.fxml;
     
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
     
    public final class Main extends Application {
        public static void main(final String... args) {
            launch(args);
        }
     
        @Override
        public void start(final Stage stage) throws Exception {
            final var fxmlURL = getClass().getResource("test.fxml");
            final var fxmlLoader = new FXMLLoader(fxmlURL);
            final var root = fxmlLoader.<Parent>load();
            final var scene = new Scene(root);
            stage.setScene(scene);
            stage.setTitle("Test");
            stage.show();
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package test.image.pan.fxml;
     
    import javafx.fxml.FXML;
    import test.image.pan.ImagePanView;
     
    public final class TestController {
        @FXML
        private ImagePanView imagePanView;
     
        public void initialize() {
            assert imagePanView != null;
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    module dvp.fx {
        exports test.image.pan;
        exports test.image.pan.fxml;
        //opens test.image.pan to javafx.fxml; // Apparemment c'est pas nécessaire....
        opens test.image.pan.fxml to javafx.fxml;
        requires javafx.graphics;
        requires javafx.controls;
        requires javafx.fxml;
    }
    EDIT - par contre il est vrai que la nouvelle version de SceneBuilder est moins tolerante envers les classes qu'elle ne connait pas, et plante avec une exception contrairement aux anciennes qui se contentaient d'afficher un rectangle gris.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  15. #15
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Pour ce qui est de SceneBuilder, aucun soucis a avoir un contrôle qui est une Region.

    Je viens de tester, le probleme est cause par le fait que la dernière version stable et gratuite de SceneBuilder tourne sur le JDK 11 et donc qu'il est incapable de lire/d'importer du bytecode produit aux formats JDK 12, 13 et 14.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  16. #16
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2020
    Messages : 11
    Par défaut
    Alors le problème viens de moi je vais revoir ma façon de faire, juste une dernière petite question, ce bout de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    module dvp.fx {
        exports test.image.pan;
        exports test.image.pan.fxml;
        //opens test.image.pan to javafx.fxml; // Apparemment c'est pas nécessaire....
        opens test.image.pan.fxml to javafx.fxml;
        requires javafx.graphics;
        requires javafx.controls;
        requires javafx.fxml;
    }
    Il se met où? J'ai jamais entendu/vu cette chose..

    Merci beacoup du temps que tu prend pour m'aider !

  17. #17
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Les modules sont un système de découpage des bibliothèques, de détection des dépendances et de gestion des protections des accès aux packages qui sont apparus avec le JDK 9. Ils arrivent avec une nouvelle notion, celle de modulepath qui vient en complément du classpath habituel.

    Le fichier module-info.java, qui n'utilise pas vraiment une syntaxe Java , doit se placer a la racine des sources de ton projet (ex: si tes packages et sources sont dans un répertoire src, alors ce fichier doit se trouver dans ce répertoire et non-pas dans un sous-répertoire).

    Parmi les choses (il y en a d'autres) qui peuvent être définies dans ce fichier :
    • Le nom du module, si possible unique et propre a ton projet.
    • exports - les packages qui sont visibles a l’extérieur du module. Ex: ici les packages contenant des classes Main doivent être visibles pour pouvoir lancer les applications de test.
    • opens - les autorisations d’accès des modules extérieurs pour la réfection/transitivité. Ex: ici le contrôleur doit être injecté par transitivité par le loader FXML, il faut donc ouvrir mon package contenant le contrôleur au module javafx.fxml qui contient le loader FXML.
    • requires - les modules extérieurs requis pour compiler et faire tourner cette application. Il est alors possible de construire un graphe de dépendances car ces memes modules ont des dépendances implicites ou explicites (ex: presque tous les modules javafx ont une dépendance vers le module javafx.base qui sera donc inclus dans le graphe). Cela permet aussi lorsqu'on package une application de packager avec uniquement ce qui est nécessaire pour la faire tourner et ainsi réduire drastiquement la taille finale du paquetage.


    Note : tout cela s'applique uniquement dans le cadre d'une application modulaire. Pour le moment (mais ca ne durera peut-etre pas), les applications non-modulaires (a l'ancienne) ignorent totalement ces règles.

    En théorie, la modularisation est optionnelle mais fortement conseillée pour les nouveaux développement post-JDK 9.
    En théorie, il est toujours possible de créer et d'utiliser des applications non-modulaires via des dépendances directes sur le CLASSPATH comme avant (mais en pratique ça ne fonctionne pas toujours bien).
    En théorie, il est possible d’utiliser des JAR non-modulaires dans une application modulaire avec une modularisation automatique et une génération du nom du module implicite en fonction du nom du JAR (mais en pratique ça ne fonctionne pas toujours également).

    Justement tu ne nous as pas trop dit quelle version du JDK ou de JavaFX tu utilisais, il me semble. Il reste possible en JDK 11, 12, 13 et 14 de faire des applications JavaFX non-modulaires mais comme les libs ne sont plus intégrées dans le JDK, cela demande de jongler avec des paramètres supplémentaires de la JVM tels que -add-modules et -module-path.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  18. #18
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2020
    Messages : 11
    Par défaut
    Citation Envoyé par bouye Voir le message
    Justement tu ne nous as pas trop dit quelle version du JDK ou de JavaFX tu utilisais, il me semble. Il reste possible en JDK 11, 12, 13 et 14 de faire des applications JavaFX non-modulaires mais comme les libs ne sont plus intégrées dans le JDK, cela demande de jongler avec des paramètres supplémentaires de la JVM tels que -add-modules et -module-path.
    Justement, pour mon application, je suis obliger de d'ajouter comme argument :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    --module-path C:\Users\ouist\Utils\JFX\javafx-sdk-11.0.2\lib 
    --add-modules=javafx.controls,javafx.fxml
    Donc si j'ai bien compris, suffit d'ajouter un fichier module-info.java a la racine de mon projet pour éviter de devoir faire ceci ? Et d'ajouter le bout de code qui me posait problème ? (:

    En tout cas, j'apprend beaucoup avec tes réponses et je t'en suis reconaissant !

    Edit : En essayant je me suis apeçut que j'ai pleins d'erreurs qui sont apparues notament avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    import java.sql.Connection;
    si j'ai bien compris je devrai mettre : requires java.sql ?

  19. #19
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2020
    Messages : 11
    Par défaut
    Bon, après passer toute l'après midi à essayer de serais-ce que de me déplacer dans l'image, ça ne fonctionne pas.
    Je ne comprend pas où je merde..

    Mes fonctions pour me déplacer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
        double clamp(double min, double value, double max) {
            double result = Math.max(min, value);
            result = Math.min(result, max);
            return result;
        }
     
        private void handleMousePressed(MouseEvent e) {
            startX = e.getX();
            startY = e.getY();
            //System.out.println("Mousse pressed on : " + startX + " - " + startY);
        }
     
        private void handleMouseDragged(MouseEvent e) {
            double draggedDistanceX = startX - e.getX();
            double draggedDistanceY = startY - e.getY();
            //System.out.println("Drag : " + draggedDistanceX + " - "+ draggedDistanceY);
     
            startX = e.getX();
            startY = e.getY();
     
            double viewWidth = imagePanView.getViewport().getWidth() * 1 / zoom;
            double viewHeight = imagePanView.getViewport().getHeight() * 1 / zoom;
     
            //System.out.println("View W/H : " + viewWidth + " - " + viewHeight);       
            //System.out.println("Clip propriety : " + imagePanView.getClipImage());
     
     
            double curMinX = imagePanView.getViewPortX();
            double curMinY = imagePanView.getViewPortY();
            //System.out.println("Viewport :  " + curMinX + " - " + curMinY);
     
            double newMinX = curMinX + draggedDistanceX;
            double newMinY = curMinY + draggedDistanceY;
     
            //System.out.println("NewMin : " + newMinX + " -- " + newMinY);
            newMinX = clamp(newMinX, 0, Math.max(0, imagePanView.getContent().getImage().getWidth() - viewWidth));
            newMinY = clamp(newMinY, 0, Math.max(0, imagePanView.getContent().getImage().getHeight() - viewHeight));
     
            System.out.println("New : " + newMinY + " " + newMinX);
     
            imagePanView.idontknow(newMinX, newMinY, viewWidth, viewHeight);
            System.out.printf("%f x %f \t %f x %f%n", newMinX, newMinY, imagePanView.getContent().getImage().getWidth(), imagePanView.getContent().getImage().getHeight());
            System.out.println("");
        }
    Et ma classe ImagePanView :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    package historia.visioneuse.utils;
     
    import javafx.beans.property.BooleanProperty;
    import javafx.beans.property.ObjectProperty;
    import javafx.beans.property.SimpleBooleanProperty;
    import javafx.beans.property.SimpleObjectProperty;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.Region;
    import javafx.scene.shape.Rectangle;
     
    public final class ImagePanView extends Region {
        private Rectangle clip = new Rectangle();
        private ImageView content = new ImageView();
        private Region viewport = new Region() {
            {
                getChildren().add(content);
            }
     
            @Override
            protected void layoutChildren() {
                content.resizeRelocate(0, 0, getWidth(), getHeight());
            }
        };
        double viewPortX ;
        double viewPortY ;
        double viewPortW ;
        double viewPortH ;
        double insetsLeft ;
        double insetsRight ;
        double insetsTop ;
        double insetsBot ;
     
     
        public ImagePanView() {
            this(null);
        }
     
        public ImagePanView(final Image image) {
            super();
            System.out.println();
            setId("imagePanView");
            getStyleClass().add("image-pan-view");
            viewport.setId("viewport");
            viewport.getStyleClass().add("viewport");
            content.setId("content");
            content.getStyleClass().add("content");
     
            content.imageProperty().bind(imageProperty());
            viewport.setClip(clip);
            getChildren().addAll(viewport);
            clipImageProperty().addListener((observable, oldValue, newValue) -> viewport.setClip(newValue ? clip : null));
            setImage(image);
        }
     
        public ImageView getContent() {
    		return content;
    	}
     
    	public Region getViewport() {
    		return viewport;
    	}
     
    	public BooleanProperty getClipImage() {
    		return clipImage;
    	}
     
    	public void setClip(Rectangle clip) {
    		this.clip = clip;
    	}
     
    	public double getViewPortX() {
    		return viewPortX;
    	}
     
    	public void setViewPortX(double viewPortX) {
    		this.viewPortX = viewPortX;
    	}
     
    	public double getViewPortY() {
    		return viewPortY;
    	}
     
    	public void setViewPortY(double viewPortY) {
    		this.viewPortY = viewPortY;
    	}
     
    	public double getViewPortW() {
    		return viewPortW;
    	}
     
    	public void setViewPortW(double viewPortW) {
    		this.viewPortW = viewPortW;
    	}
     
    	public double getViewPortH() {
    		return viewPortH;
    	}
     
    	public void setViewPortH(double viewPortH) {
    		this.viewPortH = viewPortH;
    	}
     
    	public void setContent(ImageView content) {
    		this.content = content;
    	}
     
    	public void setViewport(Region viewport) {
    		this.viewport = viewport;
    	}
     
    	@Override
        protected void layoutChildren() {
            super.layoutChildren();
            final double width = getWidth();
            final double height = getHeight();
     
            insetsLeft = getInsets().getLeft();
            insetsRight = getInsets().getRight() ;
            insetsTop = getInsets().getTop();
            insetsBot = getInsets().getBottom();
     
            viewPortX = insetsLeft;
            viewPortY = insetsTop;
            viewPortW = Math.max(0, width - (insetsLeft + insetsRight));
            viewPortH = Math.max(0, height - (insetsTop + insetsBot));
            viewport.resizeRelocate(viewPortX, viewPortY, viewPortW, viewPortH);
            System.out.println("ViewPortX" + viewPortX + " Y : " + viewPortY + "W : " + viewPortW + " H " + viewPortH);
            clip.setWidth(viewPortW);
            clip.setHeight(viewPortH);
        }
     
    	public void idontknow(double newMinX, double newMinY, double viewWidth, double viewHeight) {
    		viewPortX = newMinX;
    	    viewPortY = newMinY;
    	    viewPortW = viewWidth;
    	    viewPortH = viewHeight;
    		viewport.resizeRelocate(newMinX, newMinY, viewWidth, viewHeight);
    	}
        private final ObjectProperty<Image> image = new SimpleObjectProperty<>(this, "image");
     
        public final Image getImage() {
            return image.get();
        }
     
        public void setImage(final Image value) {
            image.set(value);
        }
     
        public ObjectProperty<Image> imageProperty() {
            return image;
        }
     
        private final BooleanProperty clipImage = new SimpleBooleanProperty(this, "clipImage", true);
     
        public final BooleanProperty clipImageProperty() {
            return clipImage;
        }
    }
    Le code est pas propre du tout étant donné que j'ai essayer pas mal de choses.

    PS : Après le déplacement j'ai essayer le zoom mais étant donné que je pense que ça repose sur le même principe j'ai pas mis le code.

  20. #20
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 897
    Billets dans le blog
    54
    Par défaut
    Alors j'ai eut plus de temps pour mieux réfléchir a la chose et me poser tout en simplifiant le code. Bon il reste encore des bugs (entre autre lorsqu'on redimensionne la fenêtre alors que la vue est positionnée sur le bord de l'image, ou lorsqu'on essaie de scroll a haut taux de zoom) et le déplacement est pas toujours smooth (un soucis de JavaFX) mais c'est deja une bonne base. Dans cette version du code, vu que je me repose entièrement sur le calcul de la vue logique (le viewport de l'ImageView).

    A noter l'usage du clip dans l’aperçu sur le coté de la fenêtre : cela est destiné a éviter des micro-déplacements de l'ImageView, lorsque le Group se redimensionne quand le Rectangle est place sur le bord de l'image.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    import javafx.application.Application;
    import javafx.geometry.BoundingBox;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.HBox;
    import javafx.scene.layout.Priority;
    import javafx.scene.shape.Rectangle;
    import javafx.stage.Stage;
     
    import java.util.function.Consumer;
     
    public final class Main extends Application {
        public static void main(final String... args) {
            launch(args);
        }
     
        private Image image;
     
        @Override
        public void init() throws Exception {
            image = new Image(getClass().getResource("04_klein_pipeline_hawaii_march2011_003799.jpg").toExternalForm());
        }
     
        @Override
        public void start(final Stage stage) throws Exception {
            int sideZoom = 10;
            final var sideView = new ImageView();
            sideView.setPreserveRatio(true);
            sideView.setFitWidth(image.getWidth() / sideZoom);
            sideView.setImage(image);
            final var sideViewBounds = new Rectangle();
            sideViewBounds.setStyle("-fx-fill: null; -fx-stroke: yellow;");
            final var sideClip = new Rectangle(0, 0, image.getWidth() / sideZoom, image.getHeight() / sideZoom);
            sideViewBounds.setClip(sideClip);
            final var sideGroup = new Group();
            sideGroup.getChildren().setAll(sideView, sideViewBounds);
            final var imagePanView = new ImagePanView(image);
            HBox.setHgrow(imagePanView, Priority.ALWAYS);
            final var root = new HBox();
            root.setFillHeight(true);
            root.setSpacing(3);
            root.getChildren().setAll(imagePanView, sideGroup);
            final var scene = new Scene(root, 800, 600);
            stage.setScene(scene);
            stage.setTitle("Test");
            stage.show();
            final Consumer<BoundingBox> onNewViewport = box -> {
                final double x = box.getMinX() / sideZoom;
                final double y = box.getMinY() / sideZoom;
                final double w = box.getWidth() / sideZoom;
                final double h = box.getHeight() / sideZoom;
                System.out.printf("%f %f %f %f%n", x, y, w, h);
                sideViewBounds.setX(x);
                sideViewBounds.setY(y);
                sideViewBounds.setWidth(w);
                sideViewBounds.setHeight(h);
     
            };
            imagePanView.viewportProperty().addListener((observable, oldValue, newValue) -> onNewViewport.accept(newValue));
            onNewViewport.accept(imagePanView.getViewport());
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    import javafx.beans.property.*;
    import javafx.geometry.BoundingBox;
    import javafx.geometry.Rectangle2D;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.input.ScrollEvent;
    import javafx.scene.layout.Region;
     
    import java.util.List;
    import java.util.Objects;
     
    public final class ImagePanView extends Region {
        private final ImageView content = new ImageView();
     
        public ImagePanView() {
            this(null);
        }
     
        public ImagePanView(final Image image) {
            super();
            setId("imagePanView");
            getStyleClass().add("image-pan-view");
            content.setId("content");
            content.getStyleClass().add("content");
            content.setPreserveRatio(true);
            content.imageProperty().bind(imageProperty());
            content.setMouseTransparent(true);
            getChildren().addAll(content);
            imageProperty().addListener((observable, oldValue, newValue) -> {
                offsetX = (newValue == null) ? 0 : Math.min(offsetX, newValue.getWidth());
                offsetY = (newValue == null) ? 0 : Math.min(offsetY, newValue.getHeight());
                computeView();
            });
            widthProperty().addListener((observable, oldValue, newValue) -> computeView());
            heightProperty().addListener((observable, oldValue, newValue) -> computeView());
            setImage(image);
            //
            addEventFilter(MouseEvent.MOUSE_PRESSED, this::handleMousePressed);
            addEventFilter(MouseEvent.MOUSE_DRAGGED, this::handleMouseDragged);
            addEventFilter(ScrollEvent.SCROLL, this::handleZoomByScroll);
        }
     
        @Override
        protected void layoutChildren() {
            super.layoutChildren();
            final double width = getWidth();
            final double height = getHeight();
            final var insets = getInsets();
            final double insetsLeft = insets.getLeft();
            final double insetsRight = insets.getRight();
            final double insetsTop = insets.getTop();
            final double insetsBot = insets.getBottom();
            final double viewPortX = insetsLeft;
            final double viewPortY = insetsTop;
            final double viewPortW = Math.max(0, width - (insetsLeft + insetsRight));
            final double viewPortH = Math.max(0, height - (insetsTop + insetsBot));
            content.setLayoutX(viewPortX);
            content.setLayoutY(viewPortY);
            content.setFitWidth(viewPortW);
            content.setFitHeight(viewPortH);
        }
     
        private static final BoundingBox EMPTY_BOUNDS = new BoundingBox(0, 0, 0, 0);
        private static final Rectangle2D EMPTY_CONTENT_VIEWPORT = new Rectangle2D(0, 0, 0, 0);
     
        private void computeView() {
            System.out.println("computeView()");
            final var image = getImage();
            if (Objects.isNull(image)) {
                viewport.set(EMPTY_BOUNDS);
                content.setViewport(EMPTY_CONTENT_VIEWPORT);
                return;
            }
            final double width = getWidth();
            final double height = getHeight();
            final var insets = getInsets();
            final double insetsLeft = insets.getLeft();
            final double insetsRight = insets.getRight();
            final double insetsTop = insets.getTop();
            final double insetsBot = insets.getBottom();
            final double viewPortX = insetsLeft;
            final double viewPortY = insetsTop;
            final double viewPortW = Math.max(0, width - (insetsLeft + insetsRight));
            final double viewPortH = Math.max(0, height - (insetsTop + insetsBot));
            if (viewPortW == 0 || viewPortH == 0) {
                viewport.set(EMPTY_BOUNDS);
                content.setViewport(EMPTY_CONTENT_VIEWPORT);
                return;
            }
            final double zoom = getZoom();
            final double imageW = image.getWidth();
            final double imageH = image.getHeight();
            final double viewX = clamp(0, offsetX, image.getWidth());
            final double viewY = clamp(0, offsetY, image.getHeight());
            final double viewW = Math.min(imageW - viewX, viewPortW / zoom);
            final double viewH = Math.min(imageH - viewY, viewPortH / zoom);
            final var oldViewport = getViewport();
            if (oldViewport.isEmpty() || oldViewport.getMinX() != viewX || oldViewport.getMinY() != viewY || oldViewport.getWidth() != viewW || oldViewport.getHeight() != viewH) {
                viewport.set(new BoundingBox(viewX, viewY, viewW, viewH));
                content.setViewport(new Rectangle2D(viewX, viewY, viewW, viewH));
            }
        }
     
        private final ObjectProperty<Image> image = new SimpleObjectProperty<>(this, "image");
     
        public final Image getImage() {
            return image.get();
        }
     
        public final void setImage(final Image value) {
            image.set(value);
        }
     
        public final ObjectProperty<Image> imageProperty() {
            return image;
        }
     
        private final ReadOnlyObjectWrapper<BoundingBox> viewport = new ReadOnlyObjectWrapper<>(this, "viewport", EMPTY_BOUNDS);
     
        public final BoundingBox getViewport() {
            return viewport.get();
        }
     
        public final ReadOnlyObjectProperty<BoundingBox> viewportProperty() {
            return viewport.getReadOnlyProperty();
        }
     
        private double clamp(double min, double value, double max) {
            double result = Math.max(min, value);
            result = Math.min(result, max);
            return result;
        }
     
        private double offsetX;
        private double offsetY;
     
        private final ReadOnlyDoubleWrapper zoom = new ReadOnlyDoubleWrapper(this, "zoom", 1);
     
        public final double getZoom() {
            return zoom.get();
        }
     
        public final void setZoom(final double value) {
            if (value > 0) {
                zoom.set(value);
                computeView();
            }
        }
     
        public final ReadOnlyDoubleProperty zoomProperty() {
            return zoom.getReadOnlyProperty();
        }
     
        private double startX;
        private double startY;
     
        private void handleMousePressed(final MouseEvent event) {
            startX = event.getX();
            startY = event.getX();
        }
     
        private void handleMouseDragged(final MouseEvent event) {
            final var image = getImage();
            if (image == null) {
                return;
            }
            final double zoom = getZoom();
            final double rawDragX = startX - event.getX();
            final double rawDragY = startY - event.getY();
            startX = event.getX();
            startY = event.getY();
            final double dragX = rawDragX / zoom;
            final double dragY = rawDragY / zoom;
            System.out.printf("DRAG %f %f%n", dragX, dragY);
            final var viewport = getViewport();
            final double newOffsetX = clamp(0, offsetX + dragX, image.getWidth() - viewport.getWidth());
            final double newOffsetY = clamp(0, offsetY + dragY, image.getHeight() - viewport.getWidth());
            System.out.printf("%f -> %f%n", offsetX, newOffsetX);
            System.out.printf("%f -> %f%n", offsetY, newOffsetY);
            offsetX = newOffsetX;
            offsetY = newOffsetY;
            computeView();
        }
     
        final List<Double> ZOOM_FACTORS = List.of(0.25, 0.5, 1d, 2d, 4d, 8d, 16d);
     
        private void handleZoomByScroll(final ScrollEvent event) {
            final double deltaY = event.getDeltaY();
            final double oldZoom = getZoom();
            int zoomIndex = ZOOM_FACTORS.indexOf(oldZoom);
            // User provided zoom.
            if (zoomIndex < 0) {
                zoomIndex = ZOOM_FACTORS.stream()
                        .filter(value -> value < oldZoom)
                        .findFirst()
                        .map(ZOOM_FACTORS::indexOf)
                        .orElse(0);
            }
            int newZoomIndex = zoomIndex + ((deltaY > 0) ? -1 : 1);
            newZoomIndex = (int) clamp(0, newZoomIndex, ZOOM_FACTORS.size() - 1);
            final double zoom = ZOOM_FACTORS.get(newZoomIndex);
            setZoom(zoom);
        }
    }
    Nom : test.jpg
Affichages : 846
Taille : 146,6 Ko
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 13
    Dernier message: 23/12/2004, 18h01
  2. Problème de réaffichage d'image
    Par benj63 dans le forum C++Builder
    Réponses: 2
    Dernier message: 09/12/2004, 09h41
  3. [débutant] problème de lecture d'image
    Par shura dans le forum OpenGL
    Réponses: 16
    Dernier message: 03/07/2004, 18h05
  4. Problème de nb d'images par seconde
    Par Francky033 dans le forum DirectX
    Réponses: 7
    Dernier message: 17/04/2004, 10h37
  5. Problème de mémoire Affichage images
    Par Repti dans le forum C++Builder
    Réponses: 6
    Dernier message: 29/03/2004, 20h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo