reglage du bug save

This commit is contained in:
AlgaLaptop
2025-12-30 21:25:46 +01:00
parent f6f0eca79f
commit 2e0f44d28d
27 changed files with 239 additions and 79 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+63 -45
View File
@@ -30,8 +30,9 @@ all: \
# Compilation des classes main
$(BIN)/$(PKG_PATH)/Convertisseur.class: $(BIN) \
$(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class \
$(BIN)/$(PKG_PATH)/ConverterController.class \
$(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class \
$(BIN)/$(PKG_PATH)/ExportButtonListener.class \
$(SRC)/$(PKG_PATH)/Convertisseur.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/Convertisseur.java
@@ -46,86 +47,103 @@ $(BIN):
$(DOC):
mkdir -p $(DOC)
#Compilation des classe de mhuffman
# Compilation des classes util
$(BIN)/$(PKG_PATH)/util/ByteUtils.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/ByteUtils.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/ByteUtils.java
$(BIN)/$(PKG_PATH)/util/BitInputStream.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/BitInputStream.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/BitInputStream.java
$(BIN)/$(PKG_PATH)/util/BitOutputStream.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/BitOutputStream.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/BitOutputStream.java
# Compilation des classes mhuffman
$(BIN)/$(PKG_PATH)/mhuffman/CanonicalCode.class: $(BIN) \
$(SRC)/$(PKG_PATH)/mhuffman/CanonicalCode.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/CanonicalCode.java
$(BIN)/$(PKG_PATH)/mhuffman/FrequencyTable.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mimage/RGBImage.class \
$(SRC)/$(PKG_PATH)/mhuffman/FrequencyTable.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/FrequencyTable.java
$(BIN)/$(PKG_PATH)/mhuffman/HuffmanTree.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mhuffman/HuffmanNode.class \
$(BIN)/$(PKG_PATH)/mhuffman/HuffmanTree.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/HuffmanTree.java
$(BIN)/$(PKG_PATH)/mhuffman/HuffmanNode.class: $(BIN) \
$(SRC)/$(PKG_PATH)/mhuffman/HuffmanNode.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/HuffmanNode.java
$(BIN)/$(PKG_PATH)/mhuffman/HuffmanTree.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mhuffman/HuffmanNode.class \
$(SRC)/$(PKG_PATH)/mhuffman/HuffmanTree.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/HuffmanTree.java
# Compilation des classes mimage
$(BIN)/$(PKG_PATH)/mimage/Pixel.class: $(BIN) \
$(SRC)/$(PKG_PATH)/mimage/Pixel.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mimage/Pixel.java
# Compilation des classe mimages
$(BIN)/$(PKG_PATH)/mimage/RGBImage.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mimage/Pixel.class \
$(SRC)/$(PKG_PATH)/mimage/RGBImage.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mimage/RGBImage.java
$(BIN)/$(PKG_PATH)/mimage/Pixel.class: $(BIN) \
$(SRC)/$(PKG_PATH)/mimage/Pixel.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mimage/Pixel.java
#Compilation de l'interface graphique je compile converterWindow
$(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class: $(BIN) \
$(BIN)/$(PKG_PATH)/vconverter/ImagePreviewPanel.class \
$(BIN)/$(PKG_PATH)/vconverter/FrequencyTablePanel.class \
$(BIN)/$(PKG_PATH)/vconverter/CodeTablePanel.class \
$(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java
# ConverterWindow dépend des autres classes je les compile aussi
# Interface graphique
$(BIN)/$(PKG_PATH)/vconverter/ImagePreviewPanel.class: $(BIN) \
$(SRC)/$(PKG_PATH)/vconverter/ImagePreviewPanel.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/ImagePreviewPanel.java
$(BIN)/$(PKG_PATH)/vconverter/FrequencyTablePanel.class: $(BIN) \
$(SRC)/$(PKG_PATH)/vconverter/FrequencyTablePanel.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/FrequencyTablePanel.java
$(BIN)/$(PKG_PATH)/vconverter/CodeTablePanel.class: $(BIN) \
$(SRC)/$(PKG_PATH)/vconverter/CodeTablePanel.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/CodeTablePanel.java
# $(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class: $(BIN) \
# $(BIN)/$(PKG_PATH)/ConverterController.class \
# $(BIN)/$(PKG_PATH)/vconverter/ImagePreviewPanel.class \
# $(BIN)/$(PKG_PATH)/vconverter/FrequencyTablePanel.class \
# $(BIN)/$(PKG_PATH)/vconverter/CodeTablePanel.class \
# $(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java
# $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java
# Compilation des classes mpif
# Compilation PIFWriter
$(BIN)/$(PKG_PATH)/mpif/PIFWriter.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mimage/RGBImage.class \
$(SRC)/$(PKG_PATH)/util/BitOutputStream.class \
$(BIN)/$(PKG_PATH)/util/BitOutputStream.class \
$(SRC)/$(PKG_PATH)/mpif/PIFWriter.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mpif/PIFWriter.java
# Compilation du controleur
$(BIN)/$(PKG_PATH)/ConverterController.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mimage/Pixel.class \
$(BIN)/$(PKG_PATH)/mimage/RGBImage.class \
$(BIN)/$(PKG_PATH)/mhuffman/FrequencyTable.class \
$(BIN)/$(PKG_PATH)/mhuffman/CanonicalCode.class \
$(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class \
$(SRC)/$(PKG_PATH)/ConverterController.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/ConverterController.java
#Compilation des classes util
$(BIN)/$(PKG_PATH)/util/ByteUtils.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/ByteUtils.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/ByteUtils.java
$(BIN)/$(PKG_PATH)/util/BitInputStream.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/BitInputStream.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/BitInputStream.java
$(BIN)/$(PKG_PATH)/util/BitOutputStream.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/BitOutputStream.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/BitOutputStream.java
# GROSSE compilation du listener + ConvertController + ConvertWindow car il y a une dependance cirulaire
$(BIN)/$(PKG_PATH)/ConverterController.class \
$(BIN)/$(PKG_PATH)/ExportButtonListener.class \
$(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class: \
$(SRC)/$(PKG_PATH)/ConverterController.java \
$(SRC)/$(PKG_PATH)/ExportButtonListener.java \
$(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java \
$(BIN)/$(PKG_PATH)/mimage/Pixel.class \
$(BIN)/$(PKG_PATH)/mimage/RGBImage.class \
$(BIN)/$(PKG_PATH)/mhuffman/FrequencyTable.class \
$(BIN)/$(PKG_PATH)/mhuffman/HuffmanTree.class \
$(BIN)/$(PKG_PATH)/mhuffman/CanonicalCode.class \
$(BIN)/$(PKG_PATH)/vconverter/ImagePreviewPanel.class \
$(BIN)/$(PKG_PATH)/vconverter/FrequencyTablePanel.class \
$(BIN)/$(PKG_PATH)/vconverter/CodeTablePanel.class \
$(BIN)/$(PKG_PATH)/mpif/PIFWriter.class | $(BIN)
@$(JAVAC) -cp $(BIN) -d $(BIN) \
$(SRC)/$(PKG_PATH)/ConverterController.java \
$(SRC)/$(PKG_PATH)/ExportButtonListener.java \
$(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java
# Exécution
+75 -11
View File
@@ -1,15 +1,14 @@
package fr.iutfbleau.sae;
import fr.iutfbleau.sae.mhuffman.CanonicalCode;
import fr.iutfbleau.sae.mhuffman.FrequencyTable;
import fr.iutfbleau.sae.mhuffman.HuffmanTree;
import fr.iutfbleau.sae.mimage.Pixel;
import fr.iutfbleau.sae.mimage.RGBImage;
import fr.iutfbleau.sae.mhuffman.*;
import fr.iutfbleau.sae.mimage.*;
import fr.iutfbleau.sae.mpif.PIFWriter;
import fr.iutfbleau.sae.vconverter.ConverterWindow;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
/**
* Contrôleur pour la conversion d'images.
@@ -39,17 +38,21 @@ public class ConverterController {
// La fenêtre du convertisseur
private ConverterWindow fen;
public ConverterController(ConverterWindow fen) {
String outputPath;
String inputPath;
public ConverterController(ConverterWindow fen, String in, String out) {
this.fen = fen;
this.outputPath = out;
this.inputPath = in;
}
// charger une image depuis un fichier avec bufferedImage et la convertir en RGBImage
public void loadImage(String filepath) {
File FI = new File(filepath);
public void loadImage(File file) {
try{
// Lire l'image avec BufferedImage
BufferedImage buffimage = ImageIO.read(FI);
BufferedImage buffimage = ImageIO.read(file);
if (buffimage == null) {
throw new IllegalArgumentException("Le fichier spécifié n'est pas une image valide.");
}
@@ -134,9 +137,7 @@ public class ConverterController {
}
public void saveAsPIF(String pathfile) {
// je Vérifie que l'image et les codes canoniques sont disponibles
if(this.image == null || this.canonRED == null){
System.err.println("Impossible d'ecrire le fichier PIF : données manquantes.");
@@ -151,6 +152,69 @@ public class ConverterController {
}
}
public void saveViaBtn() {
try {
if (outputPath != null) {
saveAsPIF(outputPath);
System.out.println("Sauvegarde dans : " + outputPath);
return;
}
// Sinon JFileChooser
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Enregistrer le fichier .pif");
if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
saveAsPIF(chooser.getSelectedFile().getAbsolutePath());
System.out.println("Fichier sauvegardé : " + chooser.getSelectedFile().getAbsolutePath());
JOptionPane.showMessageDialog(null, "Fichier sauvegardé avec succès : " + chooser.getSelectedFile().getName());
}
System.out.println("Via BTN Sauvegarde terminée.");
} catch (Exception ex) {
System.out.println("Erreur lors de la sauvegarde : " + ex.getMessage());
ex.printStackTrace();
}
}
public void StartconvessionProcess(){
// chragement
if (this.inputPath != null) {
// Chargement direct depuis les arguments
File file = new File(inputPath);
this.loadImage(file);
}else{
// Sinon JFileChooser pour choisir l'image
JFileChooser choosser =new JFileChooser();
choosser.setDialogTitle("Choisissez une image");
if (choosser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
this.loadImage(choosser.getSelectedFile());
}else {
System.err.println("Aucune image choisie. Arrêt du programme.");
return;
}
}
// je place la logique de conversion dans lordre
computeFrequencies();
computeHuffman();
computeCanonical();
// Sauvegarder: un second argument est donné sauvegarde automatique
if (this.outputPath != null) {
this.saveAsPIF(this.outputPath);
System.out.println("Fichier sauvegardé automatiquement : " + this.outputPath);
}else{
// pas de deuxième argument j'ajoute un boutton pour choisir avec un jfilechoser
fen.addSaveButton(this);
}
}
public RGBImage getImage(){
return this.image;
}
+10 -18
View File
@@ -1,15 +1,13 @@
package fr.iutfbleau.sae;
import fr.iutfbleau.sae.vconverter.ConverterWindow;
public class Convertisseur {
public static void main(String[] args) {
// Créer et stocker la référence à la fenêtre
ConverterWindow window = new ConverterWindow();
// je la passe au controleur
ConverterController controller = new ConverterController(window);
// chemins de l'image
String inpuPath;
String outputPath;
String inpuPath = null;
String outputPath = null;
if (args.length >= 1) {
inpuPath = args[0];
}
@@ -17,17 +15,11 @@ public class Convertisseur {
outputPath = args[1];
}
// je charge l'image
controller.loadImage(testIMG);
// je place la logique de conversion dans lordre
controller.computeFrequencies();
controller.computeHuffman();
controller.computeCanonical();
if (condition) {
}
// Créer et stocker la référence à la fenêtre
ConverterWindow window = new ConverterWindow();
// je la passe au controleur
ConverterController controller = new ConverterController(window, inpuPath, outputPath);
controller.StartconvessionProcess();
}
}
@@ -0,0 +1,16 @@
package fr.iutfbleau.sae;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ExportButtonListener implements ActionListener {
private ConverterController controller;
public ExportButtonListener(ConverterController controller){
this.controller = controller;
}
@Override
public void actionPerformed(ActionEvent e){
controller.saveViaBtn();
}
}
@@ -4,7 +4,7 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// test
/**
* Implémente un arbre de Huffman utilisé pour la compression de données.
@@ -1,9 +1,12 @@
package fr.iutfbleau.sae.vconverter;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Map;
import java.awt.*;
import javax.swing.*;
import fr.iutfbleau.sae.ConverterController;
import fr.iutfbleau.sae.ExportButtonListener;
/**
* Fenêtre principale du convertisseur.
*
@@ -41,7 +44,9 @@ public class ConverterWindow extends JFrame {
this.setSize(900, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null); // Centre la fenêtre
this.setResizable(true); // on autorise le resize
this.setResizable(true); // on autorise le
this.setLayout(new BorderLayout());
// Initialisation des panels
@@ -78,8 +83,8 @@ public class ConverterWindow extends JFrame {
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.getVerticalScrollBar().setUnitIncrement(16); // scroll plus adouci fluide
this.add(scrollPane);
this.setVisible(true); // toi meme tu sais
this.add(scrollPane, BorderLayout.CENTER);
this.setVisible(true);
}
@@ -133,4 +138,24 @@ public class ConverterWindow extends JFrame {
Map<Integer, String> codesBleu) {
codeTablePanel.updateCanonicalCodes(codesRouge, codesVert, codesBleu);
}
public void addSaveButton(ConverterController controller) {
JButton saveBtn = new JButton("Exporter en .pif");
ExportButtonListener ecouteur =new ExportButtonListener(controller);
saveBtn.addActionListener(ecouteur);
// panneau du bas
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
bottomPanel.add(saveBtn);
// ajoute au bas de la fenêtre
this.add(bottomPanel, BorderLayout.SOUTH);
// rafraîchir l'affichage
this.revalidate();
this.repaint();
}
}
+45
View File
@@ -0,0 +1,45 @@
Learning log – Problème de blocage de la fenêtre après la sauvegarde:
Après avoir implémenté la fonctionnalité d’export au format PIF depuis l’interface du convertisseur,
j’ai rencontré un problème important : une fois que je cliquais sur le bouton d’exportation,
la fenêtre se figeait complètement. Elle restait visible, mais impossible à fermer ou à interagir avec.
Le programme semblait bloqué.
En analysant le comportement et en utilisant des impressions de debug, j’ai constaté que le blocage n’était pas lié à l’écriture du
fichier ni à la logique du convertisseur, mais bien à un problème de gestion des threads dans Swing.
Swing repose sur un fonctionnement particulier : toute l’interface graphique est gérée par un seul thread dédié,
appelé l’Event Dispatch Thread (EDT). Ce thread est responsable de tout ce qui concerne l’interface utilisateur :
la gestion des clics, le rafraîchissement de la fenêtre, la fermeture, le dessin et l’affichage en général.
Tant que ce thread tourne correctement, l’application reste réactive.
L’EDT ne démarre réellement qu’après l’appel à la méthode permettant d’afficher la fenêtre. À partir de ce moment,
toutes les opérations qui modifient l’interface devraient strictement être exécutées sur ce thread.
C’est une règle fondamentale pour éviter les blocages.
En examinant mon programme, je me suis rendu compte que le problème venait de la manière dont j’avais structuré mon point d’entrée.
Mon programme principal créait la fenêtre, le contrôleur, puis lançait immédiatement tout le processus de conversion,
qui incluait le chargement du fichier image, le calcul des fréquences, la construction des arbres de Huffman,
la génération des codes canoniques, et éventuellement l’écriture du fichier PIF.
Ce sont des opérations potentiellement longues et qui se déroulaient sur le thread principal,
avant même que l’EDT ne prenne le relais pour gérer l’interface.
Cela avait deux conséquences. D'abord, la fenêtre pouvait parfois être affichée trop tard ou de manière irrégulière.
Ensuite, après l’export, Swing se retrouvait dans un état instable, puisque certaines opérations graphiques avaient été réalisées
hors du thread dédié.
C’est exactement ce qui provoquait le gel de l’interface : une fois le fichier enregistré, la fenêtre ne répondait plus car
l’EDT était bloqué ou interrompu, empêchant toute interaction, y compris la fermeture de la fenêtre.
Une fois le problème identifié, les solutions étaient claires. Il fallait s’assurer que toutes les opérations qui touchent
a l’interface graphique soient exécutées sur l’Event Dispatch Thread. Cela signifie que toute interaction, y compris l’ouverture
d’un sélecteur de fichiers, doit obligatoirement être déclenchée dans ce contexte. De plus, il fallait veiller à ne pas exécuter
de longues opérations synchrones avant le démarrage complet de l’EDT.
La solution consiste donc à déléguer l’appel du processus de conversion au thread graphique, en utilisant le mécanisme fourni par
Swing pour garantir que le code s’exécute sur l’EDT. Une autre possibilité serait d’exécuter les opérations lourdes dans un thread en
arrière-plan pour éviter de bloquer l’interface, mais dans tous les cas le respect strict de la séparation entre traitements et interface
est essentiel.
Grâce à cette analyse, j’ai mieux compris la manière dont Swing gère les threads et j’ai pu corriger la structure de mon programme
afin qu’il reste totalement réactif, même après l’export. Cette expérience m’a rappelé l’importance de maîtriser les principes fondamentaux
des bibliothèques graphiques et leurs contraintes en matière de multithreading.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.