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

         

Ответы к задачам


1.

Private Sub Квадрат_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Квадрат.Click

        Результат.Text = Val(Число1.Text) * Val(Число1.Text)

End Sub

2.

Private Sub Сброс_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Сброс.Click

        Число1.Text = "" : Число2.Text = "" : Результат.Text = ""

End Sub

3.

Private Sub Кл_вычитания_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _

Handles Кл_вычитания.Click

        Результат.Text = Val(Число1.Text) - Val(Число2.Text)

        Кл_вычитания.Top = 30

        Кл_вычитания.Left = 100

        Кл_вычитания.Width = 300

        Кл_вычитания.Text = "Я устала вычитать"

End Sub

Private Sub Сброс_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Сброс.Click

        Число1.Text = "" : Число2.Text = "" : Результат.Text = ""

        Кл_вычитания.Top = 80



        Кл_вычитания.Left = 240

        Кл_вычитания.Width = 32

        Кл_вычитания.Text = "-"

End Sub

4.

Private Sub Каньон_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Каньон.Click

        Плеер.FileName = "D:\WINNT\Media\canyon.mid"

        Label3.Text = "Впечатляет, очень таинственно."

End Sub

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        TextBox2.Text = Плеер.CurrentPosition()                                       'Сколько прошло

        TextBox3.Text = Плеер.Duration - Плеер.CurrentPosition()          'Сколько осталось

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        Плеер.CurrentPosition = TextBox4.Text                           'Задание текущей позиции

End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click


        TextBox1.Text = Плеер.Duration                                     'Определение продолжительности клипа
End Sub
Private Sub Медленнее_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Медленнее.Click
        Плеер.Rate = 0.5
End Sub
Private Sub Тихо_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Тихо.Click
        Плеер.Volume = -1000
End Sub
Private Sub Громко_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Громко.Click
        Плеер.Volume = -10
End Sub
5.
Private Sub Кл_сложения_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Кл_сложения.Click
        Результат.Text = Val(Число1.Text) + Val(Число2.Text)
        Плеер.FileName = "D:\WINNT\Media\chimes.wav"
End Sub
Private Sub Кл_вычитания_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Кл_вычитания.Click
        Результат.Text = Val(Число1.Text) - Val(Число2.Text)
        Плеер.FileName = "D:\WINNT\Media\notify.wav"
End Sub
6.
0
7.
Будет напечатано число 211.
8.
1001
-100
15     
       -10
9.
82
10.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim Moscow, Vasyuki As Integer
        Moscow = 9000000
        Vasyuki = 1000
        WriteLine(Vasyuki + Moscow)
End Sub
11.
'Задача вычисления средней скорости
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Скорость1, Скорость2 As Double     'Скорости автомобиля на первом и втором участках пути
        Dim Время1, Время2 As Double              'Время прохождения первого и второго участков
        Dim Путь1, Путь2 As Double                    'Длина первого и второго участков
        Dim Средняя_скорость As Double          'Средняя скорость автомобиля
        'Задание исходных данных


        Скорость1 = 80 : Время1 = 3
        Скорость2 = 90 : Время2 = 2
        'Вычисление результата
        Путь1 = Скорость1 * Время1
        Путь2 = Скорость2 * Время2
        Средняя_скорость = (Путь1 + Путь2) / (Время1 + Время2)
        'Отображение результата
        Debug.WriteLine(Format(Средняя_скорость, "0.000"))
End Sub
12.
'Задача: В самом углу прямоугольного двора стоит прямоугольный дом.
'Подсчитать площадь дома, свободную площадь двора и длину забора.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        'Объявляем переменные величины
        Dim Длина_двора, Ширина_двора, Площадь_двора As Integer
        Dim Длина_дома, Ширина_дома, Площадь_дома As Integer
        Dim Периметр_двора, Полпериметра_дома As Integer
        Dim Свободная_площадь_двора, Длина_забора As Integer
        'Ввод исходных данных
        Длина_двора = InputBox("Введите длину двора")
        Ширина_двора = InputBox("Введите ширину двора")
        Длина_дома = InputBox("Введите длину дома")
        Ширина_дома = InputBox("Введите ширину дома")
        'Вычисление результатов
        Площадь_двора = Длина_двора * Ширина_двора
        Площадь_дома = Длина_дома * Ширина_дома
        Периметр_двора = 2 * (Длина_двора + Ширина_двора)
        Полпериметра_дома = Длина_дома + Ширина_дома
        Свободная_площадь_двора = Площадь_двора - Площадь_дома
        Длина_забора = Периметр_двора - Полпериметра_дома
        'Отображение результатов
        TextBox1.Text = "Площадь дома равна " & Площадь_дома
        TextBox2.Text = "Свободная площадь двора =  " & Свободная_площадь_двора
        Label1.Text = "Длина забора = " & Длина_забора
End Sub
13.
'Задача вычисления длины окружности и площади круга
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click


        Dim R As Double = 10                 'Радиус  окружности
        Dim L, S As Double                     'Длина окружности и Площадь круга
        'Вычисление результатов
        L = 2 * Math.PI * R
        S = Math.PI * R ^ 2
        'Отображение результатов с 5 знаками после запятой
        MsgBox("Длина окружности = " & Format(L, "0.00000"))
        MsgBox("Площадь круга = " & Format(S, "0.00000"))
End Sub
14.
ЦиклЦикл
ЦиклЦиклЦиклЦиклЦиклЦиклЦиклЦиклКонец цикла
15.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'Объявляем переменные величины
        Dim nazvanie1, nazvanie2 As String                      'Названия планет
        Dim r1, r2 As Double                                 'Радиусы орбит
        Dim v1, v2 As Double                                 'Скорости  планет по орбите
        Dim t1, t2 As Double                                   'Продолжительность года первой и второй планет
        'Задание исходных данных
        nazvanie1 = InputBox("Введите название первой планеты")
        nazvanie2 = InputBox("Введите название второй планеты")
        r1 = InputBox(" Введите радиус орбиты первой планеты (в миллионах километров)")
        r2 = InputBox("Введите радиус орбиты второй планеты (в миллионах километров)")
        v1 = InputBox("Введите скорость первой планеты (в миллионах километров в сутки)")
        v2 = InputBox("Введите скорость второй планеты (в миллионах километров в сутки)")
        'Вычисление результатов
        t1 = 2 * Math.PI * r1 / v1       'длина орбиты равна   два пи * радиус,
        t2 = 2 * Math.PI * r2 / v2       'а год = время 1 оборота = длина орбиты / скорость
        'Отображение результатов в трех вариантах:
        TextBox1.Text = "Продолжительность года на планете " & nazvanie1 & " - " & Format(t1, "0") _


                                                       & " суток, а на планете " & nazvanie2 & " - " + Format(t2, "0") & " суток"
        Label1.Text = "Продолжительность года на планете " & nazvanie1 & " - " & Format(t1, "0") _
                                                       & " суток, а на планете " & nazvanie2 & " - " + Format(t2, "0") & " суток"
        MsgBox("Продолжительность года на планете " & nazvanie1 & " - " & Format(t1, "0") _
                                                       & " суток, а на планете " & nazvanie2 & " - " + Format(t2, "0") & " суток")
End Sub
17.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Граф As Graphics = Me.CreateGraphics
        'Стебель:
        Граф.DrawArc(Pens.Black, -50, 100, 300, 600, 270, 90)
        'Земля:
        Граф.FillRectangle(Brushes.Aquamarine, 100, 400, 300, 30)
        Граф.DrawRectangle(Pens.Black, 100, 400, 300, 30)
        'Шесть лепестков:
        Граф.FillPie(Brushes.Chocolate, 0, 0, 300, 200, 0, 40)
        Граф.FillPie(Brushes.Blue, 0, 0, 300, 200, 50, 60)
        Граф.FillPie(Brushes.Red, 0, 0, 300, 200, 120, 50)
        Граф.FillPie(Brushes.Green, 0, 0, 300, 200, 180, 40)
        Граф.FillPie(Brushes.Brown, 0, 0, 300, 200, 230, 60)
        Граф.FillPie(Brushes.Violet, 0, 0, 300, 200, 300, 50)
        'Серединка:
        Граф.FillEllipse(Brushes.Yellow, 100, 67, 100, 67)
        Граф.DrawEllipse(Pens.Black, 100, 67, 100, 67)
End Sub
18.
'Задача: В самом углу прямоугольного двора стоит прямоугольный дом.
'Подсчитать площадь дома, свободную площадь двора и длину забора. Начертить чертеж.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click


        'Объявляем переменные величины
        Dim Граф As Graphics = Me.CreateGraphics
        Dim Длина_двора, Ширина_двора, Площадь_двора As Integer
        Dim Длина_дома, Ширина_дома, Площадь_дома As Integer
        Dim Периметр_двора, Полпериметра_дома As Integer
        Dim Свободная_площадь_двора, Длина_забора As Integer
        'Ввод исходных данных
        Длина_двора = InputBox("Введите длину двора")
        Ширина_двора = InputBox("Введите ширину двора")
        Длина_дома = InputBox("Введите длину дома")
        Ширина_дома = InputBox("Введите ширину дома")
        'Рисуем сначала двор, затем  забор, а уж потом - дом
        Граф.FillRectangle(Brushes.Aquamarine, 20, 80, Длина_двора, Ширина_двора)        'двор
        Граф.DrawRectangle(Pens.Black, 20, 80, Длина_двора, Ширина_двора)                    'забор
        Граф.FillRectangle(Brushes.Brown, 20, 80, Длина_дома, Ширина_дома)                    'дом
        'Вычисление результатов
        Площадь_двора = Длина_двора * Ширина_двора
        Площадь_дома = Длина_дома * Ширина_дома
        Периметр_двора = 2 * (Длина_двора + Ширина_двора)
        Полпериметра_дома = Длина_дома + Ширина_дома
        Свободная_площадь_двора = Площадь_двора - Площадь_дома
        Длина_забора = Периметр_двора - Полпериметра_дома
        'Отображение результатов
        Граф.DrawString("Площадь дома равна " & Площадь_дома, Me.Font, Brushes.Black, 100, 10)
        Граф.DrawString("Свободная площадь двора =  " & Свободная_площадь_двора,  _
Me.Font, Brushes.Black, 100, 30)
        Граф.DrawString("Длина забора = " & Длина_забора, Me.Font, Brushes.Black, 100, 50)
End Sub
19.
Dim Граф As Graphics
'Радиус и высота цилиндра - тип Single, так как этого требуют графические методы:
Dim r, h As Single
'Длина окружности и площадь основания, объем цилиндра, площадь боковой поверхности и полная площадь:


Dim L, Sосн, V, Sбок, Sполн As Double
'Удобно порождать графический объект при загрузке формы:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Граф = Me.CreateGraphics
End Sub
'Вычисляем и печатаем результаты:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        r = TextBox1.Text
        h = TextBox2.Text
        L = 2 * Math.PI * r
        Sосн = Math.PI * r ^ 2
        V = Sосн * h
        Граф.DrawString("Объем цилиндра = " & Format(V, "0.000"), Me.Font, Brushes.Black, 250, 20)
        Sбок = L * h
        Sполн = Sбок + 2 * Sосн
        Граф.DrawString("Полная площадь поверхности  цилиндра = " & Format(Sполн, "0.000"),  _
Me.Font, Brushes.Black, 250, 40)
End Sub
'Рисуем цилиндр:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        r = TextBox1.Text
        h = TextBox2.Text
        Граф.DrawEllipse(Pens.Black, 200, 100, 2 * r, r)                                                    'Верхнее основание
        Граф.DrawEllipse(Pens.Black, 200, 100 + h, 2 * r, r)                                              'Нижнее основание
        Граф.DrawLine(Pens.Black, 200, 100 + r / 2, 200, 100 + r / 2 + h)                         'Левый отрезок
        Граф.DrawLine(Pens.Black, 200 + 2 * r, 100 + r / 2, 200 + 2 * r, 100 + r / 2 + h)    'Правый отрезок
End Sub
'Стираем с формы:
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Граф.Clear(Color.White)
End Sub
20.
8
29
6
21.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim a, b As Double
        a = InputBox("Введите первое число")
        b = InputBox("Введите второе число")


        If a > b Then Debug.WriteLine(a + b) Else Debug.WriteLine(a * b)
        Debug.WriteLine("ЗАДАЧА РЕШЕНА")
End Sub
22.
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim a, b, c As Double
        a = InputBox("Введите первый отрезок")
        b = InputBox("Введите второй отрезок")
        c = InputBox("Введите третий отрезок")
        If a >= b + c Then Debug.WriteLine("Слишком велик") Else Debug.WriteLine("Достаточно мал")
End Sub
23.
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Dim N As Integer, Число_голов As Integer, Число_глаз As Integer
        N = InputBox("Введите возраст дракона")
        If N < 100 Then Число_голов = 3 * N Else Число_голов = 300 + 2 * (N - 100)
        Debug.WriteLine(Число_голов)
        Число_глаз = 2 * Число_голов
        Debug.WriteLine(Число_глаз)
End Sub
24.
Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click
        If Button6.Top < 100 Then Button6.Top = Button6.Top + 20
End Sub
25.
Dim Граф As Graphics
Dim Ширина_окна, Высота_окна As Single
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Граф = Me.CreateGraphics
End Sub
'Рисуем окно:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Ширина_окна = 200
        Высота_окна = 300
        Граф.FillRectangle(Brushes.Black, 100, 50, Ширина_окна, Высота_окна)
        Граф.DrawRectangle(Pens.White, 100, 50, Ширина_окна, Высота_окна)
        Граф.DrawLine(Pens.White, 100 + Ширина_окна / 2, 50, 100 + Ширина_окна / 2, 50 + Высота_окна)
End Sub
'Зажигаем звезду:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click


        Граф.DrawEllipse(Pens.White, 100 + Ширина_окна * Rnd(), 50 + Высота_окна * Rnd(), 3, 3)
End Sub
26.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Randomize()
        'Без учета Button1.Width кнопка у правого края формы часто будет видна не полностью:
        Button1.Left = (Me.Width - Button1.Width) * Rnd()
        'Без учета Button1.Height кнопка у нижнего края формы часто будет видна не полностью:
        Button1.Top = (Me.Height - Button1.Height - 30) * Rnd()
End Sub
27.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Догадка As Byte
        Randomize()
        Dim Загаданное_число As Byte = Fix(2 * Rnd())
        Догадка = InputBox("Угадай - 0 или 1?")
        If Догадка = Загаданное_число Then TextBox1.Text = "Угадал" Else TextBox1.Text = "Не угадал"
End Sub
28.
12653
29.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Имя As String
        Имя = InputBox("Как вас зовут?")
        If Имя = "Коля" Then
            MsgBox("Привет!")
        ElseIf Имя = "Вася" Then
            Me.BackColor = Color.Green
            MsgBox("Здорово!")
        ElseIf Имя = "John" Then
            MsgBox("Hi!")
        Else
            MsgBox("Здравствуйте!")
        End If
End Sub
30.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim imya, Вопрос As String
        Dim vozrast As Integer
        imya = InputBox("Здравствуй, я компьютер, а тебя как зовут?")
        vozrast = InputBox("Очень приятно, " & imya & ". Сколько тебе лет?")
        MsgBox("Ого! Целых " & vozrast & " лет! Ты уже совсем взрослый!")


        If vozrast > 17 Then
            ' Обратите внимание, что InputBox можно применять и без оператора присваивания:
            InputBox("В каком институте ты учишься?")
            MsgBox("Хороший институт")
        Else
            InputBox("В какой школе ты учишься?")
            MsgBox("Неплохая школа")
        End If
        MsgBox("До следующей встречи!")
End Sub
31.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim a, b, c As Double
        a = InputBox("Введите первый отрезок")
        b = InputBox("Введите второй отрезок")
        c = InputBox("Введите третий отрезок")
        If a >= b + c Then : MsgBox("Нельзя")
        ElseIf b >= a + c Then : MsgBox("Нельзя")
        ElseIf c >= a + b Then : MsgBox("Нельзя")
        Else : MsgBox("Можно")
        End If
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim a, b, c As Double
        a = InputBox("Введите первый отрезок")
        b = InputBox("Введите второй отрезок")
        c = InputBox("Введите третий отрезок")
        If a >= b + c Or b >= a + c Or c >= a + b Then MsgBox("Нельзя") Else MsgBox("Можно")
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim a, b, c As Double
        a = InputBox("Введите первый отрезок")
        b = InputBox("Введите второй отрезок")
        c = InputBox("Введите третий отрезок")
        If a < b + c And b < a + c And c < a + b Then MsgBox("Можно") Else MsgBox("Нельзя")
End Sub
32.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click


        Dim a As String             'Приветствие человека
        Dim b As String             'Ответ компьютера
        a = InputBox("Компьютер Вас слушает")
        If a = "Привет" Or a = "Здравствуйте" Or a = "Салют" Then
            b = a
        ElseIf a = "Добрый день" Or a = "Приветик" Then
            b = "Салют"
        ElseIf a = "Здравия желаю" Then
            b = "Вольно"
        Else
            b = "Я вас не понимаю"
        End If
        MsgBox(b)
End Sub
33.
Замысловатой принцессе нравятся черноглазые, кроме тех, чей рост находится в пределах от 180 до 184.
34.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim Граф As Graphics = Me.CreateGraphics
        Граф.DrawLine(Pens.Black, 0, 100, 1000, 100)                                           'Земля
        Граф.FillRectangle(Brushes.Black, 0, 90, 10, 10)                                        'Пушка
        Граф.FillRectangle(Brushes.Blue, 280, 90, 20, 10)                                      'Первая цель
        Граф.FillRectangle(Brushes.Blue, 650, 90, 50, 10)                                      'Вторая цель
        Dim a As Single = InputBox("Введите дальность выстрела")
        Граф.FillEllipse(Brushes.Red, 10 * a, 95, 10, 10)                                        'Попадание
        If (a > 28 And a < 30) Or (a > 65 And a < 70) Then
            MsgBox("ПОПАЛ")
        ElseIf (a > 18 And a < 40) Or (a > 55 And a < 80) Then
            MsgBox("БЛИЗКО")
        ElseIf a > 80 Then
            MsgBox("ПЕРЕЛЕТ")
        ElseIf a > 30 And a < 65 Then
            MsgBox("МЕЖДУ ЦЕЛЯМИ")
        ElseIf a < 0 Then
            MsgBox("НЕ БЕЙ ПО СВОИМ")
        Else
            MsgBox("НЕДОЛЕТ")


        End If
End Sub
35.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Граф As Graphics = Me.CreateGraphics
        'Три отрезка (a, b, c),  они же в другом порядке (bol, drug1, drug2),
        'площадь, высота, полупериметр треугольника (S, h, p), координаты трех вершин тр-ка:
        Dim a, b, c, bol, drug1, drug2, S, h, p, x1, y1, x2, y2, x3, y3 As Single
        a = InputBox("Введите первый отрезок")
        b = InputBox("Введите второй отрезок")
        c = InputBox("Введите третий отрезок")
        'Находим самый большой отрезок bol и присваиваем значения drug1 и  drug2:
        If a >= b And a >= c Then
            bol = a : drug1 = b : drug2 = c
        ElseIf b >= a And b >= c Then
            bol = b : drug1 = a : drug2 = c
        ElseIf c >= a And c >= b Then
            bol = c : drug1 = a : drug2 = b
        End If
        If bol < drug1 + drug2 Then
            p = (a + b + c) / 2
            S = Math.Sqrt(p * (p - a) * (p - b) * (p - c))                        'формула Герона
            h = 2 * S / bol
            'Пусть самая длинная сторона тр-ка будет горизонтальна, а третья  вершина ниже ее.
            'Выбираем произвольно первую вершину треугольника:
            y1 = 100
            x1 = 100
            'Самая длинная сторона тянется от нее строго направо ко второй вершине:
            y2 = y1
            x2 = x1 + bol
            'Третья вершина будет лежать ниже нее на высоту h:
            y3 = y1 + h
            'и правее первой вершины (применяем теорему Пифагора):
            x3 = x1 + Math.Sqrt(drug1 ^ 2 - h ^ 2)
            'Рисуем треугольник:
            Граф.DrawLine(Pens.Black, x1, y1, x2, y2)
            Граф.DrawLine(Pens.Black, x2, y2, x3, y3)
            Граф.DrawLine(Pens.Black, x3, y3, x1, y1)
        Else
            MsgBox("Треугольник невозможен")


        End If
End Sub
36.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Буква As String = InputBox("Введите строчную букву русского алфавита")
        Select Case Буква
            Case "а", "и", "о", "у", "ы", "э"
                MsgBox("гласный")
            Case "б", "з", "в", "г", "д", "ж", "й", "л", "м", "н", "р"
                MsgBox("согласный звонкий")
            Case "п", "с", "ф", "к", "т", "ш", "х", "ц", "ч", "щ"
                MsgBox("согласный глухой")
            Case "е", "ё", "ю", "я", "ъ", "ь"
                MsgBox("какой-нибудь другой, не знаю")
            Case Else
                MsgBox(" Это не строчная буква русского алфавита")
        End Select
End Sub
38.
Считаем зайцев
10 зайцев
10 зайцев
11 зайцев
13 зайцев
16 зайцев
20 зайцев
25 зайцев
. . . . .
39.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
m:    PictureBox1.Left = PictureBox1.Left - 1        'Налево
        GoTo m
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
m:    PictureBox1.Top = PictureBox1.Top + 1        'Вниз
        GoTo m
End Sub
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
m:    PictureBox1.Top = PictureBox1.Top - 1        'Вверх
        GoTo m
End Sub
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click


m:    PictureBox1.Left = PictureBox1.Left + 1        'Направо
        PictureBox1.Top = PictureBox1.Top + 1        'и вниз - получается наискосок
        GoTo m
End Sub
40 В.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'Печатаем  1  2  3  4  . . . 100:
        Dim a As Integer = 1
m1:  Debug.Write(a & " ")
        a = a + 1
        If a <= 100 Then GoTo m1
        'Печатаем  99  98  97  96  . . . 1:
        a = 99
m2:  Debug.Write(a & " ")
        a = a - 1
        If a >= 1 Then GoTo m2
End Sub
41.
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim x, y, z As Double
        x = 2700
m1:  y = x / 4 + 20
        z = 2 * y + 0.23
        If y * z < 1 / x Then GoTo m2
        Debug.WriteLine(Format(x, "0.000000") & "  " & Format(y, "0.000000") & "  " & Format(z, "0.000000"))
        x = x / 3
        GoTo m1
m2:
End Sub
Если вам непонятно, почему применена такая странная логика программы, то отложите понимание до того момента, когда закончите изучение циклов.
42.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim x As Double
        x = 50                                   'Начальная точка движения
m:    PictureBox1.Left = x            'Изображение встает на место, указанное гориз. координатой
        x = x + 0.0001                      'Компьютер увеличивает в уме горизонтальную координату
        If x <= 300 Then GoTo m        'Движемся до точки 300
End Sub
43.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim x, y As Single
        x = 50 : y = 100                     'Начальная точка движения
        Label1.Text = "Двигаюсь вправо"


        Label1.Refresh()
        PictureBox1.Top = y           ' Изображение встает на место, указанное вертик. координатой
m:    PictureBox1.Left = x            'Изображение встает на место, указанное гориз. координатой
        x = x + 0.0001                     'Компьютер увеличивает в уме горизонтальную координату
        If x <= 500 Then GoTo m    'Движемся до точки 500 по горизонтали
        Label1.Text = "Двигаюсь вниз"
        Label1.Refresh()
m1:  PictureBox1.Top = y            'Изображение встает на место, указанное вертик  координатой
        y = y + 0.0001                      'Компьютер увеличивает в уме вертикальную координату
        If y <= 400 Then GoTo m1  'Движемся до точки 400 по вертикали
End Sub
44.
        Dim f, s As Integer
        f = 0
        Do
            s = 1000 - f
            Debug.Write(f & " " & s & "     ")
            f = f + 1
        Loop While f <= 1000
2 вариант отличается лишь одним оператором:
        Loop Until f > 1000
45.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim x, y As Single
        x = 50 : y = 100                               'Начальная точка движения
        Label1.Text = "Двигаюсь вправо"
        Label1.Refresh()
        PictureBox1.Top = y                 'Изображение встает на место, указанное вертик. координатой
        Do While x <= 500                   'Движемся до точки 500 по горизонтали
            PictureBox1.Left = x             'Изображение встает на место, указанное гориз. координатой
            x = x + 0.0001                             'Компьютер увеличивает в уме горизонтальную координату
        Loop
        Label1.Text = "Двигаюсь вниз"
        Label1.Refresh()
        Do Until y > 400                        'Движемся до точки 400 по вертикали
            PictureBox1.Top = y             'Изображение встает на место, указанное вертик  координатой


            y = y + 0.0001                             'Компьютер увеличивает в уме вертикальную координату
        Loop
End Sub
46.
        Dim Slovo As String
        Dim Номер As Integer = 1
        Do
            Slovo = InputBox("Введите слово")
            Debug.WriteLine(Номер & "   " & Slovo & "!")
            If Len(Slovo) > 10 Then Debug.WriteLine("Тяжелая жизнь.")
            Номер = Номер + 1
        Loop Until Slovo = "Хватит"
        Debug.WriteLine("Хватит так хватит")
47.
'Вычислительная часть отдельно:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim v, t, h, s As Double
        v = 20 : t = 0 : h = 100 : s = 0
        Do
            s = v * t
            h = 100 - 9.81 * t ^ 2 / 2
            Debug.WriteLine(Format(t, "0.0") & "   " & Format(s, "0.000") & "   " & Format(h, "0.000"))
            t = t + 0.2
        Loop Until h < 0
End Sub
'Вычислительная и графическая части вместе:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim v, t, h, s As Double
        Dim x, y As Single                                                     'Координаты камня на форме
        Dim Граф As Graphics = Me.CreateGraphics
        v = 20 : t = 0 : h = 100 : s = 0
        Граф.DrawLine(Pens.Black, 10, 110, 200, 110)       ' Земля расположена на 110 ниже края формы
        'Верх башни расположен на 10 ниже края формы, низ - на 110:
        Граф.FillRectangle(Brushes.Green, 10, 10, 20, 100)
        MsgBox("Башня построена")
        Do
            s = v * t
            h = 100 - 9.81 * t ^ 2 / 2
            Debug.WriteLine(Format(t, "0.0") & "   " & Format(s, "0.000") & "   " & Format(h, "0.000"))


            x = s + 20                                            ' Бросаем камень из точки, на 20 правее края формы
            y = 110 - h
            'В начальный момент времени h = 100 и получается,
            ‘что мы бросаем камень из точки, на 10 ниже края формы
            'Когда камень прилетит на землю,  h = 0 и получается,
             ‘что камень прилетает в точку, на 110 ниже края формы
            Граф.DrawEllipse(Pens.Black, x, y, 5, 5)                  'Рисуем очередной кружок
            t = t + 0.2
        Loop Until h < 0
End Sub
48.
        Dim Slovo As String
        Do
            Slovo = InputBox("Введите слово")
            If Slovo = "Хватит" Then Exit Do
            Debug.WriteLine(Slovo & "!")
        Loop
        Debug.WriteLine("Хватит так хватит")
49.
        Dim i As Integer
        Debug.Write("Прямой счет  ")
        For i = -5 To 5
            Debug.Write(i & " ")
        Next
        Debug.Write("Обратный счет  ")
        For i = 5 To -5 Step -1
            Debug.Write(i & " ")
        Next
        Debug.Write("Конец счета")
50.
Dim i, Размер_круга As Single
For i = 1 To 20
    Размер_круга = 80 * Rnd()
    Граф.DrawEllipse(Pens.Black, PictureBox1.Width * Rnd(), PictureBox1.Height * Rnd(),  _
Размер_круга, Размер_круга / 2)
Next i
51.
        Dim i, Размер As Single
        For i = 1 To 5
            Размер = 200 * Rnd()
            Граф.DrawEllipse(Pens.Red, PictureBox1.Width * Rnd(), PictureBox1.Height * Rnd(), Размер, Размер)
            Граф.DrawEllipse(Pens.Yellow, PictureBox1.Width * Rnd(), PictureBox1.Height * Rnd(), Размер, Размер)
            Граф.DrawEllipse(Pens.Blue, PictureBox1.Width * Rnd(), PictureBox1.Height * Rnd(), Размер, Размер)
            Граф.DrawEllipse(Pens.Green, PictureBox1.Width * Rnd(), PictureBox1.Height * Rnd(), Размер, Размер)
            Граф.DrawEllipse(Pens.White, PictureBox1.Width * Rnd(), PictureBox1.Height * Rnd(), Размер, Размер)


        Next i
52.
    Dim i As Integer
    For i = 1 To 10000          'Большое число - чтобы долго рисовалось. Сам процесс приятен.
        'Каждый луч прожектора - отрезок от центральной точки формы с координатами
        'Me.Width / 2 по горизонтали и Me.Height / 2 по вертикали до случайной с координатами Me.Width * Rnd() .
        'по горизонтали и Me.Height * Rnd()  по вертикали. Для совместимости с типом параметров
        'метода пришлось при помощи CSng преобразовывать два параметра к типу Single.
        Граф.DrawLine(Pens.White, CSng(Me.Width / 2), CSng(Me.Height / 2), Me.Width * Rnd(), Me.Height * Rnd())
        Граф.DrawLine(Pens.Yellow, CSng(Me.Width / 2), CSng(Me.Height / 2), Me.Width * Rnd(), Me.Height * Rnd())
        Граф.DrawLine(Pens.Blue, CSng(Me.Width / 2), CSng(Me.Height / 2), Me.Width * Rnd(), Me.Height * Rnd())
        Граф.DrawLine(Pens.Red, CSng(Me.Width / 2), CSng(Me.Height / 2), Me.Width * Rnd(), Me.Height * Rnd())
        Граф.DrawLine(Pens.Green, CSng(Me.Width / 2), CSng(Me.Height / 2), Me.Width * Rnd(), Me.Height * Rnd())
    Next i
53.
        For i = 1 To 300
            'Левая треть стога имеет горизонтальные координаты от 0 до 200,
            'значит случайная точка внутри этой части - (200 * Rnd)
            'Правая треть стога имеет горизонтальные координаты от 400 до 600,
            'значит случайная точка внутри этой части - (400 + 200 * Rnd)
            'Что касается вертикальных координат, то все они случайны от 0 до 600.
            Граф.DrawLine(Pens.Yellow, 200 * Rnd(), 600 * Rnd(), 400 + 200 * Rnd(), 600 * Rnd())
            Граф.DrawLine(Pens.Green, 200 * Rnd(), 600 * Rnd(), 400 + 200 * Rnd(), 600 * Rnd())
            Граф.DrawLine(Pens.Wheat, 200 * Rnd(), 600 * Rnd(), 400 + 200 * Rnd(), 600 * Rnd())
        Next
54А.
            x = x + 5
54Б.
        x = 0
        Do Until x > Me.Width - 30
            Граф.DrawEllipse(Pens.Black, x, 100, 20, 20)
            x = x + 5


        Loop
54В.
            Граф.DrawEllipse(Pens.Black, x, 100, 40, 40)
55.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim Граф As Graphics = Me.CreateGraphics
        Dim x, y As Integer
        'Первая очередь:
        x = 0 : y = 0                                       'Встаем в левый верхний угол
        Do Until x > Me.Width                       ' Пока не дойдем до правого края формы
            Граф.FillEllipse(Brushes.White, x, y, 4, 4)
            x = x + 15 : y = y + 10
        Loop
        'Вторая очередь:
        x = 0 : y = Me.Height – 30                  'Встаем в левый нижний угол
        Do Until x > Me.Width                        'Пока не дойдем до правого края формы
            Граф.FillEllipse(Brushes.White, x, y, 4, 4)
            x = x + 15 : y = y - 10
        Loop
End Sub
56.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim x, y, D As Integer
        Dim Граф As Graphics = Me.CreateGraphics
        x = 0 : y = 0 : D = 0
        Do Until x > 400
            Граф.DrawEllipse(Pens.Black, x, y, D, D)
            x = x + 5
            y = y + 2
            D = D + 1
        Loop
End Sub
57.
 Отличается от «круглого трубопровода» единственным словом:
           Граф.DrawRectangle(Pens.Black, x, y, D, D)
58А.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Граф As Graphics = Me.CreateGraphics
        Dim y As Integer
        y = 0                                     'Разлиновывать начинаем с верхнего края формы
        Do Until y > Me.Height         'Разлиновываем до нижнего края формы
            'Линию проводим горизонтально от левого до правого края формы:
            Граф.DrawLine(Pens.Black, 0, y, Me.Width, y)
            y = y + 20                          'Расстояние между линиями = 20


        Loop
End Sub
58Б.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim Граф As Graphics = Me.CreateGraphics
        Dim x, y As Integer
        'Разлиновываем горизонтальными линиями:
        y = 0                                     'Разлиновывать начинаем с верхнего края формы
        Do Until y > Me.Height         'Разлиновываем до нижнего края формы
            ' Линию проводим горизонтально от левого до правого края формы:
            Граф.DrawLine(Pens.Black, 0, y, Me.Width, y)
            y = y + 10                          'Расстояние между линиями = 10
        Loop
        'Разлиновываем вертикальными линиями:
        x = 0                                     'Разлиновывать начинаем с левого края формы
        Do Until x > Me.Width          'Разлиновываем до правого края формы
            'Линию проводим вертикально от верхнего до нижнего края формы:
            Граф.DrawLine(Pens.Black, x, 0, x, Me.Height)
            x = x + 10                         'Расстояние между линиями =10
        Loop
End Sub
58В.
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim Граф As Graphics = Me.CreateGraphics
        Dim x, y As Integer
        'Разлиновываем горизонтальными линиями:
        y = 0                                               'Разлиновывать начинаем с верхнего края формы
        Do Until y > Me.Height                     'Разлиновываем до нижнего края формы
            'Линию проводим горизонтально от левого до правого края формы:
            Граф.DrawLine(Pens.Black, 0, y, Me.Width, y)
            y = y + 20                                    'Расстояние между линиями = 20
        Loop
        'Разлиновываем косыми линиями:
        x = 0                                               'Разлиновывать начинаем с левого края формы
        Do Until x > Me.Width + 300            'Разлиновываем до правого края формы с запасом в 300 пикселов


            ' Линию проводим наискосок от верхнего до нижнего края формы:
            Граф.DrawLine(Pens.Black, x, 0, x - 200, Me.Height)
            x = x + 10                                    'Расстояние между линиями =10
        Loop
End Sub
59.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim Граф As Graphics = Me.CreateGraphics
        Dim x, Высота_столбца, i, Число_городов, Число_жителей As Integer
        Dim Название As String
        Число_городов = InputBox("Введите число городов на диаграмме")
        x = 20                                                                             'Отступ столбца от левого  края формы
        For i = 1 To Число_городов
            Название = InputBox("Введите название города")
            Число_жителей = InputBox("Введите число жителей в тысячах")
            Высота_столбца = Число_жителей / 100
            'Масштаб 100 нужен для того, чтобы столбцы умещались по высоте на форме
            'Рисуем столбец (50 - его отступ от верхнего края формы, 60 - ширина):
            Граф.FillRectangle(Brushes.Black, x, 50, 60, Высота_столбца)
            'Пишем над столбцом название города:
            Граф.DrawString(Название, Me.Font, Brushes.Black, x, 30)
            'Пишем под столбцом число жителей:
            Граф.DrawString(Число_жителей * 1000, Me.Font, Brushes.Black, x, Высота_столбца + 60)
            x = x + 70                                                                                            'Шаг от столбца к столбцу
        Next
End Sub
60А.
Компьютер спросит размеры только одного зала и три раза напечатает его площадь и объем:
Площадь пола = 300    Объем зала = 1200
Площадь пола = 300    Объем зала = 1200
Площадь пола = 300    Объем зала = 1200
60Б.
Компьютер напечатает результаты только для последнего зала:
Площадь пола = 50    Объем зала = 150
61.
А. Компьютер напечатает результат, на 10 превышающий правильный


Б. Компьютер напечатает результат, в 2 раза превышающий правильный
В. Компьютер напечатал бы 200 нарастающих значений счетчика
Г. Компьютер напечатает 1, если последнее число положительное, и 0 – если неположительное
Д. Компьютер запросит только одно число и напечатает 200, если оно положительное, и 0 – если неположительное
62.
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim N, a, i, c_полож, c_отриц, c_больше_10 As Integer
        c_полож = 0                             'Обнуляем счетчик положительных чисел
        c_отриц = 0                             'Обнуляем счетчик отрицательных чисел
        c_больше_10 = 0                     'Обнуляем счетчик чисел, превышающих 10
        N = InputBox("Сколько всего чисел?")
        For i = 1 To N
            a = InputBox("Введите очередное число")
            If a > 0 Then c_полож = c_полож + 1
            If a < 0 Then c_отриц = c_отриц + 1
            If a > 10 Then c_больше_10 = c_больше_10 + 1
        Next i
        Debug.WriteLine("Из них положительных - " & c_полож & ",   отрицательных - " & c_отриц _
     & ",   чисел, превышающих десятку - " & c_больше_10)
End Sub
Здесь операторы Select Case и многострочный If плохо подошли бы, так как случаи невзаимоисключающие.
63.
        Dim a, b, c As Integer
        c = 0                             'Обнуляем счетчик пар
        Do
            a = InputBox("Введите первое число пары")
            b = InputBox("Введите второе число пары")
            If a = 0 And b = 0 Then Exit Do
            If a + b = 12 Then c = c + 1
        Loop
        Debug.WriteLine(c)
64.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim i, Счетчик_лев, Счетчик_верх, Счетчик_низ As Integer
        Dim x, y, Ширина_формы, Высота_формы As Single


        Ширина_формы = Me.Width
        Высота_формы = Me.Height
        ' Рисуем для наглядности вертикальную линию, делящую форму пополам:
        Граф.DrawLine(Pens.White, Ширина_формы / 2, 0, Ширина_формы / 2, Высота_формы)
        'Рисуем для наглядности квадрат 100 на 100 в левом верхнем углу:
        Граф.DrawRectangle(Pens.White, 0, 0, 100, 100)
        'Рисуем  квадрат 100 на 100 в левом нижнем углу (28 - учет высоты заголовка формы):
        Граф.DrawRectangle(Pens.White, 0, Высота_формы - 100 - 28, 100, 100)
        Счетчик_лев = 0 : Счетчик_верх = 0 : Счетчик_низ = 0
        Randomize()
        For i = 1 To 100
            x = Me.Width * Rnd()
            y = Me.Height * Rnd() - 28
            Граф.FillEllipse(Brushes.White, x, y, 3, 3)                                               'Рисуем звезду
            If x < Ширина_формы / 2 Then Счетчик_лев = Счетчик_лев + 1
            If x < 100 And y < 100 Then Счетчик_верх = Счетчик_верх + 1
            If x < 100 And y > Высота_формы - 128 Then Счетчик_низ = Счетчик_низ + 1
        Next
        'Печатаем результаты:
        Debug.WriteLine(Счетчик_лев)
        Debug.WriteLine(Счетчик_верх)
        Debug.WriteLine(Счетчик_низ)
        'Определяем, где звезд больше:
        If Счетчик_верх > Счетчик_низ Then
            Debug.WriteLine("Сверху звезд больше")
        ElseIf Счетчик_верх < Счетчик_низ Then
            Debug.WriteLine("Снизу звезд больше")
        Else
            Debug.WriteLine("Одинаково")
        End If
End Sub
65.
А. 18
Б. 10
В. 5 и 8
Г. 3
Д. 10
Е. 3
Ж. 5
66.
        Dim Dlina, Shirina, S As Double
        Dim i As Integer
        S = 0                                                            'Обнуляем сумматор площади пола
        For i = 1 To 40
            Dlina = InputBox("Введите длину")
            Shirina = InputBox("Введите ширину")
            S = S + Dlina * Shirina                        'Наращиваем сумматор площади пола


        Next
        Debug.WriteLine("Общая площадь пола= " & S)
67.
        Dim i, N, Балл, s As Integer
        Dim Средний_балл As Double
        N = InputBox("Сколько учеников в классе?")
        s = 0                               'Обнуляем сумматор баллов
        For i = 1 To N
            Балл = InputBox("Введите оценку по физике")
            s = s + Балл                'Наращиваем сумматор баллов
        Next i
        Средний_балл = s / N
        MsgBox("Средний балл по физике = " & Format(Средний_балл, "0.000"))
68.
    Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Dim i, N, Число, proizv As Integer
        N = InputBox("Сколько сомножителей?")
        proizv = 1                              'Cумматор обнуляем, а накопитель произведения приравниваем 1. Почему?
        For i = 1 To N
            Число = InputBox("Введите очередной сомножитель")
            proizv = proizv * Число                                      'Наращиваем произведение
        Next i
        MsgBox("Произведение равно " & proizv)
    End Sub
69А.
        For k = 3 To 8
            For l = 0 To 7
                Debug.WriteLine(k & l)                         'Печатаем очередное сочетание
            Next l
        Next k
69Б.
        i = 0                                                                 'Обнуляем счетчик
        For k = 1 To 3
            For l = 1 To 3
                For m = 1 To 3
                    For n = 1 To 3
                        Debug.WriteLine(k & l & m & n)      'Печатаем очередное сочетание
                        i = i + 1
                    Next n
                Next m
            Next l
        Next k
        Debug.WriteLine(i)                                          'Печатаем количество сочетаний
69В.
       i = 0                                                                      'Обнуляем счетчик


        For k = 1 To 3
            For l = 1 To 3
                For m = 1 To 3
                    For n = 1 To 3
                        If k <= l And l <= m And m <= n Then
                            i = i + 1
                            Debug.WriteLine(k & l & m & n)      'Печатаем очередное сочетание
                        End If
                    Next n
                Next m
            Next l
        Next k
        Debug.WriteLine(i)                                               'Печатаем количество сочетаний
70.
       Размер = 30                                'Размер окружности
        Шаг = 16                                     'Шаг между окружностями
        y = 10
        Do Until y > 400
            x = 20
            Do Until x > 500
                Граф.DrawEllipse(Pens.Black, x, y, Размер, Размер)
                x = x + Шаг
            Loop
            y = y + Шаг
        Loop
70А.
Вместо строки
               Граф.DrawEllipse(Pens.Black, x, y, Размер, Размер)
пишем строку
                If Not (x > 400 And y < 100) Then Граф.DrawEllipse(Pens.Black, x, y, Размер, Размер)
которую можно вольно перевести так:
ЕСЛИ  НЕПРАВДА, что (это верхний правый угол),  ТО  рисуй кружок
70Б.
Вместо строки
                If Not (x > 400 And y < 100) Then Граф.DrawEllipse(Pens.Black, x, y, Размер, Размер)
пишем строку
If Not (x > 400 And y < 100) And Not (x > 200 And x < 300 And y > 150 And y < 250) Then _
                                                                                 Граф.DrawEllipse(Pens.Black, x, y, Размер, Размер)
которую можно вольно перевести так:
ЕСЛИ  НЕПРАВДА, что (это верхний правый угол)  И  НЕПРАВДА, что (это квадрат в центре),  ТО  рисуй кружок
71.
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Dim i, j, x, y, Размер, Зазор As Integer
        Размер = 40                      'Размер клетки


        Зазор = 5                           'Зазор между клетками
        y = 20                                 'Отступ от верхнего края формы
        For i = 1 To 8                     'Пробегаем 8 рядов по вертикали сверху вниз,  i - номер ряда
            x = 20                             'Отступ от левого края формы
            For j = 1 To 8                  'Пробегаем 8 клеток по горизонтали слева направо, j - номер клетки в ряду
                'ЕСЛИ сумма номеров столбца и ряда четная, то заливка квадрата желтая, ИНАЧЕ красная:
                If (i + j) Mod 2 = 0 Then
                    Граф.FillRectangle(Brushes.Yellow, x, y, Размер, Размер)
                Else
                    Граф.FillRectangle(Brushes.Red, x, y, Размер, Размер)
                End If
                Граф.DrawRectangle(Pens.Black, x, y, Размер, Размер)           'Черное обрамление квадрата
                x = x + Размер + Зазор
            Next
            y = y + Размер + Зазор
        Next
End Sub
72.
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Dim a, b, proizv, x, y As Integer
        Граф.DrawString("Таблица умножения", Me.Font, Brushes.Black, 300, 10)
        y = 30
        For a = 1 To 10
            x = 10
            For b = 1 To 10
                proizv = a * b
                Граф.DrawRectangle(Pens.Black, x, y, 60, 15)
                Граф.DrawString(a & "*" & b & "=" & proizv, Me.Font, Brushes.Black, x, y)
                x = x + 70
            Next
            y = y + 20
        Next
End Sub
73А.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim max, chislo, i As Integer
        For i = 1 To 10
            chislo = InputBox("Введите число")
            If i = 1 Then
                max = chislo
            ElseIf chislo > max Then


                max = chislo
            End If
        Next i
        Debug.WriteLine(max)
End Sub
73Б.
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim max, chislo, i As Integer
        max = -100000
        For i = 1 To 10
            chislo = InputBox("Введите число")
            If chislo > max Then max = chislo
        Next i
        Debug.WriteLine(max)
End Sub
74.
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
        Dim min, chislo, i, N, Номер_мин_числа As Integer
        N = InputBox("Сколько чисел?")
        min = InputBox("Введите число")
        Номер_мин_числа = 1
        For i = 2 To N
            chislo = InputBox("Введите число")
            If chislo < min Then
                min = chislo
                Номер_мин_числа = i
            End If
        Next i
        Debug.WriteLine(min)
        Debug.WriteLine(Номер_мин_числа)
End Sub
75.
   Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click
        Dim i, N As Integer
        Dim Результат, Min, Max As Double
        N = InputBox("Сколько бегунов?")
        Min = 5000   'Заведомо невозможный сверхмедленный бег
        Max = 0        'Заведомо невозможный сверхбыстрый бег
        For i = 1 To N
            Результат = InputBox("Введите результат в секундах")
            If Результат < Min Then Min = Результат
            If Результат > Max Then Max = Результат
        Next i
        If Max - Min > 0.4 Then MsgBox("Правда") Else MsgBox("Неправда")
    End Sub
76.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim i, x, y, Самый_правый_х, Самый_правый_у As Integer
        Самый_правый_х = -100000                              'Заведомо "невозможно левая" координата


        For i = 1 To 4
            x = 400 * Rnd()
            y = 300 * Rnd()
            Граф.FillEllipse(Brushes.White, x, y, 3, 3)
            If x > Самый_правый_х Then
                Самый_правый_х = x
                Самый_правый_у = y
            End If
        Next i
        Debug.WriteLine(Самый_правый_х & "   " & Самый_правый_у)
End Sub
77.
Я, король Франции, спрашиваю вас - кто вы такие? Вот ты - кто такой?
Я - Атос
А ты, толстяк, кто такой?
А я Портос! Я правильно говорю, Арамис?
Это так же верно, как то, что я - Арамис!
Он не врет, ваше величество! Я Портос, а он Арамис.
А ты что отмалчиваешься, усатый?
А я все думаю, ваше величество - куда девались подвески королевы?
Анна! Иди-ка сюда!!!
78.
Private Sub Крестик(ByVal x As Single, ByVal y As Single, ByVal Размер As Single)
        'Крестик - это 2 пересекающихся отрезка
        Граф.DrawLine(Pens.Black, x + Размер / 2, y, x + Размер / 2, y + Размер)
        Граф.DrawLine(Pens.Black, x, y + Размер / 2, x + Размер, y + Размер / 2)
End Sub
Private Sub Треугольник(ByVal x As Single, ByVal y As Single, ByVal Размер As Single)
        'Треугольник - это 3 отрезка  с общими концами
        'x и y - координаты левого нижнего угла треугольника
        Граф.DrawLine(Pens.Black, x, y, x + Размер, y)
        Граф.DrawLine(Pens.Black, x, y, x + Размер / 2, y - Размер)
        Граф.DrawLine(Pens.Black, x + Размер, y, x + Размер / 2, y - Размер)
End Sub
80.
Function Длина(ByVal Slovo1 As String, ByVal Slovo2 As String) As Integer
        If Len(Slovo1) < Len(Slovo2) Then Return Len(Slovo1) Else Return Len(Slovo2)
End Function
81.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'Круги на воде:
        Dim П As Rectangle
        Dim i As Integer
        П.X = 100 : П.Y = 100 : П.Width = 10 : П.Height = 10
        For i = 1 To 10
            Гр.DrawEllipse(Pens.Black, П)
            П.Inflate(10, 10)


        Next
End Sub
82.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        'Компакт-диск:
        Dim П As Rectangle
        П.X = 400 : П.Y = 300 : П.Width = 100 : П.Height = 100
        Do Until П.Width > 500
            Гр.DrawEllipse(Pens.Gold, П)
            П.Inflate(3, 3)
        Loop
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        'Летающая тарелка:
        Dim П As Rectangle
        П.X = 400 : П.Y = 300 : П.Width = 100 : П.Height = 50
        Do Until П.Width > 500
            Гр.DrawEllipse(Pens.Gold, П)
            П.Inflate(4, 2)
        Loop
End Sub
83.
    Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        'Башня:
        Dim П As RectangleF
        П.X = 200 : П.Y = 400 : П.Width = 100 : П.Height = 50
        ' Рисуем снизу вверх, постепенно сужая, пока толщина башни не сойдет на нет:
        Do Until П.Width < 0
            Гр.DrawEllipse(Pens.Black, П)
            П.Inflate(-1, -0.5)                                              'Сужаем
            П.Y = П.Y - 5
        Loop
    End Sub
84.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Гр As Graphics = Label1.CreateGraphics                                                 'Рисовать будем на метке
        Dim Перо As New Pen(Color.Blue, 5)                                                              'Перо для координатных осей
        Перо.EndCap = Drawing.Drawing2D.LineCap.ArrowAnchor                           'Стрелка к перу
        Dim Шрифт As New Font("Times", 28, FontStyle.Bold Or FontStyle.Italic)
        Dim x, y, Xo, Yo, Xмет, Yмет, dx As Single
        Xo = 30                      'Начало координат лежит по горизонтали чуть правее левого края метки


        Yo = Label1.Height / 2                              ' Начало координат лежит по высоте посредине метки
        Гр.DrawLine(Перо, 10, Yo, Label1.Width - 10, Yo)                             'Рисуем горизонтальную  ось абсцисс
        Гр.DrawLine(Перо, Xo, Label1.Height - 10, Xo, 10)                            'Рисуем вертикальную  ось ординат
        Гр.DrawString("x", Шрифт, Brushes.Red, Label1.Width - 40, Yo)       'Пишем букву x
        Гр.DrawString("y", Шрифт, Brushes.Red, Xo - 30, 0)                          'Пишем букву y
        Гр.DrawString("График функции", Шрифт, Brushes.Red, Xo + 30, 0)        'Пишем заголовок
        Гр.DrawString("sin x / x", Шрифт, Brushes.Red, Xo + 120, 40)                    'Пишем заголовок
        'Рисуем в цикле множество точек графика:
        dx = 0.01                                  'Шаг по x маленький, чтобы точки графика  лежали плотнее
        For x = 0 To 3000 * dx Step dx
            y = (Math.Sin(x)) / x                   'Вычисляем "настоящий" y
            Xмет = Xo + 10 * x                    'Вычисляем горизонтальную координату точки на графике
            Yмет = Yo - 100 * y                   'Вычисляем вертикальную координату точки на графике
           Гр.FillEllipse(Brushes.Black, Xмет, Yмет, 3, 3)       'Рисуем точку графика
        Next
End Sub
Пояснения: Здесь числа 5, 28, 30, 10, 40, 120 в первых 13 строках процедуры подобраны на опыте исходя из соображений наилучшего внешнего вида чертежа. Число 3000 получилось как 30 / 0.01. Если бы мы наносили на чертеж точки с координатами x и y, то ввиду малости чисел x и y все эти точки находились бы в левом верхнем углу чертежа. Пришлось вычислять реальные координаты точек на чертеже:  Xмет  и  Yмет:
            Xмет = Xo + 10 * x                    'Вычисляем горизонтальную координату точки на графике
Здесь начало координат сместилось вправо на Xo и ось абсцисс растянулась в 10 раз. Число 10 подобрано на опыте исходя из соображений наилучшего внешнего вида чертежа.


            Yмет = Yo - 100 * y                   ' Вычисляем вертикальную координату точки на графике
Здесь начало координат сместилось вниз на Yo и ось ординат растянулась в 100 раз. Число 100 подобрано на опыте исходя из соображений наилучшего внешнего вида чертежа. Обратите внимание на минус перед 100 * y. Он нужен потому, что на математических чертежах ось Y направлена вверх, а в компьютере вниз.
Обратите внимание, что при делении на x = 0 в первой итерации VB# не выдал сообщение об ошибке, так как тип чисел – Single.
В дальнейшем мы познакомимся со специальными методами для преобразования осей координат.
85.
'На форме Form1 ближе к краю размещены два маленьких объекта-"кнопки"  PictureBox1 и PictureBox2
'с уже загруженными в них картинками, а также большой объект - "рамка"  PictureBox3.
Dim Продолг_формы, Продолг_картинки As Single
'ЧТО ДОЛЖНО ПРОИЗОЙТИ ПРИ ЩЕЛЧКЕ МЫШКОЙ ПО "КНОПКЕ" PictureBox1:
Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)  _
Handles PictureBox1.Click
        'Это чтобы большая "рамка"  PictureBox3 приняла форму и размеры картины:
        PictureBox3.SizeMode = PictureBoxSizeMode.AutoSize   
        PictureBox3.Image = PictureBox1.Image                     'Копируем картинку с "кнопки" в большую "рамку"
        'А это чтобы картинка изменяла размеры вслед за "рамкой" PictureBox3:
        PictureBox3.SizeMode = PictureBoxSizeMode.StretchImage  
        PictureBox1.BorderStyle = BorderStyle.Fixed3D        'А это чтобы мы видели, какую картинку уже смотрели
        Продолг_формы = Me.Width / Me.Height                   'Это продолговатость формы по горизонтали
        'Это продолговатость по горизонтали "рамки" PictureBox3, принявшей картинку:
        Продолг_картинки = PictureBox3.Width / PictureBox3.Height        
        If Продолг_картинки > Продолг_формы Then            'ЕСЛИ картинка продолговатей, чем форма, ТО ...


            PictureBox3.Width = 0.9 * Me.Width            'картинка, конечно, должна быть чуть поуже формы (на 1/10)
            PictureBox3.Left = 0.05 * Me.Width             'а это для симметричности по горизонтали (на 1/20 от краев)
            PictureBox3.Height = PictureBox3.Width / Продолг_картинки   'Чтобы не исказились пропорции картинки
            PictureBox3.Top = (Me.Height - PictureBox3.Height) / 2         'А это для симметричности по вертикали
        Else                                                                                  'ИНАЧЕ ...
            PictureBox3.Height = 0.9 * Me.Height   'Картинка, конечно, должна быть чуть покороче формы (на 1/10)
            PictureBox3.Top = 0.05 * Me.Height     'А это для симметричности по вертикали (на 1/20 от краев)
            PictureBox3.Width = PictureBox3.Height * Продолг_картинки  'Чтобы не исказились пропорции картинки
           PictureBox3.Left = (Me.Width - PictureBox3.Width) / 2             'А это для симметричности по горизонтали
        End If
End Sub
'ЧТО ДОЛЖНО ПРОИЗОЙТИ ПРИ ЩЕЛЧКЕ МЫШКОЙ ПО "КНОПКЕ" PictureBox2:
Private Sub PictureBox2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)  _
Handles PictureBox2.Click
        PictureBox3.SizeMode = PictureBoxSizeMode.AutoSize
        PictureBox3.Image = PictureBox2.Image
        PictureBox3.SizeMode = PictureBoxSizeMode.StretchImage
        PictureBox2.BorderStyle = BorderStyle.Fixed3D
        Продолг_формы = Me.Width / Me.Height
        Продолг_картинки = PictureBox3.Width / PictureBox3.Height
        If Продолг_картинки > Продолг_формы Then
            PictureBox3.Width = 0.9 * Me.Width
            PictureBox3.Left = 0.05 * Me.Width
            PictureBox3.Height = PictureBox3.Width / Продолг_картинки
            PictureBox3.Top = (Me.Height - PictureBox3.Height) / 2
        Else
            PictureBox3.Height = 0.9 * Me.Height
            PictureBox3.Top = 0.05 * Me.Height
            PictureBox3.Width = PictureBox3.Height * Продолг_картинки


            PictureBox3.Left = (Me.Width - PictureBox3.Width) / 2
        End If
End Sub
86.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Гр As Graphics = Me.CreateGraphics
        Dim i As Integer
        For i = 1 To 100
            Dim Кисть As New SolidBrush(Color.FromArgb(255 * Rnd(), 255 * Rnd(), 255 * Rnd(), 255 * Rnd()))
            Гр.FillEllipse(Кисть, 800 * Rnd(), 600 * Rnd(), 800 * Rnd(), 600 * Rnd())
        Next
End Sub
87.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Толщина, Непрозрачность As Single
        Dim i As Integer
        Dim Перо As Pen
        Dim Гр As Graphics = PictureBox1.CreateGraphics
        Dim Картинка As New Bitmap("Силуэт.JPG")
        'Создаем прямоугольник по размерам картинки:
        Dim П As New Rectangle(0, 0, Картинка.Width, Картинка.Height)
        Гр.DrawImage(Картинка, П)        'Рисуем фотографию
        П.Inflate(-150, -150)          'Начнем с самого маленького эллипса
        Толщина = 8                     ' Это толщина пера, которым рисуются эллипсы
        For i = 0 To 40                   'Нарисовано будет 40 эллипсов
            П.Inflate(Толщина, Толщина)        'Следующий эллипс больше предыдущего
            Непрозрачность = 20 * i                'Наращиваем непрозрачность
            'Непрозрачность не должна превышать 255:
            If Непрозрачность > 255 Then Непрозрачность = 255
            Перо = New Pen(Color.FromArgb(Непрозрачность, 255, 255, 255), Толщина)
            Гр.DrawEllipse(Перо, П)
        Next
End Sub
88.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Номер_цвета, Насыщенность As Integer
        Номер_цвета = InputBox  _
("Введите число 1, 2 или 3. Если фиксированный цвет красный, то 1,  если зеле-ный - 2, синий - 3")


        Насыщенность = InputBox("Введите насыщенность фиксированного цвета - число от 0 до 255")
        Рисуем_срез(Номер_цвета, Насыщенность)
End Sub
Private Sub Рисуем_срез( ByVal Выбор_цвета As Integer, ByVal Насыщенность As Integer)
        Dim Размер As Single = 1                               'Это длина стороны квадратика
        Dim i, j As Integer
        Dim x, y As Single
        Dim Гр As Graphics = Me.CreateGraphics
        Dim Кисть As New SolidBrush(Color.White)
        For j = 0 To 255                   'Внешний цикл - рисует строки квадратиков  сверху вниз
            y = j * Размер                        'Вертикальная координата строки квадратиков
            For i = 0 To 255               'Внутренний цикл - рисует квадратики в строке слева направо
                x = i * Размер             'Горизонтальная координата квадратика
                Select Case Выбор_цвета
                    Case 1 : Кисть.Color = Color.FromArgb(Насыщенность, i, j)
                    Case 2 : Кисть.Color = Color.FromArgb(i, Насыщенность, j)
                    Case 3 : Кисть.Color = Color.FromArgb(i, j, Насыщенность)
                End Select
                Гр.FillRectangle(Кисть, x, y, x + Размер, y + Размер)         'Рисуем квадратик
            Next i
        Next j
End Sub
89.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Гр As Graphics = Me.CreateGraphics
        Dim Фото As New Bitmap("Spacescape.JPG")
        Dim Фото1 As New Bitmap(Фото, 500, 400)
        Dim Цвет_точки As Color
        Dim x, y, Красный, Зеленый, Синий As Integer
        Гр.DrawImage(Фото1, 0, 0)
        x = InputBox("Введите горизонтальную координату точки")
        y = InputBox("Введите вертикальную координату точки")
        Гр.DrawEllipse(New Pen(Color.Yellow, 3), x - 5, y - 5, 10, 10)     'Рисуем маленькую окружность
        Цвет_точки = Фото1.GetPixel(x, y)      'Определяем  цвет заданной точки


        Красный = Цвет_точки.R                     'Количество красного
        Зеленый = Цвет_точки.G                     'Количество зеленого
        Синий = Цвет_точки.B                         'Количество синего
        'Определяем, какого цвета больше:
        If Красный > Зеленый And Красный > Синий Then
            Debug.WriteLine("Красного больше")
        ElseIf Зеленый > Красный And Зеленый > Синий Then
            Debug.WriteLine("Зеленого больше")
        ElseIf Синий > Красный And Синий > Зеленый Then
            Debug.WriteLine("Синего больше")
        Else
            Debug.WriteLine(" Два самых ярких или все три цвета одинаково интенсивны")
        End If
End Sub
90.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Гр As Graphics = Me.CreateGraphics
        Dim Монетка As New Bitmap("DIME.WMF")
        Гр.TranslateTransform(Me.Width / 2, Me.Height / 2)            'Смещаем начало координат в центр формы
        Do
            'Рисуем монетку так, чтобы ее центр был поближе к началу координат:
            Гр.DrawImage(Монетка, -190, -188)     'Числа 190 и 188 подобраны на опыте
            Гр.RotateTransform(2)                           'Вращаем систему координат вокруг ее начала на 2 градуса
        Loop
End Sub
91.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Дата_со_временем As DateTime
        Dim Только_дата As String
        Дата_со_временем = DateAdd("ww", 52, Now)
        Только_дата = Дата_со_временем.ToLongDateString
        Debug.WriteLine(Только_дата)
End Sub
92.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim Дата_рождения As DateTime
        Дата_рождения = InputBox("Введите дату своего рождения")
        Debug.WriteLine(DateDiff("s", Дата_рождения, Now))


End Sub
93.
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim Дата_рождения, День_рождения_в_этом_году, День_рождения_в_следующем_году As DateTime
        Dim Сколько_мне_лет, Сколько_дней_осталось As Integer
        'Переменная  Сколько_мне_лет   не совсем точно соответствует общепринятому смыслу.
        'Это разность между текущим годом и годом рождения.
        Дата_рождения = InputBox("Введите дату своего рождения")
        Сколько_мне_лет = DateDiff("yyyy", Дата_рождения, Today)
        День_рождения_в_этом_году = DateAdd("yyyy", Сколько_мне_лет, Дата_рождения)
        День_рождения_в_следующем_году = DateAdd("yyyy", Сколько_мне_лет + 1, Дата_рождения)
        If День_рождения_в_этом_году >= Today Then      'Если день рождения в этом году сегодня или позже
            Сколько_дней_осталось = DateDiff("y", Today, День_рождения_в_этом_году)
        Else
            Сколько_дней_осталось = DateDiff("y", Today, День_рождения_в_следующем_году)
        End If
        Debug.WriteLine(Сколько_дней_осталось)
End Sub
94.
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        'Эта процедура отлавливает лишние високосные года (не кратные 4) между 1920 и 2940 годами.
        Dim Текущая_дата, Дата_через_год As DateTime
        Текущая_дата = #1/1/1920#
        Dim Число_дней_в_году, Год As Integer
        Do Until Текущая_дата > #1/1/2940#
            Дата_через_год = DateAdd("yyyy", 1, Текущая_дата)
            Число_дней_в_году = DateDiff("y", Текущая_дата, Дата_через_год)
            Год = DatePart("yyyy", Текущая_дата)
            If (Число_дней_в_году = 366) And Not (Год Mod 4 = 0) Then
                Debug.WriteLine("Лишний високосный год - " & Год)
                Debug.WriteLine("Число дней в году - " & Число_дней_в_году)


            End If
            Текущая_дата = Дата_через_год
        Loop
    End Sub
95.
Dim k As Long = 100
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Debug.WriteLine(k)
        k = k + 1
        If k > 110 Then Timer1.Enabled = False
End Sub
98.
Dim x As Integer = 100                                                                         'Координаты  вагона
Dim y As Integer = 150
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Dim Граф As Graphics = Me.CreateGraphics
        Dim Черное_перо As Pen = New Pen(Color.Black, 5)
        Dim Перо_цвета_фона As Pen = New Pen(Me.BackColor, 5)
        Dim i As Integer
        Граф.DrawEllipse(Черное_перо, x, y, 20, 20)                              'Рисуем заднее колесо
        Граф.DrawEllipse(Черное_перо, x + 100, y, 20, 20)                     'Рисуем переднее колесо
        Граф.DrawRectangle(Черное_перо, x, y - 20, 120, 20)                'Рисуем прямоугольник
        For i = 1 To 5000000 : Next 'Пустой цикл для задания паузы
        Граф.DrawEllipse(Перо_цвета_фона, x, y, 20, 20)                      'Стираем заднее колесо
        Граф.DrawEllipse(Перо_цвета_фона, x + 100, y, 20, 20)           'Стираем переднее колесо
        Граф.DrawRectangle(Перо_цвета_фона, x, y - 20, 120, 20)       'Стираем прямоугольник
        x = x + 1                                                                                             'Перемещаемся немного направо
End Sub
99.
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        PictureBox1.Left = PictureBox1.Left - 1
        PictureBox2.Left = PictureBox2.Left - 1
    End Sub
100.
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Button1.Left = Button1.Left + 1
        Button2.Left = Button2.Left - 1


        Button3.Top = Button3.Top - 1
        Button4.Top = Button4.Top + 1
        Button5.Left = Button5.Left + 1
        Button5.Top = Button5.Top - 1
    End Sub
 
101.
Dim Шаг As Integer = 2
Dim x As Integer = 0
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Button1.Left = x
        x = x + Шаг
        If x > Width - Button1.Width Then Шаг = -2 ' Если объект улетел за правый край формы, то лететь обратно
        If x < 0 Then Шаг = 2 'Если объект улетел за левый край формы, то лететь обратно
End Sub
Я написал   Width - Button1.Width,   а не   Width,  чтобы объект не скрывался за правым краем формы.
102.
Dim x, y As Integer 'Координаты шарика
'dx - шаг шаpика по гоpизонтали,  то есть pасстояние по гоpизонтали между двумя последовательными
'положениями шарика при движении.    dy - аналогично по веpтикали
Dim dx As Integer = 4
Dim dy As Integer = 6                                                                    '4 и 6 - напpавление движения - впpаво вниз
Dim Размер_шарика As Integer
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)  _
Handles MyBase.Paint
        Dim Граф As Graphics = Me.CreateGraphics
        Граф.DrawRectangle(Pens.Black, 20, 20, 600, 300)            'Рисуем биллиардный стол
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Размер_шарика = PictureBox1.Height
        x = PictureBox1.Left : y = PictureBox1.Top                           'Начальные координаты шарика
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        x = x + dx : y = y + dy                                                      'Двигаем шарик "в уме"
        PictureBox1.Left = x : PictureBox1.Top = y                           'Двигаем шарик на форме
        If x < 20 Or x > 620 - Размер_шарика Then dx = -dx           'Удаpившись о левый или пpавый боpт,


        ' шаpик меняет гоpизонтальную составляющую скоpости на пpотивоположную
        If y < 20 Or y > 320 - Размер_шарика Then dy = -dy           'Удаpившись о веpхний или нижний боpт,
        'шаpик меняет веpтикальную составляющую скоpости на пpотивоположную
        'Если шаpик в левом веpхнем углу или в левом нижнем
        'или в пpавом веpхнем или в пpавом нижнем, то останавливай шаpик:
        If (x < 40 And y < 40) Or (x < 40 And y > 300 - Размер_шарика) Or (x > 600 - Размер_шарика And y < 40)  _
                                    Or (x > 600 - Размер_шарика And y > 300 - Размер_шарика) Then Timer1.Enabled = False
End Sub
103.
Dim D As Single = 400                                                                                'Диаметр циферблата
Dim t As Integer = 0                                                                                    'Время в секундах
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)  _
Handles MyBase.Paint
        Dim Граф As Graphics = Me.CreateGraphics
        Граф.DrawEllipse(Pens.Black, 0, 0, D, D)                                             'Рисуем циферблат
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Dim Граф As Graphics = Me.CreateGraphics
        Dim Кисть_цвета_фона As New SolidBrush(Me.BackColor)
        Граф.FillPie(Кисть_цвета_фона, 4, 4, D - 8, D - 8, 6 * t, 1)                   'Стираем предыдущую стрелку
        t = t + 1
        Граф.FillPie(Brushes.Black, 4, 4, D - 8, D - 8, 6 * t, 1)                              'Рисуем следующую стрелку
End Sub
4 – это на сколько радиус стрелки меньше радиуса циферблата. Я запрограммировал только секундную стрелку. Интервал таймера установил в 1000, то есть в 1 секунду. 6 – это результат деления 360 градусов на 60 секунд, за которые стрелка эти градусы обегает.
104.
Dim v, t, h, s As Double                                              'Смотри пояснения к задаче 47


    Dim x, y As Single
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim Граф As Graphics = Me.CreateGraphics
        v = 20 : t = 0 : h = 100 : s = 0
        Граф.DrawLine(Pens.Black, 10, 110, 200, 110)
        Граф.FillRectangle(Brushes.Green, 10, 10, 20, 100)
        MsgBox("Башня построена")
        Timer1.Enabled = True                                     'Бросаем камень
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        s = v * t
        h = 100 - 9.81 * t ^ 2 / 2
        x = s + 20                                                          'Кооpдинаты камня в полете
        y = 110 - h
        PictureBox1.Left = x
        PictureBox1.Top = y
        t = t + 0.03
        If h < 0 Then Timer1.Enabled = False                'Если камень упал, время останавливается
End Sub
108.
Dim Кадр1_левый As New Bitmap("Кадр1.png")                               'Три исходных кадра, глядящие влево
    Dim Кадр2_левый As New Bitmap("Кадр2.png")
    Dim Кадр3_левый As New Bitmap("Кадр3.png")
    Dim Кадр1_правый, Кадр2_правый, Кадр3_правый As Bitmap   'Три исходных кадра, глядящие вправо
    Dim Кадр1, Кадр2, Кадр3 As Bitmap                                               'Три рабочих кадра для PictureBox
    Dim N As Integer = 0
    Dim dx As Integer
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.BackgroundImage = Image.FromFile("Пирамиды.jpg")
        Кадр1_левый.MakeTransparent(Color.White)
        Кадр2_левый.MakeTransparent(Color.White)
        Кадр3_левый.MakeTransparent(Color.White)
        Кадр1_правый = New Bitmap(Кадр1_левый)                             'Получаем три правых кадра из левых ...
        Кадр2_правый = New Bitmap(Кадр2_левый)
        Кадр3_правый = New Bitmap(Кадр3_левый)


        Кадр1_правый.RotateFlip(RotateFlipType.RotateNoneFlipX)      ' и зеркально отражаем их направо
        Кадр2_правый.RotateFlip(RotateFlipType.RotateNoneFlipX)
        Кадр3_правый.RotateFlip(RotateFlipType.RotateNoneFlipX)
        PictureBox1.BorderStyle = BorderStyle.None
        PictureBox1.BackColor = Color.Transparent
        PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize
        PictureBox1.Image = Кадр1_левый                                             'Ставим человечка в исходное положение
        Timer1.Enabled = False                                                                'Пусть стоит на месте
    End Sub
    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Select Case N
            Case 0 : PictureBox1.Image = Кадр1
            Case 1 : PictureBox1.Image = Кадр2
            Case 2 : PictureBox1.Image = Кадр3
            Case 3 : PictureBox1.Image = Кадр2
        End Select
        N = (N + 1) Mod 4
        PictureBox1.Left = PictureBox1.Left + dx
    End Sub
    'Кнопка движения направо:
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        dx = 10
        Кадр1 = Кадр1_правый                                                        'Все рабочие кадры будут правыми
        Кадр2 = Кадр2_правый
        Кадр3 = Кадр3_правый
        Timer1.Enabled = True                                                         'Надо идти
    End Sub
    'Кнопка движения налево:
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        dx = -10
        Кадр1 = Кадр1_левый                                                         'Все рабочие кадры будут левыми
        Кадр2 = Кадр2_левый
        Кадр3 = Кадр3_левый
        Timer1.Enabled = True                                                         'Надо идти
    End Sub


    'Кнопка остановки:
    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        If dx = 10 Then PictureBox1.Image = Кадр1_правый Else PictureBox1.Image = Кадр1_левый
        Timer1.Enabled = False
        N = 0
    End Sub
110.
Dim Сообщение As String = "Мышь не находится над кнопкой"
Private Sub Button2_MouseEnter( ByVal sender As Object, ByVal e As EventArgs) Handles Button2.MouseEnter
        Сообщение = "Мышь  - над кнопкой"
End Sub
Private Sub Button2_MouseLeave(ByVal sender As Object, ByVal e As EventArgs) Handles Button2.MouseLeave
        Сообщение = "Мышь не находится над кнопкой"
End Sub
Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)  _
Handles MyBase.MouseMove
        TextBox1.Text = ""
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        TextBox1.Text = Сообщение
End Sub
111.
Dim Толщина As Integer = 5
Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)  _
Handles MyBase.MouseMove
        Dim Граф As Graphics = Me.CreateGraphics
        'След остается лишь при нажатой левой клавише:
        If e.Button = MouseButtons.Left Then Граф.FillEllipse(Brushes.Black, e.X, e.Y, Толщина, Толщина)
End Sub
Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)  _
Handles MyBase.MouseDown
        'При одинарном щелчке правой клавишей толщина возрастает на 1:
        If e.Button = MouseButtons.Right And e.Clicks = 1 Then Толщина = Толщина + 1
        'При двойном щелчке правой клавишей толщина убывает на 1 (а не на 2):
        If e.Button = MouseButtons.Right And e.Clicks = 2 Then Толщина = Толщина - 2
        If Толщина < 2 Then Толщина = 2 'Не даем толщине стать меньше 2


End Sub
Пояснение: Во время двойного щелчка событие MouseDown наступает два раза. В первый раз значение e.Clicks еще равно 1, поэтому толщина вопреки нашему желанию не убывает, а вырастает на 1. Через мгновение событие MouseDown выполняется второй раз и значение e.Clicks уже равно 2. Тут нам нужно не зевать и уменьшать толщину на 2, чтобы нейтрализовать ее возрастание.
112.
Dim dx, dy As Integer
Dim Шаг As Integer = 1
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        PictureBox1.Left = PictureBox1.Left + dx        'Двигаем PictureBox
        PictureBox1.Top = PictureBox1.Top + dy
End Sub
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles MyBase.KeyDown
        Select Case e.KeyCode
            Case Keys.Left        : dx = -Шаг : dy = 0
            Case Keys.Right             : dx = Шаг   : dy = 0
            Case Keys.Up          : dx = 0              : dy = -Шаг
            Case Keys.Down            : dx = 0              : dy = Шаг
        End Select
End Sub
113.
Dim Огонь As Char
Private Sub Form1_KeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs) Handles MyBase.KeyPress
        Огонь = Char.ToUpper(e.KeyChar)                                        'Превращаем строчную букву в заглавную
        Me.Refresh()                                                                           'Перерисовываем поверхность формы
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
        Dim Гр As Graphics = Me.CreateGraphics
        Гр.DrawRectangle(Pens.Black, 20, 20, 100, 300)                  'Прямоугольник
        Select Case Огонь
            Case "R"
                Гр.FillEllipse(Brushes.Red, 30, 30, 80, 80)                    'Красная_лампа загорается
                Гр.FillEllipse(Brushes.Black, 30, 130, 80, 80)                'Желтая_лампа гаснет


                Гр.FillEllipse(Brushes.Black, 30, 230, 80, 80)                'Зеленая_лампа гаснет
            Case "Y"
                Гр.FillEllipse(Brushes.Black, 30, 30, 80, 80)                   'Красная_лампа гаснет
                Гр.FillEllipse(Brushes.Yellow, 30, 130, 80, 80)               'Желтая_лампа загорается
                Гр.FillEllipse(Brushes.Black, 30, 230, 80, 80)                 'Зеленая_лампа гаснет
            Case "G"
                Гр.FillEllipse(Brushes.Black, 30, 30, 80, 80)                   'Красная_лампа  гаснет
                Гр.FillEllipse(Brushes.Black, 30, 130, 80, 80)                 'Желтая_лампа гаснет
                Гр.FillEllipse(Brushes.Green, 30, 230, 80, 80)                'Зеленая_лампа  загорается
            Case Else
                MsgBox("Наберите символы R, Y или G")
        End Select
End Sub
114.
В режиме проектирования поместим на форму два PictureBox. Назовем их Самолет и Снаряд.
Dim Клавиша_нажата As Boolean = False                                  'Поначалу клавиш не нажимали
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Самолет.Left = Самолет.Left - 1                                      'Движем самолет
        If Not Клавиша_нажата Then Exit Sub 'Если клавиша не нажата, ничего дальше делать не надо
        Снаряд.Top = Снаряд.Top - 3                                             'Движем снаряд
        'Условие попадания: Если координаты самолета и снаряда достаточно близки
        'как по горизонтали, так и по вертикали:
        If Math.Abs(Снаряд.Top - Самолет.Top) < 20 And Math.Abs(Снаряд.Left - Самолет.Left) < 40 Then
            Timer1.Enabled = False
            MsgBox("Попадание!")
        End If
End Sub
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles MyBase.KeyDown
        Клавиша_нажата = True
End Sub
115-1.
Добавляем в процедуру Form1_Load оператор Машина.Visible = False, а в процедуру Кнопка_начинай_сначала_Click – оператор Машина.Visible = True.


115-2.
В процедуре Timer1_Tick меняем строку:
        Машина.Left = x - Машина.Width / 2 : Машина.Top = y - Машина.Height / 2
В процедуре Ставим_машину_на_старт меняем строку:
         x = X_старта + Размер_старта / 2 : y = Y_старта + Размер_финиша / 2
115-3.
Private Sub Form1_MouseDown( ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)  _
Handles MyBase.MouseDown
        Секундомер_запущен = True
        Dim Xмыши As Short = e.X         'Координаты щелчка мыши на форме
        Dim Yмыши As Short = e.Y
        Dim dx As Short = Xмыши - x    'На сколько щелчок мыши правее машины
        Dim dy As Short = Yмыши - y    'На сколько щелчок мыши ниже машины
        Dim Где As типРуль            'Где (в каком направлении) мы щелкнули мышкой по отношению к машине
        'Определяем это направление:
        If dx > Math.Abs(dy) Then Где = типРуль.вправо
        If dx < -Math.Abs(dy) Then Где = типРуль.влево
        If dy > Math.Abs(dx) Then Где = типРуль.вниз
        If dy < -Math.Abs(dx) Then Где = типРуль.вверх
        'Определяем, что делать при щелчке по левой клавише мыши:
        If e.Button = MouseButtons.Left Then
            If Где = Руль Then Газ = True Else Руль = Где
        End If
        'Определяем, что делать при щелчке по правой клавише мыши:
        If e.Button = MouseButtons.Right Then Тормоз = True
End Sub
Пояснения: Придадим точное, математическое значение словам «Мышка щелкнула справа от машины» или, скажем, «сверху от машины». Проведем через машину две воображаемые взаимно перпендикулярные прямые, обе под 45 градусов к осям координат. Эти прямые делят плоскость формы на 4 части. Пусть эти части как раз и соответствуют по смыслу определяемым направлениям. Если мы мышкой щелкнули по форме в пределах той из 4 частей, что глядит на восток, будем считать, что «мышка щелкнула справа от машины». И так далее.
Оператор
            If Где = Руль Then Газ = True Else Руль = Где
можно перевести так:


«Если мышкой щелкнули в том направлении, куда ориентирована машина, то газуй, иначе поворачивай машину в направлении щелчка».
Недостаток приведенной процедуры в том, что после того, как машина врезалась в ограждение и финиш, она продолжает слушаться щелчков мыши. С этим можно бороться, введя дополнительное состояние машины, например, переменную «Машина_неподвижна» булевского типа.
116.
1)      a(i) = a(i-1) + 4
2)      a(i) = 2 * a(i-1)
3)      a(i) = 2 * a(i-1) - 1
117.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Число_дней As Integer = 7
        Dim t() As Integer = {0, 8, 14, 19, 22, 25, 28, 26}
        Dim i, k, s, Min, Nomer As Integer
        'Определим среднюю температуру:
        s = 0
        For i = 1 To Число_дней : s = s + t(i) : Next
        Debug.WriteLine(s / Число_дней)
        'Определим количество теплых дней:
        k = 0
        For i = 1 To Число_дней
            If t(i) > 20 Then k = k + 1
        Next
        Debug.WriteLine(k)
        'Определим, каким по порядку идет самый жаркий день:
        Min = t(1)
        Nomer = 1
        For i = 2 To Число_дней
            If t(i) > Min Then Min = t(i) : Nomer = i
        Next
        Debug.WriteLine(Nomer)
End Sub
Вот что напечатает программа:
20,2857142857143
4
6
118.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim fib(200) As Decimal
        Dim i As Integer
        fib(1) = 1 : fib(2) = 1
        For i = 3 To 139
            fib(i) = fib(i - 2) + fib(i - 1)
            Debug.WriteLine(i & "           " & fib(i))
        Next
End Sub
Последнее, 139-е распечатанное число Фибоначчи равно
50095301248058391139327916261
Следующее, 140-е, уже не умещается в тип Decimal.
119.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click


        Dim t(,) As Integer = {{99, 99, 99, 99, 99}, {99, -8, -14, -19, -18}, {99, 25, 28, 26, 20}, {99, 11, 18, 20, 25}}
        Dim i, j, Min, Max As Integer
        Min = t(1, 1) : Max = t(1, 1)
        For i = 1 To 3
            For j = 1 To 4
                If t(i, j) > Max Then Max = t(i, j)
                If t(i, j) < Min Then Min = t(i, j)
            Next j
        Next i
        Debug.Write(Max - Min)
End Sub
Эта программа напечатает число 47.
120.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim a() As Integer = {5, 4, 2, 4, 3, 5, 5, 3, 4, 3}                            'Оценки одного класса
        Dim b() As Integer = {3, 4, 3, 4, 3, 5, 4, 4, 3, 4, 4, 4, 4, 3, 4, 4}    'Оценки другого класса
        If Разница(a) < Разница(b) Then Debug.WriteLine("Первый класс учится ровнее") _
                                                      Else Debug.WriteLine("Второй класс учится ровнее")
End Sub
Function Минимум(ByVal c() As Integer) As Integer
        Dim i As Integer
        Минимум = c(0)
        For i = 1 To c.Length - 1
            If c(i) < Минимум Then Минимум = c(i)
        Next
End Function
Function Максимум(ByVal c() As Integer) As Integer
        Dim i As Integer
        Максимум = c(0)
        For i = 1 To c.Length - 1
            If c(i) > Максимум Then Максимум = c(i)
        Next
End Function
Function Разница(ByVal c() As Integer) As Integer
        Разница = Максимум(c) - Минимум(c)
End Function
121.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'Для отладки приняли, что в году 4 дня
        Dim A() As Integer = {25, 22, 18, 20}                  'Показания термометра на станции A
        Dim B() As Integer = {4, 5, 4, 4}                           'Показания термометра на станции B
        Исправление(-2, A)


        Исправление(3, B)
        Dim i As Integer
        For i = 0 To 3                 'Распечатываем исправленные значения температур
            Debug.WriteLine(A(i) & "           " & B(i))
        Next
End Sub
Sub Исправление( ByVal Поправка As Integer, ByVal c() As Integer)
        Dim i As Integer
        For i = 0 To 3
            c(i) = c(i) + Поправка
        Next
End Sub
Примечание: Обратите внимание на то, что я смог объявить параметр c как ByVal вместо ByRef. И это несмотря на то, что процедура должна исправлять исходный массив. Это стало возможным потому, что массивы ByVal не защищает.
122.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Debug.WriteLine(fib(30))
End Sub
Private Function fib(ByVal N As Integer) As Decimal
        If N = 1 Or N = 2 Then fib = 1 Else fib = fib(N - 2) + fib(N - 1)              'Изумительная лаконичность!
End Function
'За изумительную лаконичность расплачиваемся удручающе низким быстродействием.
'Когда N переваливает за пару десятков, результата приходится долго ждать.
'Ничего подобного не было при вычислении чисел Фибоначчи простым циклом.
'Почему так? А попробуйте подсчитать, сколько раз компьютеру приходится
'обращаться к  функции fib. Миллионы и миллиарды раз. Для неверующих – F11.
123.
Sub puziryok_3(ByVal mass1() As String, ByVal mass2() As Integer, ByVal mass3() As Integer, ByVal N As Integer)
        Dim i, c, m As Integer
        Dim s As String                             'Транзитный элемент для строкового массива
        For m = N To 1 Step -1
            For i = 0 To m - 1
                If mass3(i) > mass3(i + 1) Then
                    s = mass1(i) : mass1(i) = mass1(i + 1) : mass1(i + 1) = s         'Обмен в 1 массиве
                    c = mass2(i) : mass2(i) = mass2(i + 1) : mass2(i + 1) = c         'Обмен во 2 массиве
                    c = mass3(i) : mass3(i) = mass3(i + 1) : mass3(i + 1) = c         'Обмен в 3 массиве


                End If
            Next i
        Next m
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Фамилия() As String = {"Иванов", "Петров", "Сидоров", "Николаев"}
        Dim Рост() As Integer = {173, 182, 169, 175}
        Dim Вес() As Integer = {71, 93, 62, 70}
        Dim N As Integer = Вес.Length - 1                                       'Это размер таблицы без 1
        puziryok_3(Фамилия, Рост, Вес, N)                                    'Сортируем массивы
       'Распечатываем  отсортированную  таблицу:
        Dim i As Integer
        For i = 0 To N
            Debug.WriteLine(Фамилия(i) & "       " & Рост(i) & "       " & Вес(i))         
        Next
End Sub
Пояснение: Мы выбрали метод пузырька, но теперь обмен элементами идет не в одном массиве, а в трех.
126.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Объект As Control
        Dim Флажок As CheckBox
        Dim Коллекция_флажков As New Collection
        'Заполняем флажками с формы коллекцию флажков:
        For Each Объект In Controls
            If TypeName(Объект) = "CheckBox" Then Коллекция_флажков.Add(Объект)
        Next
        'Распечатываем выбранные блюда:
        For Each Флажок In Коллекция_флажков
            If Флажок.Checked Then Debug.WriteLine(Флажок.Text)
        Next
End Sub
Пояснения: Если бы на форме присутствовали только флажки и не было бы кнопки и метки, можно было бы не создавать коллекцию флажков, а обойтись коллекцией Controls.
127.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Радиокнопка As RadioButton
        For Each Радиокнопка In GroupBox1.Controls
            If Радиокнопка.Checked Then Debug.WriteLine(Радиокнопка.Text) : Exit For


        Next
        For Each Радиокнопка In GroupBox2.Controls
            If Радиокнопка.Checked Then Debug.WriteLine(Радиокнопка.Text) : Exit For
        Next
End Sub
128.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Label1.Text = HScrollBar1.Minimum
        Label2.Text = HScrollBar1.Maximum
End Sub
Private Sub HScrollBar1_Scroll(ByVal sender As System.Object,  _
ByVal e As System.Windows.Forms.ScrollEventArgs) Handles HScrollBar1.Scroll
        Label3.Text = HScrollBar1.Value
End Sub
129.
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles ComboBox1.SelectedIndexChanged
        ComboBox2.Text = ComboBox2.Items(ComboBox1.SelectedIndex)
End Sub
130.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim Блюдо As Object
        For Each Блюдо In CheckedListBox1.CheckedItems
            Debug.WriteLine(Блюдо)
        Next
End Sub
Обратите внимание, что поскольку я «не очень уверен», что Блюдо имеет тип String, я для безопасности объявил его типом Object.
131.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        MsgBox("Осталось ждать "  &    DateDiff("d", Today, DateTimePicker1.Value)    &   " дн.")
End Sub
132.
Private Sub NumericUpDown1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)  _
Handles NumericUpDown1.ValueChanged
        Вычисляем_сколько_заплатили()
End Sub
Private Sub NumericUpDown2_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)  _
Handles NumericUpDown2.ValueChanged
        Вычисляем_сколько_заплатили()
End Sub
Sub Вычисляем_сколько_заплатили()
        lbl_Сколько_заплатили.Text = NumericUpDown1.Value * NumericUpDown2.Value
End Sub
Здесь именем  lbl_Сколько_заплатили  я назвал метку.


133.
Я
134.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        'Шифруем слово из 6 букв
        Dim s As String = "Корова"
        Debug.WriteLine(Mid(s, 1, 2) + "быр" + Mid(s, 3, 2) + "быр" + Mid(s, 5, 2) + "быр")       '1 вариант
        Debug.WriteLine(s.Insert(6, "быр").Insert(4, "быр").Insert(2, "быр"))                               '2 вариант
        ' Здесь мы сначала вставляем последнее быр. Получившаяся строка имеет тип String,
        'поэтому можно после нее ставить точку и снова писать Insert. И так далее.
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        'Шифруем произвольное слово
        Dim s As String = "Консенсус"
        Dim Результат As String = ""                                    'Результат пока пустой
        Dim i As Integer
        For i = 0 To s.Length \ 2 - 1                                        'Len(s) \ 2  -  это число полных пар букв в слове
            'Наращиваем Результат на очередную пару букв и "быр":
            Результат = Результат + s.Substring(2 * i, 2) + "быр"
        Next
        'Наращиваем Результат на последнюю нечетную букву, если она есть:
        If Len(s) Mod 2 = 1 Then Результат = Результат + Strings.Right(s, 1)
        Debug.WriteLine(Результат)
End Sub
135.
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Dim s, s1 As String                            'Исходная и результирующая строки
        Dim Старый_символ, Новый_символ As Char
        s = "Взирая на солнце, прищурь глаза свои, и ты смело разглядишь в нем пятна."
        s1 = ""                                                   'Результирующую строку строим с нуля
        Dim i As Integer
        For i = 0 To Len(s) - 1                          'Просматриваем исходную строку слева направо


            Старый_символ = s.Chars(i)          'Выделяем очередной символ в исходной строке
            Новый_символ = ChrW(AscW(Старый_символ) + 1)
            s1 = s1 &  Новый_символ            ' Наращиваем результирующую строку на очередной символ
        Next
        Debug. WriteLine (s1)                       'Печатаем результат
End Sub
136.
'Для хранения информации об одном жителе организуем структуру:
Structure типЖитель
        Dim ФИО As String
        Dim Дата_рождения As DateTime
End Structure
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Житель(5000) As типЖитель       'Массив структур в памяти для считанных из файла данных
        'СЧИТЫВАЕМ ИНФОРМАЦИЮ ИЗ ФАЙЛА:
        Dim Чтение As New System.IO.StreamReader("E:\VB\Список_жителей.txt")
        Dim i As Integer = 1                                                   'Счетчик жителей
        'Считываем все строки  файла в массив структур, пропустив двух уехавших:
        Do While Чтение.Peek() <> -1
            Житель(i).ФИО = Чтение.ReadLine
            Житель(i).Дата_рождения = Чтение.ReadLine
            If Житель(i).ФИО = "Янзаев Федор Карпович"  _
Or Житель(i).ФИО = "Кропоткин Владлен Фотиевич" Then i = i - 1
            i = i + 1
        Loop
        Чтение.Close()                                                          'Закрываем файл
        'ОБРАБАТЫВАЕМ ИНФОРМАЦИЮ В ОПЕРАТИВНОЙ ПАМЯТИ:
        Dim Число_жителей_в_городе As Integer = i - 1
        For i = 1 To Число_жителей_в_городе
            If Житель(i).ФИО = "Страшный Гектор Васильевич"  _
Then Житель(i).ФИО = "Благодатный Гектор Васильевич"
            If Недавний_именинник(Житель(i)) Then Debug.WriteLine(Житель(i).ФИО)
        Next
        'ЗАПОЛНЯЕМ ФАЙЛ ОБРАБОТАННОЙ ИНФОРМАЦИЕЙ:
        Dim Запись As New System.IO.StreamWriter("E:\VB\Список_жителей.txt")


        For i = 1 To Число_жителей_в_городе
            Запись.WriteLine(Житель(i).ФИО)
            Запись.WriteLine(Житель(i).Дата_рождения)
        Next
        Запись.Close()                                                           'Закрываем файл
End Sub
Function Недавний_именинник( ByVal Человек As типЖитель) As Boolean
        Dim Разница_в_днях = Today.DayOfYear - Человек.Дата_рождения.DayOfYear
        If (Разница_в_днях >= 0 And Разница_в_днях <= 7) Or Разница_в_днях <= (7 - 365)  _
Then Return True Else Return False
End Function
Пояснения: Янзаев и Кропоткин тоже, конечно, считываются из файла и попадают в массив, но из-за того, что счетчик жителей при этом уменьшается на 1, следующий житель попадает в массив на их место и затирает их.
Функция Недавний_именинник принимает структуру Житель, как параметр, и определяет, правда ли, что день рождения жителя был на этой неделе. Разница_в_днях – переменная, показывающая, сколько дней прошло от дня рождения жителя до сегодняшнего дня. Фрагмент  Разница_в_днях <= (7 - 365) нужен для учета ситуации, когда программа запускается в первую неделю января.
137.
Structure типЖитель
        Dim ФИО As String
        Dim Дата_рождения As DateTime
End Structure
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Житель(5000) As типЖитель
        Dim Чтение As New System.IO.StreamReader("E:\VB\Список_жителей.txt")
        Dim i As Integer = 1
        Do While Чтение.Peek() <> -1
            Житель(i).ФИО = Чтение.ReadLine
            Житель(i).Дата_рождения = Чтение.ReadLine
            ListBox1.Items.Add(Житель(i).ФИО)
            i = i + 1
        Loop
        Чтение.Close()
End Sub
138.
Dim SecretNumber As Decimal                                      'Загаданное компьютером число
Dim A As Decimal                                                          'Число - попытка человека
Dim Сообщение As String


Dim Количество_попыток As Integer = 0
' ПРИ ЗАПУСКЕ ПРОЕКТА ВЫБИРАЕМ НОВУЮ ИЛИ СТАРУЮ ИГРУ:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim Выбор = MsgBox("Продолжим старую игру?", MsgBoxStyle.YesNo)
        If Выбор = MsgBoxResult.Yes Then Загружаем_сохраненную_игру() Else Настраиваем_новую_игру()
End Sub
Private Sub Настраиваем_новую_игру()
        Randomize()
        SecretNumber = Math.Round(1000000000 * Rnd())      'Компьютер загадывает число
        txtNumber.Text = 0                                                         'Текстовое поле для ввода человеком числа
        lblMessage.Text = "Попыток не было"                          'Метка для вывода компьютером сообщений
        'Метка для вывода количества попыток:
        lblNumberTry.Text = "Количество попыток = " & Количество_попыток    
        Dim Запись As New System.IO.StreamWriter("E:\VB\История.txt")     'Открыть файл для записи
        Запись.WriteLine(SecretNumber)                                                          'Запись в файл загаданного числа
        Запись.Close()
End Sub
'ЧТО ДЕЛАТЬ ПРИ ОЧЕРЕДНОЙ ПОПЫТКЕ ОТГАДАТЬ ЧИСЛО:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click                  
        A = CDec(txtNumber.Text)                'Преобразуем содержимое текстового поля в целое число
        If A > SecretNumber Then                 'В этом операторе If вся несложная логика игры
            Сообщение = "Много"
        ElseIf A < SecretNumber Then
            Сообщение = "Мало"
        Else
            Сообщение = "Вы угадали"
        End If
        Количество_попыток = Количество_попыток + 1
        lblNumberTry.Text = "Количество попыток = " & Количество_попыток
        lblMessage.Text = Сообщение
        'Запись в файл данных очередной попытки:


        Dim Дозапись As New System.IO.StreamWriter("E:\VB\История.txt", True) 'Открыть файл для дозаписи
        Дозапись.WriteLine(Количество_попыток)
        Дозапись.WriteLine(A)
        Дозапись.WriteLine(Сообщение)
        Дозапись.Close()
End Sub
Private Sub Загружаем_сохраненную_игру()
        Dim Чтение As New System.IO.StreamReader("E:\VB\История.txt")       'Открыть файл для чтения
        SecretNumber = Чтение.ReadLine                                              'Чтение из файла загаданного числа
        Debug.WriteLine("И С Т О Р И Я    И Г Р Ы")
        'Чтение из файла и печать данных очередной попытки:
        Do While Чтение.Peek() <> -1
            Количество_попыток = Чтение.ReadLine
            A = Чтение.ReadLine
            Сообщение = Чтение.ReadLine
            Debug.WriteLine(Количество_попыток & "        " & A & "                   " & Сообщение)
        Loop
        Чтение.Close()                                                                            'Закрываем файл
        'Восстанавливаем содержимое текстового поля и меток на форме:
        txtNumber.Text = A
        lblMessage.Text = Сообщение
        lblNumberTry.Text = "Количество попыток = " & Количество_попыток
End Sub
Пояснения: На форме размещены: текстовое поле txtNumber, в которое играющий вводит очередное число, метка lblNumberTry, в которой отображается количество попыток играющего, метка lblMessage для сообщений «Много», «Мало» и др. и кнопка Button1, которую играющий нажимает после ввода очередного числа в текстовое поле. В файле записывается вся история игры, сколько бы раз играющий не сохранялся. При выборе новой игры содержимое файла стирается.
139.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.BackgroundImage = Image.FromFile("Пирамиды.jpg")
        PictureBox1.BorderStyle = BorderStyle.None


        PictureBox1.BackColor = Color.Transparent
        Кадры.TransparentColor = Color.White
        PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Static N As Integer
        Select Case N
            Case 0 : PictureBox1.Image = Кадры.Images(1)
            Case 1 : PictureBox1.Image = Кадры.Images(2)
            Case 2 : PictureBox1.Image = Кадры.Images(3)
            Case 3 : PictureBox1.Image = Кадры.Images(2)
        End Select
        N = (N + 1) Mod 4
        PictureBox1.Left = PictureBox1.Left - 10
End Sub
Пояснения: Элемент управления ImageList мы назвали Кадры.
140.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Реши_задачу(TreeView1)
End Sub
Sub Реши_задачу(ByVal Вершина As Object)
        If Вершина.GetNodeCount(False) = 2 Then Вершина.BackColor = Color.Yellow
        Dim Дочь As TreeNode
        For Each Дочь In Вершина.Nodes
            Реши_задачу(Дочь)
        Next
End Sub
141.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Реши_задачу(TreeView1)
End Sub
Sub Реши_задачу(ByVal Вершина As Object)
        Dim K As Integer = 0                                             'Счетчик детей, имя которых начинается на Л
        Dim Дочь As TreeNode
        For Each Дочь In Вершина.Nodes
            If Дочь.Text.StartsWith("Л") Then K = K + 1
            Реши_задачу(Дочь)
        Next
        If K = 2 Then Вершина.ForeColor = Color.Blue
End Sub
142.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Реши_задачу(TreeView1)
End Sub
Sub Реши_задачу(ByVal Вершина As Object)
        Dim Дочь As TreeNode
        For Each Дочь In Вершина.Nodes
            Реши_задачу(Дочь)


        Next
        If Вершина.GetNodeCount(False) = 0 Then
            Вершина.Nodes.Add(Вершина.Text & "1")
            Вершина.Nodes.Add(Вершина.Text & "2")
        End If
End Sub
Если вы поменяете местами операторы For и If, это приведет к безграничному разрастанию дерева. Почему?
143.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Реши_задачу(TreeView1)
End Sub
Sub Реши_задачу(ByVal Вершина As Object)
        Dim Дочь As TreeNode
        For Each Дочь In Вершина.Nodes
            If Дочь.Text.StartsWith("Ф") Then Пометь(Дочь) Else Реши_задачу(Дочь)
        Next
End Sub
Sub Пометь(ByVal Вершина As TreeNode)
        Вершина.BackColor = Color.LightGreen
        Dim Дочь As TreeNode
        For Each Дочь In Вершина.Nodes
            Пометь(Дочь)
        Next
End Sub
145.
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim Запись As DataRow
        For Each Запись In DataSet11.Книги.Rows
            Запись("Kol_str") = Запись("Kol_str") + 2
        Next
End Sub
146.
50
100
Специально для http://all-ebooks.com
[†] Программа на машинном языке представлена по-другому.

Панель инструментов Toolbar


Все вы видели панели инструментов. Они имеются в большинстве солидных приложений Windows. Так, панели инструментов VS вы можете видеть в 4.5. Панель инструментов представляет набор кнопок и других элементов, предназначенный для быстрого выполнения наиболее часто встречающихся действий, таких как открытие, сохранение файлов, выбор размера шрифта и т.п. Те же самые действия обычно можно выполнить и при помощи меню, но панель инструментов всегда на виду, поэтому с ее помощью действия выполняются быстрее.

Создаем панель инструментов. Поставим задачу создать панель инструментов на 4 кнопки (см. Рис. 20.8).

Рис. 20.8

На Рис. 20.9 вы видите ту же панель с некоторыми кнопками уже нажатыми.

Рис. 20.9

Создайте проект. Поместите на форму элемент управления ToolBar

(Панель инструментов). Он получит имя ToolBar1. При этом панель инструментов сразу «прилипнет» к верхнему краю формы, как ей в общем-то и положено. Пока панель пуста. Давайте заполним ее кнопками.

Чтобы кнопки не были простыми прямоугольниками, а имели вид разных красивых значков, нам в проекте необходим ImageList с картинками этих значков. Поместите ImageList в проект, а походящие иконки найдете по адресу

Program Files\Microsoft Visual Studio .NET\Common7\Graphics\icons

Далее нам нужно сказать панели инструментов, из какого именно элемента ImageList она должна брать картинки. Ведь элементов ImageList в проекте может быть несколько. Для этого заглянем в окно свойств элемента ToolBar1 и установим соответствующим образом свойство ImageList.

А теперь нас интересует свойство Buttons. Оно представляет собой коллекцию кнопок, содержащихся в панели инструментов. Щелкните по трем точкам в поле значения этого свойства. Возникнет Редактор коллекции кнопок (на Рис. 20.10 вы видите его уже заполненным несколькими кнопками). Пока же он пустой.

Рис. 20.10

Заполним его кнопками. Процесс аналогичен работе с Редактором коллекции картинок (20.5). Нажимая кнопку Add, мы добавляем на панель кнопку за кнопкой. Слева от кнопки вы видите ее номер в коллекции Buttons. В правой части окна Редактора – информация о выделенной кнопке, причем ее можно задавать. Две кнопки со стрелками вверх и вниз перемещают выделенную кнопку внутри коллекции. Кнопка Remove удаляет ее.


Настраиваем кнопки. Вот какую информацию о выделенной кнопке можно задавать и изменять в полях правой части окна Редактора (остановлюсь на главных с моей точки зрения полях):

Прежде всего, это имя кнопки (Name). Называйте кнопку в соответствии с ее предназначением, как вы его понимаете.

В поле Style нам нужно выбрать тип кнопки. Кнопки на панели инструментов могут быть трех типов и еще одного:

Тип

Описание

PushButton

Обычная кнопка. У нас это две левые кнопки.

ToggleButton

Кнопка-переключатель. Когда на нее нажмешь, она переходит в нажатое состояние до следующего нажатия. В Microsoft Word это кнопки выравнивания абзаца и форматирования шрифта. У нас это кнопка со снежинкой.

DropDownButton

Справа от нее – черная треугольная стрелка. При нажатии на стрелку выпадает меню. У нас это кнопка со светофором.

Separator

Это, собственно, не кнопка, а разделитель. У нас это серенькая вертикальная черточка слева от кнопки со снежинкой. Нажимать на разделитель нельзя, он нужен только для того, чтобы создать пространственный промежуток между кнопками. Используется для пространственной группировки кнопок по смыслу.

Таким образом, у нас на панели пять кнопок, включая разделитель. Все они перечислены в порядке слева-направо в списке Members в левой части окна Редактора.

В поле ImageIndex мы выбираем для каждой кнопки картинку из заранее подготовленной галереи ImageList.

Полезно заполнить поле ToolTipText, в этом случае при подведении мыши к кнопке будет всплывать подсказка. 

Если вы заполните текстом поле Text, этот текст будет присутствовать на кнопке рядом с картинкой.

Если кнопка имеет тип DropDownButton, то вы, конечно, хотите, чтобы из нее выпадало меню. Меню это создается привычным вам элементом управления ContextMenu. Поместите его в проект, настройте и запрограммируйте нужным вам образом (см. 18.9). Затем привяжите его к кнопке, установив значение поля DropDownMenu (см. Рис. 20.10).

Если кнопка имеет тип ToggleButton, то вы можете задать, чтобы при запуске проекта она была нажатой, установив поле Pushed в True.



Настраиваем панель инструментов. Упомяну еще о трех свойствах элемента управления ToolBar:

Свойство

Описание

Appearance

Внешний вид кнопок. Может быть таким, как на Рис. 20.8. Это вид плоский (Flat). Кнопки плоские, без границ, видны одни значки. Разделитель – вертикальная черточка. Внешний вид может быть и нормальным (Normal). В этом случае кнопки имеют привычный вид, разделитель – просто пустой промежуток.

Dock

Определяет, к какому краю формы будет «приклеена» панель инструментов и будет ли «приклеена» вообще.

TextAlign

Где находится на кнопке текст по отношению к значку – под значком или справа.

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

Придумаем дела для наших кнопок. Для иллюстрации вполне достаточно, если каждая кнопка будет просто сообщать о своем нажатии оператором Debug.WriteLine. Ведь вы всегда сможете на место этого оператора подставить обращение к любой самой сложной процедуре.

Снежинке придумаем дополнительное дело: пусть она управляет значением булевской переменной Снег_идет. Если кнопка нажата, эта переменная должна иметь значение True, если отжата – False.

А вот дополнительное дело для светофора: пусть выпадающее меню из 3 пунктов позволяет красить форму в цвета светофора.

Важное отличие программирования кнопок панели от программирования обычных кнопок состоит в том, что процедура обработки нажатия на кнопки панели одна для всех кнопок, а у обычных кнопок, как вы знаете, для каждой кнопки своя процедура.

Сделаем двойной щелчок по панели инструментов. Появится заготовка нужной процедуры ToolBar1_ButtonClick . А вот и вся программа:

Dim Снег_идет As Boolean = False

Private Sub ToolBar1_ButtonClick(ByVal sender As System.Object,  _

ByVal e As System.Windows.Forms.ToolBarButtonClickEventArgs) Handles ToolBar1.ButtonClick

        If e.Button Is

кнопка_Открыть Then Debug.WriteLine("Нажата кнопка Открыть")



        If e.Button Is

кнопка_Сохранить     Then Debug.WriteLine("Нажата кнопка Сохранить")

        If e.Button Is

кнопка_Снег        Then Debug.WriteLine("Нажата кнопка Снег")                                      : Переключаем_снег()

        If e.Button Is

кнопка_Светофор     Then Debug.WriteLine("Нажата кнопка Светофор")

End Sub

Sub Переключаем_снег()

        Снег_идет = Not Снег_идет

        Debug.WriteLine(Снег_идет)

End Sub

Private Sub MenuItem_красный_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)  _

Handles MenuItem_красный.Click

        Me.BackColor = Color.Red

End Sub

Private Sub MenuItem_желтый_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)  _

Handles MenuItem_желтый.Click

        Me.BackColor = Color.Yellow

End Sub

Private Sub MenuItem_зеленый_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)  _

Handles MenuItem_зеленый.Click

        Me.BackColor = Color.Green

End Sub

Пояснения: Объект e, являющийся параметром процедуры ToolBar1_ButtonClick, хранит в своем свойстве Button указание на то, какая именно кнопка на панели была нажата. Слово Is можно перевести, как «является». Поэтому фрагмент

        If   e.Button   Is   кнопка_Открыть    Then

можно перевести как «Если нажатая кнопка является кнопкой Открыть, то …».

Слово Is мы раньше использовали в операторе Select Case. Там его смысл был похожим на только что использованный.

Оператор

        Снег_идет = Not Снег_идет

занимается исключительно тем, что меняет значение переменной Снег_идет на противоположное.

Обратите внимание, что нажатие на собственно кнопку со светофором, не приводит к появлению меню. Для этого нужно нажать на черную треугольную стрелку.

Улучшаем калькулятор. Последнее, чем созданный нами ранее калькулятор хуже стандартного – у него нет 10 цифровых клавиш, нажимая на которые мы набираем числа в текстовом поле. В принципе, мы уже давно могли разместить 10 кнопок на калькуляторе, написав к каждой кнопке коротенькую процедуру обработки нажатия на кнопку. Но 10 процедур – пожалуй, слишком громоздко. Сейчас у нас появился шанс обойтись одной процедурой, разместив 10 кнопок на панели инструментов. Подумайте, как это сделать. Вам не придется писать 10 операторов If, если вы обратитесь к номеру нажатой кнопки в коллекции:

ToolBar1.Buttons.IndexOf(e.Button))

Наращивать число в текстовом поле можно так:

TextBox1.Text = TextBox1.Text & Нажатая_цифра


Перечень обычных и ссылочных типов


Обычные типы (Value Types) включают в себя:

Все числовые типы (Integer и пр.)

Boolean

Char

Date

Перечисления (Enum)

Все структуры (Structure), даже если они включают в качестве своих элементов ссылочные типы

Ссылочные типы (Reference Types) включают в себя:

Все массивы, даже если они состоят из элементов обычного типа

Классы

Строки (String)

Что касается строк, то тут тонкость. Строки хоть и являются ссылочным типом, во многом ведут себя, как обычный тип. Так оператор присваивания B = A дает видимый результат, свойственный обычным типам.

Object. Нам остается упомянуть тип Object – тип-хамелеон. Вы знаете, что переменной, объявленной этим типом, вы можете в разные моменты присваивать значения любых типов: числовых, классов и т.д. Например:

        Dim A As Object

        A = 5

        A = Button1

Так вот, Object – это ссылочный тип. Но пока переменная, объявленная этим типом, хранит в себе значение обычного типа, он ведет себя, как обычный тип, а если ссылочного – то как ссылочный. Так, на протяжении приведенного фрагмента переменная A успеет побывать и обычной, и ссылочной.

Заключение. Ссылки придают программированию дополнительную гибкость. В частности они позволяют организовывать в памяти конструкции переменного размера, такие как списки, деревья, очереди, стеки и тому подобные известные программистам вещи.



Передача ссылочных параметров по значению


В 11.4.1 я без объяснений упомянул, что при передаче параметров процедур слово ByVal теряет свою способность к защите по отношению к строкам, массивам и объектам. Теперь мы можем понять, почему это происходит. Рассмотрим такой код:

Public Class Form1

    Inherits System.Windows.Forms.Form

Windows Form Designer generated code

    Class Класс

        Public Поле As Integer

    End Class

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim A As New Класс

        A.Поле = 5

        Процедура(A)

        Debug.WriteLine(A.Поле)

    End Sub

    Sub Процедура(ByVal

Объект As Класс)

        Объект.Поле = 999

    End Sub

End Class

По замыслу работы слова ByVal при нажатии кнопки должно было напечататься число 5, но напечатается отчего-то 999. «Значение» переменной A неожиданно изменилось. Происходит это вот почему. При вызове процедуры Процедура значение переменной A копируется в переменную Объект. Но если параметр имеет ссылочный тип, то его значением является ссылка. Получается, что копируется ссылка. Это значит, что переменная A и переменная Объект теперь указывают на одну и ту же область памяти, где хранится значение поля Поле. Раз так, то внутри процедуры Процедура мы можем как угодно менять значение этого поля, что немедленно «почувствует» и переменная A.

То, что здесь сказано, относится, естественно, и к массивам, но не относится к строкам, которые, как я уже говорил, во многом ведут себя, как обычный тип.



Перегрузка


Перегрузка (Overloading) – ситуация, когда в коде класса присутствует несколько процедур с одинаковыми именами, делающих одно и то же дело, добивающихся одних и тех же результатов, и различающихся только параметрами.

Этот термин применим не только к процедурам, но и к функциям, и к свойствам, и к конструкторам.

С перегрузкой мы в этой книге встречались не раз. Перелистайте книжку назад и загляните в 6.2.8. Там вы увидите 4 варианта метода DrawLine класса Graphics. Все эти варианты различались количеством или типом параметров метода. Программист мог выбирать вариант по вкусу или по возможностям.

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

Public Class Участок

    Public Владелец As String

    Public Высота_забора As Integer

    Public Shared Расход_краски_на_кв_м As Integer

    Public Function Периметр(ByVal Длина As Integer, ByVal Ширина As Integer) As Integer

        Return 2 * (Длина + Ширина)

    End Function

    Public Function Площадь_забора(ByVal Длина As Integer, ByVal Ширина As Integer) As Integer

        Return Периметр(Длина, Ширина) * Высота_забора

    End Function

    Public Function Расход_краски_на_забор(ByVal Длина As Integer, ByVal Ширина As Integer) As Integer

        Return Расход_краски_на_кв_м * Площадь_забора(Длина, Ширина)

    End Function

End Class

Обратите внимание вот на что. Мы отказались от полей Длина и Ширина, так как  теперь объект получает их значения в виде параметров. Теперь извне мы должны обращаться к функциям с указанием параметров, например, так:

        Debug.WriteLine(Участок1.Расход_краски_на_забор(100, 50))

Это в чем-то удобно, в чем-то – нет. Неудобно, в частности, вот в чем. Если мы захотим включить параметры только в функцию периметра, оставив две другие функции без параметров, у нас ничего не получится. Ведь в тело функции Площадь_забора входит вызов функции Периметр с параметрами, а откуда взять их значения, если нет полей? Только из собственных параметров. По той же причине придется снабдить параметрами и функцию Расход_краски_на_забор.


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

    Public Function Периметр  _

(ByVal X1 As Integer, ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer) As Integer

        Return    2 * (Math.Abs(X1 - X2) + Math.Abs(Y1 - Y2))

    End Function

Пояснения:  Math.Abs(X1 - X2) – не что иное, как длина участка, Math.Abs(Y1 - Y2) – высота.

Поместим эту функцию в код класса рядом с ее тезкой. У одной функции 2 параметра, у другой – 4. Когда вы будете обращаться к этой функции, VB по числу параметров догадается, к какой именно функции из двух вы обращаетесь.

Сказавший «А» должен сказать и «Б». Если вы хотите вычислять с этими 4 параметрами также и расход краски, вам придется сделать перегрузку и остальных двух процедур. Вот какой получится у вас код класса:

Public Class Участок

    Public Владелец As String

    Public Высота_забора As Integer

    Public Shared Расход_краски_на_кв_м As Integer

    Public Function Периметр(ByVal Длина As Integer, ByVal Ширина As Integer) As Integer

        Return 2 * (Длина + Ширина)

    End Function

    Public Function Периметр  _

(ByVal X1 As Integer, ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer) As Integer

        Return 2 * (Math.Abs(X1 - X2) + Math.Abs(Y1 - Y2))

    End Function

    Public Function Площадь_забора(ByVal Длина As Integer, ByVal Ширина As Integer) As Integer

        Return Периметр(Длина, Ширина) * Высота_забора

    End Function

    Public Function Площадь_забора  _

(ByVal X1 As Integer, ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer) As Integer

        Return Периметр(X1, Y1, X2, Y2) * Высота_забора

    End Function

    Public Function Расход_краски_на_забор(ByVal Длина As Integer, ByVal Ширина As Integer) As Integer



        Return Расход_краски_на_кв_м * Площадь_забора(Длина, Ширина)

    End Function

    Public Function Расход_краски_на_забор  _

( ByVal X1 As Integer, ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer) As Integer

        Return Расход_краски_на_кв_м * Площадь_забора(X1, Y1, X2, Y2)

    End Function

End Class

А вот как можно проверить работу наших перегруженных функций, вычислив два раза расход краски на одном и том же участке (сначала участок задан длиной и шириной, а второй раз – координатами):

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim Участок1 As New Участок

        Участок1.Владелец = "Римский"

        Участок1.Высота_забора = 3

        Участок1.Расход_краски_на_кв_м = 2

        Debug.WriteLine(Участок1.Расход_краски_на_забор(100, 50))

        Debug.WriteLine(Участок1.Расход_краски_на_забор(1000, 2000, 1100, 2050))

End Sub

Перегруженные компоненты класса могут иметь и одинаковое число параметров. Тогда, чтобы VB их не перепутал, хотя бы у одного параметра должны быть разные типы.

Чтобы подчеркнуть, что компоненты перегруженные, вы можете писать в их заголовке слово Overloads.

Не путайте перегрузку с полиморфизмом. Перегрузка толкует о тезках в одном классе, полиморфизм – в разных; перегруженные функции получают один результат, полиморфные – разный.


Переключатель из радиокнопок (RadioButton)


Вы, возможно, знакомы с кнопками переключения диапазонов на радиоприемниках. Там в ряд стоят несколько кнопок. Нажатой в каждый момент может быть только одна. Нажимая какую-то кнопку, вы тем самым отжимаете ту, что была нажата раньше.

Аналогичный элемент управления есть и в VB. Называется он RadioButton (радиокнопка). Применяется он там, где нужно выбрать только одну из нескольких возможностей. Например, пусть персонажу вашей игры нужно выбрать одно оружие из четырех. На Рис. 18.2 вы видите группу из 4 соответствующих радиокнопок. Назовем такую группу переключателем. Здесь тоже, как и в случае с флажками, можно сколько угодно колебаться, передумывать и переключаться между радиокнопками, прежде, чем сделать решающее нажатие на кнопку «Берем оружие».

Рис. 18.2

Создайте проект в соответствии с этим рисунком. Запустите проект. Пощелкайте внутри кружочков. Вы видите, что из всех радиокнопок в любой момент времени только одна может быть выбрана, остальные автоматически отключаются.

А что делать, если вам на той же форме нужно организовать еще один переключатель, например, для выбора поля сражения? Для этого нужно каждую группу радиокнопок поместить в свой контейнер, например, рамку или панель (см. Рис. 18.3).

Рис. 18.3

В противном случае из всех семи радиокнопок в любой момент времени будет выбрана только одна.

Вы скажете, что радиокнопки и флажки – это одно и то же. Неверно. Флажков в любой момент времени может быть установлено сколько угодно, а из радиокнопок переключателя в любой момент времени может быть выбрана только одна.

Так же, как и у флажка, главным свойством радиокнопки является свойство Checked, которое имеет значение True, если кнопка выбрана, и False – если нет. Поэтому и программы работы с радиокнопками очень похожи на программы работы с флажками:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        If RadioButton1.Checked Then

            TextBox1.Text = "Переключатель в положении 1"


        ElseIf RadioButton2.Checked Then

            TextBox1.Text = "Переключатель в положении 2"

        ElseIf RadioButton3.Checked Then

            TextBox1.Text = "Переключатель в положении 3"

        End If

End Sub

Если в переключателе много радиокнопок, то вышеприведенная процедура получается длинной. Можно ее укоротить применением цикла. Вот процедура для поиска выбранной радиокнопки в рамке:

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        Dim Радиокнопка As RadioButton

        For Each Радиокнопка In GroupBox1.Controls

            If Радиокнопка.Checked

Then Debug.WriteLine(Радиокнопка.Text) : Exit For

        Next

End Sub

Поэкспериментируйте с цветами, шрифтом радиокнопок. При свойстве Appearance равном Button радиокнопка выглядит, как нажатая или отжатая кнопка. Вы можете убрать с радиокнопки текст и придать ей картинку (задать свойство Image). Получается, что можно выбирать не только из текста, но и из картинок.

Задание 2.    

Снабдите проект на Рис. 18.3 кнопкой, при нажатии на которую распечатывается выбранное оружие и выбранное поле сражения.


Первый способ обработки событий: WithEvents и Handles


Это самый простой и короткий способ.

Когда мы в режиме проектирования помещаем элемент управления на форму и хотим написать для него обработчик какого-нибудь из его событий, то VB привычным образом помогает нам получить в окне кода заготовку обработчика (3.11): в поле, расположенном в верхней левой части окна кода, мы выбираем этот элемент управления, а в поле, расположенном в верхней правой части окна кода, мы выбираем нужное событие этого элемента. А что делать, если элементы управления помещены на форму программным путем? – То же самое, но с одним маленьким предварительным дополнением в программе.

Создайте проект из одной формы, без кнопок. Введите такой код:

Dim WithEvents

 

b As New Button          'Создаем кнопку

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Me.Controls.Add(b)                          'Добавляем созданную кнопку в коллекцию формы

End Sub

Запустите проект. Вы видите, что на форме присутствует кнопка без надписи. Щелкните по ней – ничего не происходит.

Пояснения: Первая строка рождает кнопку, третья – размещает ее на форме. Слово WithEvents  переводится «с событиями». Имеется в виду, что здесь кнопка рождается с возможностью обработки событий. Но обработчиков мы ведь пока не написали.

В подтверждение слов о возможности обработки событий загляните в поле, расположенное в верхней левой части окна кода. Вы увидите, что там появился элемент b. Остается только выбрать в поле, расположенном в верхней правой части окна кода, нужное событие этого элемента. Выберем Click. В окне кода появится привычная заготовка процедуры-обработчика:

Private Sub b_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles b.Click

End Sub

Напомню, что завершается заголовок обработчика словами Handles b.Click. Слово Handles переводится «обрабатывает», выражение b.Click – это событие Click объекта b. Получается, что обработчик «обрабатывает событие Click объекта b». Наличие слова Handles заставляет процедуру запускаться в тот самый момент, когда возникает событие b.Click. Если мы сотрем слова Handles b.Click, обработчик превратится в обычную процедуру пользователя и на события реагировать не будет.


Запишем в тело обработчика две простейшие строки:

Private Sub b_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles b.Click

        b.Text = "Нажали"

        b.Left = b.Left + 30

End Sub

Запустите проект. Щелкните по кнопке – она прыгнет направо на 30 пикселей и на ней появится надпись «Нажали».

Параметры обработчика. В нашем случае обработчику положено иметь два параметра: Первый (с именем sender) имеет тип Object и указывает на объект, с которым произошло событие (у нас это кнопка b). Второй параметр (с именем e)  указывает на объект, который должен содержать полезную информацию о событии (правда, в нашем случае это объект типа EventArgs, который такой информации, к сожалению, не содержит).

Перепишем тело обработчика:

Private Sub b_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles b.Click

        sender.Text = "Нажали"

        sender.Left = sender.Left + 30

End Sub

Действие обработчика не изменилось, однако он стал более универсальным. Теперь по какому бы подходящему объекту не щелкнули, он прыгнет направо, надо только в заголовке процедуры после Handles изменить имя b на имя этого объекта.

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

Private Sub Обработчик_нажатия_на_кнопку(ByVal На_кого_нажали As Object,  _

ByVal Информация

As EventArgs) Handles b.Click

        На_кого_нажали.Text = "Нажали"

        На_кого_нажали.Left = На_кого_нажали.Left + 30

End Sub

Несколько обработчиков у одного события. Перепишите обработчик, а затем скопируйте, чуть-чуть изменив его имя и тело. Теперь у вас в коде – два обработчика:

Private Sub b_Click (ByVal sender As Object, ByVal e As EventArgs) Handles b.Click

        MsgBox("Сработал 1-й обработчик")

End Sub

Private Sub b_Click1 (ByVal sender As Object, ByVal e As EventArgs) Handles b.Click



        MsgBox("Сработал 2-й обработчик")

End Sub

Запустите проект. Щелкните один раз по кнопке – у вас последовательно появятся два сообщения. Таким образом, вы можете писать несколько обработчиков с разными именами для одного события, все они будут запускаться один за другим в результате наступления события.

Используем информацию о событии. Вспомним материал 14.2.2 о событиях мыши. Создадим такой обработчик вместо предыдущих:

Private Sub Обработчик_нажатия_на_кнопку(ByVal На_кого_нажали As Object,  _

ByVal Информация As MouseEventArgs) Handles b.MouseDown

        На_кого_нажали.Left = На_кого_нажали.Left + 30

        If  Информация.Button = MouseButtons.Left  Then  На_кого_нажали.Text = "Левая"

        If  Информация.Button = MouseButtons.Right  Then  На_кого_нажали.Text = "Правая"

End Sub

Обработчик обрабатывает событие b.MouseDown и пользуется информацией из объекта типа MouseEventArgs. Надпись на кнопке меняется в зависимости от того, какую клавишу мыши мы нажали.

Если вы хотите, вы можете в выражении, стоящем после слова Handles, стереть событие MouseDown, вам тут же будет предложен на выбор список всех возможных событий элемента b. Выберите подходящее другое – и обработчик будет обрабатывать уже его (о том, какие события будут подходящими, написано чуть ниже). Вы можете даже стереть b, вам тут же будет предложен на выбор список всех возможных элементов, порождающих события.

Один обработчик для нескольких событий. Одним обработчиком можно обрабатывать события разных объектов, причем и события тоже могут быть разные. Создайте проект без кнопок. Запишите такой код:

Dim WithEvents b1, b2, b3 As New Button

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Me.Controls.Add(b1)

        Me.Controls.Add(b2)

        Me.Controls.Add(b3)

End Sub

Private Sub Обработчик_событий_кнопки(ByVal Кнопка As Object,  _

ByVal Информация As EventArgs) Handles  b1.Click,  b2.Click,  b3.MouseEnter

        Кнопка.Left = Кнопка.Left + 30

End Sub

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

Не любые события можно перечислять через запятую в заголовке обработчика, а лишь те, для обработки которых подходят параметры именно тех типов, что указаны в скобках. Какие именно типы параметров подходят, вы узнаете, поставив текстовый курсор на название события (например, MouseEnter) и нажав F1. В появившемся окне помощи щелкните по слову EventHandler. Вы увидите шаблон с указанием параметров.

К сожалению, словом WithEvents нельзя объявлять массив объектов.


Первый способ создания и обработки событий: WithEvents


Задача. Давайте смоделируем такую ситуацию: На вашем счете в банке лежит какая-то сумма. Вы приходите в магазин и хотите расплатиться за покупку кредитной карточкой, открытой на этот счет в банке. Вы отдаете карточку кассиру, тот направляет в банк приказ снять с вашего счета нужную сумму, приказ выполняется, кассир вам карточку возвращает. Все, покупка сделана. Задача программиста состоит в том, чтобы предусмотреть запрет на выполнение этой операции, если вы накупили товаров на сумму, превышающую ту, что у вас на счете. При этом у кассира должно возникнуть сообщение «На счете не хватает денег».

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

Создайте проект. Разместите на форме текстовое поле, кнопку и метку. Создайте в проекте класс clsСчет. В этом классе будет присутствовать переменная Сумма_на_счете, объявленная Private, чтобы в магазине случайно не раскрыли тайну вклада клиента. Кроме этого в классе будет присутствовать метод Снятие_со_счета, смысл которого ясен из названия. Кассир вводит в текстовое поле сумму покупок, затем нажатием на кнопку формы запускает упомянутый метод, метод проверяет, хватает ли денег на счете, и если да, то уменьшает эти деньги на сумму покупок, а если нет, то порождает некое событие («передает сигнал» – RaiseEvent). На форме уже ждет наготове обработчик этого события. Он его воспринимает («принимает сигнал») и начинает выполняться, в результате чего метка на форме покажет текст «На счете не хватает денег».

С учетом сказанного разберитесь в приведенном ниже коде, а новинки я поясню:

Форма:

Private WithEvents

Счет As New clsСчет

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Счет.Снятие_со_счета(Val(TextBox1.Text))

End Sub


Private Sub Счет_Не_хватает_денег() Handles Счет.Не_хватает_денег

        Label1.Text = "На счете не хватает денег"

End Sub

Класс:

Public Class clsСчет

    Private Сумма_на_счете As Decimal = 1000

    Public Event

Не_хватает_денег()

    Public Sub Снятие_со_счета(ByVal Сумма_к_снятию As Decimal)

        If Сумма_на_счете - Сумма_к_снятию >= 0 Then

            Сумма_на_счете = Сумма_на_счете - Сумма_к_снятию

        Else

            RaiseEvent

Не_хватает_денег()

        End If

    End Sub

End Class

Пояснения: Вот последовательность действий банковского программиста, пишущего код класса и решившего использовать события:

Сначала он должен придумать событиям подходящие имена и объявить их при помощи слова Event (событие):

    Public Event

Не_хватает_денег()

Затем он должен крепко подумать, в какие моменты выполнения кода его класса должны возникать эти события и во все места кода класса, где оно должно возникать, вставить оператор, порождающий это событие:

            RaiseEvent

Не_хватает_денег()

В нашем случае событием является любая попытка сделать значение переменной Сумма_на_счете отрицательным. Такая попытка предпринята только в одном месте программы, поэтому оператор RaiseEvent встречается только один раз. В больших программах мест в коде, где встречаются соответствующие попытки, может быть несколько. В каждое место нужно будет вставить RaiseEvent.

Затем наш банковский программист должен позвонить магазинному программисту, пишущему код формы, и предупредить его, что класс теперь использует события, а значит порождать из него объекты нужно с использованием слова WithEvents:

Private WithEvents

Счет As New clsСчет

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



Private Sub Счет_Не_хватает_денег() Handles Счет.Не_хватает_денег

Важно понять следующую вещь: Событие не несет в себе никакой информации о том, что именно произошло. В нем ничего нет, кроме его названия. Как тогда программист, пишущий код формы, может быть уверен, что событие Не_хватает_денег возникает именно в тот момент, когда со счета пытаются снять больше, чем там есть? Уверенность может возникнуть только в том случае, если программист, пишущий код класса, пообещает, что так оно и есть на самом деле. Конечно, если код формы и класса пишет один и тот же программист (как в нашем случае), тогда другое дело.

Рассеиваем сомнения. Вы скажете: Того же эффекта можно добиться безо всяких событий, просто написав в коде класса вместо RaiseEvent Не_хватает_денег() оператор, меняющий текст на метке. Но я думаю, магазин не очень будет доволен, что банк протягивает свои длинные руки и так грубо вмешивается во внутренние дела фирмы (то есть формы). Конечно, есть и другие способы решить задачу, но все они хуже. Механизм событий очень гибок и не сует нос в чужие дела. Программисту класса в нашем случае не нужно даже ничего знать о том, как именно на форме будут обрабатывать его событие и будут ли обрабатывать вообще. Его дело – породить событие, а там хоть трава не расти.


Полиморфизм


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

В VB полиморфизм осуществляется при помощи наследования и при помощи так называемых интерфейсов. При наследовании полиморфизм проявляется тогда, когда мы у наследника как-то изменяем (переопределяем) процедуру родителя.

Интерфейсы мы рассматривать не будем. Можно сказать, что интерфейс – это одна из масок, которую объект надевает на себя, чтобы с нами пообщаться.

Должен сказать, что Visual Basic версий 6.0 и более ранних не поддерживает настоящие полиморфизм и наследование. Впервые их поддержка осуществлена в Visual Basic.NET.

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

Public Class Участок

    Public Владелец As String

    Public Длина, Ширина As Integer

    Public Высота_забора As Integer

    Public Shared Расход_краски_на_кв_м As Integer

    Public Function Периметр() As Integer

        Return 2 * (Длина + Ширина)

    End Function

    Public Function Площадь_забора() As Integer

        Return   Периметр() * Высота_забора

    End Function

    Public Function Расход_краски_на_забор() As Integer

        Return Расход_краски_на_кв_м * Площадь_забора()

    End Function

End Class

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


Public Class Участок_штакетник

    Inherits Участок

    Public Overrides

Function Площадь_забора() As Integer

        Return    0.5 * Периметр() * Высота_забора

    End Function

End Class

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

Однако мы привыкли, что при вызове методов наследника на самом деле вызываются родительские методы. В данной ситуации нам это не подойдет. Поэтому мы дописываем в заголовок функции наследника слово Overrides, что значит «пересиливает, переопределяет». Имеется в виду – пересиливает функцию родителя. С этой же целью мы дописываем в заголовок функции родителя слово Overridable, что значит «позволяет себя пересилить, переопределить»:

    Public Overridable

Function Площадь_забора() As Integer

        Return   Периметр() * Высота_забора

    End Function

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

MyBase и MyClass. Итак, у нас теперь две функции Площадь_забора, одна у родителя, другая – у наследника. Теперь, когда бы мы в коде наследника ни обратились к функции Площадь_забора, вызовется функция наследника, а не родителя. А если нам захочется обратиться из кода наследника именно к родительской функции? Вы спрашиваете, зачем это нужно? Вот конкретный пример. Замечаем, что площадь забора из штакетника вдвое меньше, чем у обычного. В связи с этим нам кажется проще вычислить площадь обычного забора, а затем поделить ее пополам. Переписываем функцию в классе Участок_штакетник:

    Public Overrides Function Площадь_забора() As Integer



        Return   0.5 * MyBase.Площадь_забора

    End Function

Слово MyBase  с точкой указывает, что имеется в виду именно родительская функция.

Когда возникает потребность в коде наследника указать, что имеется в виду именно компонент наследника, а не родителя или кого-то другого, то вместо MyBase употребляют слово MyClass.

Shadows. Когда большой проект, использующий наследование, разрабатывает группа программистов, часто случается, что через некоторое время после того, как проект уже сдан в эксплуатацию и широко используется, выявляются некоторые недостатки проекта, требующие исправления. При этом какие-то родительские классы подвергаются доработке. В результате доработки в коде родительских классов могут возникнуть новые программные элементы (переменные, процедуры и др.), случайно получившие такие же имена, как совсем другие программные элементы ничего не подозревающих наследников. Например, в родительском классе появляется процедура А1, в то время как в наследнике уже давно имеется переменная А1.  VB не любит такие ситуации, считает их конфликтными и рекомендует программистам классов-наследников «на всякий пожарный» явно указывать, что их программный элемент пересиливает (затеняет) любой могущий объявиться программный элемент родителя. Делается это в классе-наследнике так:

Public  Shadows  А1  As  String

Слово Shadows переводится с английского, как «затеняет».

Данная ситуация похожа на ситуацию с переопределением, но это не одно и то же. На различиях я не останавливаюсь.


Поля и свойства объектов


Функция вместо поля. Вернемся к нашему садовому хозяйству. Вот кому-то снаружи класса понадобился периметр участка. А он его не видит, так как он у нас объявлен Private. Пожалуйста, нам не жалко, сделаем его полем:

Public Периметр As Integer

Теперь он виден всем. И это хорошо. Плохо то, что теперь все, кому не лень, смогут менять наш периметр операторами типа

Участки(k).Периметр = 25

Что же получается? Мы старались, вычисляли периметр по правильной формуле, а тут кто-то раз! – и присвоил ему значение, которое непонятно откуда взялось! Нет, так не годится, вернем все как было:

Private Периметр As Integer

Но теперь недоволен заказчик: ему нужно знать периметр. Что же делать? Нужно устроить так, чтобы периметр был все-таки виден и в то же время защитить его от посягательств. Читать – читайте, а менять извне его значение нельзя!

Как этого добиться? Вот простой способ. Придумаем функцию Периметр_участка, все тело которой состоит из единственного оператора:

    Public Function Периметр_участка() As Integer

        Return Периметр

    End Function

Теперь любой желающий извне может узнать значение периметра таким, например, оператором:

        Debug.WriteLine(Участки(k).Периметр_участка)

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

А где же здесь желанная цель «только для чтения»? А она достигнута. Потому что присваивать значение функции мы можем только в ее теле, а уж никак не из других модулей. Попробуйте – VB придерется.

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

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


    Public Function Периметр_участка() As Integer

        If Периметр > 10000 Then

            MsgBox("Периметр участка засекречен")

            Return 0

        Else

            Return Периметр + 1         'Приписка

        End If

    End Function

Вместо функции – свойство «только для чтения». Идея « Функция вместо поля» настолько хороша, что появилась потребность оформить ее синтаксически.

Сотрите нашу функцию. Создадим ее другим, общепринятым путем. Введите такую строку:

    Public  Property  Периметр_участка As Integer

Нажмите Enter. Перед вами появилась заготовка:

    Public Property

Периметр_участка() As Integer

        Get

        End Get

        Set(ByVal Value As Integer)

        End Set

    End Property

Слово Property означает «свойство». Периметр участка перестал быть просто переменной, перестал быть полем, перестал быть функцией, он стал свойством. Так мы его и будем называть.

Слово Get означает "Получи (узнай) значение свойства", а слово Set означает "Установи (присвой) значение свойству". Наша конструкция состоит из двух частей. Внутрь части  Get – End Get мы пишем код, показывающий значение свойства наблюдателю извне. Фактически мы просто переписываем туда тело нашей функции. Внутрь части  Set – End Set мы пишем код, позволяющий наблюдателю извне менять значение свойства. Об этой части мы поговорим чуть позже, а сейчас, поскольку мы не собираемся давать возможность изменения значений свойства извне, мы просто стираем эту часть, а в подтверждение своей решимости добавляем в объявление свойства слово ReadOnly («только для чтения»). Вот что у нас получилось:

    Public ReadOnly Property Периметр_участка() As Integer

        Get

            Return Периметр

        End Get

    End Property

Мы решили поставленную задачу.

Свойства «для чтения-записи». Теперь займемся полями нашего класса, например, полем Длина. Хорошо бы уже при присвоении этому полю значения из текстового поля осуществлялся некоторый контроль значений. Например, мы хотим запретить участки длиннее 500 метров. Однако поле Длина имеет тип Integer и поэтому допускает очень большие числа. Мы можем написать ограничение в коде формы, но это будет нарушением принципа инкапсуляции. Общепринятое средство – создать свойство.



Превратим переменную Длина из поля в модульную переменную, защитив тем самым от воздействия извне:

    Private Длина As Integer

Затем создадим свойство Длина_участка:

    Public Property Длина_участка() As Integer

        Get

            Return Длина

        End Get

        Set(ByVal Value As Integer)

            If Value < 500 Then

                Длина = Value

            Else

                MsgBox("Слишком длинный участок")

                Длина = 0

            End If

        End Set

    End Property

Мы предоставляем возможность каждому извне узнавать без ограничений значение свойства, поэтому часть Get – End Get у нас заполняется стандартно.

Поговорим о части Set – End Set. Внутренним неприкасаемым хранителем значения длины в нашем классе является модульная переменная Длина. Свойство Длина_участка придумано только для того, чтобы показывать вовне значение этой переменной и по-возможности безопасным и контролируемым образом разрешать извне это значение менять. Часть Set – End Set поэтому имеет своей конечной целью присвоение переменной Длина нужного значения.

Если часть Get – End Get – это функция, то часть Set – End Set – это процедура. Причем с параметром Value. Каждый раз, когда кто-то пытается извне присвоить свойству Длина_участка какое-нибудь значение, это значение приходит в объект-участок в качестве значения параметра Value свойства Длина_участка. Остается только написать в части Set – End Set единственный оператор

                Длина = Value

И если бы он остался единственным, то в этом случае мы получили бы свойство для чтения-записи безо всяких ограничений. Но тогда не стоило и огород городить. Ведь поле Длина обеспечивало то же самое. Однако мы помнили о нашем запрете на длинные участки и поэтому часть Set – End Set сделали подлиннее. Теперь каждый, желающий из текстового поля задать длину участка равную 500 и выше, столкнется с сообщением "Слишком длинный участок" и вынужден будет вводить данные вновь.

Обратите внимание, что классу совершенно все равно, что



физически является передатчиком значения извне внутрь свойства. Это может быть текстовое поле, как в нашем случае, или InputBox, или файл. В любом случае значение приходит в объект в качестве значения параметра Value и анализируется согласно коду, написанному в теле свойства программистом.

Итак, какова обычная последовательность создания свойств? Организуется модульная переменная Private – хранительница значения свойства, а затем организуется свойство Property для связи этой переменной с внешним миром.

Если же эта переменная вам внутри класса не нужна, то вы можете обойтись и без нее и вычислять значение свойства прямо в теле свойства в части Get – End Get.

Свойства «только для записи». Не правда ли, звучит странно? Они напоминают писателей, которым нельзя читать. Или фехтующих в потемках.

Предположим, мы не хотим, чтобы снаружи знали, кто является владельцем участка. Вы скажете: Как же так? Ведь тот, кто вписывает имя владельца в текстовое поле на форме, знает это имя! Какой же смысл скрывать? Да, конечно, он знает. С этим ничего не поделаешь. Ну так чтоб хоть другие-то не знали! Если хотят изменить это имя, испортить, – пусть портят, лишь бы не узнали настоящего имени!

Превращаем поле Владелец в  модульную переменную:

    Private Владелец As String

Вот как выглядит свойство Владелец_участка:

    Public WriteOnly

Property Владелец_участка() As String

        Set(ByVal Value As String)

            Владелец = Value

        End Set

    End Property

Мы здесь стерли часть Get – End Get и добавили в объявление свойства слово WriteOnly («только для записи»).


Полосы прокрутки (ScrollBars) и ползунок (TrackBar)


Для определенности поговорим о горизонтальной полосе прокрутки (HScrollBar). Все сказанное будет полностью относиться и к вертикальной полосе (VScrollBar).

Поместите на форму горизонтальную полосу (вы можете ее видеть на Рис. 18.4). Запустите проект. Потаскайте бегунок мышкой или клавишами перемещения курсора. Вы, безусловно, знакомы с полосой прокрутки по другим приложениям Windows. Она используется в основном для того, чтобы прокручивать информацию в окне или же просто менять значение какой-нибудь величины.

Задача: Изменять с помощью полосы прокрутки значение переменной величины W в пределах от 20 до 80. При щелчке по стрелкам полосы или по клавишам перемещения курсора на клавиатуре значение переменной должно меняться на 4, а при щелчке по полосе слева или справа от бегунка значение переменной должно меняться на 10. После запуска проекта бегунок должен стоять на отметке 47.

Ваши действия: Создайте проект и поместите на форму метку и горизонтальную полосу прокрутки. Ее имя HScrollBar1. Установите в соответствии с числами из задания следующие свойства полосы:

Minimum                            -              20

Maximum                           -              80

SmallChange                    -              4

LargeChange                    -              10

Value                                   -              47

Вы можете сделать это в режиме проектирования или в коде – в процедуре Form1_Load.  Проверьте правильность работы полосы, запустив программу:

Private Sub HScrollBar1_Scroll(ByVal sender As Object,  ByVal e As ScrollEventArgs) Handles HScrollBar1.Scroll

        Dim W As Integer

        W = HScrollBar1.Value

        Label1.Text = W

End Sub

Важное замечание: Вам никак не удастся вручную добраться до 80. Максимум, чего вы способны достигнуть, это 71. Таков закон работы полос прокрутки в VB – ближе, чем на значение LargeChange - 1, вы вручную до максимума не доберетесь (а в коде можно). Чтобы решить проблему, увеличьте немного Maximum или уменьшите до единицы LargeChange.


Событие Scroll  возникает при любом ручном перемещении бегунка. Мышью вы можете перетаскивать бегунок и меньше, чем на SmallChange.

Задание 3.    

Поместите рядом с полосой три метки:



Рис. 18.4

Левая метка должна  указывать минимальное значение, правая – максимальное, средняя – текущее. Усложнение: Хорошо бы средняя метка бегала рядом с бегунком.

Как прокручивать окно полосами прокрутки. Попробуйте сымитировать работу графических редакторов. Там, если картинка не умещается в окне, окно прокручивается полосами прокрутки и в результате в поле зрения можно поместить любую часть картинки. Идея такова. Окно – это форма. Распахните форму пошире. Поместите в большое графическое поле (PictureBox) на этой форме большую картинку. Уменьшите теперь форму так, чтобы поле на нем не умещалось. Вот вам и нужная ситуация: картинка не умещается в окне. Поместите с правого края формы вертикальную полосу, а с нижнего – горизонтальную. Чтобы «прилепить» полосы к краям формы, обязательно используйте их свойство Dock. Теперь нужно добиться, чтобы при перемещении бегунков поле двигалось по форме в нужном направлении. Сделайте так, чтобы горизонтальная координата поля (PictureBox1.Left) была тем меньше, чем правее бегунок на горизонтальной полосе (она должна быть даже отрицательной). Для этого достаточно написать что-нибудь вроде:

PictureBox1.Left = - HScrollBar1.Value

Подобрав правильно численные значения свойств полосы, вы добьетесь нужного эффекта. Аналогично поступите с вертикальной координатой.

TrackBar. Внешний вид ползунка вы видите на Рис. 18.5. Его действие и свойства (Minimum, Maximum, SmallChange, LargeChange, Value) аналогичны действию и свойствам полосы прокрутки. Только свойство SmallChange относится к клавиатуре, а LargeChange – к мышке.



Рис. 18.5

Ползунок может располагаться и вертикально (свойство Orientation). Некоторое удобство придает наличие шкалы. Бегунок может перемещаться только по делениям шкалы. Расстояние между делениями определяет свойство TickFrequency (с учетом значений  Minimum и Maximum). Свойство TickStyle определяет положение шкалы на регуляторе.


Понятие о базах данных


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

Фамилия И.О.

Дата рождения

Спортивное общество

Разряд по боксу

Агамалов С.В.

12.4.78

Трудовые резервы

3

Парменов Л.В.

31.11.82

Динамо

3

Васин А.Н.

16.10.71

ЦСКА

3

Попов А.А.

14.2.79

Спартак

2

Яньков В.Ю.

27.1.84

Спартак

2

Иноземцев И.М.

3.3.80

Восток

1

Столбцы таблицы называют также полями, строки – записями. Поля могут быть текстовыми (Спортивное общество), числовыми (Разряд по боксу), типа даты и времени (Дата рождения), булевскими, содержать объекты (например, картинки, звук, видео). Количество записей в таблицах реальных баз данных достигает многих тысяч.

Для того, чтобы человек мог удобно работать с базами данных, написаны специальные программы – системы управления базами данных (СУБД). Основное, что нужно человеку от СУБД при работе с реальной базой данных – это найти в море ее информации нужную ему каплю. Например, в таблице о 20000 преступников нужно быстро осуществить поиск записи о некоем Вольдемаре Сидорове, 1972 года рождения, по кличке Бармалей, чтобы посмотреть, есть ли у него шрам на левой щеке. Или же мы ищем неизвестного преступника по приметам и из 20000 записей хотим вывести на экран только те несколько, что соответствуют кареглазым блондинам ростом от 175 до 180 см с татуировкой на правой руке. Остальные же записи мы не хотим видеть и ждем, что компьютер их отфильтрует. Почти всегда мы хотим, чтобы найденная информация была отсортирована. Так, наша таблица боксеров отсортирована по убыванию разряда. Пользователь должен иметь возможность легко сортировать таблицу по любому полю (столбцу).

Кроме этих основных задач порядочная СУБД позволяет пользователю изменять содержимое записей, дополнять таблицы новыми записями, стирать ненужные, распечатывать в удобном виде нужную информацию из базы данных, позволяет при помощи программирования автоматизировать наиболее трудоемкие операции с базами данных и приспосабливать базы данных к конкретным нуждам пользователя. Все это вы научитесь делать после изучения этой главы.


Связанные таблицы. Вы спросите: А зачем в одной базе данных иметь несколько таблиц? Вот зачем. Возьмем, например, базу данных «Бокс в России». Очевидно, кроме таблицы боксеров она должна содержать таблицу тренеров, таблицу спортивных обществ, культивирующих бокс, таблицу спортивных залов, имеющих ринги, и другие таблицы. Имеет смысл держать эти таблицы в одной базе потому, что часто нам нужно искать информацию, касающуюся не одной таблицы, а сразу нескольких. Например, нужно узнать (сделать запрос), в каком году создано спортивное общество, к которому принадлежит боксер Васин А.Н.? Для этого нужно по таблице боксеров узнать название этого общества и тут же по таблице обществ узнать год его создания. Держать же все сведения о боксерах, обществах и всем прочем  в одной таблице неудобно и невыгодно – таблица получится слишком уж огромной.

Чтобы иметь возможность делать запрос сразу к нескольким таблицам, нужно сделать эти таблицы связанными. В этой книге я не буду касаться работы со связанными таблицами и ограничусь базами данных, состоящими из одной таблицы.

Одной из популярных СУБД является Microsoft Access – программа, входящая в пакет Microsoft Office Professional. Я упоминаю именно ее потому, что Microsoft Office почти наверняка установлен на вашем компьютере. В Access вы можете и безо всякого программирования прекрасно работать с реальными базами данных. Ну а когда возникнет необходимость в программировании, то и программировать вы сможете прямо в Access на специальном языке Visual Basic for Applications, который является «диалектом» языка Visual Basic применительно к пакету Microsoft Office.

Таким образом, если вы решили осваивать базы данных, то я рекомендую два пути:

Освоить на уровне пользователя Access, и тогда ваша работа с базами данных будет удобной и приятной, а необходимость в программировании вы почувствуете не скоро. Когда же почувствуете, то будете программировать на близком вам Visual Basic for Applications. Это наилучший способ для новичка быстро и без программирования разобраться в реальных базах данных. Однако этот способ слаб для быстрой работы с очень большими базами данных.

Осваивать работу с базами данных на VB. Это несколько труднее, но зато вы почти сразу же начнете программировать и сможете создавать проекты, включающие одновременно и базу данных и другие вещи, которые вы научились делать на VB (например,  игры). VB предоставляет для работы с базами данных самые современные и мощные средства (так называемая технология ADO.NET).

Название книги обязывает меня выбрать второй путь, поэтому на работе в Access я остановлюсь только кратко.


Понятие об Интернет, Web-страницах и языке HTML


Интернет – это сто миллионов компьютеров на всем земном шаре, соединенных между собой телефонными линиями и другими, более быстрыми, каналами связи с целью обмена информацией. Упрощенно структуру Интернета вы можете видеть на Рис. 23.1.

Рис. 23.1

В мире существуют тысячи (не миллионы) мощных компьютеров, которые соединены между собой высокоскоростными линиями связи и никогда не выключаются. Называют их узлами или Web-серверами. Они-то и составляют «спинной хребет» Интернета. Если вы хотите подключить ваш домашний компьютер к Интернету, то можете это сделать, только подключившись к какому-нибудь узлу, чаще всего ближайшему. Узлом (Web-сервером) владеет фирма, которая называется провайдером, она берет с вас деньги и разрешает подключаться к своему Web-серверу. К этому же серверу подключены и тысячи других желающих из ваших мест.

Вы знаете, что для большинства владельцев компьютеров путешествие по Интернету – это бесконечное перелистывание Web-страничек. Многие их миллионы накоплены в Интернете. Любая из них круглосуточно доступна каждому подключившемуся к Интернету. Спрашивается: где хранятся все эти странички? На вашем компьютере? Нет, там бы они просто не уместились. На других домашних компьютерах, подключенных к Интернету? Тоже нет, ведь если домашний компьютер выключен, что с ним частенько бывает, то страничка, размещенная на нем, никому не доступна.

Все странички размещены на Web-серверах. Как они туда попадают? Очень просто. Их создают на домашних компьютерах, а размещают на узлах. В настоящее время вы имеете возможность простыми средствами создать свою собственную Web-страницу и подключившийся к Интернету сделать ее видимой всему миру. Страничку вы не спеша создаете на своем компьютере, помещая туда любую не противоречащую закону информацию, затем соединяетесь со своим сервером (можно и с некоторыми другими серверами) и следуя несложной инструкции, которой вас снабдил сервер, помещаете ее на его жесткий диск. На жестком диске сервера ваша и тысячи других Web-страниц будут неограниченно долго храниться.


Давайте представим, что происходит, когда вы хотите увидеть на экране своего компьютера страничку, размещенную на сервере где-нибудь в Африке. У каждой странички есть адрес, который вы узнаете в Интернете же. Вы посылаете адрес странички на свой сервер, тот по линии связи соединяется с сервером в Африке и нужная страничка отправляется с африканского сервера на ваш сервер, а оттуда – к вам в компьютер.

Все вы видели Web-странички, они напоминают страницы красочных журналов, на них много текста на красочном фоне, есть фотографии, анимация, иногда даже музыка и видео. Тот, кто знаком с красочной графикой, музыкой и видео, знает, что они требуют для своего представления большого объема информации. Такое количество информации слишком долго будет передаваться по линиям связи и поэтому ваш Интернет будет нещадно тормозить. Как же решается эта проблема? Приведу аналогию.

Два художника живут в разных городах. Один звонит другому и говорит, что хочет посмотреть на его новую картину. Тому посылать картину по почте долго и дорого, поэтому вместо картины он присылает письмо такого содержания: «Возьми холст и краски. В нижнем левом углу холста нарисуй златокудрую нимфу, малюсенькая фотография которой вложена в письмо. Справа вверху нарисуй грозовую тучу. Внизу напиши крупными буквами «Пейзаж» …». И так далее. Первый художник, выполнив все, что сказано в письме, будет иметь перед собой картину, похожую на оригинал. Похожую, а не копию!

В Интернете по линиям связи с узла на ваш компьютер передается не сама страница, а описание того, как ее рисовать, что и каким шрифтом писать плюс очень экономно закодированные фотографии, звук и видео с этой страницы и некоторые другие элементы. В вашем компьютере эту информацию поджидает программа, которая играет роль художника, рисующего картину по ее описанию в письме. Эта программа называется браузером. Браузер не только рисует на экране страничку по описанию, но и позволяет удобно листать странички и делать почти все, что нужно для работы в Интернет. В мире наиболее распространен браузер Internet Explorer. Он входит в состав Windows.

Описание Web-страницы  выполняется на специальном языке, который называется HTML. Язык этот прост и понятие о нем дается в 23.3.


Постановка задачи


Давайте создадим такую игру (см. Рис. 22.1):

Рис. 22.1

При нажатии на кнопку Начинай сначала 10 шариков разлетаются из места старта во все стороны со случайными скоростями и в случайных направлениях. Они ведут себя как биллиардные шары на столе. Ударившись о бортик, любой шарик отскакивает по закону отражения (что такое «по закону отражения», объяснено в Задание 102). Трения нет – и шарики могут бесконечно кататься по столу. Для простоты я не стал программировать взаимные соударение шариков, хотя при знании законов школьной физики это вполне можно было сделать. Поэтому шарики при столкновении просто пролетают друг сквозь друга. На поле присутствует Ловец (на рисунке он имеет вид улыбающейся рожицы). Ловцом управляет с клавиатуры игрок. Ловец может двигаться с постоянной скоростью в 4 направлениях: вверх, вниз, влево, вправо, подчиняясь соответствующим клавишам клавиатуры, а также стоять (клавиша Ctrl). Каждый раз, когда ловец соприкасается с шариком, шарик исчезает (он пойман). Задача игрока – побыстрее поймать все 10 шариков. Счетчик времени (импульсов таймера) замирает в момент поимки последнего шарика, чтобы вы могли запомнить результат. При нажатии на кнопку Начинай сначала игра начинается вновь. Вот и все.

Что здесь будет объектом? Несмотря на то, что у нас нет опыта, интуиция подскажет нам: конечно же, объектами будут шары и ловец.


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

Автор

Название книги

Дата выпуска

Количество страниц

Стругацкие

Понедельник начинается в субботу

3.5.1965

187

Конан Дойль

Затерянный мир

15.11.1920

210

Стругацкие

За миллиард лет до конца света

14.7.1974

118

Достоевский

Белые ночи

30.9.1848

55

Ефремов

Туманность Андромеды

12.9.1957

348

Гоголь

Сорочинская ярмарка

31.12.1831

26

Наша задача – создать эту базу и таблицу и научиться осуществлять с ними все основные необходимые операции: заполнение таблицы данными, изменение данных, разнообразные запросы.

Конечно же, мы не будем пользоваться тем трудоемким программированием, которое мы использовали в 16.3. В VB имеются специальные инструменты для быстрого и удобного выполнения нужных операций.

Базы данных, созданные в разных СУБД, имеют разные типы и каждый тип требует особого программирования. Однако VB обеспечивает работу со всеми наиболее популярными типами баз данных. Более того, с помощью технологии ADO.NET он делает эту работу совершенно одинаковой независимо от типа. Для удобства мы с вами будем работать с базами данных, совместимыми с Microsoft Access. Это позволит нам работать с одной и той же базой данных как в VB, так и в Access.

База данных упомянутого типа хранится целиком в одном файле с расширением mdb. Мы будем действовать в такой последовательности:

Создадим пустой файл базы данных

Создадим в нем пустую таблицу книг, задав в ней только имена и типы полей

Заполним таблицу данными о книгах

Будем осуществлять различные запросы к базе данных

Сначала я кратко остановлюсь на работе с базами данных в Access, а затем – более подробно – в VB. Если вы даже не собираетесь работать в Access или он у вас не установлен, вам все равно будет полезно пробежаться по материалу посвященного ему раздела, так как там рассматриваются некоторые необходимые понятия и термины и там вы легче и быстрее всего почувствуете, что такое конкретная база данных.



Потоки


Проблема в том, чтобы заставить обе процедуры работать одновременно. Решается она организацией так называемых потоков. Если вы хотите, чтобы некая процедура позволяла остальным частям проекта работать одновременно с ней и реагировать на события независимо от нее, вы выделяете ее в поток. Процесс выполнения процедуры при этом становится во многих отношениях независимым от выполнения остальной части проекта.

Свой поток вы можете организовать для любой процедуры. Получится многопоточный проект. Рассмотрим пример.

 Создайте проект с тремя кнопками и двумя текстовыми полями. Вот код:

Dim Поток1 As New System.Threading.Thread(AddressOf Процесс_потока1)

Dim Поток2 As New System.Threading.Thread(AddressOf Процесс_потока2)

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Поток1.Start()

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        Поток2.Start()

End Sub

Private Sub Процесс_потока1()

        Dim i As Integer = 1

        Do

            TextBox1.Text = i

            Debug.WriteLine("Работает 1 поток:" & i)

            i += 1

        Loop

End Sub

Private Sub Процесс_потока2()

        Dim i As Integer = 1

        Do

            TextBox2.Text = i

            Debug.WriteLine("Работает 2 поток:" & i)

            i += 1

        Loop

End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

        MsgBox("Привет!")

End Sub

Пояснения: Вы придумали две процедуры: Процесс_потока1 и Процесс_потока2, которые хотите выделить в отдельные потоки. Первая из этих процедур бесконечно печатает возрастающие числа в текстовом поле 1 и в окне Output, вторая – в текстовом поле 2 и в окне Output.

Для организации потоков вы написали первые две строки кода:

Dim Поток1 As New System.Threading.Thread(AddressOf Процесс_потока1)


Dim Поток2 As New System.Threading.Thread(AddressOf Процесс_потока2)

Получается, что создать поток – значит создать объект класса Thread пространства имен System.Threading, указав в качестве параметра адрес процедуры, образующей поток.

Запустите проект. Щелкните по 1 кнопке. Выполнится метод Start объекта Поток1, запускающий поток. В текстовом поле 1 и окне Output побегут числа. Теперь нажмите на 3 кнопку. Она нажмется и, как положено, появится сообщение. Обратите внимание, что поток при этом не прервался, числа в поле и окне продолжают бежать. (Возможно, числа в окне Output отстают от чисел в текстовом поле.)

Закройте сообщение. Закройте крестиком форму. Обратите внимание, что числа в окне Output продолжают бежать. Кнопка Stop Debugging на панели Debug в виде черного квадратика не стала бледной. Это значит, что выполнение проекта закрытием формы не завершилось. Работа потока продолжается. Завершите проект и поток кнопкой Stop Debugging.

 Снова запустите проект. Щелкните по 1 кнопке. В текстовом поле 1 и окне Output побегут числа. Нажмите кнопку 2. Запустился 2 поток. Числа побежали теперь и в текстовом поле 2.  В окне Output вдобавок к числам от 1 потока побежали вперемежку с ними и числа от 2 потока (возможно, не сразу, а с задержкой в несколько секунд):

Работает 1 поток:22900

Работает 2 поток:31

Работает 1 поток:22901

Работает 2 поток:32

Работает 1 поток:22902

Работает 2 поток:33

Работает 1 поток:22903

Работает 1 поток:22904

Работает 2 поток:34

Мы видим, что компьютер выполняет одновременно два независимых друг от друга потока. Как будто одновременно работают две независимые программы. Однако, если ваш компьютер однопроцессорный, одновременность выполнения потоков только кажущаяся, как кажущейся была одновременность движения шариков в игре «Ловец». Каждому потоку компьютер по-очереди выделяет небольшие отрезки времени. Пока один поток работает, другой спит.

Обратите внимание, что очередность печати чисел из двух потоков выполняется не всегда строго. Здесь вы впервые сталкиваетесь с некоторой неопределенностью в действиях компьютера. Если раньше мы могли абсолютно точно сказать, когда компьютер переходит от выполнения одной процедуры проекта к выполнению другой, то теперь не можем. Распределением времени и ресурсов между двумя потоками компьютер управляет сам, не докладывая нам подробностей.



Однако, мы можем управлять приоритетом каждого из потоков. Если мы хотим, чтобы 2 поток выполнялся почаще по сравнению с 1 потоком, мы можем перед стартом 2 потока написать:

        Поток2.Priority = Threading.ThreadPriority.Highest

и соответственно перед стартом 1 потока:

        Поток1.Priority

= Threading.ThreadPriority.Lowest

Здесь мы выбрали самый высокий и самый низкий приоритеты. У перечисления ThreadPriority есть и промежуточные градации.

Теперь печать будет такая:

Работает 2 поток:758

Работает 2 поток:759

Работает 2 поток:760

Работает 2 поток:761

Работает 1 поток:212

Работает 2 поток:762

Работает 2 поток:763

Работает 1 поток:213

Работает 2 поток:764

Работает 2 поток:765

Работает 2 поток:766

Как видите, 2 поток выполняется чаще.

Вот несколько методов класса Thread, которые помогут вам управлять потоками:

Метод

Действие

Sleep (2000)

Пауза в работе потоков на 2 секунды. Метод статический.

Suspend

Приостановить работу потока

Resume

Возобновить работу потока

Abort

Прекратить работу потока


Потоки и DoEvents


Создайте проект с двумя кнопками. В обработчик нажатия каждой кнопки поместите бесконечный цикл печати чисел:   1  2  3  4  …  Вот код:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim i As Integer = 1

        Do

            Debug.WriteLine("Работает 1 кнопка:" & i)

            i += 1

        Loop

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        Dim i As Integer = 1

        Do

            Debug.WriteLine("Работает 2 кнопка:" & i)

            i += 1

        Loop

End Sub

Запустите проект. Щелкните по первой кнопке. В окне Output побегут числа. Попробуйте теперь нажать вторую кнопку – у вас просто не получится. Пока процедура не выполнилась, ни форма, ни элементы управления не реагируют на ваши действия. И не только на ваши действия нет реакции, никакая часть кода проекта не работает. Таков известный нам до сих пор закон VB  – когда процедура выполняется, все остальные части проекта – «в обмороке».

Завершите проект кнопкой Stop Debugging (квадратик на панели Debug)

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

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

Но не всегда это удается и уж никогда не удается без дополнительных хлопот. Однако, есть два инструмента, которые помогут вам избежать этих хлопот. Первый – метод DoEvents, он действует частично. Во втором случае применяем так называемые потоки, этот инструмент действует радикально.



Правильное включение и выключение компьютера Первые шаги


Итак, вы никогда не садились за компьютер. Не беда. Книжка у вас в руках. Все, что вам нужно знать, это то, что компьютер исправен и что на нем установлены и нормально работают Windows и Visual Studio .NET. Если VS не установлена, то изучите этот раздел, а затем попытайтесь установить VS, как это сказано в 4.1.

Включите компьютер. Некоторое время по экрану будет бежать всякая информация, наконец картинка установится. Если компьютер требует, введите свое имя пользователя и пароль. Через некоторое время картинка снова установится. Пространство экрана в Windows, которое вы сейчас видите, называется рабочим столом. На нем вы должны сейчас видеть как минимум значок Корзины и панель задач. Панель задач – это серая (обычно) «доска», «приклеенная» к одному из краев экрана (почти всегда – к нижнему). На левом конце панели задач должна находиться кнопка «Пуск» (Start). Если панель задач не видна (что иногда бывает), значит она спрятана (для экономии места) за одним из краев экрана. Попробуйте достать ее оттуда мышиным курсором, копнув им край экрана, как лопатой. Если она снова убежит за край – не беда, вы всегда при необходимости выкопаете ее оттуда. Если вы никогда не держали мышку в руках, прочитайте сначала чуть ниже «Работу с окнами Windows».

Щелкните кнопку «Пуск» на панели задач. (Когда я говорю «Щелкните», я всегда подразумеваю «Щелкните левой клавишей мыши».) Перед вами появится стартовое меню (или по-другому меню «Пуск») Windows – список приказов, которые вы можете отдать компьютеру, или, что точнее, – список программ, установленных на данном компьютере. Чтобы выполнить программу, щелкнете по пункту меню мышкой.

Стартовое меню ступенчатое, то есть некоторые пункты меню открывают вложенное в них другое меню. Такие пункты помечены черной треугольной стрелочкой. Аналогия: Ресторанное меню содержит пункты «Завтрак», «Обед», «Ужин». Пункт «Обед» содержит вложенное меню с пунктами «Закуски», «Горячие блюда», «Десерт». Пункт «Десерт» содержит вложенное меню с пунктами «Мороженое», «Клубника со сливками» и т.д.

Когда вам захочется выключить компьютер, не рекомендую сразу же нажимать кнопку выключения компьютера на системном блоке. Ваши действия: Кнопка «Пуск» на стартовом меню ® пункт «Завершение работы компьютера» ® в возникшем окне выберите пункт «Выключить компьютер» или щелчком по черной треугольной стрелке добейтесь, чтобы в окне появились именно эти слова ® ОК. Через некоторое время компьютер или выключится сам или на экране появится надпись, разрешающая отключить питание.



Представление и кодирование информации в компьютере


Физический уровень. Поговорим о том, как физически представлена информация в компьютере. Что значит «физически»? Вот, например, на листе учебника буквы физически представлены типографской краской, на старой грампластинке звук представлен изгибами звуковой дорожки, в человеческом мозге информация представлена электрическими импульсами, которые передаются от одной нервной клетки мозга в другую. В компьютере принят тот же способ представления, что и в мозге – из одного устройства компьютера в другое и внутри устройств информация передается электрическими импульсами. Посмотрим поподробнее, как электрические импульсы несут информацию в компьютере.

Логический уровень. Когда мы говорим о логическом уровне, мы говорим о кодировании (строении, структуре) информации, а не о том, как она физически представлена.

Прежде всего заметим, что информация в компьютере – это или программы или данные, с которыми эти программы работают.

Из чего состоит программа? Программа на языке программирования  состоит из команд, записанных при помощи букв, цифр, знаков математических действий, знаков препинания и других символов[†]. Будем понимать под символом любой знак (букву, цифру, знак математического действия, знак препинания и др.), который понимает компьютер. Самые популярные символы вы можете видеть на клавиатуре.

Из чего состоят данные? Если это текстовые данные, то они тоже состоят из символов. О числах, графических данных (изображениях), видео и звуке поговорим чуть ниже.

Таким образом, значительная часть информации в компьютере состоит из символов. Посмотрим, как в компьютере представлены символы. Для этого вспомним, как кодируются символы в азбуке Морзе, активно использовавшейся не так давно для передачи сообщений на расстояние. Каждый символ (буква, цифра) представлен в ней цепочкой точек и тире. Например, буква А представлена, как . -, буква Ч – как - - - . . В компьютере каждый символ тоже кодируется, но по-другому – цепочкой из 8 или 16 единиц и ноликов. Например, буква А может быть представлена, как 10000000, буква Ч – как 10010111, а цифра 7 – как 00110111.


Кстати, вот полезная задачка для будущего программиста: Сколько всего символов можно закодировать цепочкой из восьми единиц и ноликов? Подумайте на досуге.

Физический уровень. Пока мы с вами говорили о символах и их кодировании безотносительно к тому, какими физическими процессами и величинами они представлены в компьютере. Мы были на так называемом «логическом» уровне. Теперь перейдем на физический уровень. Пусть память передает на принтер букву Ч. В этом случае она посылает по шине в течение, скажем, восьми микросекунд,  серию из восьми электрических импульсов и промежутков между импульсами:

Первая микросекунда                              -              импульс

Вторая микросекунда                               -              промежуток

Третья микросекунда                               -              промежуток

Четвертая микросекунда         -              импульс

Пятая микросекунда                 -              промежуток

Шестая микросекунда              -              импульс

Седьмая микросекунда            -              импульс

Восьмая микросекунда             -              импульс

Как видите, последовательность импульсов и промежутков в серии соответствует последовательности единиц и ноликов в коде буквы Ч. Величина импульса не играет никакой роли, все импульсы в микросхемах компьютера имеют обычно одну и ту же величину, скажем 1 вольт.

Таким же примерно образом обмениваются группами из 8 импульсов все устройства компьютера. В памяти эти группы живут в «замороженном» виде. В каждом байте оперативной памяти или памяти на диске умещается ровно одна такая группа, поэтому говорят, что устройства обмениваются байтами информации.

В оперативной памяти единичка представляется наличием электрического потенциала (заряда) в определенной точке электронной микросхемы, а нолик – его отсутствием. А поскольку таких точек в памяти многие миллионы, то столько же там и единиц с ноликами. В памяти на магнитных дисках единичка представляется наличием намагниченности в определенной точке диска, а нолик – его отсутствием или намагниченностью в другом направлении. В лазерных дисках единичка – это бороздка или бугорок в определенной точке диска, а нолик – его отсутствие, то есть участочек с зеркальной поверхностью.



Впрочем, в отдельных устройствах может быть и наоборот – единички это отсутствие потенциала или намагниченности или бороздок и т.д., а нолики – наличие. Это не принципиально.

Логический уровень. Перейдем снова на логический уровень. Когда кодируется изображение, то кодируется информация о каждом пикселе изображения (в виде группы единиц и ноликов). Например,

         Код 111                 -              пиксель горит белым цветом

         Код 100                 -              пиксель горит синим цветом

         Код 010                 -              пиксель горит красным цветом

         Код 001                 -              пиксель горит зеленым цветом

         .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 

         Код 000                 -              пиксель не горит (черный)

Если программа предназначена для распечатки изображения с экрана монитора на цветном принтере, то она просто посылает на принтер по очереди коды информации о каждом пикселе изображения.

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

Коды чисел в компьютере часто не являются совокупностью кодов цифр, эти числа образующих. Так, число 88 часто не представляется цепочкой  00111000   00111000, а для кодирования используется другой, более экономный способ выстраивания в ряд ноликов и единиц.

Вывод – любая информация в компьютере закодирована в виде цепочек, состоящих из единиц и нулей, и в таком закодированном виде передается внутри устройств и между устройствами компьютера. Обычно длина цепочки равна 8 и тогда такая цепочка называется байтом. Каждый из восьми ноликов или единичек называется битом. Таким образом, 1 байт = 8 битов.

________   _   _________

Тех сведений, которые вы получили в этом приложении, достаточно для того, чтобы приступить к сознательному программированию на VB.


Придаем экзотической форме подвижность


Поскольку заголовка формы не видно, поставим задачу таскать форму по экрану, ухватившись мышью за любую точку ее поверхности. Для этого используем события формы MouseDown и MouseMove (14.2). Дополним код нашей формы из предыдущего подраздела следующим текстом:

'Координаты мыши при нажатии над формой на левую кнопку мыши:

Private X_нажатия_мыши As Integer

Private Y_нажатия_мыши As Integer

Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)  _

Handles MyBase.MouseDown

        If e.Button = MouseButtons.Left Then

            X_нажатия_мыши = e.X

            Y_нажатия_мыши = e.Y

        End If

End Sub

Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)  _

Handles MyBase.MouseMove

        If e.Button = MouseButtons.Left Then

            Me.Left = Me.Left + (e.X - X_нажатия_мыши)

            Me.Top = Me.Top + (e.Y - Y_нажатия_мыши)

        End If

End Sub

Пояснения: Чтобы перетащить форму по экрану, мы над формой нажимаем левую кнопку мыши (однократно срабатывает событие MouseDown) и, не отпуская кнопку, тащим мышь по экрану (многократно срабатывает событие MouseMove). Форма, как привязанная, следует за мышью. Разберем этот процесс подробнее.

В момент нажатия левой кнопки мыши фиксируются координаты нажатия мыши. Не забывайте, что e.X и e.Y  – координаты мыши относительно левого верхнего угла формы, а не экрана. Тут же мы начинаем мышь перемещать. Через доли секунды впервые срабатывает событие MouseMove. К этому моменту между значениями  e.X  и  X_нажатия_мыши  накапливается небольшая разница (несколько пикселей). В результате горизонтальная координата формы Me.Left благодаря оператору

            Me.Left = Me.Left + (e.X - X_нажатия_мыши)

изменяется на столько же пикселей. Форма сдвигается вслед за мышью на это число пикселей и поэтому разница становится нулевой. Форма догнала мышь. Но мы продолжаем тащить мышь. Еще через доли секунды событие MouseMove срабатывает во второй раз. К этому моменту между значениями  e.X  и  X_нажатия_мыши  снова накапливается небольшая разница, снова форма сдвигается и снова благодаря сдвигу формы разница становится нулевой. И так далее.

Все вышесказанное относится и к вертикальной координате.



Практика работы на компьютере Ввод текста


Это приложение – для тех, у кого не хватает опыта работы на компьютере. Здесь я вкратце напомню вам все умения, которые необходимы и достаточны для того, чтобы работать с VB. Здесь ничего не будет говориться о смысле, я буду только учить нажимать на кнопки. Можете начать изучение, даже если вы за компьютер не садились ни разу.



Теория – о компьютере ипрограмме


Если вы ничего не знаете о компьютере и программах, начинайте читать книгу именно с этого приложения. Здесь излагаются на уровне «для начинающего» следующие вещи:  

Принцип действия компьютера и его устройств: оперативной памяти, принтера, винчестера и других.

Взаимодействие устройств во время работы компьютера.

Принципы кодирования информации в разных устройствах компьютера.

Без знания этих вещей сознательное программирование невозможно. Если что-то из вышеупомянутого вам знакомо, вы можете этот материал пропустить или прочитать «по диагонали». В этой части мы не будем программировать.



Приложения


Приложение 1 предназначено для тех, кто не знает, как устроен и работает компьютер. Это теория.

Приложение 2 предназначено для тех, кто ни разу не садился за компьютер или садился только для игр. Здесь вы научитесь работать с окнами, папками и файлами Windows, вводить в компьютер текст, то есть приобретете все необходимые навыки, чтобы спокойно начать работу в среде Visual Studio .NET.



Создать кнопку следующего вида, поведения


Задача: Создать кнопку следующего вида, поведения и содержания:
В левой части кнопки находится иконка с луной.
В правой части кнопки имеется изменяющийся текст, указывающий, сколько раз по кнопке щелкнули с момента ее создания, например, «19 щелч.».
У кнопки есть дополнительное ReadOnly свойство Число_щелчков, смысл которого очевиден.
На 10-м щелчке по кнопке она порождает событие Наступление_зрелости. Подразумевается, что пока на кнопку не нажали 10 раз, она еще неопытная, незрелая, а когда нажали – она уже опытная, зрелая, ветеран. Таким образом, у кнопки есть дополнительное событие.
У кнопки есть дополнительное ReadOnly булевское свойство Ветеран, которое равно False до 10-го щелчка и True – после.
У кнопки есть дополнительный метод Прыжок, который заставляет кнопку прыгнуть направо. Дальность прыжка является параметром метода.
Решение: Создайте проект с кнопкой Button1, которая нужна только для проверки работы нашей создаваемой кнопки. Вот код:
Форма:
Dim WithEvents Кнопка As New clsКнопка
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.Controls.Add(Кнопка)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Кнопка.Прыжок(40)
        Debug.WriteLine(Кнопка.Число_щелчков)
        Debug.WriteLine(Кнопка.Ветеран)
End Sub
Private Sub Кнопка_Наступление_зрелости() Handles Кнопка.Наступление_зрелости
        MsgBox("Зрелость наступила")
End Sub
Класс:
Public Class clsКнопка
    Inherits Button
    Private Число_щелчков_по_кнопке As Integer = 0
    Public ReadOnly Property Число_щелчков() As Integer
        Get
            Return Число_щелчков_по_кнопке
        End Get
    End Property
    Private Опытная_кнопка As Boolean = False
    Public ReadOnly Property Ветеран() As Boolean
        Get
            Return Опытная_кнопка
        End Get
    End Property


    Public Event Наступление_зрелости()
    Public Sub New()
        Me.Image = Image.FromFile("MOON06.ICO")
        Me.ImageAlign = ContentAlignment.MiddleLeft         'Луна - налево
        Me.Text = Число_щелчков_по_кнопке  &   "  щелч."
        Me.TextAlign = ContentAlignment.MiddleRight         'Текст - направо
    End Sub
    Private Sub clsКнопка_Click( ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Click
        Число_щелчков_по_кнопке = Число_щелчков_по_кнопке + 1
        Me.Text = Число_щелчков_по_кнопке  &   "  щелч."
        If Число_щелчков_по_кнопке = 10 Then
            RaiseEvent Наступление_зрелости()
            Опытная_кнопка = True
        End If
    End Sub
    Public Sub Прыжок(ByVal Дальность As Integer)
        Me.Left = Me.Left + Дальность
    End Sub
End Class
Из кода формы мы обращаемся к новым свойствам, методам нашей кнопки и обрабатываем ее событие Наступление_зрелости. Когда при наборе программного текста в окне кода формы вы вводите точку после слова Кнопка, перед вами возникает список свойств и методов обычной кнопки, к которому добавились свойства Число_щелчков и Ветеран и метод Прыжок. При создании обработчика события Наступление_зрелости вы видите это событие в поле в правом верхнем углу окна кода формы наряду с обычными событиями кнопки.
Запустите проект. Пощелкайте по обеим кнопкам. При щелчке по кнопке Button1 наша кнопка прыгает направо на 40 пикселей. При щелчке по нашей кнопке ее текст меняется. После 10-го щелчка возникает сообщение «Зрелость наступила».

Сейсмодатчик»


Здесь мы рассмотрим пример работы с нетипизированными файлами.

Задание. Высоко в Гималаях расположена автоматическая сейсмостанция. Находящийся на ней сейсмодатчик измеряет колебания земной коры. Каждое измерение представляет собой целое число в диапазоне от 0 до 100, характеризующее амплитуду колебаний. Данные измерений передаются на компьютер, находящийся где-нибудь в Дели, и пишутся в файл. Время от времени (нерегулярно) в тот же файл записывается и точное время (в формате строки). Иногда до сейсмодатчика добирается Йети и бьет по нему лапой, тогда показания датчика превышают число 100. За лето 2005 года в файл было записано несколько миллионов чисел – результатов измерений и несколько тысяч моментов времени.

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

Данные в файл писались последовательно. Это значит после нескольких сотен или тысяч чисел – результатов измерений попадается строка времени, затем опять идет цепочка чисел, затем снова время и так далее. Чтобы при считывании можно было отличить время от чисел, перед записью каждого момента времени записывался байт с числом 255 (пусть это и ненадежная «метка» (вспомним хотя бы Йети!), но для учебного примера сойдет). Поскольку время писалось нерегулярно, представить этот файл типизированным никак нельзя. Значит нужно работать с ним, как с нетипизированным.

Задача программиста: Считывать все байты из файла по порядку. Наткнувшись на байт с числом 255, проверять записанное время. Если это 28 августа, распечатывать байты и строки времени до тех пор, пока не наткнешься на 29 августа или более позднюю дату. Если число превышает 100, печатать сообщение «Это Йети!».  Если момента времени 28 августа в файле не было вообще и достигнут конец файла, выдать сообщение «Колебаний не было».


Пишем в файл. Чтобы отлаживать нашу будущую программу, нужен исходный файл. Пусть данные в нем записаны в таком порядке:
23
17
86
255
28.08.2005 8:59:27
90
47
35
205
19
255
29.08.2005 1:19:11
46
90
164
18
Как видите, станцию два раза посетил Йети.
В учебных целях напишем программу, которая не считывает, а записывает эту информацию в файл:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim FS As New FileStream("E:\Папка\Сейсмостанция.Ind", FileMode.OpenOrCreate)
        Dim BW As New BinaryWriter(FS)
        Dim B1() As Byte = {23, 17, 86}
        Dim B2() As Byte = {90, 47, 35, 205, 19}
        Dim B3() As Byte = {46, 90, 164, 18}
        Dim Метка As Byte = 255
        BW.Write(B1)
        BW.Write(Метка)
        BW.Write(CStr(#8/28/2005 8:59:27 AM#))
        BW.Write(B2)
        BW.Write(Метка)
        BW.Write(CStr(#8/29/2005 1:19:11 AM#))
        BW.Write(B3)
        BW.Close()
        FS.Close()
End Sub
Пояснения: Метод Write умеет записывать не только байты, но и многие другие простые типы данных, например, дробные числа или строки. К сожалению, класс BinaryReader не умеет читать даты, поэтому я вынужден был записывать их в файл преобразованными к типу String.
Читаем из файла. Вот готовая программа:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim FS As New FileStream("E:\Папка\Сейсмостанция.Ind", FileMode.Open)
        Dim BR As New BinaryReader(FS)
        Dim By As Byte
        Dim Время As DateTime
        Dim Были_колебания As Boolean = False
        Do Until BR.PeekChar() = -1
              By = BR.ReadByte
              If By = 255 Then
                      Время = CDate(BR.ReadString)
                      If Время.Date
> #8/28/2005# Then Exit Do
                      Debug.WriteLine(Время)
              ElseIf Время.Date = #8/28/2005# Then


                      Были_колебания = True
                      Debug.WriteLine(By)
                      If By > 100 Then Debug.WriteLine("Это Йети!")
              End If
        Loop
        BR.Close()
        FS.Close()
        If Not Были_колебания Then MsgBox("Колебаний не было")
End Sub
При работе с нашим примером файла программа распечатывает такую информацию:
28.08.2005 8:59:27
90
47
35
205
Это Йети!
19
Пояснения: Вначале переменной Были_колебания, естественно, присваивается значение False, но если 28 августа было хоть одно показание датчика, то программа меняет его на True. Последняя строка программы в зависимости от значения этой переменной выдает или не выдает сообщение «Колебаний не было».
Данные из файла считываются в цикле Do-Loop. Чтобы остановить чтение при достижении конца файла, используется функция PeekChar (попробуй символ) класса BinaryReader. Она работает аналогично функции Peek класса StreamReader (19.2.5). При достижении конца файла чтение становится невозможным и функция принимает значение -1.
Вы видите, что если считано число 255, то компьютер его не распечатывает, а методом ReadString класса BinaryReader считывает строку, в которой записано время. У класса BinaryReader есть несколько методов для считывания из файла данных разных простых типов, например, ReadBoolean или ReadDouble. Но нет метода для считывания дат, поэтому даты и были записаны в файл в строковом виде. А сейчас они функцией CDate преобразовываются опять к типу DateTime.
Если эта дата Время.Date является более поздней (>), чем 28 августа, то компьютер выходит из цикла, иначе время распечатывается.
Если считанный байт не является числом 255, то проверяется, не 28 ли августа нынче в файле, и если да, то делается вывод о том, что колебания, точно, были, и распечатывается численное значение считанного байта, а если оно еще и превосходит 100, то в этом обвиняется Йети.

Привязываем справку к приложению Windows


Теперь нужно сделать, чтобы справка нормально работала из нашего игрушечного проекта, для которого она и предназначена. Подобно всем солидным приложениям Windows создадим в проекте меню Help с двумя пунктами: Содержание и Index. Кроме того предусмотрим контекстно-зависимую справку, а именно, когда в фокусе находится кнопка (а она, по правде говоря, у нас всегда будет в фокусе), то при нажатии на F1 должна появляться справка про действие именно этой кнопки (пусть это будет Звук.htm).

Для удобства адресации переместите файл Справка.chm в папку BIN проекта.

Чтобы справка работала из приложения, ее нужно к приложению привязать. Поместим в проект элемент управления HelpProvider. В окне его свойств зададим в качестве свойства HelpNamespace файл Справка.chm. Привязка закончена.

Теперь настроим контекстно-зависимую справку. Зайдем в окно свойств нашей кнопки. Там появились три новых свойства, имеющие отношение к справке, два из которых нас интересуют. Установите свойству HelpKeyword on HelpProvider1 значение Звук.htm, а свойству HelpNavigator on HelpProvider1 – значение Topic.

Запустите проект. Нажмите F1. Поскольку кнопка в фокусе, вы увидите окно справки с открытым документом Звук.htm, что и требовалось.

Если бы у вас на форме было несколько элементов управления, то вы для каждого могли бы установить упомянутые два свойства и тогда при нажатии на F1 вы бы видели справку, касающуюся именно того элемента управления, который находится в фокусе.

Чтобы на экране справка показывалась без нажатия на F1, а при выполнении оператора, вам нужно использовать методы класса Help. Чтобы справка появлялась с содержанием, вам нужно использовать метод ShowHelp, а чтобы с алфавитным указателем – метод ShowHelpIndex. Ниже вы видите код нашего проекта:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Beep()

End Sub

Private Sub Меню_содерж_Click(ByVal sender As Object, ByVal e As EventArgs)  Handles Меню_содерж.Click

        Help.ShowHelp(Me, "Справка.chm")

End Sub

Private Sub MenuIndex_Click(ByVal sender As Object, ByVal e As EventArgs)  Handles MenuIndex.Click

        Help.ShowHelpIndex(Me, "Справка.chm")

End Sub

Задание выполнено. Справка работает.



Процессор


Рассмотрим, чем занимается каждое устройство компьютера в отдельности. Прежде всего выделим два устройства, образующие «мозг» компьютера – это процессор и оперативная память. Именно эти два устройства осуществляют главную обработку информации, они решают все задачи, вычисляют траектории, обдумывают шахматные ходы и т.д. Только не надо забывать, что все это они делают, слепо выполняя команды программы, а это значит, что весь интеллект компьютера сосредоточен не в них, а в программе. Умен не сам компьютер, а умна находящаяся в нем программа. Поэтому часто вместо того, чтобы сказать «компьютер решил задачу», говорят «программа решила задачу».

Процессор можно назвать «начальником» над остальными устройствами компьютера, так как он во время выполнения программы руководит работой всех устройств. Именно он «понимает смысл» каждой команды программы. Он выполняет ее сам или приказывает выполнить другим устройствам. Однако, процессор почти ничего не помнит. Вернее, его память очень быстра, но и очень мала.

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

Быстродействие процессора во многом определяется его тактовой частотой, которая показывает, как часто «бьется его сердце». У современных компьютеров тактовая частота составляет сотни и тысячи мегагерц (миллионов герц, то есть миллионов тактов, ударов в секунду). Когда вы слышите слова «Селерон 2400», это значит, что имеется в виду процессор «Селерон» с тактовой частотой 2400 мегагерц. За 1 такт компьютер выполняет одну или несколько коротких команд программы.



Проект без формы, но со стандартным модулем


Создайте проект. В окне Solution Explorer сотрите значок формы Form1.vb, ответив ОК на предупреждение компьютера. Все – проект лишился формы, а значит и окна кода, принадлежавшего этой форме. Что же теперь делать, где программировать?

Создаем модуль. Ваши действия: Project ® Add New Item (Добавить новый компонент) ® в возникшем окне Add New Item (Рис. 21.1) выбираем Module ® Open.

Рис. 21.1

Вы видите, что в окне Solution Explorer появился значок Module1.vb (Рис. 21.2),

Рис. 21.2

а в проект добавилось окно Module1.vb, явно предназначенное для ввода кода:

Module Module1

   

End Module

Кстати, пролистайте список компонентов в окне Add New Item. Там вы увидите много полезных и любопытных вещей, которые можно вставлять в проект. Здесь и форма, и класс, и собственный элемент управления (User Control), и Интернет-страничка, и просто текстовый файл, и графические файлы (в том числе иконки и курсоры), и многое другое.

В наш проект добавился так называемый стандартный модуль или просто модуль. Мы уже знаем, что некие модули наряду с классами входят в состав пространств имен. Теперь мы видим, что эти самые модули могут входить и в состав проекта. Ну что ж, посмотрим на них «живьем», проверим, на что они способны.

Обратите внимание, что окно кода для модуля появилось, а вот соответствующего окна конструктора, куда бы мы могли помещать кнопки, метки и другие элементы управления, нет. Его и не будет. Ничего похожего на форму тоже не появилось. Ни формы, ни кнопок, ни меток, никаких других элементов управления в модуле кода нет и быть не может. Ничего такого, что можно увидеть. Получается, что если форма без кода – тело без души, то модуль – душа без тела.

Процедура Main. Запустите проект. VB жалуется на ошибки. Дело в том, что он привык при запуске загружать форму, а формы нет. Эту проблему нужно решать. И решать ее нужно еще и вот по какой причине. Как мы раньше заставляли VB выполнять то, что написано в окне кода? Создавая процедуры обработки событий, самыми популярными из которых были  Form1_Load и Button1_Click, а затем, после запуска проекта, щелкая по кнопкам. Теперь формы нет, элементов управления нет, кнопок, по которым можно было бы щелкнуть, нет, событий тоже нет, обрабатывать нечего. Тогда, если мы даже и запишем какой-то код в окне кода модуля, как заставим его выполниться?


На этот случай в модуле (и не только в нем) может существовать процедура с именем Main. Давайте создадим ее:

Module Module1

    Sub Main()

        Dim x As Integer = InputBox("Введите число")

        MsgBox(x ^ 2)

    End Sub

End Module

Теперь нам нужно сказать компьютеру, что начинать выполнение проекта нужно не с загрузки формы, которой все равно нет, а с выполнения процедуры Main в модуле Module1. Ваши действия: Project ® WindowsApplication1 Properties ® в возникшем окне (Рис. 21.3)  в поле Startup object (объект, с которого стартовать) выбираем Module1 ® ОК.



Рис. 21.3

В это же поле Startup object вам нужно заходить, когда вы переименовали форму Form1, чтобы сообщить VB, что проект нужно запускать с формы, имеющей уже другое имя.

Запускаем проект. Все сработало. Обошлись без формы. Обратите внимание, что работа проекта завершилась сама, автоматически, а когда стартовым объектом является форма, для завершения работы проекта приходится прикладывать усилия.

В окне кода нашего модуля вы можете объявлять какие угодно переменные и записывать какие угодно процедуры пользователя, запуская их из процедуры Main. То есть создавать полноценную программу. Конечно, нужно помнить, что без формы и элементов управления возможности ваши ограничены. Однако множество задач решается и без них. Ну, например, задача суммирования всех чисел из некоего файла.

Модулей добавлять в проект можно сколько угодно.

Термином модуль часто называют не только стандартный модуль, но и форму, и неведомый пока нам модуль класса и, как это ни странно, структуру. Я тоже буду так делать, когда это не будет вызывать путаницы.


Проект без формы Стандартные модули


Какой бы проект мы с вами ни запускали, на экране неизбежно появлялась форма. Обычно сразу, а иногда – с некоторой задержкой (когда в процедуре Form1_Load были предусмотрены какие-то медленные действия). У нас создалось впечатление, что без формы ничего полезного компьютер и сделать не может. Неверно. Вот пример:



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


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

Рисовать мышкой, как карандашом.

При помощи счетчика выбирать толщину карандаша.

Выбирать цвет карандаша.

Загружать картинки из графического файла.

Сохранять рисунки в графическом файле.

Внешний вид нашего графического редактора вы можете видеть на Рис. 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


Проект с формой, но форму не показываем


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim x As Integer = InputBox("Введите число")

        MsgBox(x ^ 2)

        End

End Sub

Вы помните, что форма появляется на экране только после завершения работы процедуры Form1_Load. Здесь компьютер просит нас ввести число, затем вычисляет и показывает нам его квадрат. Проект завершает свою работу оператором End, вследствие чего форма на экране так и не успевает появиться.

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



Проект с несколькими формами


Все приложения Windows, которые мы до этой главы создавали, после запуска работали в одном окне. Окном этим служила форма, на которой мы и собирали проект. Однако, вы вполне можете создать приложение, которое работает в двух или нескольких окнах. В этом случае для каждого окна вам понадобится в проекте своя форма.

Зачем это нужно? Вот зачем. Пусть, например, вы создали игру в шахматы. Игра идет, как обычно, в одном окне. Пока компьютер обдумывает свой ход, вы, чтобы не скучать, щелчком по кнопке запускаете новое окно, в котором играете с компьютером в созданный вами же тетрис. Теперь у вас на экране два окна. Когда компьютер сделает ход, вы можете поставить тетрис на паузу и продолжить игру в шахматы. При создании этого проекта вам нужно иметь в проекте две формы, одну для шахмат, другую – для тетриса.

Как. Посмотрим, как создать в проекте вторую форму и как наладить взаимодействие между двумя формами.

Создадим новый проект. При этом, как обычно, будет автоматически создана форма Form1. Чтобы добавить в проект еще одну форму, поступаем так же, как при добавлении модуля: Project ® Add New Item ® в возникшем окне Add New Item (Рис. 21.1) выбираем Windows Form ® Open. Вы видите, что в окне Solution Explorer появился значок Form2.vb, а в проект добавилась форма Form2, которую мы видим в окне Form2.vb[design]. Щелкните по значку Form1.vb в окне Solution Explorer, затем View ® Code, затем проделайте то же для другой формы – и вот у вас в проекте уже 4 окна: окно кода и окно конструктора для каждой из форм. Таким образом VB предоставляет удобную возможность программировать все происходящее в каждой форме в окне кода, принадлежащем именно этой форме.

Запустите проект. На экране появилась первая форма, а вторая – нет. Зайдите в Project ® WindowsApplication1 Properties и в качестве стартового объекта выберите Form2. Теперь на экране появилась вторая форма, а первая – нет. Снова выберите Form1.

Разместите на формах элементы управления согласно Рис. 21.6 и Рис. 21.7.

Рис. 21.6




Рис. 21.7

Добавьте в проект стандартный модуль. Поместите в окна кода модуля и обеих форм следующий текст:

Модуль:

Module Module1

    Public F1 As Form1

    Public F2 As Form2

End Module

Первая форма:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Me.BackColor = Color.Blue

        F2.BackColor = Color.Yellow

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        TextBox1.Text = "Форма Form1 приветствует саму себя!"

        F2.TextBox1.Text = "Привет форме 2 от формы 1!"

        F2.Focus()

End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        F1 = Me

End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

        F2 = New Form2

        F2.Show()

End Sub

Вторая форма:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Me.BackColor = Color.White

        F1.BackColor = Color.Tomato

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        TextBox1.Text = "Форма Form2 приветствует саму себя!"

        F1.TextBox1.Text = "Привет форме 1 от формы 2!"

        F1.Focus()

End Sub

Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        TextBox1.Text = "Я родилась!"

End Sub

Пояснения: Прежде всего, несколько слов о том, видны ли модульные переменные из других модулей. Если они объявлены как обычно словом Dim, то не видны, а если словом Public – то видны. Более подробно об этом написано в 21.9.

Модули обычно используются в качестве общедоступного склада для переменных, констант, процедур, функций и других элементов VB. Возьмите, например, модули Strings и DateAndTime пространства имен Microsoft. VisualBasic.



В нашем случае модуль понадобился для объявления двух общедоступных переменных: F1 и F2. Зачем они нужны? Почему именно модуль? Ограничусь «полуобъяснением», отложив объяснение до более поздних времен. Переменная F1 объявляется, как объект класса Form1. Это значит, что после загрузки формы Form1 мы хотим к ней обращаться по имени F1. Но этого мало. С этой же целью в процедуру Form1_Load вставлен оператор

        F1 = Me

чтобы «все» знали, что F1 ссылается именно на этот «экземпляр» формы. 

После запуска проекта форма Form1 появляется на экране. Чтобы появилась и форма Form2, нажимаем кнопку Button3. Оператор

        F2 = New Form2

порождает эту форму как объект класса Form2. А чтобы форма стала видна, выполняется оператор

        F2.Show()

Теперь у вас на экране обе формы и вы можете работать с каждой из них, нажимая кнопки и вводя текст в текстовые поля (Рис. 21.8).



Рис. 21.8

Я понимаю, что после такого «полуобъяснения» у вас возникло множество «почему». Отложите их на потом. К концу книги они должны рассеяться.

Посмотрите на содержимое процедур Button1_Click в обоих окнах кода. Вы видите, что первая строка обеих процедур красит своего хозяина, вторая – соседа. Таким образом, в каждом окне кода можно, как и обычно, писать операторы, приказывающие что-то сделать в форме-хозяине данного окна, а можно с таким же успехом писать операторы, приказывающие что-то сделать в любой другой форме проекта. Чтобы VB понимал, о какой форме идет речь, перед именем свойства, принадлежащего чужой форме, нужно писать имя этой формы (в нашем случае F1 или F2) с точкой. Если же форма своя, то вместо имени хозяина можно писать слово Me или вообще ничего не писать. Так в процедуре Button1_Click первой формы вместо

        Me.BackColor = Color.Blue

можно написать

        F1.BackColor = Color.Blue

или просто

        BackColor = Color.Blue

Теперь посмотрите на содержимое процедур Button2_Click в обоих окнах кода. Вы видите, что первая строка обеих процедур выводит текст в текстовое поле TextBox1 своего хозяина, вторая – в текстовое поле TextBox1 соседа. Третья строка обеих процедур при помощи метода Focus, принадлежащего соседу, переводит фокус на соседа. Таким образом, мы можем обращаться не только к свойствам чужой формы, но и к ее элементам управления, и к методам. К ним тоже применимо соглашение об имени хозяина с точкой.

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

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


Программа для компьютера на машинном языке


Мы знаем, что на одном и том же компьютере можно программировать на разных языках программирования: VB, C++ и т.д. Аналогично с человеком, знающим иностранные языки, можно говорить на нескольких языках. Возникает вопрос: а какой же из этих языков для компьютера родной? Ни один из них. У компьютера есть свой собственный родной язык, на котором уже лет 50 никто из людей не программирует. Называют этот язык машинным языком, потому что компьютер – машина. Если команды обычных языков примитивны, то команды машинного языка – суперпримитивны! Каждая из этих команд заставляет компьютер выполнить какое-то одно простейшее, очень маленькое, элементарное действие, меньше которого не бывает. По своей незначительности на фоне большой задачи, решаемой компьютером, оно подобно мимолетному сгибанию мизинца человеком, своими руками собирающим автомобиль и в настоящий момент берущим в руки отвертку.

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

Примеры действий, выполняемых командами  машинного языка:

Сложить два числа.

Определить, какое из двух чисел больше.

Следующие действия уже слишком трудны для одной команды машинного языка и под силу только совокупности таких команд:

Изобразить на экране в заданном месте светящуюся точку заданного цвета.

Изобразить на экране заданную букву или цифру.

Запомнить, какую клавишу нажал человек на клавиатуре.

В машинном языке еще много команд, и все они такие же «мелкие». Спрашивается, как же при помощи таких слабеньких команд заставить компьютер сделать хоть что-нибудь путное, скажем, написать слово «ЭВМ» или нарисовать кружочек? Я думаю, вы уже догадались, что нужно сделать – нужно написать процедуры. Вот, например, алгоритм процедуры, изображающей на экране слово «ЭВМ»:

Изобразить на экране букву "Э"

Изобразить на экране букву "В"

Изобразить на экране букву "М"

А вот алгоритм процедуры, вычисляющей выражение  (5?7)/(10+40):

Вычти 7 из 5

Прибавь 40 к 10

Раздели первый результат на второй

Покажи результат деления на экране монитора

Это ничего, что результат получился отрицательный и дробный. Компьютеры справляются с такими числами непринужденно.

А как же нарисовать кружочек, если компьютер может нарисовать только точку? Если вы посмотрите на экран монитора в увеличительное стекло, то заметите, что изображение любого предмета состоит из маленьких светящихся точек (пикселей), которые расположены так близко друг к другу, что сливаются в единое изображение (см. Рис. П1). Примерно то же самое вы видите через лупу на фотографии в газете. Вполне можно написать программу, которая рисует рядышком одну за другой множество точек так, чтобы они образовали окружность.



Программа-шпион


Мы можем воспользоваться умением создавать обработчики событий, чтобы написать любопытную программку.

Вообразите ситуацию. Вы подозреваете, что в ваше отсутствие кто-то включает компьютер и производит нежелательные изменения в многочисленных файлах и папках внутри вашей персональной папки (например, какой-то документ стерт или переименован, или в него что-то дописано). Чтобы выследить нарушителя, вы хотите знать, в какие моменты времени и какие именно файлы и папки подверглись изменениям.

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

Для того, чтобы программа запускалась при включении компьютера, ее ярлык достаточно поместить в папку автозагрузки Windows (пункт Автозагрузка (StartUp) меню Пуск Windows). Остается создать саму программу, чем мы сейчас и займемся.

Вот программа:

Private Шпион As New System.IO.FileSystemWatcher

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'Настраиваем шпиона:

        Шпион.Path = "C:\Дела"

        Шпион.IncludeSubdirectories

= True

        Шпион.Filter = "*.*"

        AddHandler Шпион.Created, AddressOf Фиксируем_создание

        AddHandler Шпион.Deleted, AddressOf Фиксируем_уничтожение

        AddHandler Шпион.Renamed, AddressOf Фиксируем_переименование

        AddHandler Шпион.Changed, AddressOf Фиксируем_изменение

        Шпион.EnableRaisingEvents = True

        'Маскируем шпиона:

        Me.Opacity = 0

        Me.ShowInTaskbar = False

End Sub

Private Sub Фиксируем_создание(ByVal source As Object, ByVal e As IO.FileSystemEventArgs)

        Дописываем_в_файл("Создан файл или папка:  " & e.FullPath)

End Sub

Private Sub Фиксируем_уничтожение(ByVal source As Object, ByVal e As IO.FileSystemEventArgs)


        Дописываем_в_файл("Стерт файл или папка:  " & e.FullPath)

End Sub

Private Sub Фиксируем_переименование( ByVal source As Object, ByVal e As IO.RenamedEventArgs)

        Дописываем_в_файл("Файл или папка  " & e.OldFullPath & "  переименован в  " & e.FullPath)

End Sub

Private Sub Фиксируем_изменение(ByVal source As Object, ByVal e As IO.FileSystemEventArgs)

        Дописываем_в_файл("Изменен файл или папка:  " & e.FullPath)

End Sub

Private Sub Дописываем_в_файл(ByVal Строка As String)

        Dim Дозапись As New System.IO.StreamWriter("Журнал.txt", True)

        Дозапись.WriteLine(DateTime.Now & "  " & Строка)

        Дозапись.Close()

End Sub

Вот пример содержимого файла Журнал.txt, заполненного этой программой:

13.05.2004 16:36:24  Стерт файл или папка:  E:\Дела\колледж.txt

13.05.2004 16:38:16  Создан файл или папка:  E:\Дела\new text document.txt

13.05.2004 16:38:32  Файл или папка  E:\Дела\new text document.txt

                        переименован в  E:\Дела\институт.txt

13.05.2004 16:41:04  Изменен файл или папка:  E:\Дела\работа.txt

13.05.2004 16:41:04  Изменен файл или папка:  E:\Дела\работа.txt

Вот пояснения:

В библиотеке классов .NET Framework для присмотра за изменениями в файлах и папках существует специальный класс  FileSystemWatcher («Надсмотрщик за файловой системой») пространства имен System.IO. У него есть несколько событий, которые генерируются при вышеупомянутых изменениях. Написав обработчики этих событий, мы можем как угодно на них реагировать, в том числе и записывать информацию о них в какой-нибудь файл.

Вначале мы создаем объект Шпион указанного класса. Все действия по его настройке осуществляются при загрузке формы:

Прежде всего мы указываем шпиону, что следить нужно только за содержимым папки C:\Дела:

        Шпион.Path = "C:\Дела"

Далее мы объясняем, что нас интересует также содержимое папок, вложенных в папку Дела:



        Шпион.IncludeSubdirectories = True

Далее мы объясняем, что нас интересуют все файлы. Для этого мы настраиваем фильтр аналогично тому, как настраивали фильтр диалогового окна (20.2.2):

        Шпион.Filter = "*.*"

Следующие 4 оператора указывают на обработчиков четырех событий объекта Шпион: Created, Deleted, Renamed, Changed. Рассмотрим обработчики по порядку.

Событие Created генерируется при создании файла или папки. Параметр обработчика e принадлежит к типу FileSystemEventArgs и содержит информацию о событии. Его свойство FullPath  представляет полный адрес и имя созданного файла или папки.

Все 4 обработчика обращаются к процедуре пользователя Дописываем_в_файл, которая оператором Дозапись.WriteLine дописывает в файл Журнал.txt одну строчку. Начинается строчка с указания момента времени, когда наступило событие (DateTime.Now), а заканчивается текстом, задаваемым параметром Строка, формируемым каждым обработчиком.

В обработчике события Changed этот текст такой:

"Создан файл или папка:  " & e.FullPath

Событие Deleted генерируется при уничтожении файла или папки. Организован обработчик аналогично предыдущему.

Событие Renamed генерируется при переименовании файла или папки. Организован обработчик аналогично предыдущим с одним отличием. Параметр обработчика e принадлежит к типу RenamedEventArgs. Его свойство OldFullPath представляет полный старый адрес и имя файла или папки, а свойство FullPath представляет полный новый адрес и имя переименованного файла или папки.

Событие Changed генерируется при различных изменениях в файле или папке, например, когда содержимое файла изменилось. Организован обработчик аналогично обработчику Created.

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

Не забудьте, что шпиону нужно разрешить генерировать события:

        Шпион.EnableRaisingEvents = True

А теперь о секретности работы шпиона. Я добился ее тем, что сделал форму прозрачной и запретил значку формы появляться на панели задач:

        Me.Opacity = 0

        Me.ShowInTaskbar = False


Программный доступ к каждой ячейке таблицы через DataSet


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

Для этого нам нужно кое-что знать о строении объекта DataSet. Я не буду перечислять все свойства и методы класса DataSet. Не буду также останавливаться на типах свойств. Нам пока достаточно знать, что объект DataSet включает коллекцию Tables, состоящую из таблиц типа DataTable, входящих в базу. Каждая таблица из этой коллекции включает в свою очередь коллекцию Columns столбцов (полей) типа DataColumn и коллекцию Rows строк (записей) типа DataRow. Каждая строка к тому же позволяет обращаться к своим полям (ячейкам) по индексу, как к элементам массива. (Если вы подзабыли, что такое коллекции, перечитайте 16.2.)

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

        Debug.WriteLine (DataSet11.Tables ("Книги") .Rows (4)(2))

Этот оператор распечатает название книги Ефремова «Туманность Андромеды».

Пояснения: Выражение

DataSet11.Tables("Книги")

есть объект, представляющий нашу таблицу «Книги». У него есть свойство Rows, являющееся коллекцией строк таблицы. Строки пронумерованы с нуля, поэтому выражение 

DataSet11.Tables("Книги").Rows(4)

есть не что иное, как запись о книге Ефремова «Туманность Андромеды».

Каждая запись – это объект. Отдельные поля записи тоже пронумерованы с нуля, поэтому выражение 

DataSet11.Tables("Книги").Rows(4)(2)

есть не что иное, как название

книги Ефремова «Туманность Андромеды».

Значения ячеек таблицы можно менять банальным присваиванием. Оператор

        DataSet11.Tables ("Книги") .Rows (1)(4)= 208

устанавливает книге Конан Дойля «Затерянный мир» число страниц равное 208.

Экономим чернила. VB допускает и сокращенный синтаксис. Так, когда вы поставите точку после имени нашего объекта DataSet11, вы увидите в раскрывшемся списке готовенькое и удобное для нас свойство Книги, имеющее своим значением нашу таблицу «Книги». Открыв скобку после слова Книги, мы увидим приглашение ввести индекс – номер строки из этой таблицы. В результате вместо длинного


Обратите внимание, что для только-что описанного способа работы с ячейками таблицы нам совершенно не нужно было иметь на форме элемент DataGrid. Вся работа велась через DataSet. То есть, описанный способ хорош для работы вслепую, когда умный компьютер без нашего ведома делает свои дела с базой данных. Однако часто мы хотим совмещать ручной и программный способы работы, наблюдая базу данных воочию или даже вводя в нее изменения от руки. В этом случае наличие DataGrid очень удобно.

Имейте в виду, что порядок строк в DataGrid и DataSet неодинаков. Как только вы посортируете записи в DataGrid щелчками по заголовкам полей, их порядок в сетке DataGrid, естественно, переменится. А вот в DataSet он останется прежним. Вам вполне может захотеться работать именно с ячейками DataGrid, а не DataSet. Например, заполнить список или массив из отсортированного поля из DataGrid вам может показаться приятнее, чем из того же неотсортированного поля из DataSet. Для этого вам нужен доступ к ячейкам DataGrid.

Я не буду останавливаться на многочисленных и полезных свойствах и методах DataGrid. Здесь я воспользуюсь только свойством Item, о котором удобно думать, как  о двумерном массиве ячеек DataGrid. Вот примеры:

        Debug.WriteLine(DataGrid1.Item(4, 2))

        DataGrid1.Item(5, 3) = #12/30/1831#

Если вы еще не успели отсортировать сетку, то первый оператор напечатает «Туманность Андромеды», а второй установит книге Гоголя «Сорочинская ярмарка» дату 30.12.1831.

Примечание: Вы только что программным методом установили значение #12/30/1831# в ячейке DataGrid. Автоматически оно изменилось и в DataSet. Однако, возьмите на заметку, что довести эти изменения до исходного файла базы данных у вас так просто не получится. Проще программно менять значения ячеек непосредственно в DataSet, как мы делали раньше.

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

        For i = 0 To DataSet11.Книги.Rows.Count - 1

            ListBox1.Items.Add(DataGrid1.Item(i, 2))

        Next

Пояснения: Число 2 – это номер столбца с названиями книг. Выражение DataSet11.Книги.Rows.Count – это количество (Count) строк (Rows) в таблице DataSet11.Книги.

Впрочем, вы можете настроить заполнение ListBox еще на этапе проектирования, зайдя в окно свойств и выбрав для его свойства DataSource значение DataSet11.Книги, а для свойства DisplayMember значение Nazvanie.




DataSet11.Tables("Книги").Rows(4)(2)

получим короткое

DataSet11.

Книги (4)(2)

К полям записи можно обращаться и по имени поля. Выражение

DataSet11.Книги (4) ("Nazvanie")

тождественно предыдущему.

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

Dim D As DataRowCollection

Затем выполните оператор

        D = DataSet11.Книги.Rows

присваивающий этой переменной значение коллекции строк из конкретной таблицы Книги.

Теперь к этой коллекции вы можете обращаться и при помощи переменной D, например, так:

        D (2)(4) = 500

Вот фрагмент, распечатывающий всю нашу таблицу:

        Dim i, j As Integer

        For i = 0 To 5

            For j = 0 To 4

                Debug.WriteLine (D(i)(j))

            Next

        Next

Вот фрагмент, делающий то же по-другому:

        Dim j As Integer

        Dim Запись As DataRow

        For Each Запись In D

            For j = 0 To 4

                Debug.WriteLine(Запись(j))

            Next

        Next    

Задание 20.        

Увеличьте на 2 число страниц в каждой книге из таблицы.


Простейший текстовый редактор


Создадим простейший текстовый редактор. Для этого разместим на форме текстовое поле, две кнопки и элементы управления SaveFileDialog и OpenFileDialog. Текстовое поле сделаем многострочным и снабдим его вертикальной полосой прокрутки (см. 3.4.2). В работе наш проект должен выглядеть так, как на Рис. 20.2.

Рис. 20.2

В текстовое поле мы вводим произвольный текст, затем нажатием на кнопку Сохранить помещаем на экран диалоговое окно сохранения файла, после чего обычным образом выбираем в нем произвольный текстовый файл (с расширением txt) из уже существующих или вводим обычным образом в диалоговое окно имя нового текстового файла и весь текст из текстового поля записываем в него.

Аналогично нажатием на кнопку Открыть помещаем на экран диалоговое окно открытия файла, затем обычным образом выбираем в нем произвольный текстовый файл (с расширением txt) и весь текст из него открываем в текстовом поле. После чего редактируем текст и снова сохраняем.

Вот программа:

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

        SaveFileDialog1.ShowDialog()                                        'Показать диалоговое окно сохранения файла

        Dim Файл As String = SaveFileDialog1.FileName           'Это имя файла выбрано из диалогового окна

        Dim Запись As New System.IO.StreamWriter(Файл)        'Открываем выбранный файл для записи

        'Запись всего текста из текстового поля  в выбранный файл:

        Запись.Write(TextBox1.Text)

        Запись.Close()                                                                'Закрываем файл

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        OpenFileDialog1.ShowDialog()                                        'Показать диалоговое окно открытия файла

        Dim Файл As String = OpenFileDialog1.FileName          'Это имя файла выбрано из диалогового окна

        Dim Чтение As New System.IO.StreamReader(Файл)     'Открываем выбранный файл для чтения


        ' Считывание всего текста из выбранного файла в текстовое поле:

        TextBox1.Text = Чтение.ReadToEnd

        Чтение.Close()                                                               'Закрываем файл

End Sub

Пояснения: На операторе

        SaveFileDialog1.ShowDialog()                                        'Показать диалоговое окно сохранения файла

появляется диалоговое окно сохранения файла, программа останавливается и ждет. Мы выбираем в окне какой-нибудь текстовый файл или вводим в поле окна File name имя нового текстового файла и нажимаем на кнопку Save диалогового окна. После нажатия окно пропадает, имя файла из окна File name вместе с адресом этого файла на диске становится значением свойства FileName объекта SaveFileDialog1 и программа продолжает работу.

Мы привыкли, что в приложениях Windows, таких как, скажем, Word или Paint, после нажатия на кнопку Save файл сохраняется сам собой, безо всяких хлопот с нашей стороны. В VB же, конечно, ничего подобного нет. Чтобы сохранить файл, нужно приложить небольшие усилия:

Следующим оператором

        Dim Файл As String = SaveFileDialog1.FileName            'Это имя файла выбрано из диалогового окна

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

Свойство Text текстового поля рассматривается как одна длинная строка, поэтому оператор

        Запись.Write(TextBox1.Text)

записывает все содержимое текстового поля, включая невидимые символы возврата каретки, в файл. Вот теперь файл сохранен.

Аналогично работает окно открытия файла. При нажатии кнопки Открыть появляется диалоговое окно открытия файла, программа останавливается и ждет. Мы выбираем в окне какой-нибудь текстовый файл и нажимаем на кнопку Open диалогового окна. После нажатия окно пропадает, имя файла из окна File name вместе с адресом этого файла на диске становится значением свойства FileName объекта OpenFileDialog1 и программа продолжает работу.

Мы привыкли, что в приложениях Windows после нажатия на кнопку Open открываемый файл становится безо всяких хлопот с нашей стороны виден нам в каком-нибудь окне. В VB этого нет. Чтобы увидеть файл, нужно постараться. В нашем случае оператор

        TextBox1.Text = Чтение.ReadToEnd

считывает в текстовое поле как единую строку все содержимое файла, включая невидимые символы возврата каретки. На Рис. 20.2 вы видите проект сразу же после открытия файла. Вот теперь мы файл увидели.

Что делать, если вы нажали на кнопку Cancel или на крестик в правом верхнем углу окна, написано в следующем подразделе.

Итак, наш текстовый редактор работает.


Пространства имен


Начнем с самых крупных единиц кода – с пространств имен. До сих пор пространства имен были для нас вместилищем классов из библиотеки классов .NET Framework и не имели никакого отношения к коду и структуре нашего проекта. Правда, заглядывая в Object Browser, мы привыкли видеть там сборку нашего проекта и в ней – пространство имен нашего проекта. Для чего они нужны, было непонятно. Вникнем.

Оказывается, мы можем разделить проект на несколько

пространств имен. Сначала рассмотрим, как это сделать, а потом – зачем.

Создайте проект библиотеки классов, как мы это делали в 25.2Назовите его Сборка. Введите в окно кода такой код:

Public Class КлассНоль

    Public Shared Sub ПроцНоль()

        MsgBox("Сработала процедура Ноль класса Ноль из  пространства имен Сборка ")

    End Sub

End Class

Namespace Пространство1

    Public Class Класс1

        Public Shared Sub Проц1()

            MsgBox("Сработала процедура 1 класса 1 из 1 пространства имен ")

        End Sub

    End Class

    Public Module Модуль1

        Public Sub Проц2()

            MsgBox("Сработала процедура 2 модуля 1 из 1 пространства имен ")

        End Sub

    End Module

End Namespace

Namespace Пространство2

    Public Class Класс1

        Public Shared Sub Проц1()

            MsgBox("Сработала процедура 1 класса 1 из 2 пространства имен ")

        End Sub

    End Class

    Public Module Модуль2

        Public Sub Проц2()

            MsgBox("Сработала процедура 2 модуля 2 из 2 пространства имен ")

        End Sub

    End Module

End Namespace

Откомпилируйте его.

Создайте обычный проект приложения Windows. Назовите его Проект. Сделайте в нем ссылку на библиотеку классов Сборка.dll. Поместите на форму кнопку. Введите в окно кода формы такой код:

Public Class Form1

    Inherits System.Windows.Forms.Form

Windows Form Designer generated code

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click


        Сборка.КлассНоль.ПроцНоль()

        Сборка.Пространство1.Класс1.Проц1()

        Сборка.Пространство1.Модуль1.Проц2()

        Сборка.Пространство2.Класс1.Проц1()

        Сборка.Пространство2.Проц2()

        Пространство3.Класс3.Проц3()

        Проект.Пространство3.Класс3.Проц3()

    End Sub

End Class

Namespace Пространство3

    Public Class Класс3

        Public Shared Sub Проц3()

            MsgBox("Сработала процедура 3 класса 3 из 3 пространства имен ")

        End Sub

    End Class

    Public Module Модуль1

        Public Sub Проц2()

            MsgBox("Сработала процедура 2 модуля 1 из 3 пространства имен ")

        End Sub

    End Module

End Namespace

Загляните в Object Browser. Вы видите в нем несколько сборок библиотеки классов .NET Framework и две сборки наших проектов: Проект и Сборка. Разверните в нем Проект и Сборку, как показано на Рис. 27.1.



Рис. 27.1

Пояснения: В Object Browser вы видите, что каждый наш проект представляет собой одновременно и пространство имен. У нас это пространства имен {}Проект и {}Сборка.   В этом есть логика. Действительно, в Object Browser представлены пространства имен, чьи классы, модули и другие компоненты мы можем с пользой для дела использовать в проекте. Все полезное находится в пространствах имен. Какая разница, откуда это полезное взято: из библиотеки классов .NET Framework или из наших проектов Проект и Сборка? А раз так, пусть наши проекты тоже будут пространствами имен, которые соседствуют в Object Browser со стандартными пространствами имен библиотеки классов .NET Framework.

Пространства имен Проект и Сборка порождаются автоматически, без нашего участия.  Теперь посмотрим на пространства имен, входящие в упомянутые два пространства. На рисунке мы видим, что внутрь пространства имен Проект входят класс Form1 и пространство имен Пространство3 со своими классом и модулем, а внутрь пространства имен Сборка входят класс КлассНоль и два пространства имен: Пространство1 и Пространство2, каждое со своим классом и модулем.



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

Namespace …………

End Namespace

Теперь, если между этими строками мы напишем классы, модули и другие компоненты, то они будут нормально существовать, но при этом уже не просто сами по себе, а как принадлежащие пространству имен.

Класс КлассНоль записан вне созданных нами пространств имен, но он все равно входит в пространство имен Сборка, так как все, что написано в окнах кода какого-нибудь проекта, автоматически входит в пространство имен этого проекта. Аналогично класс Form1 входит в пространство имен Проект.

Чтобы получить пространства имен В и С, входящие внутрь пространства имен А, запишите так:

Namespace А

        Namespace В

        End Namespace

        Namespace С

        End Namespace

End Namespace

Смысл пространств имен. Среди огромного количества классов, модулей и других компонентов библиотеки классов .NET Framework наверняка есть «тезки». Чтобы их не перепутать, «тезок» «рассовали» по разным пространствам имен. Вот половина ответа.

Вот другая половина. Предположим, вы создаете проект библиотеки из нескольких десятков классов, в которой встречаются классы, посвященные музыке, и классы, посвященные графике. У вас может встретиться класс TransFormat, посвященный преобразованию формата звуковых файлов, и класс с тем же именем TransFormat, посвященный преобразованию формата графических файлов. Но тезки в пределах одного пространства имен недопустимы, поэтому вам придется один из этих классов переименовывать, чего вам делать не хочется. Удобная и изящная альтернатива: организовать пространство имен Music и пространство имен Графика, а затем «распихать» классы между этими пространствами.

Обратите внимание, что и в нашем примере в пространствах имен 1 и 2 есть одноименные классы, которые без них конфликтовали бы. А вот организовывать пространство имен 3, оказывается, не было никакой нужды, так как его модуль 1 все равно находился бы в другом пространстве имен, чем его тезка из пространства имен 1.


Проводник


Находясь в Windows, вы можете в любой момент посмотреть структуру папок и файлов любого диска вашего компьютера. Сделать это можно по-разному. Фирма Microsoft рекомендует для этого (и многого другого) использовать Проводник – стандартную программу, входящую в состав Windows. Чтобы ее запустить, выберите в стартовом меню Windows пункт «Программы» или «Все программы», в нем – «Стандартные», а в нем – пункт «Проводник». На Рис. П5 вы видите в работе окно проводника, в котором отображена часть папок жесткого диска.

Рис. П5

Окно проводника разбито на две панели - левую и правую. Разберемся в левой панели.

Отвлечемся пока от белых квадратиков с плюсами и минусами. Желтые прямоугольные значки (

) - это обозначения папок на диске. По взаимному расположению папок можно понять, внутрь какой папки входит данная папка – это первая из вышерасположенных папок, которая находится левее данной. Например, папка «Переписка с Васей» находится внутри папки «Личная переписка», а та – внутри папки «Переписка». Помогают понять структуру папок и линии, выходящие из данной папки и идущие вниз – потом направо – в папки, находящиеся внутри нее. В совокупности эти линии образуют лежащее дерево: ствол – слева, самые тоненькие ветки – справа. Правда, в Windows XP этих линий уже нет.

Если папка содержит внутри себя хотя бы одну папку, слева от нее вы видите квадратик с плюсом или минусом. Щелчком по квадратику вы можете менять плюс на минус и наоборот. Поменяв минус на плюс, вы скрываете из вида папки, находящиеся внутри данной (хотя бы для того, чтобы не утомлять глаза). Поменяв минус на плюс, вы снова их показываете.

Если вы щелкнете в левой панели по значку папки, а не по квадратику, имя папки потемнеет, а ее содержимое вы увидите в правой панели. У нас в правой панели вы видите два файла из папки  «Переписка с Асей». Файлы обозначаются значками самой разной формы, но всегда отличающейся от формы папок. В левой панели файлы не видны, видны только папки.

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

Кроме просмотра папок проводник позволяет делать массу других вещей. Часть из них (например, копирование, перемещение, создание, удаление и переименование файлов и папок) вы можете проделать с помощью правой клавиши мыши примерно так, как это описано в следующем подразделе.



Работа с базами данных в Microsoft Access


В Access мы не будем программировать, все будем делать вручную.

Выйдите из VS. В этом разделе он вам не нужен. Находясь в Windows, запустите Microsoft Access.



Работа с базами данных в проекте


Предыдущие разделы были подготовительными. Только в этом разделе мы научимся использовать базы данных в наших проектах.



Работа с CheckedListBox 


Разместим на форме CheckedListBox (его внешний вид показан на Рис. 18.12) и кнопку. Свойства, события и методы, рассмотренные в предыдущем подразделе, относятся также и к списку с флажками. Однако их недостаточно, чтобы что-нибудь делать сразу со всеми элементами, на которых установлены флажки. Посмотрим, как с ними работать.

Основой списка с флажками являются три коллекции:

Коллекция Items, состоящая, как и у остальных списков, изо всех элементов списка.

Коллекция CheckedItems, состоящая из элементов списка, помеченных флажками.

Коллекция CheckedIndices, состоящая из номеров (в коллекции Items) тех элементов списка, которые помечены флажками.

Для иллюстрации сказанного создадим процедуру:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Debug.WriteLine(CheckedListBox1.Items(2))                       '3-й элемент списка (его номер = 2)

        Debug.WriteLine(CheckedListBox1.CheckedItems(2))        '3-й помеченный флажком элемент списка

        Debug.WriteLine(CheckedListBox1.CheckedIndices(2))     'Номер 3-го помеч-го флажком элемента списка

        'Правда ли, что элемент списка номер 2 помечен флажком:

        Debug.WriteLine(CheckedListBox1.GetItemChecked(2))

End Sub

Запустим проект. Расставим флажки так, как на Рис. 18.12. Щелкнем по кнопке. Вот что будет напечатано:

ЦСКА

Локомотив

4

False

Не забывайте, что нумерация в коллекциях, принадлежащих спискам, идет с нуля, а не с 1.

Не кажется ли вам, что список с флажками делает то же самое, что и простой набор флажков в рамке? В общем – да. Но когда список большой, CheckedListBox гораздо удобнее и компактнее. Ведь он может уместить десятки элементов, не занимая много места на форме. А удобство программирования вы оцените, увидев как элементарно решается Задание 126, когда вместо обычных флажков используется список с флажками. Вот вам это новое задание:

Задание 5.    

Выполните Задание 126 «Виртуальный ресторан» с использованием CheckedListBox. То есть при нажатии на кнопку «Заказать» проект должен печатать в окне Output список помеченных флажками в CheckedListBox блюд. Указание: Основное преимущество программы, которая у вас получится – вам не придется создавать коллекцию. Она в готовом виде уже существует.



Работа с файлами


Если вы играли в компьютерные игры или создавали текстовые документы или рисунки, то наверняка сохраняли свою игру, документ или рисунок. А задумывались ли вы над тем, что значит сохранить что-то? Данный раздел учит нас программировать сохранение информации в компьютере.



Работа с несколькими строками


Ваша задача – ввести такой текст из нескольких строк:

В небе

Облака из серой ваты

Сыровато-сероваты,

Не беда - ведь я привык.

В луже

Эта вата намокает

И волнуясь пробегает

Под водою мой двойник.

Нужную реакцию на могущие возникнуть неожиданности вы можете найти в дальнейшем материале вплоть до конца этого подраздела. А пока начнем по порядку.

Ввод нескольких строк. Как сделать так, чтобы, введя слова «В небе», следующие слова начать с новой строки? Для этого нужно нажать клавишу Enter, по-другому Return, по-другому «Клавиша ввода». Курсор перепрыгивает в начало следующей строки. Введя вторую строку, снова нажатием на Enter перейдите в начало следующей и так далее.

А теперь введите все восемь строк задания.

Перемещение курсора по экрану. При помощи четырех клавиш перемещения курсора  ¬  ®  ­  ¯

 

потренируйтесь перемещать курсор куда только можно. Вы скоро обнаружите, что курсор можно свободно перемещать только там, где имеется текст. Ни правее, ни ниже введенного текста курсор переместить не удается. Поначалу вам это может показаться непривычным и неприятным, и вы захотите расширить поле действия курсора. Удовлетворить вашу прихоть довольно легко.

Подведя курсор в правый край самой нижней строки, нажмите на клавишу ввода несколько раз. У вас ниже текста образовалось несколько невидимых пустых строк, по которым вверх-вниз может свободно ходить курсор.

Подведя курсор в правый край любой строки, нажмите несколько раз на клавишу пробела. У вас правее текста образовалось несколько невидимых пробелов, по которым влево-вправо может свободно ходить курсор.

Я назвал это прихотью, так как при вводе текста это никогда не бывает нужно. Но то, что вы сейчас проделали, вам полезно для свободной ориентации на листе.

Собственно работа с несколькими строками. А теперь вам полезно выполнить несколько заданий.

Чтобы вставить пустые строки между строчкой «Не беда - ведь я привык.»  и строчкой  «В луже», поставьте курсор в конец первой из этих строк или в начало второй и несколько раз нажмите клавишу ввода.


А как теперь убрать эти пустые строки? Поставьте курсор в начало самой верхней из пустых строк и несколько раз нажмите Delete.

Как разделить строку на две части? Например, вместо «Не беда - ведь я привык.» нужно получить

Не беда -

ведь я привык.

Поставьте курсор перед буквой "в" и нажмите клавишу ввода.

А как слить эти две строки? Поставьте курсор в правый конец верхней из этих строк и нажмите Delete один или несколько раз, пока строки не сольются.

Невидимые символы. Все эти правила могут показаться запутанными и не имеющими внутренней логики. А логика есть. И если вы ее поймете, то и правил запоминать не нужно. Вот она:

Нажатие на клавишу ввода вызывает появление на экране в том месте, где был перед нажатием курсор, специального невидимого символа, точно так же, как нажатие на клавишу пробела вызывает появление невидимого символа – пустого места. Обозначим для удобства символ клавиши ввода – p. Только если пробел имеет хоть какую-то ширину в строке, то символ p и ширины не имеет.

Рассмотрим с новой точки зрения действие различных клавиш:

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

Нажатие на клавишу ввода вызывает перемещение вниз на одну строку всего текста, находящегося правее и ниже курсора, причем правая часть текста в строке, где был курсор, перемещается в начало следующей строки. Отсюда видно, что в текстовом редакторе VS строка обязательно кончается символом p. Это не относится к тем текстовым редакторам (Word), которые переводят строку автоматически. Также ясно, что кроме как в конце строки, символ p нигде встречаться не может.

Клавиша Delete стирает любой символ справа от курсора, будь то буква, пробел или p.  Стирание символа уничтожает не только сам символ, но и его действие. Поэтому, стерев p, мы выполняем действие, обратное действию клавиши ввода, то есть нижние строки поднимаются, а ближайшая нижняя сливается с текущей.

Аналогично действует клавиша BackSpace.

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

Впечатление такое, что имеется большой неподвижный лист с текстом, а окно кода является небольшим подвижным окном, через которое вы можете видеть этот лист. Движением окна можно управлять клавишами перемещения курсора или щелкая мышкой по кнопкам полос прокрутки, которые возникают у правого и нижнего края окна кода. Можно также таскать бегунки полос прокрутки.


Работа с одной строкой текста


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

Ввод строки. Пусть мы хотим ввести строчку «юный пионер Коля любит Bubble Gum». Первая клавиша, по которой мы должны щелкнуть, – русская буква «ю». Но где буква появится на экране? – В том месте, где сейчас мигает текстовый курсор – маленькая вертикальная черточка. А в начале работы редактора он должен мигать в левом верхнем углу пустого окна (вы видите его на рисунке). Если не мигает, щелкните мышкой по окну редактора.

Не путайте текстовый курсор с мышиным. Мышиный свободно перемещается по экрану вслед за движениями мыши по коврику и не мигает, у текстового такой свободы нет и он мигает.

Итак, щелкаем по клавише «ю» –  и на экране на месте текстового курсора возникает буква «ю», а сам текстовый курсор перемещается чуть вправо Если у вас получилась не буква «ю», а точка, значит прочитайте чуть ниже про английские и русские буквы. Если буква получилась заглавной, почитайте про заглавные буквы. Вот какая получается картина – «ю|». По клавише именно щелкаем, «клюем» ее, а не нажимаем, потому что компьютер настроен так, что если мы задерживаем палец на клавише дольше некоторой доли секунды, он считает, что нажатий было не одно, а два, еще подольше – три, и так далее, а это значит, что на экране мы увидим «ююююююююю|». Поэтому в дальнейшем изложении, когда я говорю «Нажмите клавишу», я буду иметь в виду «Щелкните по клавише».

Где бы текстовый курсор ни находился, следующая буква возникает на его месте. Получив на экране «ю», щелкнем по «н». На экране видим «юн|». И так далее, пока на экране мы не получим «юный|».

Если мы в процессе работы случайно ввели что-нибудь не то, то щелкнем один или несколько раз по клавише BackSpace. Эта клавиша находится над центральной клавишей Enter и имеет еще маркировку BS или  ï.  Она стирает последнюю введенную букву.


После ввода слова «юный» нужно ввести пробел  перед следующим словом. Для этого щелкните по самой длинной горизонтальной клавише. Затем аналогично введите слово «пионер» и пробел.

Заглавные буквы. До сих пор у вас все буквы получались строчными. Говорят, что вы работали в нижнем регистре. Чтобы буква «к» в слове «Коля» получилась заглавной, нужно нажать на клавишу Shift и держать ее нажатой. Смело держите ее нажатой сколько угодно – ничего плохого от этого не произойдет. Затем, удерживая ее нажатой, щелкните по букве «к» – она получится заглавной. Если вы щелкнете и по другим буквам, они тоже получатся заглавными. Говорят, что вы работаете в верхнем регистре. Теперь отпустите Shift. Можно работать дальше со строчными буквами. Часто клавиша Shift имеет маркировку ñ.

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

Английские и русские буквы. Вот вы дошли до английских слов «Bubble Gum». Как их набрать? Вы уже заметили, что на большинстве клавиш букв две – сверху английская (латинская), снизу русская. Предположим, до сих пор у вас при нажатии на клавишу всегда выходила русская буква. Говорят, что вы работали в русском регистре. Если вы нажмете на пару служебных клавиш, то теперь при нажатии на любую буквенную клавишу у вас будут получаться английские буквы, пока вы снова не нажмете на эти самые служебные клавиши, чтобы вернуться к русским буквам. Вот эти клавиши:

Левая Alt - Shift

На клавиатуре находятся две клавиши Alt. Имеется в виду, что удерживая нажатой левую из них, вам нужно щелкнуть по одной из клавиш Shift.

Ctrl - Shift

Удерживая нажатой клавишу Ctrl, вам нужно щелкнуть по клавише Shift.

Если вдруг эти клавиши не подействуют, то найдите в правой части панели задач индикатор с обозначением En



или Ru и щелкните по нему, после чего в открывшемся меню выберите мышкой нужный язык.

Знаки препинания. Вы набрали все предложение. Теперь вам самое время поставить точку, а мне поговорить о знаках препинания и других полезных символах. Над буквами вы увидите горизонтальный ряд клавиш с цифрами от 0 до 9. На эти же клавиши нанесены и многие символы. Вы их сможете получить при нажатой клавише Shift. Если кроме цифры на клавишу нанесены два значка, то левый из них получается при работе в английском регистре, а правый – в русском. Кроме этого, работая в английском регистре, вы можете получить остальные нужные символы на русских буквах  Х, Ъ, Ж, Э, Б, Ю и еще на паре клавиш. Работая в русском регистре, удобно точку и запятую получать на клавише со знаком вопроса рядом с правой клавишей Shift, причем запятая получится при нажатой клавише Shift. Можно также воспользоваться для этого клавишами Б и Ю при нажатой клавише Alt.

Удаление букв из текста. Вот вы напечатали всю строку «юный пионер Коля любит Bubble Gum.». Теперь попробуем удалить слово «пионер». Для этого нам нужно уметь перемещать курсор. Для перемещения курсора служат клавиши перемещения курсора – четыре клавиши внизу клавиатуры: ¬  ®  ­  ¯. Попробуйте, как они работают. Особой свободы вы не почувствуете. Текстовый курсор передвигается только в пределах введенного текста.

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

Поставьте текстовый курсор на пробел между словом «пионер» и словом «Коля» вплотную к букве «р». Мы уже начинаем привыкать, что если нажать какую-нибудь клавишу, то что-то произойдет именно в том месте, где находится текстовый курсор. Чтобы стереть по очереди все буквы слова «пионер», несколько раз нажмите на клавишу BackSpace. Обратите внимание, что буквы слова «пионер» слева от курсора исчезают по одной, текст справа от курсора смыкается налево, так что пустого пространства на месте слова «пионер» не остается. У вас должно получиться «юный Коля любит Bubble Gum.».



Для стирания символов существует еще одна клавиша – Delete. Иногда она имеет маркировку Del. Давайте сотрем слово «любит». Поставим курсор на пробел между словом «Коля» и словом «любит». Нажмем несколько раз на Delete. Слово «любит» стерлось, а текст справа от курсора снова сомкнулся налево.

Таким образом, клавиша BackSpace стирает символ слева от курсора а клавиша Delete – справа. В обоих случаях текст справа от курсора смыкается налево к курсору.

Вставка букв в текст. Теперь у нас на экране строка «юный Коля Bubble Gum.». Давайте вставим перед словом «Коля» слово «бойскаут». Для этого поставим курсор на пробел перед словом «Коля» вплотную к букве «К». После этого напечатаем слово «бойскаут» и пробел. Мы увидим, что буквы слова «бойскаут» появляются на месте курсора, «Коля» вместе с  «Bubble Gum» подвинулись направо и мы достигли поставленной цели. Теперь у нас на экране строка «юный бойскаут Коля Bubble Gum.».

Этот способ работы текстового редактора, когда вставляемый текст отодвигает вправо остальной текст, называется режимом вставки. Если вы щелкнете по клавише Insert, иногда маркируемую Ins, то перейдете в режим замещения, когда текст не будет отодвигаться, а «бойскаут» сотрет «Колю». В этом режиме курсор увеличивает свою толщину и имеет вид черного прямоугольничка, целиком покрывающего букву, которой предстоит быть замещенной. Чтобы вернуться в режим вставки, еще раз нажмите на Insert.

А теперь вставьте в подходящее место предложения слово «ненавидит» и сделайте заглавной букву «ю» в слове «юный».


Работа с окнами Windows


Когда вы работаете в Windows, VS или других приложениях Windows, все, что вы видите на экране, вы видите в окнах. Не зря же слово Windows переводится с английского, как «окна». Окно имеет вид прямоугольника в тоненькой рамочке, внутри которого находится нужная вам информация. Окна – весьма удобная вещь и работа с ними ведется так же естественно, как с документами на рабочем столе.

Для дальнейшей работы вам понадобится на рабочем столе значок «Мой компьютер». Если его там нет, найдите «Мой компьютер» в стартовом меню и перетащите его мышкой оттуда на рабочий стол. Как «тащить», написано ниже.

Открытие окон из значков. Значки (пиктограммы, иконки) – это, упрощенно говоря, закрытые окна. Чтобы их открыть, нужно проделать одно из трех действий (для примера попробуйте открыть окно из значка «Мой компьютер»):

Поставьте острие стрелки мышиного курсора (в дальнейшем я просто буду говорить «Поставьте мышку») на значок. (Только не на название под значком, а на сам значок.)  Теперь, держа мышь совершенно неподвижно (как прибитую к коврику!), сделайте двойной щелчок, то есть, щелкнув пальцем по левой клавише совершенно неподвижной мыши, тут же, через какую-то долю секунды, не сдвинув мышь ни на йоту, щелкните еще раз. Окно откроется. У начинающего с первого раза двойной щелчок не получится ни за что. Этот способ самый быстрый, но требует тренировки, поэтому для начала предлагаю два других способа, полегче. Впрочем, ваша Windows может быть настроена на одинарные, а не на двойные щелчки, тогда вам в данном случае достаточно будет сделать одинарный щелчок.

Держа мышь неподвижно, щелкните мышкой по значку (не по названию под значком, а по самому значку). Если щелкнули успешно, значок должен потемнеть. Теперь нажмите на клавиатуре клавишу Enter. Окно откроется.

Держа мышь неподвижно, щелкните по значку правой клавишей мыши. Правая клавиша мыши – очень удобная клавиша. Это «палочка-выручалочка». Если вы хотите что-нибудь сделать со значком или с каким-нибудь другим объектом на экране, но забыли, на какие кнопки нужно при этом нажимать, и даже не уверены что именно хотите сделать, щелкните по этому объекту правой клавишей мыши – из объекта выскочит так называемое контекстное меню – список самых популярных действий, которые можно проделать с этим объектом. Вам остается только щелкнуть мышкой по нужному. В нашем случае выбирайте пункт Open (открыть). Окно откроется. Новички! Будьте осторожны. Не выбирайте Cut (вырезать) или Delete (удалить).


Что такое окно. Итак, окно – это прямоугольная рамочка, внутри которой видна та или иная информация, будь то текст, картинка, видео, содержимое папки, игра или наша VS. Когда вы открываете значок папки, то открывается окно с содержимым этой папки. Когда вы открываете значок файла, то открывается окно с программой, тип которой определяется типом файла. Так, если ваш файл – это текстовый документ, то открывается окно с программой Блокнот, показывающей в окне содержание этого документа. Если ваш файл – запускающий файл какой-нибудь программы, то открыть этот файл – значит запустить программу. Так, файл Cat.exe запускает игру «Кошки». (О том, что такое файл и папка, смотрите ниже).

Давайте для примера откроем окно Корзины, щелкнув как положено по значку «Корзина» на рабочем столе (см. Рис. П4). Корзина содержит выброшенные вами ненужные папки и файлы.



Рис. П4

Что можно делать с окном. Посмотрим, что можно делать с окном. Прежде всего, окно можно мышкой перемещать («таскать») по экрану. Для этого нужно поместить острие мышиного курсора на полосу заголовка окна, нажать левую клавишу мыши и, не отпуская ее, перемещать курсор по экрану (это называется «тащить»

мышь). Окно «потащится» за мышью.

Вы можете изменять размеры окна, перетаскивая мышью его границы. Для этого нужно поместить острие мышиного курсора точно на одну из четырех границ окна. В этом случае курсор приобретет форму двойной стрелки (-). В этот момент начинайте тащить мышь. Граница «потащится» за мышью. Удобно таскать и углы окон.

Три кнопки. В правом верхнем углу окна имеются три кнопки. Щелкните по кнопке «Закрыть» в виде крестика. Окно исчезнет с экрана. Для того, чтобы снова его открыть, нужно будет снова щелкать по его значку.

Щелкните по кнопке «Свернуть». Окно свернется, то есть уйдет с экрана на панель задач, где будет существовать в виде прямоугольного значка. Достаточно одинарного (не двойного) щелчка по этому значку на панели задач, чтобы окно снова развернулось. Обратите внимание, что значок на панели задач при этом не исчезнет. Пощелкайте по нему.



Щелкните по средней из трех кнопок – кнопке «Максимизировать», которая имеет вид квадратика. Окно развернется на весь экран. Обратите внимание, что средняя кнопка теперь изменила вид, она стала такой –
. Щелкнем по ней. Окно уменьшилось до прежних размеров.

Работа с несколькими окнами. Когда на тесном экране располагаются несколько окон, они загораживают друг друга и мешают друг другу. Откройте, например, два окна щелчками по значкам «Мой компьютер» и «Корзина». Увеличьте в размерах окно «Корзина» и надвиньте его на окно «Мой компьютер» так, чтобы оно полностью его загородило. Как теперь добраться до окна «Мой компьютер»? Очень просто. У каждого окна есть свой значок на панели задач. И быстрее всего – щелкнуть по значку «Мой компьютер» на панели задач.

Мой совет: Когда на рабочем столе много окон, переключайтесь между ними щелчками по их значкам на панели задач. Закрывать окно также удобно, щелкнув правой клавишей мыши по его значку на панели задач и выбрав Close (закрыть).


Работа в окне конструктора запросов Заполняем таблицу данными


Итак, соединение установлено и мы видим структуру базы данных. Но пока мы не видим самих данных и не можем с ними работать. Чтобы иметь возможность работать с данными таблицы Книги, щелкните правой клавишей мыши по значку таблицы Книги и в контекстном меню выберите Retrieve Data from Table (получить данные из таблицы). В среду VS будет загружено окно конструктора запросов (Query and View Designer), в котором вы увидите таблицу «Книги» (пустую, так как мы ее еще не заполняли). Заполните ее вручную данными примерно так же, как вы это делали в Access, после чего окно конструктора запросов будет выглядеть как на Рис. 24.16.

Рис. 24.16

По мере ввода данных они будут сохраняться в файле базы данных.

Поле Код будет заполняться автоматически и VB не даст вам менять числа в этом поле, причем при попытке изменения будет реагировать не очень дружественно, так что вам придется даже закрывать окно конструктора.

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



Работа в панели Grid Pane Выполняем запросы


Итак, вы находитесь в окне конструктора запросов. Выполните View ® Toolbars ® Query.  На экране появится панель инструментов Query (запрос) (Рис. 24.17).

Рис. 24.17

Она поможет нам выполнять основные операции с запросами.

Три панели. Щелкните по кнопкам Show Grid Pane

 (показать панель конструктора) и Show SQL Pane
 (показать панель SQL). Теперь окно конструктора выглядит, как на Рис. 24.18.

Рис. 24.18

Оно состоит теперь из трех панелей, разделенных двумя серыми горизонтальными границами, которые можно передвигать мышкой. Нижняя панель нам знакома, мы в ней заполняли таблицу, она называется Results Pane

 (панель результатов). Верхняя панель в виде пустой сетки – это Grid Pane. Между ними – в виде пары строк текста (SELECT …) находится SQL Pane.

При помощи любой из двух верхних панелей мы будем делать запросы, а в панели результатов будем наблюдать результаты запроса.

Создаем запрос при помощи Grid Pane. Щелкая мышкой по ячейкам сетки Grid Pane, выберите из возникающих списков или введите вручную информацию, которую вы видите на Рис. 24.19 (пояснения приведены чуть ниже). Обратите внимание, что при этом автоматически меняется информация на панели SQL Pane. Затем щелкните на панели запросов кнопку

 – Выполнить запрос. Панель результатов принимает тот вид, что вы видите на Рис. 24.19.

Рис. 24.19

Пояснения. Что мы сделали? В Grid Pane мы сконструировали запрос, а в Results Pane наблюдали результаты запроса. Обратите внимание, что панель Grid Pane – это тот же конструктор запросов Access с Рис. 24.11, только положенный набок. Правда, у Grid Pane возможностей побольше. Итак, вот что мы сделали:

В столбце Column мы выбрали поля, которые хотим видеть в запросе.

В столбце Alias (псевдоним) мы написали названия некоторых полей по-русски, как хотим видеть их в запросе. При наличии пробелов псевдоним берется в квадратные скобки.

В столбце Table указывается, из какой таблицы берется поле, так как таблиц в базе данных может быть несколько.

Отсутствие галочки в столбце Output прячет поле.



В столбце Sort Type мы


В столбце Sort Type мы указали, по каким полям и как нужно сортировать информацию (Ascending – по возрастанию, Descending – по убыванию ). 

В столбце Sort Order мы указали приоритет сортировки (числа 1, 2 и т.д.). У нас сортировка идет по убыванию даты, а в случае, если даты одинаковые, то по фамилии автора в алфавитном порядке.

В столбце Criteria мы указываем условие (критерий) отбора записей в запросе. В нашем случае нас интересуют книжки толще 100 страниц, изданные раньше 1970 года.

Вычисление выражений. В столбце Column мы можем вместо имен полей писать выражения.  В этом случае в столбце запроса мы увидим не значение поля, а значение вычисленного выражения. На таблице это не отразится. Пусть мы хотим прикинуть, сколько бы стоили книжки, если за 10 страниц брать по рублю. Результат вы видите на Рис. 24.20.



Рис. 24.20


Работа в VS с базами данных без проекта с помощью Server Explorer


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

Если вы не хотите управлять базой данных из проекта, то открывать или создавать проект вам даже не нужно. Для работы с базой данных просто запустите VS.

Работу мы будем осуществлять с помощью инструмента VS, который называется Server Explorer и предназначен для связи VS с разнообразными данными, расположенными на вашем и на других компьютерах, а также в Интернете. Располагается он обычно слева, рядышком с Toolbox, в связке с ним, и выдвигается так же, как и он. Если вы его не видите, тогда – View ® Server Explorer. Вот его окно, на Рис. 24.12.

Рис. 24.12

Toolbox обозначается значком

, а Server Explorer –
.



Работа в Windows


Поскольку на вашем компьютере установлена операционная система Windows, то для вас слова «работать на компьютере» и «работать в Windows» – синонимы.



Работаем и с документами RTF и текстовыми файлами (txt)


В поле RichTextBox мы можем загружать не только RTF-файлы, но и обычные текстовые файлы с расширением txt. Более того, мы можем сохранять содержимое поля RichTextBox не только в RTF-файлы, но и в обычные текстовые файлы с расширением txt. В последнем случае, конечно, все форматирование будет потеряно.

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

Private Sub Открыть_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Открыть.Click

        OpenFileDialog1.Filter = "Текстовые файлы|*.txt|RTF-файлы|*.RTF"

        If OpenFileDialog1.ShowDialog() = DialogResult.Cancel Then Exit Sub

        Dim Файл As String = OpenFileDialog1.FileName

        If Файл.EndsWith(".RTF") Or Файл.EndsWith(".rtf") Then

            RTB.LoadFile(Файл)

        ElseIf Файл.EndsWith(".TXT") Or Файл.EndsWith(".txt") Then

            RTB.LoadFile(Файл, RichTextBoxStreamType.PlainText)

        Else

            MsgBox("Не могу открыть файл такого формата")

        End If

End Sub

Private Sub Сохран_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Сохран.Click

        SaveFileDialog1.Filter = "Текстовые файлы|*.txt|RTF-файлы|*.RTF"

        If SaveFileDialog1.ShowDialog() = DialogResult.Cancel Then Exit Sub

        Dim Файл As String = SaveFileDialog1.FileName

        If Файл.EndsWith(".RTF") Or Файл.EndsWith(".rtf") Then

            RTB.SaveFile(Файл)

        ElseIf Файл.EndsWith(".TXT") Or Файл.EndsWith(".txt") Then

            RTB.SaveFile(Файл, RichTextBoxStreamType.PlainText)

        Else

            MsgBox("Не хочу сохранять файл с таким расширением")

        End If

End Sub

Пояснения: Обе процедуры сделаны одинаково. В обеих оператор If анализирует расширение файла и если это RTF-файл, то открытие или сохранение идет при помощи уже известных нам вариантов методов LoadFile или SaveFile с одним параметром. Если же это текстовый файл с расширением txt, то открытие или сохранение идет при помощи другого варианта методов LoadFile или SaveFile, а именно варианта с двумя параметрами. Второй параметр уточняет, какого типа текст содержится в файле. Этот тип является значением перечисления RichTextBoxStreamType. Для обычного текста это значение –  PlainText («простой текст»).

Ну вот, пожалуй, и достаточно о RichTextBox. В остальных многочисленных его свойствах и методах вы при необходимости сможете разобраться сами.