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

AWT/Swing Java Discussion :

Adapter une police avant une exportation en image d'un JPanel


Sujet :

AWT/Swing Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Homme Profil pro
    Etudiant
    Inscrit en
    Janvier 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Etudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 9
    Par défaut Adapter une police avant une exportation en image d'un JPanel
    Bonjour à tous !

    J'ai effectué des recherches mais les solutions que je trouvais n'étaient soit pas adaptées à mon problème, soit je les appliquais mal ^^"

    Dans le cadre d'une reprise d'un projet, je dois mettre à jour l'application afin d'améliorer l'ergonomie. Pour faire une rapide présentation, l'application permet de créer des schémas à partir de composants Swing, et il est possible d'exporter ce schéma sous forme d'image au format PNG. De plus, il est possible de "zoomer" sur ce schéma (depuis l'application) en modifiant la taille de la police des composants (on a alors un effet de zoom puisque les composants adaptent leur taille selon la taille de leur contenu). Le problème était que lors de l'export en image du schéma (c'est un JPanel), l'image générée prenait en compte le "zoom" (c'est problématique surtout si la taille de la police était très petite).

    J'ai alors essayé d'imposer une taille au schéma juste avant le traitement d'exportation en image, puis à la suite de ce traitement, de rétablir la taille d'origine.

    Le code suivant illustre de manière simplifiée cette étape du projet :

    MainPanel.java (JPanel principal)
    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
     
    public class MainPanel extends JPanel {
     
    	private JFrame parent;
     
    	/**
             * Construit le panneau principal de l'application (MainPanel)
             * 
             * @param parent
             */
    	public MainPanel(JFrame parent) {
    		// initialisation du layout manager
    		this.setLayout(new FlowLayout());
    		this.parent = parent;
     
    		// mise en place des composants
    		init();
     
    		// initialisation de la police
    		this.setFont(new Font("Arial", Font.PLAIN, 40));
    	}
     
    	/**
             * Met en place les composants dans le JPanel
             */
    	private void init() {
    		// panel 1
    		PanelBis p1 = new PanelBis("Bouton 1", "Label 1");
    		this.add(p1);
     
    		// panel 2
    		PanelBis p2 = new PanelBis("Bouton 2", "Label 2");
    		this.add(p2);
     
    		// bouton et label
    		this.add(new JButton("Bouton principal"));
    		this.add(new JLabel("Label principal"));
     
    	}
     
    	/*
    	 * (non-Javadoc) 
    	 * Lors de l'initialisation d'une police sur un MainPanel,
    	 * application de la police sur tous ses sous-composants
    	 * 
    	 * @see javax.swing.JComponent#setFont(java.awt.Font)
    	 */
    	@Override
    	public void setFont(Font font) {
    		super.setFont(font);
    		// pour chaque sous-composant du MainPanel, appliquer la nouvelle police
    		for (Component c : this.getComponents())
    			c.setFont(font);
    	}
     
    	/**
             * Exporte en image le MainPanel
             */
    	public void exporterImage() {
    		String nomFich = ".";
    		Dimension size = this.getSize();
    		System.out.println("Dimension : " + size.width + " x " + size.height);
     
    		// récupère la police utilisé actuellement
    		Font font = this.getFont();
     
    		// applique une police avec une taille de 40 pour l'exportation en image
    		this.setFont(new Font(font.getFontName(), font.getStyle(), 40));
     
    		// sauvegarde le MainPanel dans un fichier sous forme d'image au format PNG
    		this.saveAsPNG(this, nomFich);
     
    		// réinitialise la police d'origine sur le MainPanel
    		this.setFont(font);
    	}
     
    	@Override
    	protected void paintComponent(Graphics g) {
    		super.paintComponent(g);
    	}
     
    	/**
             * Sauvegarde le MainPanel dans un fichier sous forme d'image au format PNG
             * 
             * @param component
             * @param filename
             */
    	void saveAsPNG(Component component, String filename) {
    		try {
    			// initialisation d'un BufferedImage à partir des dimensions du
    			// composant passé en paramètre (pour un JPanel par exemple)
    			Dimension d = component.getSize();
    			BufferedImage bimage = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_RGB);
    			component.paint(bimage.createGraphics());
    			// si le nom du fichier ne se termine pas par l'extension .png,
    			// l'ajouter
    			if (!filename.endsWith(".png"))
    				filename += ".png";
     
    			// ecrit dans l'output l'image "bimage" au format png
    			File output = new File(filename);
    			ImageIO.write(bimage, "png", output);
     
    		} catch (Exception excep) {
    			excep.printStackTrace();
    		}
    	}
     
    }
    PanelBis.java (JPanel secondaire)
    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
     
    public class PanelBis extends JPanel {
     
    	private JLabel l;
    	private JButton b;
     
    	public PanelBis() {
    		this("b","l");
    	}
     
    	public PanelBis(String bTitle, String lTitle) {
    		// initialisation du LayoutManager
    		this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
     
    		b = new JButton(bTitle);
    		b.setBackground(Color.WHITE);
    		this.add(b);
     
    		l = new JLabel(lTitle);
    		this.add(l);
     
    		this.setFont(new Font("Serial", Font.PLAIN, 12));
    	}
     
    	public void setButtonTitle(String title) {
    		this.b.setText(title);
    	}
     
    	public void setLabelTitle(String title) {
    		this.l.setText(title);
    	}
     
    	@Override
    	protected void paintComponent(Graphics g) {
    		super.paintComponent(g);
    		System.out.println("paintComponent Bis");
    	}
     
     
     
    }
    Fenetre.java (JFrame avec un main)
    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
     
            private MainPanel mainPanel;
    	private ArrayList<Font> fonts;
    	private int i;
     
    	public Fenetre(String title) {
            ...
     
     
    		// bouton pour exporter en image
    		JMenuItem itemExportImage = new JMenuItem("Exporter en image");
    		itemExportImage.addActionListener(new ActionListener() {
    			@Override
    			public void actionPerformed(ActionEvent arg0) {
    				Fenetre.this.mainPanel.exporterImage();
    			}
    		});
     
     
            ...
     
    		// bouton pour changer de police (zoom)
    		JMenuItem itemChangeFont = new JMenuItem("Changer de police");
    		itemChangeFont.addActionListener(new ActionListener() {
    			@Override
    			public void actionPerformed(ActionEvent arg0) {
    				// change la taille de la police du MainPanel
    				Fenetre.this.mainPanel.setFont(Fenetre.this.getNext());
    			}
    		});
     
            ...
     
    	}
     
            /**
             * Charge plusieurs polices dans la liste des polices
             */
    	private void loadFonts() {
    		this.fonts.add(new Font("Arial", Font.PLAIN, 40));
    		this.fonts.add(new Font("Arial", Font.PLAIN, 20));
    		this.fonts.add(new Font("Arial", Font.PLAIN, 10));
    	}
     
    	/**
             * Retourne la police suivante dans la liste des polices
             * @return
             */
    	private Font getNext() {
    		i++;
    		return this.fonts.get(i%this.fonts.size());
    	}
     
    	public static void main(String[] args) {
    		Fenetre f = new Fenetre("Test police");
    	}
    Par défaut, la taille de la police est de 40 (c'est gros j'avoue mais c'est pour les tests ^^) et un bouton permet de modifier la police directement sur l'application (la taille alterne entre 10, 20 et 40). J'ai souhaité que si j'avais initialisé une taille à 10 et que je cliquais sur le bouton pour exporter en image :
    • la police 10 était enregistrer dans une variable
    • on applique la police 40 sur le JPanel principal
    • on effectue le traitement d'export en image
    • on réapplique une police de 10 au JPanel principal


    Le problème est que l'image obtenue est "tronquée" : c'est comme si la taille du texte avait bien été agrandie à 40, mais que la taille des boutons ne s'était pas adaptée. J'ai essayé d'appeler la méthode repaint() à chaque fois que je modifiais la police mais ça ne changeait rien
    Nom : ..png
Affichages : 115
Taille : 1,3 Ko
    Je pense que le problème vient du fait que le JPanel ne se rafraîchisse pas correctement entre le moment où j'applique un changement de police et le moment où je réalise l'export (même si j'appelais repaint()). A noter que si je ne faisais pas le changement de police dans la méthode exporterImage() de la classe MainPanel, l'export se passait très bien peu importe le zoom que j'appliquais.

    Autre chose que j'ai remarqué, en plaçant des sysout un peu partout dans le programme, lorsque j'appelais la méthode repaint() explicitement, cela ne faisait pas tout de suite appel à la méthode paintComponent() (que j'ai essayé de redéfinir en plaçant un sysout dedans pour voir si elle était appelée). Du coup, même en faisant un repaint() entre le changement de police et l'export en image, paintComponent() n'était pas appelé entre les deux. Je me dis donc que le rafraîchissement n'a effectivement pas eu lieu au moment voulu.

    Donc ma question est de savoir si il y a un moyen de rafraîchir le JPanel au milieu du traitement ? Ou s'il faut résoudre le problème autrement ?

    En espérant avoir été clair :s et en vous remerciant de votre aide

    N'hésitez pas à poser des questions si je n'ai pas été assez clair

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Salut,

    En plus de repaint(), fais revalidate() juste avant.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre habitué
    Homme Profil pro
    Etudiant
    Inscrit en
    Janvier 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Etudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 9
    Par défaut
    Salut, j'ai essayé de placer un repaint() et le revalidate comme ceci :

    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
     
    /**
             * Exporte en image le MainPanel
             */
    	public void exporterImage() {
    		...
     
    		// récupère la police utilisé actuellement
    		Font font = this.getFont();
     
            	repaint();
    		revalidate();
     
    		// applique une police avec une taille de 18
    		this.setFont(new Font(font.getFontName(), font.getStyle(), 40));
     
    		// sauvegarde le MainPanel dans un fichier sous forme d'image au format PNG
    		this.saveAsPNG(this, nomFich);
     
    		...
    	}
    Mais j'obtient toujours l'image tronquée

    J'ai essayé de faire passer tout d'abord le revalidate() avant le repaint(), ou encore d'appeler le repaint() et le revalidate() du composant parent (je sais pas si ça change quelque chose) mais j'ai le même résultat

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Il faut le faire après avoir changé la police :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     
    // applique une police avec une taille de 18
    this.setFont(new Font(font.getFontName(), font.getStyle(), 40));
     
    repaint();
    revalidate();
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre habitué
    Homme Profil pro
    Etudiant
    Inscrit en
    Janvier 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Etudiant

    Informations forums :
    Inscription : Janvier 2016
    Messages : 9
    Par défaut
    Oops j'ai donné le mauvais code ^^"
    J'ai effectivement placé repaint() et revalidate() après avoir changé la police sans changement.

    J'ai effectué d'autres tests à côté pour voir si les méthodes paint() et paintComponent() du JPanel étaient appelées tout de suite lorsque l'on appelait repaint() et revalidate() :

    Fenetre.java (contient le main)
    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
     
    public class Fenetre extends JFrame {
     
    	public Fenetre(String title) {
    		this.setTitle(title);
    		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
    		// initialise le JPanel dans le JFrame
    		Vue vue = new Vue();
    		System.out.println("a");
    		this.getContentPane().add(vue);
    		System.out.println("b");
     
    		// affiche le JFrame
    		this.pack();
    		this.setLocationRelativeTo(null);
    		this.setVisible(true);
    		System.out.println("c");
     
    		// appel aux méthodes repaint() et revalidate de du JPanel
    		this.repaint();
    		this.revalidate();
    	}
     
    	public static void main(String[] args) {
    		Fenetre f = new Fenetre("test paintComponent");
    		System.out.println("d");
    	}
     
    }
    Vue.java (JPanel principal)
    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
     
    public class Vue extends JPanel {
     
    	public Vue() {
    		// initialisation du layout manager
    		this.setLayout(new FlowLayout());
     
    		// initialisation des composants
    		init();
     
    	}
     
    	private void init() {
    		this.add(new JButton("Bouton 1"));
    		this.add(new JLabel("Label 1"));
    		this.add(new JButton("Bouton 2"));
    		this.add(new JLabel("Label 2"));
    	}
     
    	@Override
    	public void paint(Graphics g) {
    		System.out.println("paint");
    		super.paint(g);
    	}
     
    	@Override
    	protected void paintComponent(Graphics g) {
    		System.out.println("paintComponent");
    		super.paintComponent(g);
    	}
     
    }
    J'ai placé des sysout pour voir à quel moment était appelé les méthodes paint() et paintComponent(), et même si je faisais des appels avec repaint() et revalidate(), les 2 premières méthodes n'étaient appelées qu'à la fin de l'exécution du traitement en entier :

    Résutat de la console
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    a
    b
    c
    d
    paint
    paintComponent

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Tehemou Voir le message
    J'ai placé des sysout pour voir à quel moment était appelé les méthodes paint() et paintComponent(), et même si je faisais des appels avec repaint() et revalidate(), les 2 premières méthodes n'étaient appelées qu'à la fin de l'exécution du traitement en entier :
    Ah bah oui c'est normal, ton code s'exécute dans l'Event Dispatch Thread ([Edit] je me disais aussi qu'il n'était pas nécessaire de faire explicitement de revalidate()/repaint() sur un setFont()). Donc tous les ordres que tu fais ont lieu après la fin de l'exécution de ce code. Cela devient complexe et je me demande s'il ne serait pas plus simple de faire un mode impression plutôt que de faire de la copie d'écran (je n'utilise jamais ce système parce que ce n'est pas très beau et très contraint), surtout que cette bidouille a un effet sur l'affichage dans ton cas, pas que sur l'impression.
    Il va falloir que tu exécutes ton code en dehors de l'EDT tout en synchronisant les aspect graphique dans l'EDT... soit enchaîner au moins 1 invokeLater après le setFont().
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 7
    Dernier message: 25/03/2011, 10h52
  2. [XL-2002] Macro de comparaison d'une cellule d'une feuille avec une cellule d'une autre feuille.
    Par steelydan dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 08/09/2010, 12h59
  3. Réponses: 4
    Dernier message: 15/10/2009, 13h33
  4. [XL-2007] Afficher une checkbox dans une feuille si une checkbox d'une autre feuille est cochée
    Par JessieCoutas dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 18/08/2009, 13h35
  5. Recherche une valeur d'une cellule dans une colonne d'une autre feuille
    Par kourria dans le forum Macros et VBA Excel
    Réponses: 8
    Dernier message: 21/06/2007, 13h48

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