Justifier un texte pour l'impression

Résolu
cs_wizad Messages postés 355 Date d'inscription samedi 30 octobre 2004 Statut Membre Dernière intervention 14 avril 2009 - 19 juin 2006 à 15:40
cs_wizad Messages postés 355 Date d'inscription samedi 30 octobre 2004 Statut Membre Dernière intervention 14 avril 2009 - 20 juin 2006 à 14:52
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

dgouttegattat Messages postés 129 Date d'inscription mardi 22 novembre 2005 Statut Membre Dernière intervention 30 décembre 2007 3
20 juin 2006 à 12:05
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 />
3
cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
20 juin 2006 à 08:26
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
0
cs_wizad Messages postés 355 Date d'inscription samedi 30 octobre 2004 Statut Membre Dernière intervention 14 avril 2009
20 juin 2006 à 09:46
Merci pour le lien je regarde
0
dgouttegattat Messages postés 129 Date d'inscription mardi 22 novembre 2005 Statut Membre Dernière intervention 30 décembre 2007 3
20 juin 2006 à 09:53
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 !
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_wizad Messages postés 355 Date d'inscription samedi 30 octobre 2004 Statut Membre Dernière intervention 14 avril 2009
20 juin 2006 à 10:01
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.
0
cs_wizad Messages postés 355 Date d'inscription samedi 30 octobre 2004 Statut Membre Dernière intervention 14 avril 2009
20 juin 2006 à 13:27
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é.
0
cs_wizad Messages postés 355 Date d'inscription samedi 30 octobre 2004 Statut Membre Dernière intervention 14 avril 2009
20 juin 2006 à 14:13
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.
0
dgouttegattat Messages postés 129 Date d'inscription mardi 22 novembre 2005 Statut Membre Dernière intervention 30 décembre 2007 3
20 juin 2006 à 14:47
Quelle surcharge as-tu utilisée ?
Moi j'ai fait :
<hr />MeasureString(temp1, font, 0, StringFormat.GenericTypographic);<hr />
et ça marche assez bien.
0
cs_wizad Messages postés 355 Date d'inscription samedi 30 octobre 2004 Statut Membre Dernière intervention 14 avril 2009
20 juin 2006 à 14:49
e.Graphics.MeasureString(temp[j-1], font, larg_dispo, StringFormat.GenericTypographic)
celle-ci (j'avais pas songé au zéro faut que j'essai)
0
cs_wizad Messages postés 355 Date d'inscription samedi 30 octobre 2004 Statut Membre Dernière intervention 14 avril 2009
20 juin 2006 à 14:52
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...
0
Rejoignez-nous