Justifier un texte pour l'impression [Résolu]

Signaler
Messages postés
355
Date d'inscription
samedi 30 octobre 2004
Statut
Membre
Dernière intervention
14 avril 2009
-
Messages postés
355
Date d'inscription
samedi 30 octobre 2004
Statut
Membre
Dernière intervention
14 avril 2009
-
Bonjour à tous!
je suis entrain de créer une méthode permettant de justifier du texte pour l'impression (peut aussi être utilisé pour écrire avec la lib GDI).
Les variables d'entrées sont : un tableau de string pour chaque paragraphe, la taille de la page, la font à utilisé.
Principe de fonctionnement : à partir du tableau de paragraphe, effectuer le découpage des chaine de caractère en fonction de la place disponible. Pour ce faire je commence par découpé un paragraphe mot par mot, j'effectue un calcul pour déterminé le dernier mot qui peut être affiché en entier. Je calcul ensuite la longueur de la chain de mot mis bout à bout (sans aucun espace). A partir de cette distance, de la place disponible et du nombre de mot je calcul l'espace à mettre entre chaque mots.
A partir de la je place les mots un par un.

PrintPageEventArgs e //(paramètre de la méthode)
Brush PrintColor = Brushes.Black; //Brush standart
int abscisse = e.PageSettings.Margins.Left;
int ordonnee = e.PageSettings.Margins.Top;
int largeur = e.PageSettings.Bounds.Size.Width - (2 * abscisse); // Largeur de la zone cliente de la page

Font font = new Font("Times New Roman", 12, FontStyle.Regular); // Font utilisé pour le corps

// Variables pour le placement des mots composant le corps du document
float mot_y = ordonnee + 375;
float mot_x = abscisse;

// Le texte à écrire
string[] corps =
                    {
                        "Par la présente lettre, nous vous confirmons l'acceptation de votre inscription à la manifestation RétroGrainville qui se déroulera le Dimanche 3 septembre 2006 à Grainville sur Odon.",
                        "Conformément aux informations contenues dans votre dossier, vous participerez " + cat_info + " (voir convocation ci_jointe). Nous vous rappelons aussi que le petit déjeuner, et le déjeuner sont inclus dans votre inscription."
};

// Algorithme d'affichage
for (int i = 0; i < corps.Length; i++) // Boucle principale pour les paragraphes
            {
                string[] temp = corps[i].Split(' '); // On scinde le paragraphe en mots par mots
                float alinea = 60; // Définition de la taille d'un alinéa
                mot_x = abscisse + alinea; // On est au début du paragraphe on force donc l'alinéa
                int first_word_ligne = 0; // Premier mot de la ligne (numéro dans le tableau)
                int last_word_ligne = 0; //Dernier mot de la ligne
                float larg_dispo = largeur - alinea; // Place disponible

                while (last_word_ligne < (temp.Length-1)) // boucle pour chaque ligne
                {
                    string temp1 = null;
                    float len = 0;

                    for (int j = first_word_ligne; j < temp.Length; j++) // on boucle pour trouver l'intervalle de mots à afficher (qui rentre dans la ligne)
                    {
                        if (j != 0) // juste pour éviter un espace devant le premier mot
                        {
                            temp1 = temp1 + " " + temp[j];
                        }
                        else
                        {
                            temp1 = temp[j];
                        }
                       
                        // On cherche le dernier mot possible en ajoutant des espaces pour s'assurer d'avoir au minimum un espace normal entre chaque mot
                        if (e.Graphics.MeasureString(temp1, font).Width >= larg_dispo) // Si le dernier mot provoque le dépassement on enregistre et on sort de la boucle
                        {
                            last_word_ligne = j - 1;
                            break;
                        }
                        else
                        {
                            last_word_ligne = j; // Utilisé pour les fin de paragraphe : pu de mot mais bout de la ligne non atteint
                        }   
                    }

                    //On calcul la taille de la chaine sans espace (mot collé les uns aux autres)
                    string temp2 = null;
                    for (int j = first_word_ligne; j <= last_word_ligne; j++)
                    {
                        temp2 = temp2 + temp[j];
                    }
                    len = e.Graphics.MeasureString(temp2, font).Width;

                    // on calcule l'espace à positioné entre chaque mots                  
                    float esp = (larg_dispo - len) / (last_word_ligne - first_word_ligne + 1);
                    // On boucle pour l'affichage des mots un par un
                    for (int j = first_word_ligne; j <= last_word_ligne; j++)
                    {
                        if (j != first_word_ligne)
                            mot_x = mot_x + esp + e.Graphics.MeasureString(temp[j-1], font).Width;
                        // On affiche chaque mot à sa place
                        e.Graphics.DrawString(temp[j], font, PrintColor, mot_x, mot_y);                     
                    }

                    // On passe à la ligne suivante
                    first_word_ligne = last_word_ligne + 1;
                    larg_dispo = largeur;
                    mot_y = mot_y + 14;
                    mot_x = abscisse;
                 }
                 // On passe au paragraphe suivant
                 mot_y = mot_y + 4;
            }

Voilà l'algo en l'état actuel. Il ne produit aucune erreur mais par contre n'affiche pas le rendu escompté (les lignes dépasse de la pages et pas de justification aparente). Je poste donc pour avoir un avis extérieur...
Je suis bien entendu à toutes critiques constructives pour l'améliorer et l'optimiser.

10 réponses

Messages postés
129
Date d'inscription
mardi 22 novembre 2005
Statut
Membre
Dernière intervention
30 décembre 2007
3
J'ai fait quelques essais : le résultat est déjà beaucoup plus joli si tu utilises une des surcharges de la méthode MeasureString qui prend en paramètre un objet StringFormat, et en utilisant le StringFormat.GenericTypographic.

En revanche, comme la dernière ligne d'un paragraphe ne doit pas être justifié (sauf si tu tiens à avoir trois ou quatre mots répartis sur toute la largeur de la page avec une espace énorme entre eux, ce qui est très moche), il faut ajouter à ton code un test permettant de déterminer si tu es en train d'imprimer la dernière ligne, et si tel est le cas, tu utilises une espace normale. Rapidement, j'ai fait quelque chose comme ça :


<hr />

// Au début de la boucle "ligne"

bool is_last_line_of_paragraph = false
...
else
{
   last_word_ligne = j;

// Utilisé pour les fin de paragraphe : pu de mot mais bout de la ligne non atteint   is_last_line_of_paragraph (j temp.Length - 1);
}
...
float esp;
if (is_last_line_of_paragraph)
   esp = 5.55f;   // espace normale
else
   esp = (larg_dispo - len) / (last_word_ligne - first_word_ligne + 1);
...
// On passe à la ligne suivante
is_last_line_of_paragraph = false;
...
<hr />
Messages postés
5487
Date d'inscription
dimanche 4 août 2002
Statut
Modérateur
Dernière intervention
20 juin 2013
54
Salut,
A mon avis, tu t'es lancé dans un projet dont tu sous-estimes un peu l'ampleur...
Voici néanmoins une page sur le sujet qui devrait passablement t'aider !

VC# forever
=13319
Messages postés
355
Date d'inscription
samedi 30 octobre 2004
Statut
Membre
Dernière intervention
14 avril 2009

Merci pour le lien je regarde
Messages postés
129
Date d'inscription
mardi 22 novembre 2005
Statut
Membre
Dernière intervention
30 décembre 2007
3
Salut,


Je suis d'accord avec Bidou, tu t'attaques à un gros morceau.


Je pense qu'au lieu d'essayer de créer ta propre logique, tu devrais plutôt essayer d'implémenter des algorithmes qui ont déjà fait leurs preuves. En la matière, l'algorithme utilisé par TEX est généralement considéré comme l'un des meilleurs -- moi, je dirais LE meilleur, mais je ne suis pas objectif, je suis un utilisateur de TEX ;)

Cet algoritme est décrit dans TEX: The Program, de Donald E. Knuth, aux éditions Addison-Wesley. Le code source original (en WEB) est également disponible sur ftp://tug.ctan.org/pub/tex-archive/systems/knuth/tex/tex.web.

Bon courage !

P. S. : Merci pour le lien, Bidou, effectivement c'est très instructif !
Messages postés
355
Date d'inscription
samedi 30 octobre 2004
Statut
Membre
Dernière intervention
14 avril 2009

Je cherche pas à créer un algorithme aussi performant et évolué que celui de tex mais plutôt un système me permettant d'avoir des lettre généré par mon programme suffisament propre pour être utilisé : bref mon premier objectif et de gérer les retour à la ligne de façon automatique et de conserver une marge minimum (comme un texte aligné à gauche) ce qui pour l'instant ne fonctionne pas tout à fait correctement.

Note : je ferais un screenshot de l'effet actuel si ça peu vous aider.
Messages postés
355
Date d'inscription
samedi 30 octobre 2004
Statut
Membre
Dernière intervention
14 avril 2009

je vais jetté un oeil sur les surcharges (j'y avais pas trop pensé :( )
 sinon pour la fin de paragraphe j'avais prévu le code mais ne l'avais pas encore réalisé.
Messages postés
355
Date d'inscription
samedi 30 octobre 2004
Statut
Membre
Dernière intervention
14 avril 2009

Effectivement le résultat est propre à condition de ne pas toucher ce test
if (e.Graphics.MeasureString(temp1, font).Width >= larg_dispo)
sur lui la surcharge semble empècher le retour à la ligne.
Messages postés
129
Date d'inscription
mardi 22 novembre 2005
Statut
Membre
Dernière intervention
30 décembre 2007
3
Quelle surcharge as-tu utilisée ?
Moi j'ai fait :
<hr />MeasureString(temp1, font, 0, StringFormat.GenericTypographic);<hr />
et ça marche assez bien.
Messages postés
355
Date d'inscription
samedi 30 octobre 2004
Statut
Membre
Dernière intervention
14 avril 2009

e.Graphics.MeasureString(temp[j-1], font, larg_dispo, StringFormat.GenericTypographic)
celle-ci (j'avais pas songé au zéro faut que j'essai)
Messages postés
355
Date d'inscription
samedi 30 octobre 2004
Statut
Membre
Dernière intervention
14 avril 2009

en fait celà ne change rien... du moins visiblement... (même si le découpage me semble un peu moins précis)

J'ai aussi un doute sur le calcul de l'espace... au niveau du diviseur suit pas sur de faire le bon calcul...