Опубликован: 11.09.2006 | Уровень: специалист | Доступ: платный
Лекция 6:

Работа с печатью и изображениями

Рисование в Windows-формах

Библиотека .NET Framework предоставляет чрезвычайно большой набор классов для реализации рисования в Windows-формах. Кривые Безье, текстурные кисти и перья, трансформация изображения, всевозможные виды градиентной заливки, слои, — практически все атрибуты крупного графического пакета могут быть воссозданы на одном из языков .NET Framework. Для рассмотрения этих методов и свойств потребовалась бы отдельная книга, поэтому мы ограничимся простым приложением, позволяющим рисовать линиями различного цвета и толщины. Создайте новое приложение и назовите его EasyPaint. Устанавливаем следующие значения свойств формы:

Form1, форма, свойство Значение
BackColor ActiveCaptionText
Icon ICOCode\Glava6\EasyPaint\Icon\rc_bitmap.ico
Text EasyPaint

Добавляем на форму элементы управления MainMenu и ColorDialog. Создаем следующие пункты меню:

Name Text
mnuFormat &Формат
mnuColor &Цвет
mnuWidth &Толщина линии

Как обычно, рисовать мы будем при удержании и перемещении левой кнопки мыши. В классе формы добавляем объекты:

//Переменная, отвечающая за включения режима рисования.
//Значение true — режим включен
bool DrawMode = false;
//Создаем массив точек, из которых будут формироваться линии
ArrayList points = new ArrayList();

Для рисования линий и кривых в библиотеки .NET Framework имеется класс Pen, экземпляр которого нам и нужно создать:

Pen mainPen;

В графических программах принято в рабочей области изменять курсор — пользователю удобнее рисовать, когда он имеет вид карандаша. Можно просто установить значение из перечисления свойства Cursor формы (рис. 6.16), но как быть, если нужен вид, не входящий в это перечисление?

Свойство Cursor формы

Рис. 6.16. Свойство Cursor формы

Самый простой способ добавить произвольный курсор к приложению — это поместить изображение курсора (в данном случае, Pencil.cur) в папку bin\Debug приложения и в конструкторе формы указать этот курсор в качестве основного:

public Form1()
  {
    InitializeComponent();
    this.Cursor = new Cursor("Pencil.cur");
    mainPen = new Pen(this.ForeColor);
  }

Во второй строчке мы также устанавливаем цвет созданного пера mainPen. Переключаемся в режим дизайна, в окне Properties в событиях формы дважды щелкаем в поле событий MouseDown, MouseMove, MouseUp:

//Событие возникает при нажатии на кнопку мыши.
  private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
  {
    //Если нажата левая кнопка мыши
    if(e.Button==MouseButtons.Left)
    {
      //Включаем режим рисования
      DrawMode = true;
      //Удаляем все элементы из массива points
      points.Clear();
    }
  
  }
//Событие возникает при перемещении мыши
  private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
  {
    //Если включен режим рисования
    if(DrawMode)
    {
      //Создаем экземпляр pt класса Point,
      //представляющий собой точку с координатами мыши в данный момент
      Point pt = new Point(e.X, e.Y);
      //Добавляем созданную точку в массив points
      points.Add(pt);
      if (points.Count<=1) return;
      //Создаем новый массив pts, содержащий число  точек в массиве points
      Point [] pts = new Point [ points.Count];
      //Преобразуем массив points в массив pts, начиная с первого элемента
      points.CopyTo(pts, 0);
      //Создаем экземпляр graph класса Graphics для рисования
      Graphics graph = this.CreateGraphics();
      //Вызываем метод DrawCurve для рисования кривой, которому 
      //передаем перо mainPen и массив pts
      graph.DrawCurve(mainPen, pts);
    
    }
  
  }
//Событие возникает при отпускании кнопки мыши
  private void Form1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
  {
    //Отключаем режим рисования.
    DrawMode = false;
  }
Листинг 6.11.

Логика работы предельно проста — при нажатии левой кнопки мыши включается режим рисования; при ее перемещении формируется массив точек с текущими координатами мыши, массив изображений точек pts затем передается методу DrawCurve, который и рисует линию. При отпускании кнопки режим рисования отключается.

В обработчике пункта меню Color при выборе цвета будет создаваться новое перо:

private void mnuColor_Click(object sender, System.EventArgs e)
    {
      if(colorDialog1.ShowDialog()==DialogResult.OK)
      {
        mainPen = new Pen(colorDialog1.Color);
      }
    }

Запускаем приложение. Вызывая диалоговое окно выбора цвета, можно рисовать разными цветами на форме (рис. 6.17).

Приложение EasyPaint. Курсор имеет точно такой же вид, как и в редакторе Microsoft Paint

Рис. 6.17. Приложение EasyPaint. Курсор имеет точно такой же вид, как и в редакторе Microsoft Paint

Диалоговое окно выбора ширины линии. Элемент управления TrackBar

Займемся теперь линией для рисования — создадим собственное диалоговое окно, позволяющее устанавливать ее ширину. В окне Solution Explorer щелкаем правой кнопкой на имени проекта и в появившемся контекстном меню выбираем Add/Add Windows Form… . Называем новую форму LineWidth.cs, из окна Toolbox перетаскиваем на нее две кнопки, надпись, панель, элементы NumericUpDown , TrackBar (рис. 6.18) и устанавливаем следующие значения свойств:

button1, свойство Значение
Name btnOK
Location 32; 224
Text &OK
button2, свойство Значение
Name btnCancel
Location 136; 224
Text &Отмена
LineWidth, форма, свойство Значение
Name LineWidth
AcceptButton BtnOK
CancelButton BtnCancel
FormBorderStyle FixedDialog
MaximizeBox False
MinimizeBox False
Size 254; 286
Text Толщина линии
label1, свойство Значение
Location 8; 136
Text Толщина
numericUpDown1, свойство Значение
DecimalPlaces 1
Increment 0,1
Location 120; 136
Minimum 1
Value 1
trackBar1, свойство Значение
DecimalPlaces 1
Location 16; 168
Maximum 100
Minimum 1
Size 224; 45
TickFrequency 5
Value 5
Форма LineWidth в режиме дизайна

Рис. 6.18. Форма LineWidth в режиме дизайна

Наша задача — сделать так, чтобы при перемещении ползунка или вводе значения на форме LineWidth выводился эскиз линии, а затем, после закрытия диалогового окна, можно было рисовать линией с выбранной толщиной. В классе формы создаем метод DrawLine, который будет рисовать на панели эскиз линии:

private void DrawLine()
    {
      //Создаем переменную, которая равна ординате точки, 
      //делящий элемент panel1 по высоте пополам
      int y = panel1.Bottom/2;
      //Создаем точку point1 лежащей на левой границе панели, c ординатой y
      Point point1 = new Point(panel1.Left,y);
      //Создаем точку point2 лежащей на правой  границе панели, c ординатой y
      Point point2 = new Point(panel1.Right,y);
      //Создаем экземпляр graph класса Graphics для рисования
      Graphics graph = panel1.CreateGraphics();
      //Определяем толщину линии, равную значению в элементе numericUpDown1
      float f = Decimal.ToSingle(numericUpDown1.Value);
      //Создаем экземпляр pen для рисования линии 
      Pen pen = new Pen (Color. Blue, f);
      //Соединяем точки point1 и point2
      graph.DrawLine(pen, point1, point2);
    }

Создаем свойство PenWidth, которое будет возвращать значение толщины для пера главной формы:

public float PenWidth
    {
      get
      {
        float f = Decimal.ToSingle(numericUpDown1.Value);
        return f;
      }
    }

При вызове диалогового окна на панели сразу будет появляться эскиз линии по умолчанию, для этого создаем обработчик события Paint формы, в котором вызываем метод DrawLine:

private void LineWidth_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
      DrawLine();
    }

Связываем перемещение ползунка элемента trackBar1 со значением в поле элемента numericUpDown1, для чего в обработчике события Scroll вводим переменную val, связывающую свойства Value этих элементов:

private void trackBar1_Scroll(object sender, System.EventArgs e)
    {
      int val = trackBar1.Value;
      numericUpDown1.Value = val;
    }

Аналогично, для связывания значения в поле элемента numericUpDown1 с перемещением ползунка в обработчике события ValueChanged вводим переменную val2:

private void numericUpDown1_ValueChanged(object sender, System.EventArgs e)
    {
      int val2 = (int)numericUpDown1.Value;
      trackBar1.Value = val2;
      DrawLine();
    }

В этом обработчике мы также вызываем метод DrawLine для вывода эскиза линии на форме. Последнее, что нам осталось сделать, — добавить обработчик в пункте меню "Толщина линии" главной формы:

private void mnuWidth_Click(object sender, System.EventArgs e)
    {
      LineWidth diag = new LineWidth();
      if (diag.ShowDialog(this)== DialogResult.OK)
      {
        mainPen = new Pen(mainPen.Color, diag.PenWidth);
      }
    }

Запускаем приложение. Теперь можно рисовать не только разными цветами, но и разной толщиной пера (рис. 6.19).

Приложение EasyPaint и его диалоговое окно "Толщина линии"

Рис. 6.19. Приложение EasyPaint и его диалоговое окно "Толщина линии"

На диске, прилагаемом к книге, вы найдете приложение EasyPaint (Code\Glava6\ EasyPaint).

Елена Дьяконова
Елена Дьяконова

При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: 

Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll

Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан.

Затем:

Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll

Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз.

Александр Сороколет
Александр Сороколет

Свойство WindowState формы blank Maximized. Не открывается почемуто на всё окно, а вот если последующую форму бланк открыть уже на макс открывается :-/

Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000