Волченков Проектирование Wиндоwс-Приложений на языке Висуал Басиц 2010
.pdfПосле старта приложения массив фамилий создаётся с помощью команды меню Генератор слов. Число элементов этого массива, равное числу элементов исходного списка, пользователь задаёт на этапе загрузки формы с помощью окна ввода.
После срабатывания команды Генератор слов она должна стать недоступной. Затем выполняется команда Сортировка. В данном случае элементы массива – это данные строкового типа, поэтому для его сортировки достаточно присвоить свойству Sorted окна списка с исходными данными значение True (Истина), а потом в цикле заполнить этот массив. Только после этого пользователь вносит интересующую его фамилию в поле поискового запроса и щёлкает команду Поиск.
Код 6.2 содержит процедуры для всех перечисленных этапов работы данного приложения.
Код 6.2
Public Class Form1
Dim w, a() As String
Dim n, k, i, j, imin, imax, limit As Integer Dim d As Double
Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load
n = InputBox("Ведите число слов", _ "Объём массива", "100")
ReDim a(n - 1)
РусскиеФамилии.Visible = False End Sub
Private Sub ГенераторСлов_Click(ByVal sender _ As Object, ByVal e As System.EventArgs) _ Handles ГенераторСлов.Click
Randomize()
For i = 0 To n - 1
w = РусскиеФамилии.Items.Item(CInt(Rnd() * _ (РусскиеФамилии.Items.Count - 1)))
If Rnd() > 0.75 Then w = w & "а" ' Женщин будет только 25% ИсходныйСписок.Items.Add(w)
Next
ГенераторСлов.Enabled = False End Sub
81
Private Sub Сортировка_Click(ByVal sender _ As System.Object, _
ByVal e As System.EventArgs) _ Handles Сортировка.Click
ИсходныйСписок.Sorted = True For i = 0 To n - 1
a(i) = ИсходныйСписок.Items.Item(i)
Next End Sub
Private Sub Поиск_Click(ByVal _ sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Поиск.Click
ПротоколПоиска.Items.Clear() imin = 0 : imax = n + 1
i = n - 1 : k = 0 k = 0
limit = Math.Log(n) / Math.Log(2) + 1 Do Until k > limit
i = (imax + imin) \ 2 If i > n - 1 Then _
РезультатПоиска.Items.Add("Нет") : Exit Sub ПротоколПоиска.Items.Add(Format(k + 1, "00") _
& ":" & Format(i, "0000")) k = k + 1
If a(i) > ИскомыйЭлемент.Text Then imax = i
ElseIf a(i) < ИскомыйЭлемент.Text Then imin = i
Else
Exit Do End If
Loop
If k <= limit Then РезультатПоиска.Items.Add(Format(i, "0000") & _
":" & ИсходныйСписок.Items.Item(i))
Else
РезультатПоиска.Items.Add("Нет") End If
End Sub
End Class
2. Можно вместо списка фамилий сгенерировать список дат – так, как было сделано в примере выполнения задания 6.1. Форма изменённого приложения будет выглядеть, как показано на рис. 6.3.
82
Рис. 6.3. Пример бинарного (быстрого) поиска заданной даты
Для перехода от фамилий к датам необходимо несколько откорректировать начало процедуры для команды Поиск:
Код 6.3
Dim dx As Date
dx = CDate(ИскомыйЭлемент.Text)
ПротоколПоиска.Items.Clear() imin = 0 : imax = n + 1
i = n - 1 : k = 0 k = 0
limit = Math.Log(n) / Math.Log(2) + 1 Do Until k > limit
i = (imax + imin) \ 2 If i > n - 1 Then _
РезультатПоиска.Items.Add("Нет") : Exit Sub ПротоколПоиска.Items.Add(Format(k + 1, "00") & _
":" & Format(i, "0000"))
k = k + 1
If d(i) > dx Then imax = i
ElseIf d(i) < dx Then imin = i
Else
Exit Do End If
Loop
83
Варианты задания 6.2. Оба варианта данного задания предполагают, во-первых, отладку проекта задания 6.2 и, во-вторых, дополнение процедуры бинарного поиска дополнительной возможностью получения всех значений индекса для повторяющихся значений фамилии (или даты). С этой целью необходимо сделать «вставку» в код процедуры для команды меню Поиск.
Вариант 1. Найти все индексы (а не только один из индексов) для заданной фамилии – так, как показано на рис. 6.4.
Рис. 6.4. Пример бинарного поиска всех индексов для заданной фамилии
Вариант 2. Найти все индексы (а не только один из индексов) для заданной даты – так, как показано на рис. 6.5.
Рис. 6.5. Пример бинарного поиска всех индексов для заданной даты
84
Указание. Необходимо просмотреть элементы массива a(…) – фамилий, или массива d(…) – дат, которые предшествуют найденному элементу, и добавить их индексы в результат, если они совпадают с найденным элементом:
j = i - 1
If j < 0 Then Exit Sub Do While d(j) = dx
'или a(j) = ИскомыйЭлемент.Text
РезультатПоиска.Items.Add(Format(j, "0000") _ & ":" & ИсходныйСписок.Items.Item(j))
j = j - 1
If j < 0 Then Exit Sub Loop
Также необходимо просмотреть элементы массива a(…) – фамилий, или d(…) – дат, следующие за найденным элементом, и добавить их индексы в результат, если они совпадают с найденным элементом:
j = i + 1
If j >= n Then Exit Sub Do While d(j) = dx
'или a(j) = ИскомыйЭлемент.Text
РезультатПоиска.Items.Add(Format(j, "0000") _ & ":" & ИсходныйСписок.Items.Item(j))
j = j + 1
If j >= n Then Exit Sub Loop
Задание 6.3. Создать и отладить проект Windows приложения «Обработка изображения как двумерного массива пикселей».
Рассмотрим приложение, которое демонстрирует возможность использования двумерного динамического массива для хранения «точек» растрового изображения произвольного размера с целью его обработки. В данном приложении рассматриваются следующие виды обработки:
•преобразование данного цветного изображения в чёрно-белое изображение;
•получение негативного изображения;
•построение изображения, симметричного данному изображению относительно вертикальной оси;
85
•построение изображения, симметричного данному изображению относительно горизонтальной оси;
•построение увеличенного изображения;
•построение уменьшенного изображения.
Под «точкой» изображения в данном случае понимается цвет отдельного пикселя этого изображения с заданными координатами.
На рис. 6.6 показано окно данного приложения после построения негативного изображения.
Идея проектирования данного приложения заключается в сле-
дующем. На языке Visual Basic .NET (2005, 2008) можно создать и использовать особый виртуальный графический объект, например, с именем Page1, который является «bmp-копией» файла произвольного графического формата. Вместо графического файла можно воспользоваться значением свойства Image объекта класса PictureBox:
Dim Page1 As Bitmap
Page1 = New Bitmap(PictureBox1.Image)
Рис. 6.6. Окно приложения в процессе работы – после построения негативного изображения и рисования результата
С помощью двойного цикла и метода GetPixel языка VB .NET данный объект может быть «отсканирован» – цвет каждого его
86
пикселя с координатами (x, y) может быть помещён в двумерный массив c(x, y) типа Color (Цвет):
For y …
For x …
c(x, y) = Page1.GetPixel(x, y)
Next
Next
Цвет каждой точки изображения – каждый элемент массива c(x, y) – может быть программно изменён в соответствии с тем, какое преобразование выбрано. Этот изменённый цвет записывается в точку с координатами (x, y) другого виртуального объекта – например, с именем Page2 – с помощью метода SetPixel. Этот объект создаётся следующим образом:
Dim Page2 As Bitmap
Page2 = New Bitmap(PictureBox2.Width, _
PictureBox2.Height)
Рассмотрим преобразование в негативное изображение. Оно реализуется следующим образом:
For y …
For x …
cp = c(x, y)
a = cp.A : r = cp.R : g = cp.G : b = cp.B
cp = Color.FromArgb(a, 255 - r, 255 - g, 255 - b)
Page2.SetPixel(x, y, cp)
Next
Next
На рис. 6.7 показана форма приложения на этапе проектирования – при построении меню. Меню содержит четыре команды. После загрузки формы (старта приложения) команда Загрузить массив должна быть доступна, а две следующие команды – Обрабо-
тать изображение и Нарисовать – должны быть недоступными.
После загрузки массива первая и вторая команды обмениваются значениями «доступности» (значением свойства Enabled). Но команда Нарисовать остаётся пока недоступной.
87
Рис. 6.7. Форма приложения на этапе проектирования
Объявление переменных и две процедуры (загрузки формы и загрузки массива точек изображения) приведены в коде 6.4.
Код 6.4
Public Class Form1
Dim w0, h0, w, h, x, y As Integer
Dim Page1, Page2 As Bitmap
Dim gr As Graphics
Dim cp, c(,) As Color
Dim grey, a, r, g, b As Integer
Dim k As Single
Dim p As String
Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load
w0 = Me.Width
h0 = Me.Height
w = PictureBox1.Width - 1
h = PictureBox1.Height - 1 ReDim c(w, h)
Page1 = New Bitmap(PictureBox1.Image)
ОбработатьИзображение.Enabled = False
Нарисовать.Enabled = False End Sub
|
88 |
Private Sub ЗагрузитьМассив_Click(ByVal sender _ As System.Object, _
ByVal e As System.EventArgs) _ Handles ЗагрузитьМассив.Click
For y = 0 To h For x = 0 To w
c(x, y) = Page1.GetPixel(x, y)
Next
Next
ОбработатьИзображение.Enabled = True ЗагрузитьМассив.Enabled = False
End Sub
Рассмотрим процедуры для команды меню Обработать изо-
бражение, четырёх команд подменю: Черно-белое, Негативное, Увеличенное и Уменьшенное, а также команды меню Нарисо-
вать (код 6.5). Процедуры для команд подменю Слева-направо и Сверху-вниз в данном примере не рассматриваются.
Щелчок команды Обработать изображение вызывает не только появление подменю, показанного на рис. 6.7, но и меняет размеры как самой формы, так и окна изображения PictureBox2, на котором будет впоследствии нарисовано новое изображение. Кроме того, создается новый виртуальный объект Page2, в котором будет создаваться это изображение. Размеры объекта Page2 «подгоняются» под размеры окна изображения PictureBox2. Эта же процедура делает доступной команду меню Нарисовать.
Щелчок каждой из команд подменю включает соответствующую процедуру обработки изображения, в результате работы которой формируется содержимое виртуального объекта Page2. Завершается этот процесс присвоением строковой переменной p одного из значений: «черно-белое», «негативное», «увеличенное», «уменьшенное» и т.д. Эти значения будут учитываться в дальнейшем, после щелчка команды меню Нарисовать.
Код 6.5
Private Sub ОбработатьИзображение_Click(ByVal sender _ As Object, ByVal e As System.EventArgs) _ Handles ОбработатьИзображение.Click
|
89 |
Me.Width = w0
Me.Height = h0 PictureBox2.Width = w + 1 PictureBox2.Height = h + 1
Page2 = New Bitmap(PictureBox2.Width, _ PictureBox2.Height)
ОбработатьИзображение.Enabled = False
Нарисовать.Enabled = True End Sub
Private Sub ЧёрноБелое_Click(ByVal sender _ As System.Object, _
ByVal e As System.EventArgs) _ Handles ЧёрноБелое.Click
For y = 0 To h For x = 0 To w
cp = c(x, y)
a = cp.A : r = cp.R : g = cp.G : b = cp.B grey = (r + g + b) / 3
cp = Color.FromArgb(a, grey, grey, grey) Page2.SetPixel(x, y, cp)
Next
Next
MsgBox("Черно-белое - на Page2") p = "черно-белое"
End Sub
Private Sub Негативное_Click(ByVal sender _ As System.Object, _
ByVal e As System.EventArgs) _ Handles Негативное.Click
For y = 0 To h For x = 0 To w
cp = c(x, y) a = cp.A
r = cp.R g = cp.G b = cp.B
cp = Color.FromArgb(a, _
255 - r, 255 - g, 255 - b) Page2.SetPixel(x, y, cp)
Next
Next
MsgBox("Негативное - на Page2") p = "негативное"
End Sub
|
90 |