Проект – Графический редактор
Проиллюстрируем применение диалоговых окон выбора цвета, открытия и сохранения файла, а также счетчика на примере создания простейшего графического редактора. Пусть наш редактор позволяет делать следующие вещи:
- Рисовать мышкой, как карандашом.
- При помощи счетчика выбирать толщину карандаша.
- Выбирать цвет карандаша.
- Загружать картинки из графического файла.
- Сохранять рисунки в графическом файле.
Внешний вид нашего графического редактора вы можете видеть на Рис. 20.19.
Рис. 20.19
Вы видите здесь загруженную с диска картинку, поверх которой линиями разной толщины и цвета от руки нарисованы самолеты и текст.
Вот программа нашего графического редактора (посмотрите, какая короткая!):
Dim Лист As Bitmap
Dim Гр, Граф As Graphics 'Объекты класса Graphics над Листом и над формой
Dim Кисть As New SolidBrush(Color.Black) 'Цвет карандаша поначалу черный
Dim Толщина As Integer = 3 'Толщина карандаша. Поначалу = 3.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Лист = New Bitmap(Me.Width, Me.Height)
Гр = Graphics.FromImage(Лист)
Граф = Me.CreateGraphics
End Sub
Private Sub Выбрать_цвет(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Выбрать_цвет.Click
ColorDialog1.ShowDialog()
Кисть.Color = ColorDialog1.Color
End Sub
Private Sub Сохранить(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Сохранить.Click
SaveFileDialog1.ShowDialog()
Dim Файл As String = SaveFileDialog1.FileName
Лист.Save(Файл)
End Sub
Private Sub Открыть(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Открыть.Click
OpenFileDialog1.ShowDialog()
Dim Файл As String = OpenFileDialog1.FileName
Dim Картинка As New Bitmap(Файл)
Гр.DrawImage(Картинка, 10, 10)
Граф.DrawImage(Картинка, 10, 10)
End Sub
Private Sub NumericUpDown1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles NumericUpDown1.ValueChanged
Толщина = NumericUpDown1.Value
End Sub
Private Sub Form1_MouseMove( ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles MyBase.MouseMove
If e.Button = MouseButtons.Left Then
Гр.FillEllipse(Кисть, e.X, e.Y, Толщина, Толщина)
Граф.FillEllipse(Кисть, e.X, e.Y, Толщина, Толщина)
End If
End Sub
Пояснения: Для понимания программы нужно вспомнить, как мы работали с картинками и рисовали на элементах управления и в памяти (6.2, 12.3 и 12.4).
Я решил рисовать именно в памяти, в объекте Лист класса Bitmap, потому что в память удобней загружать картинки и удобней из памяти сохранять нарисованное. А чтобы было видно, что мы рисуем, я продублировал рисование на форме. Пробовали вы рисовать двумя руками на двух листах бумаги одно и то же? Это примерно то же самое.
Первая строка программы объявляет Лист, а в процедуре Form1_Load он создается, причем по размерам равный форме. Поскольку рисовать я вознамерился «в двух местах», а для рисования нужны объекты класса Graphics, я их объявляю во второй строке программы и создаю в процедуре Form1_Load.
Процедура Form1_MouseMove осуществляет все рисование. Идея рисования мышкой изложена в 14.2.3, а в решении к Задание 111 сказано, как рисовать только при нажатой левой клавише мыши. Рисование линий осуществляется рисованием близко расположенных кружочков.
Поскольку для рисования методом FillEllipse нужны Кисть и Толщина, то я их объявляю 3-4 строками программы, а в процедуре Выбрать_цвет меняю цвет кисти и в процедуре NumericUpDown1_ValueChanged меняю толщину «карандаша».
Процедура Сохранить сохраняет содержимое объекта Лист в файл, выбранный нами в диалоговом окне.
Процедура Открыть загружает графический файл, выбранный нами в диалоговом окне, в «транзитный» объект Картинка, созданный нами только для этой цели. Оттуда содержимое файла рисуется на Листе и на форме.
Открывать можно графические файлы разных форматов. Сохранять – только в формате BMP. Чтобы сохранять в некоторых других форматах, нужен метод Save с двумя параметрами (см. 12.3.7).
Пишем компактнее. Процедуры сохранения и открытия можно записать покомпактнее, отказавшись от переменных Файл и Картинка и заменив эти переменные их значениями. Заодно и предусмотрим досрочный выход из диалогов:
Private Sub Сохранить(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Сохранить.Click
If SaveFileDialog1.ShowDialog() = DialogResult.Cancel Then Exit Sub
Лист.Save(SaveFileDialog1.FileName)
End Sub
Private Sub Открыть(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Открыть.Click
If OpenFileDialog1.ShowDialog() = DialogResult.Cancel Then Exit Sub
Гр.DrawImage(New Bitmap(OpenFileDialog1.FileName), 10, 10)
Граф.DrawImage(New Bitmap(OpenFileDialog1.FileName), 10, 10)
End Sub
Улучшаем рисование мышкой. У нашей процедуры рисования Form1_MouseMove есть существенный недостаток: Она рисует, по сути, не линию, а последовательность кружочков, которые сливаются в линию только при медленном движении мышки. Происходит это потому, что события MouseMove вырабатываются не непрерывно, а через некоторые, пусть небольшие, промежутки времени.
Попробуем вместо точек рисовать отрезки прямых, соединяющие между собой точки, в которых наступали соседние события MouseMove. Получится ломаная линия, но поскольку соседние точки расположены очень близко друг к другу, она будет неотличима от плавной, гладкой кривой.
Теперь, когда мы рисуем отрезки, нам вместо кисти понадобится перо.
Вот как дополнится и изменится наша программа:
Dim Перо As New Pen(Color.Black, 3) 'Цвет карандаша поначалу черный, толщина=3
'Координаты мыши при предыдущем (перед текущим) наступлении события MouseMove:
Dim X_предыдущее As Long
Dim Y_предыдущее As Long
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Лист = New Bitmap(Me.Width, Me.Height)
Гр = Graphics.FromImage(Лист)
Граф = Me.CreateGraphics
Перо.StartCap = Drawing2D.LineCap.Round 'Иначе линия получается не гладкая
Перо.EndCap = Drawing2D.LineCap.Round
End Sub
Private Sub Выбрать_цвет_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Выбрать_цвет.Click
ColorDialog1.ShowDialog()
Перо.Color = ColorDialog1.Color
End Sub
Private Sub NumericUpDown1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles NumericUpDown1.ValueChanged
Перо.Width = NumericUpDown1.Value
End Sub
Private Sub Form1_MouseMove( ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles MyBase.MouseMove
If e.Button = MouseButtons.Left Then
'Рисуем отрезок прямой от текущего положения мыши до предыдущего:
Гр.DrawLine(Перо, e.X, e.Y, X_предыдущее, Y_предыдущее)
Граф.DrawLine(Перо, e.X, e.Y, X_предыдущее, Y_предыдущее)
'Запоминаем текущее положение мыши для будущего срабатывания MouseMove,
‘когда оно будет уже предыдущим:
X_предыдущее = e.X
Y_предыдущее = e.Y
End If
End Sub
Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles MyBase.MouseDown
'В начальный момент рисования, когда мы только нажимаем кнопку мыши,
‘предыдущее и текущее положения мыши совпадают:
X_предыдущее = e.X
Y_предыдущее = e.Y
End Sub