Файлы к лабораторной работе Вы можете скачать здесь.
Изначально все формы отображаются прямоугольными. И все к этому привыкли. Нельзя пытаться удивлять пользователя экзотическими элементами программы. Ему некогда тратить время на привыкание, программа должна согласовываться с его предыдущим опытом и должна быть интуитивно понятной.
Но мы, как проектировщики, должны знать о существовании возможности создания окон или элементов управления и в нетрадиционном стиле. При создании непрямоугольных форм и элементов управления используется свойство Region базового класса System.Windows.Forms.Control всех визуальных компонентов, которое ожидает ссылки на объекты-экземпляры класса System.Drawing.Region.
Теперь класс Form1 файла Form1.cs должен стать таким
public partial class Form1 : Form { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } public Form1() { InitializeComponent(); } }Листинг 18.1. Точка входа в классе Form1 файла Form1.cs
Size=450;200
На этом подготовительная часть к выполнению упражнения завершена.
В библиотеке .NET Framework (FCL - Framework Class Library) существует класс System.Drawing.Drawing2D.GraphicsPath, который можно использовать как коллекцию для заблаговременного сохранения различных графических примитивов, которые затем можно нарисовать все "одним махом", если передать эту коллекцию в функцию
System.Drawing.Graphics.DrawPath(System.Drawing.Pen pen, System.Drawing.Drawing2D.GraphicsPath path).
Особенность такого способа рисования состоит в том, что незамкнутые контуры всех входящих в коллекцию фигур автоматически замыкаются функцией рисования. И это позволяет легко заливать сложные замкнутые фигуры функцией
System.Drawing.Graphics.FillPath(System.Drawing.Brush brush, System.Drawing.Drawing2D.GraphicsPath path)
Давайте продемонстрируем упомянутые возможности, нарисовав на новой форме головку Буратино. Код рисования поместим в отдельную функцию, а вызов этой функции разместим в переопределении метода OnPaint() формы, чтобы при каждом разрушении окна формы (перемещение, изменение размеров) прорисовка изображения повторялась.
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Drawing.Drawing2D;Листинг 18.2. Добавление к файлу Form1.cs пространства имен
// Рисование головки Буратино private void DrawBuratino() { GraphicsPath path = new GraphicsPath(); path.AddArc(20, 20, 120, 120, 0, 330); // Голова без носа path.AddArc(220, 20, 10, 10, 270, 180); // Удаленный кончик носа path.CloseFigure(); // Замкнули незаконченные дуги path.AddEllipse(90, 40, 20, 20); // Добавили глаз Graphics gr = this.CreateGraphics(); // Создаем холст gr.DrawPath(Pens.Red, path); // Рисуем контур Буратино gr.TranslateTransform(200, 0); // Смещаемся вправо gr.FillPath(Brushes.Blue, path); // Рисуем заливку Буратино gr.DrawPath(Pens.Red, path); // Рисуем контур для заливки }Листинг 18.3. Метод DrawBuratino() в классе Form1
Код начинайте вводить вручную с ключевого слова override. Когда вы его введете и нажмете клавишу пробела, подсказчик кода ( суфлер ) выдаст список переопределяемых методов формы, в котором можно быстро позиционироваться, продолжая набирать имя переопределяемого метода в любом регистре. Нажатие клавиши ввода завершит создание правильной заготовки переопределяемого метода.
// Переопределяем метод перерисовки формы protected override void OnPaint(PaintEventArgs e) { DrawBuratino(); base.OnPaint(e); }Листинг 18.4. Переопределеный метод OnPaint() перерисовки формы
Теперь сделаем форму непрямоугольной. Для этого необходимо воспользоваться свойством Region формы, определяющим ее силуэт.
// Рисование непрямоугольной формы private void DrawForm() { GraphicsPath path = new GraphicsPath(); path.AddEllipse(0, -300, this.Width, 600); this.Region = new Region(path); }Листинг 18.5. Функция задания контура формы через свойство Region
В функции
public void AddEllipse (int x, int y, int width, int height)
первые два параметра определяют координаты левого верхнего угла прямоугольника, описывающего эллипс. При этом началом координат считается левый верхний угол клиентской области формы. Последние два параметра определяют размеры описывающего прямоугольника.
// Переопределяем метод перерисовки формы protected override void OnPaint(PaintEventArgs e) { DrawBuratino(); DrawForm(); base.OnPaint(e); }Листинг 18.6. Вызов функции рисования непрямоугольной формы
private void Form1_Resize(object sender, EventArgs e) { this.Invalidate(); }Листинг 18.7. Обработчик для события Resize формы Form1
Событие Resize мы использовали для прорисовки формы на случай изменения ее размеров в сторону возрастания.
В заключение выполнения этого упражнения введем возможность перетаскивания формы не только за ее заголовок, но и за клиентскую область.
int x, y;Листинг 18.8. Объявления полей класса Form1
private void Form1_MouseDown(object sender, MouseEventArgs e) { // Сохраняем координаты мыши на момент щелчка относительно формы if (e.Button == MouseButtons.Left) { x = e.X; y = e.Y; } } private void Form1_MouseMove(object sender, MouseEventArgs e) { // Измеряем смещение относительно щелчка // и подвигаем форму на это смещение if (e.Button == MouseButtons.Left) { this.Left += e.X - x; this.Top += e.Y - y; } }Листинг 18.9. Обработчики событий MouseDown и MouseMove формы
Этот код обеспечивает перемещение формы относительно начального положения, которое она имела до нажатия левой кнопки мыши, ровно настолько, на сколько переместился курсор мыши после нажатия кнопки. Поэтому нажатый курсор и форма перемещаются синхронно.
Остался последний штрих для этого упражнения - изменять форму курсора при захвате формы.
private void Form1_MouseDown(object sender, MouseEventArgs e) { // Сохраняем координаты мыши на момент щелчка относительно формы if (e.Button == MouseButtons.Left) { x = e.X; y = e.Y; // Форма курсора Cursor.Current = Cursors.SizeAll; } }Листинг 18.10. Изменение формы курсора при нажатии кнопки мыши