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é dexport au format PIF depuis linterface du convertisseur,
jai rencontré un problème important : une fois que je cliquais sur le bouton dexportation,
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, jai 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 linterface graphique est gérée par un seul thread dédié,
appelé lEvent Dispatch Thread (EDT). Ce thread est responsable de tout ce qui concerne linterface utilisateur :
la gestion des clics, le rafraîchissement de la fenêtre, la fermeture, le dessin et laffichage en général.
Tant que ce thread tourne correctement, lapplication reste réactive.
LEDT ne démarre réellement quaprès lappel à la méthode permettant dafficher la fenêtre. À partir de ce moment,
toutes les opérations qui modifient linterface devraient strictement être exécutées sur ce thread.
Cest 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 javais structuré mon point dentré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 lEDT ne prenne le relais pour gérer linterface.
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 lexport, Swing se retrouvait dans un état instable, puisque certaines opérations graphiques avaient été réalisées
hors du thread dédié.
Cest exactement ce qui provoquait le gel de linterface : une fois le fichier enregistré, la fenêtre ne répondait plus car
lEDT é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 sassurer que toutes les opérations qui touchent
a linterface graphique soient exécutées sur lEvent Dispatch Thread. Cela signifie que toute interaction, y compris louverture
dun 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 lEDT.
La solution consiste donc à déléguer lappel du processus de conversion au thread graphique, en utilisant le mécanisme fourni par
Swing pour garantir que le code sexécute sur lEDT. Une autre possibilité serait dexécuter les opérations lourdes dans un thread en
arrière-plan pour éviter de bloquer linterface, mais dans tous les cas le respect strict de la séparation entre traitements et interface
est essentiel.
Grâce à cette analyse, jai mieux compris la manière dont Swing gère les threads et jai pu corriger la structure de mon programme
afin quil reste totalement réactif, même après lexport. Cette expérience ma rappelé limportance 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.