ПОНЯТНО О Visual Basic NET (том 3)

       

Проект – Графический редактор


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

  • Рисовать мышкой, как карандашом.
  • При помощи счетчика выбирать толщину карандаша.
  • Выбирать цвет карандаша.
  • Загружать картинки из графического файла.
  • Сохранять рисунки в графическом файле.
  • Внешний вид нашего графического редактора вы можете видеть на Рис. 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


    Содержание раздела