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)
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
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(); } } }
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 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"); } }
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 :
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"); }
- 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
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![]()
Partager