2013-02-25 12 views
5

Sto generando un mucchio di oggetti RectangleF con diverse dimensioni e posizioni. Quale sarebbe il modo migliore per riempirli con un pennello sfumato in GDI +?Un modo efficace per dipingere i rettangoli sfumati

In WPF potrei creare un LinearGradientBrush, impostare Start e Fine relative punti e WPF si prenderà cura di tutto il resto.

In GDI +, tuttavia, il costruttore del pennello sfumato richiede la posizione in coordinate assolute, il che significa che devo creare un pennello per ciascun rettangolo, operazione che sarebbe molto complessa.

Mi manca qualcosa o quello è davvero l'unico modo?

risposta

0

vi consiglio di creare un metodo generico come questo:

public void Paint_rectangle(object sender, PaintEventArgs e) 
    { 
     RectangleF r = new RectangleF(0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height); 
     if (r.Width > 0 && r.Height > 0) 
     { 
      Color c1 = Color.LightBlue; 
      Color c2 = Color.White; 
      Color c3 = Color.LightBlue; 

      LinearGradientBrush br = new LinearGradientBrush(r, c1, c3, 90, true); 
      ColorBlend cb = new ColorBlend(); 
      cb.Positions = new[] { 0, (float)0.5, 1 }; 
      cb.Colors = new[] { c1, c2, c3 }; 
      br.InterpolationColors = cb; 

      // paint 
      e.Graphics.FillRectangle(br, r); 
     } 
    } 

poi, per ogni rettangolo basta chiamare:

yourrectangleF.Paint += new PaintEventHandler(Paint_rectangle); 

Se i colori gradrients sono tutti uguali, si può fare che metodo più breve. Spero che questo abbia aiutato ..

+1

che non aiuta contro la mia paura di creare un pennello sfumato per ogni rettangolo. In realtà ho 2 pennelli che devo usare per dipingere 1000 rettangoli. – Eugen

+0

Scusa amico, ma penso che tu non abbia un'altra opzione. Se riscontri problemi di prestazioni, puoi migliorarlo utilizzando i thread. Puoi ridurre il tempo con quello. Quanto tempo ci vuole per riempire tutti quei rettangoli ora creando un LinearGradientBrush per rettangolo? – Andres

+0

Non ho ancora testato, speravo solo di avere lo stesso processo di creazione dei pennelli come in WPF e ho avuto l'idea che mi manchi qualcosa. Ma sembra che questo sia l'unico modo. – Eugen

1

È possibile specificare una trasformazione al momento appena prima dell'applicazione del gradiente se si desidera dichiarare il pennello una sola volta. Si noti che l'utilizzo delle trasformazioni sovrascrive molti degli argomenti del costruttore che possono essere specificati su un LinearGradientBrush.

LinearGradientBrush.Transform Property (System.Drawing.Drawing2D)

Per modificare la trasformazione, chiamare i metodi sull'oggetto pennello corrispondenti alle operazioni di matrice desiderati. Nota che le operazioni con le matrici non sono commutative, quindi l'ordine è importante. Per i tuoi scopi, probabilmente vorrai eseguirli in questo ordine per ogni versione dei tuoi rettangoli: Scala, Ruota, Offset/Traduci.

LinearGradientBrush.ResetTransform Method @ MSDN

LinearGradientBrush.ScaleTransform Method (Single, Single, MatrixOrder) @ MSDN

LinearGradientBrush.RotateTransform Method (Single, MatrixOrder) @ MSDN

LinearGradientBrush.TranslateTransform Method (Single, Single, MatrixOrder) @ MSDN

Si noti che gli strumenti di disegno a livello di sistema in realtà non contiene una definizione magazzino per pennello sfumato, quindi se avete problemi di prestazioni sulla creazione di più pennelli, la creazione di una moltitudine di pennelli sfumati non dovrebbe costare più del sovraccarico di GDI +/System.Drawin g mantenere i dati richiesti per definire il gradiente e lo stile. Potrebbe essere altrettanto utile creare un pennello per rettangolo, se necessario, senza dover immergersi nei calcoli necessari per personalizzare il pennello tramite la trasformazione.

Brush Functions (Windows) @ MSDN

Ecco un esempio di codice è possibile testare in un'applicazione WinForms. Questa applicazione dipinge le tessere con un pennello sfumato utilizzando un gradiente di 45 gradi, ridimensionato alla dimensione più grande della piastrella (calcolato in modo ingenuo). Se si gioca con i valori e le trasformazioni, è possibile che non valga la pena usare la tecnica che imposta una trasformazione per tutti i rettangoli se si hanno definizioni di sfumature non banali. Altrimenti, ricorda che le tue trasformazioni sono applicate a livello mondiale e, nel mondo GDI, l'asse delle ordinate è capovolto, mentre nel mondo matematico cartesiano è ordinato dal basso verso l'alto. Questo fa sì che l'angolo venga applicato in senso orario, mentre nella trigonometria, l'angolo avanza in senso antiorario aumentando il valore per un asse y rivolto verso l'alto.

using System.Drawing.Drawing2D; 

namespace TestMapTransform 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Paint(object sender, PaintEventArgs e) 
     { 
      Rectangle rBrush = new Rectangle(0,0,1,1); 
      Color startColor = Color.DarkRed; 
      Color endColor = Color.White; 
      LinearGradientBrush br = new LinearGradientBrush(rBrush, startColor, endColor, LinearGradientMode.Horizontal); 

      int wPartitions = 5; 
      int hPartitions = 5; 

      int w = this.ClientSize.Width; 
      w = w - (w % wPartitions) + wPartitions; 
      int h = this.ClientSize.Height; 
      h = h - (h % hPartitions) + hPartitions; 

      for (int hStep = 0; hStep < hPartitions; hStep++) 
      { 
       int hUnit = h/hPartitions; 
       for (int wStep = 0; wStep < wPartitions; wStep++) 
       { 
        int wUnit = w/wPartitions; 

        Rectangle rTile = new Rectangle(wUnit * wStep, hUnit * hStep, wUnit, hUnit); 

        if (e.ClipRectangle.IntersectsWith(rTile)) 
        { 
         int maxUnit = wUnit > hUnit ? wUnit : hUnit; 

         br.ResetTransform(); 
         br.ScaleTransform((float)maxUnit * (float)Math.Sqrt(2d), (float)maxUnit * (float)Math.Sqrt(2d), MatrixOrder.Append); 
         br.RotateTransform(45f, MatrixOrder.Append); 
         br.TranslateTransform(wUnit * wStep, hUnit * hStep, MatrixOrder.Append); 

         e.Graphics.FillRectangle(br, rTile); 

         br.ResetTransform(); 
        } 
       } 
      } 
     } 

     private void Form1_Resize(object sender, EventArgs e) 
     { 
      this.Invalidate(); 
     } 
    } 
} 

Ecco un'istantanea dell'output:

5x5 Form with Gradient-Tile Painting

+0

A me sembra che qui abbiamo molti più calcoli da fare. Prenderò in considerazione l'idea di usare un pennello per ogni rettangolo e vedere come va. Grazie per il chiarimento. – Eugen

+0

Eugen, misuralo. E vedi qual'è il metodo migliore .. Puoi usare qualcosa di semplice come due volte al giorno. – Andres

Problemi correlati