2013-02-25 21 views
5

Ich erstelle eine Reihe von RectangleF-Objekten mit unterschiedlichen Größen und Positionen. Was wäre der beste Weg, um sie mit einem Farbverlauf Brush in GDI + zu füllen?Eine effiziente Möglichkeit, Farbrechtecke zu malen

In WPF konnte ich einen LinearGradientBrush erstellen, Anfang und Ende setzen relative Punkte und WPF würde sich um den Rest kümmern.

In GDI + erfordert jedoch der Farbverlaufskonstruktor die Position in absoluten Koordinaten, was bedeutet, dass ich für jedes Rechteck einen Pinsel erstellen muss, was eine sehr komplexe Operation wäre.

Fehle ich etwas oder ist das in der Tat der einzige Weg?

Antwort

0

Ich empfehle Ihnen, eine generische Methode wie folgt zu erstellen:

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); 
     } 
    } 

dann für jedes Rechteck rufen Sie einfach an:

yourrectangleF.Paint += new PaintEventHandler(Paint_rectangle); 

Wenn die gradrients Farben sind alle gleich, können Sie machen, dass Methode kürzer. Hoffe, dass geholfen hat ..

+1

Das ist nicht gegen meine Angst einen Farbverlauf zu schaffen für jedes Rechteck hilft. Ich habe tatsächlich 2 Pinsel, die ich für das Malen von 1000 Rechtecken verwenden muss. – Eugen

+0

Sorry Kumpel, aber ich denke du hast keine andere Möglichkeit. Wenn Sie Leistungsprobleme haben, können Sie sie mithilfe von Threads verbessern. Sie können damit Zeit sparen. Wie lange braucht es, um alle diese Rechtecke jetzt zu füllen, indem ein LinearGradientBrush pro Rechteck erstellt wird? – Andres

+0

Ich habe noch nicht getestet, ich hatte nur gehofft, den selben Brush-Erstellungsprozess wie in WPF zu haben und hatte eine Idee, dass mir etwas fehlt. Aber es sieht so aus, als ob das der einzige Weg ist. – Eugen

1

Sie können eine Transformation im Moment kurz bevor der Farbverlauf angewendet wird angeben, wenn Sie den Pinsel nur einmal deklarieren möchten. Beachten Sie, dass die Verwendung von Transformationen viele Konstruktorargumente außer Kraft setzt, die in einer LinearGradientBrush angegeben werden können.

LinearGradientBrush.Transform Property (System.Drawing.Drawing2D)

Um die Transformation, rufen die Methoden auf dem Bürsten Objekt entsprechend den gewünschten Matrixoperationen zu ändern. Beachten Sie, dass Matrixoperationen nicht kommutativ sind, daher ist die Reihenfolge wichtig. Für Ihre Zwecke werden Sie sie wahrscheinlich in dieser Reihenfolge für jede Wiedergabe Ihrer Rechtecke verwenden wollen: Skalieren, Drehen, Versetzen/Übersetzen.

LinearGradientBrush.ResetTransform Method @ MSDN

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

LinearGradientBrush.RotateTransform Method (Single, MatrixOrder) @ MSDN

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

Beachten Sie, dass die System-Level-Zeichenwerkzeuge nicht tatsächlich eine Rohteildefinition für Farbverlauf enthalten, so dass, wenn Sie Leistungsprobleme haben Beim Erstellen mehrerer Pinsel sollte die Erstellung einer Vielzahl von Farbverlaufsbürsten nicht mehr kosten als der Aufwand von GDI +/System.Drawin g Beibehalten der Daten, die zum Definieren des Farbverlaufs und des Stylings erforderlich sind. Sie können genauso gut einen Pinsel pro Rechteck nach Bedarf erstellen, ohne in die Mathematik einzutauchen, die erforderlich ist, um den Pinsel per Transformation anzupassen.

Brush Functions (Windows) @ MSDN

Hier ist ein Codebeispiel Sie in einer WinForms-Anwendung testen können. Diese App malt Kacheln mit einem Farbverlaufsbürsten mit einem 45-Grad-Gradienten, skaliert auf die größte Dimension der Kachel (naiv berechnet). Wenn Sie sich mit den Werten und Transformationen beschäftigen, stellen Sie möglicherweise fest, dass es sich nicht lohnt, die Technik zu verwenden, die eine Transformation für alle Ihre Rechtecke vornimmt, wenn Sie nicht-triviale Gradienten-Definitionen haben. Andernfalls denken Sie daran, dass Ihre Transformationen auf der Weltebene angewendet werden, und in der GDI-Welt steht die y-Achse auf dem Kopf, während sie in der kartesischen Mathematikwelt von unten nach oben geordnet ist. Dies führt auch dazu, dass der Winkel im Uhrzeigersinn angewendet wird, während in der Trigonometrie der Winkel gegen den Uhrzeigersinn mit zunehmendem Wert für eine nach oben weisende Y-Achse fortschreitet.

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(); 
     } 
    } 
} 

Hier ist eine Momentaufnahme der Ausgabe:

5x5 Form with Gradient-Tile Painting

+0

Es sieht für mich so aus, als hätten wir viel mehr Berechnungen zu machen. Ich werde einen Pinsel für jedes Rechteck verwenden und sehen, wie es geht. Danke für die Klärung. – Eugen

+0

Eugen, messen Sie es. Und sehen Sie, was die beste Methode ist .. Sie können etwas Einfaches wie zwei Datumsangaben verwenden. – Andres

Verwandte Themen