2013-02-25 3 views
5

Я генерирую кучу объектов RectangleF, имеющих разные размеры и позиции. Каким будет лучший способ заполнить их градиентом Brush в GDI +?Эффективный способ рисования градиентных прямоугольников

В WPF я мог бы создать LinearGradientBrush, установить Start и End relative пунктов, а WPF позаботится обо всем остальном.

В GDI +, однако, конструктор градиентной кисти требует положения в абсолютных координатах, что означает, что я должен создать кисть для каждого из прямоугольников, что было бы очень сложной операцией.

Я пропустил что-то или это действительно единственный способ?

ответ

0

Я рекомендую вам создать общий метод, как это:

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

то для каждого прямоугольника просто позвонить:

yourrectangleF.Paint += new PaintEventHandler(Paint_rectangle); 

Если gradrients цвета все же, вы можете сделать это метод короче. Надеюсь, что помогло ..

+1

Это не поможет против моего страха создания градиента кисти для каждого прямоугольника. У меня действительно есть 2 кисти, которые мне нужно использовать для рисования 1000 прямоугольников. – Eugen

+0

Прошу прощения, но я думаю, у вас нет другого выбора. У вас возникают проблемы с производительностью, которые вы можете улучшить с помощью потоков. Вы можете сократить время с этим. Сколько времени требуется, чтобы заполнить все эти прямоугольники, создав один LinearGradientBrush на каждый прямоугольник? – Andres

+0

Я еще не тестировал, просто надеялся, что у меня будет такой же процесс создания кисти, как в WPF, и у меня появилась идея, что я что-то упустил. Но похоже, что это единственный способ. – Eugen

1

Вы можете указать преобразование в момент, когда применяется градиент, если вы хотите объявить кисть только один раз. Обратите внимание, что использование преобразований переопределит многие аргументы конструктора, которые могут быть указаны на LinearGradientBrush.

LinearGradientBrush.Transform Property (System.Drawing.Drawing2D)

Чтобы изменить преобразование, вызывать методы объекта кисти, соответствующие желаемым матричных операций. Обратите внимание, что операции с матрицами не являются коммутативными, поэтому порядок важен. Для ваших целей вы, вероятно, захотите сделать их в этом порядке для каждого исполнения ваших прямоугольников: масштабирование, поворот, смещение/перевод.

LinearGradientBrush.ResetTransform Method @ MSDN

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

LinearGradientBrush.RotateTransform Method (Single, MatrixOrder) @ MSDN

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

Обратите внимание, что инструменты для рисования на системном уровне фактически не содержат определения запаса для градиентной кисти, так что если у вас есть проблемы с производительностью о создании нескольких кистей, создание множества градиентных кистей не должно стоить больше, чем накладные расходы на GDI +/System.Drawin g сохраняя данные, необходимые для определения градиента и стиля. Вы можете быть таким же хорошим, чтобы создавать Brush на каждый прямоугольник по мере необходимости, без необходимости погружаться в математику, необходимую для настройки кисти с помощью преобразования.

Brush Functions (Windows) @ MSDN

Вот пример кода, вы можете проверить в приложении WinForms. Это приложение окрашивает плитки градиентной кистью с градиентом 45 градусов, масштабируется до самого большого размера плитки (наивно вычисляется). Если вы играете со значениями и преобразованиями, вы можете обнаружить, что не стоит использовать технику, устанавливающую преобразование для всех ваших прямоугольников, если у вас есть нетривиальные определения градиента. В противном случае помните, что ваши преобразования применяются на мировом уровне, а в мире GDI ось y перевернута, тогда как в картезианском математическом мире она упорядочена снизу вверх. Это также приводит к тому, что угол применяется по часовой стрелке, тогда как в тригонометрии угол прогрессирует против часовой стрелки в возрастающем значении для направленной оси y.

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

Вот снимок выхода:

5x5 Form with Gradient-Tile Painting

+0

Мне кажется, что у нас есть еще много расчетов. Я рассмотрю использование кисти для каждого прямоугольника и посмотрим, как это происходит. Thx для уточнения. – Eugen

+0

Eugen, измерить его. И посмотрите, что лучший метод. Вы можете использовать что-то простое, как два времени. – Andres

Смежные вопросы