2010-09-28 26 views
1

Étant donné le code suivant. La première méthode DrawString peut-elle dessiner dans Arial plutôt que dans Times New Roman?.NET DrawString modifie les références de police après l'appel

protected override void OnPaint(PaintEventArgs pe) 
{ 
    Font f = new Font("Times New Roman", this.TextSize); 
    pe.Graphics.DrawString("Test 1", f, Brushes.Black, loc); 
    f = new Font("Arial", this.TextSize); 
    pe.Graphics.DrawString("Test 2", f, Brushes.Black, loc); 
} 

J'ai un problème où essentiellement ce code dessine par intermittence la première chaîne dans la mauvaise police. J'ai changé le code pour avoir deux références de police statiques maintenant, mais comme je n'ai pas pu reproduire le code, je ne peux pas être sûr si le problème est résolu ou non.

Note: loc est une position qui serait modifiée par le code actuel, j'ai dépouillé un code ici pour simplifier

est ici toute la méthode avec ma solution en elle. Si vous ne pouvez pas voir quelque chose de mal avec elle - je vais blâmer quelques rayons cosmiques ou quelque chose ...

protected override void OnPaint(PaintEventArgs pe) 
{ 
     base.OnPaint(pe); 
     if (bcf == null) 
     { 
      FontFamily[] families = pfc.Families; 
      foreach (FontFamily ff in families) 
      { 
       if (ff.Name.Equals("Free 3 of 9")) 
       { 
        bcf = ff; 
       } 
      } 
     } 
     if (bcf != null) 
     { 
      Font f = new Font(bcf, this.BarcodeSize); 
      SizeF s = TextRenderer.MeasureText(barcodeValue, f); 
      Rectangle r = pe.ClipRectangle; 
      Point loc = new Point(0, 0); 
      if (s.Width < r.Width) 
      { 
       loc.X = (int)Math.Ceiling((r.Width - s.Width)/2); 
      } 
      pe.Graphics.DrawString(barcodeValue, f, Brushes.Black, loc); 

      float barcodeBottom = s.Height + 5; 

      Font fp = new Font("Arial", this.TextSize); 
      s = TextRenderer.MeasureText(barcodeValue, fp); 
      r = pe.ClipRectangle; 
      loc = new Point(0, (int)Math.Ceiling(barcodeBottom)); 
      if (s.Width < r.Width) 
      { 
       loc.X = (int)Math.Ceiling((r.Width - s.Width)/2); 
      } 
      if (s.Height + loc.Y > r.Height) 
      { 
       loc.Y = (int)Math.Ceiling(r.Height - (s.Height)); 
      } 
      pe.Graphics.FillRectangle(Brushes.White, new Rectangle(loc, new Size((int)Math.Ceiling(s.Width), (int)Math.Ceiling(s.Height)))); 
      pe.Graphics.DrawString(barcodeValue, fp, Brushes.Black, loc); 
     } 
    } 

Le code fixe ressemble maintenant à ce qui suit. Beaucoup moins GDI appelle maintenant:

protected override void OnPaint(PaintEventArgs pe) 
    { 
     base.OnPaint(pe); 
     if (bcf != null) 
     { 
      Rectangle r = pe.ClipRectangle; 
      Point loc = new Point(0, 0); 
      if (barcodeDimensions.Width < r.Width) 
      { 
       loc.X = (int)Math.Ceiling((r.Width - barcodeDimensions.Width)/2); 
      } 
      pe.Graphics.DrawString(barcodeValue, barcodeFont, Brushes.Black, loc); 

      float barcodeBottom = barcodeDimensions.Height + 5; 

      r = pe.ClipRectangle; 
      loc = new Point(0, (int)Math.Ceiling(barcodeBottom)); 
      if (plaintextDimensions.Width < r.Width) 
      { 
       loc.X = (int)Math.Ceiling((r.Width - plaintextDimensions.Width)/2); 
      } 
      if (plaintextDimensions.Height + loc.Y > r.Height) 
      { 
       loc.Y = (int)Math.Ceiling(r.Height - (plaintextDimensions.Height)); 
      } 
      pe.Graphics.FillRectangle(Brushes.White, new Rectangle(loc, new Size((int)Math.Ceiling(plaintextDimensions.Width), (int)Math.Ceiling(plaintextDimensions.Height)))); 
      pe.Graphics.DrawString(barcodeValue, plaintextFont, Brushes.Black, loc); 
     } 
    } 

Si je comptais faire ce que je serait encore plus optimale mettre toutes les pièces de mesure rectangle dans une substitution de OnResize, mais je pense que cela va faire pour l'instant ...

Répondre

2

Oui, des choses étranges commencent à se produire lorsque votre programme est sur le point de consommer 10 000 handles GDI. Il affecte presque certainement le mappeur de polices Windows sans nécessairement lancer une exception. Votre programme joue à la roulette russe avec ce problème potentiel parce que vous n'appelez pas Dispose() sur les polices que vous utilisez. Si le ramasse-miettes ne tourne pas assez souvent, vous pouvez bien vous débarrasser de ce pistolet. Vous devez écrire comme ceci:

using (Font fp = new Font("Arial", this.TextSize)) { 
    // etc.. 
} 

Notez également un autre bogue dans votre code, vous utilisez TextRenderer.MeasureText mais le dessin avec Graphics.DrawString. La mesure n'est pas identique. Vous devez utiliser Graphics.MeasureString.

+0

Je ne pense pas que cela devrait être fait dans la méthode OnPaint de toute façon. Je suis en train de refactoriser le tout pour ne définir que les polices, les tailles et l'emplacement dans le setter pour le texte qui est rendu. –

2

Non, je ne vois pas comment cela pourrait arriver - ce n'est pas comme si le premier appel connaissait la variable f - il ne connaît que sa valeur au moment où DrawString a été appelée. L'argument (une référence Font) est transmis par valeur, et non par référence. La seule manière que je pourrais imaginer ceci causant un problème est si l'objet Graphics se souvient de sa police "courante" (et la réinitialise dans l'appel à DrawString) mais diffère le dessin réel. Cela aurait toutes sortes d'effets désagréables - je ne peux pas le voir se produire.

Fondamentalement, en ce qui concerne les appels DrawString, c'est comme si vous utilisiez deux variables différentes.

+0

Je pensais autant, je n'avais pas fait grand-chose dans GDI + auparavant et je ne savais pas s'il y avait quelque chose de fou qui se passait ici ... –

+0

@Matt - C'est tout à fait possible. –

0

Skeet recouvert le boîtier de base. J'ai fait beaucoup de GDI + et je n'ai jamais vu le comportement que vous décrivez. Très probablement, il est dû à un autre effet non montré par ce code.

0

Impossible de voir aucun problème avec le code fourni. Est-il possible dans votre code complet que les emplacements de dessin sont incorrects? Êtes-vous sûr à 100% que la valeur de chaîne affichée dans Arial ne peut être rendue que par l'appel à DrawString à l'aide de la police TNR?

+0

Aye - la seule chose plus compliquée dans le code actuel est que la première police provient d'un PrivateFontCollection. Je parcourt la collection à la recherche d'une FontFamily avec un nom particulier puis restitue le texte dans un endroit particulier .... Je vais éditer la question et mettre toute la méthode dedans ainsi que la version simple juste au cas où ... –