При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан. Затем: Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз. |
Работа с печатью и изображениями
Рисование в Windows-формах
Библиотека .NET Framework предоставляет чрезвычайно большой набор классов для реализации рисования в Windows-формах. Кривые Безье, текстурные кисти и перья, трансформация изображения, всевозможные виды градиентной заливки, слои, — практически все атрибуты крупного графического пакета могут быть воссозданы на одном из языков .NET Framework. Для рассмотрения этих методов и свойств потребовалась бы отдельная книга, поэтому мы ограничимся простым приложением, позволяющим рисовать линиями различного цвета и толщины. Создайте новое приложение и назовите его EasyPaint. Устанавливаем следующие значения свойств формы:
Form1, форма, свойство | Значение |
---|---|
BackColor | ActiveCaptionText |
Icon | Code\Glava6\EasyPaint\Icon\rc_bitmap.ico |
Text | EasyPaint |
Добавляем на форму элементы управления MainMenu и ColorDialog. Создаем следующие пункты меню:
Как обычно, рисовать мы будем при удержании и перемещении левой кнопки мыши. В классе формы добавляем объекты:
//Переменная, отвечающая за включения режима рисования. //Значение true — режим включен bool DrawMode = false; //Создаем массив точек, из которых будут формироваться линии ArrayList points = new ArrayList();
Для рисования линий и кривых в библиотеки .NET Framework имеется класс Pen, экземпляр которого нам и нужно создать:
Pen mainPen;
В графических программах принято в рабочей области изменять курсор — пользователю удобнее рисовать, когда он имеет вид карандаша. Можно просто установить значение из перечисления свойства Cursor формы (рис. 6.16), но как быть, если нужен вид, не входящий в это перечисление?
Самый простой способ добавить произвольный курсор к приложению — это поместить изображение курсора (в данном случае, 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).
Диалоговое окно выбора ширины линии. Элемент управления TrackBar
Займемся теперь линией для рисования — создадим собственное диалоговое окно, позволяющее устанавливать ее ширину. В окне Solution Explorer щелкаем правой кнопкой на имени проекта и в появившемся контекстном меню выбираем Add/Add Windows Form… . Называем новую форму LineWidth.cs, из окна Toolbox перетаскиваем на нее две кнопки, надпись, панель, элементы NumericUpDown , TrackBar (рис. 6.18) и устанавливаем следующие значения свойств:
LineWidth, форма, свойство | Значение |
---|---|
Name | LineWidth |
AcceptButton | BtnOK |
CancelButton | BtnCancel |
FormBorderStyle | FixedDialog |
MaximizeBox | False |
MinimizeBox | False |
Size | 254; 286 |
Text | Толщина линии |
trackBar1, свойство | Значение |
---|---|
DecimalPlaces | 1 |
Location | 16; 168 |
Maximum | 100 |
Minimum | 1 |
Size | 224; 45 |
TickFrequency | 5 |
Value | 5 |
Наша задача — сделать так, чтобы при перемещении ползунка или вводе значения на форме 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 (Code\Glava6\ EasyPaint).