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

cs_wizad 356 Messages postés samedi 30 octobre 2004Date d'inscription 14 avril 2009 Dernière intervention - 19 juin 2006 à 15:40 - Dernière réponse : cs_wizad 356 Messages postés samedi 30 octobre 2004Date d'inscription 14 avril 2009 Dernière intervention
- 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.
Afficher la suite 

10 réponses

Répondre au sujet
dgouttegattat 129 Messages postés mardi 22 novembre 2005Date d'inscription 30 décembre 2007 Dernière intervention - 20 juin 2006 à 12:05
+3
Utile
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 />
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de dgouttegattat
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 20 juin 2006 à 08:26
0
Utile
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
Commenter la réponse de cs_Bidou
cs_wizad 356 Messages postés samedi 30 octobre 2004Date d'inscription 14 avril 2009 Dernière intervention - 20 juin 2006 à 09:46
0
Utile
Merci pour le lien je regarde
Commenter la réponse de cs_wizad
dgouttegattat 129 Messages postés mardi 22 novembre 2005Date d'inscription 30 décembre 2007 Dernière intervention - 20 juin 2006 à 09:53
0
Utile
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 !
Commenter la réponse de dgouttegattat
cs_wizad 356 Messages postés samedi 30 octobre 2004Date d'inscription 14 avril 2009 Dernière intervention - 20 juin 2006 à 10:01
0
Utile
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.
Commenter la réponse de cs_wizad
cs_wizad 356 Messages postés samedi 30 octobre 2004Date d'inscription 14 avril 2009 Dernière intervention - 20 juin 2006 à 13:27
0
Utile
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é.
Commenter la réponse de cs_wizad
cs_wizad 356 Messages postés samedi 30 octobre 2004Date d'inscription 14 avril 2009 Dernière intervention - 20 juin 2006 à 14:13
0
Utile
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.
Commenter la réponse de cs_wizad
dgouttegattat 129 Messages postés mardi 22 novembre 2005Date d'inscription 30 décembre 2007 Dernière intervention - 20 juin 2006 à 14:47
0
Utile
Quelle surcharge as-tu utilisée ?
Moi j'ai fait :
<hr />MeasureString(temp1, font, 0, StringFormat.GenericTypographic);<hr />
et ça marche assez bien.
Commenter la réponse de dgouttegattat
cs_wizad 356 Messages postés samedi 30 octobre 2004Date d'inscription 14 avril 2009 Dernière intervention - 20 juin 2006 à 14:49
0
Utile
e.Graphics.MeasureString(temp[j-1], font, larg_dispo, StringFormat.GenericTypographic)
celle-ci (j'avais pas songé au zéro faut que j'essai)
Commenter la réponse de cs_wizad
cs_wizad 356 Messages postés samedi 30 octobre 2004Date d'inscription 14 avril 2009 Dernière intervention - 20 juin 2006 à 14:52
0
Utile
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...
Commenter la réponse de cs_wizad

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.