VBA в MS Office 2007

Практика MS Excel

Разбить на страницы
Показывать лекцию целиком

17.1. Система учета домашних финансов

17-01-Система учета домашних финансов.xlsm - пример к п. 17.1.

MS Excel - это отличная среда для создания программ, автоматизирующих разного рода расчеты, для математического моделирования и т.д.. Давайте рассмотрим пример реализации простой системы учета домашних финансов.

17.1.1. Условие

Создадим в Excel простую систему учета домашних финансов. Она должна выполнять следующие функции:

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

    17.1.2. Решение: создаем формы

    Создадим в проекте Microsoft Excel следующие формы (табл. 17.1.)

    Формы в проекте
    Имя формы Назначение
    frm_Main Организация доступа к другим формам программы
    frm_In Ввод информации о доходах и расходах
    frm_Out Построчный вывод информации о доходах и расходах
    frm_Balance Вывод баланса доходов и расходов на текущую дату

    В табл. 17.2 вы можете найти информацию об элементах управления на форме frm_Main. На рис. 17.1. приведен внешний вид формы.

    Элементы управления на форме frm_Main
    Имя и тип элемента управления Назначение
    lbl_Info Информация о программе
    cmd_frm_In Вызов формы frm_In
    cmd_frm_Out Вызов формы frm_Out
    cmd_frm_Info Вызов формы frm_Info
    cmd_Exit Выход из программы
    (рис 17.1) Форма frm_Main

    В табл. 17.3. вы можете видеть информацию об элементах управления формы frm_In (рис. 17.2.)

    Элементы управления на форме frm_In
    Имя и тип элемента управления Назначение
    lbl_Date Информация о текущей дате
    lbl_RecNum Информация о номере записи
    cbo_Type Тип записи - доход или расход
    txt_Sum Сумма, в рублях
    txt_Info Примечание
    cmd_Rec Запись новой строки в файл
    cmd_Exit Выход из формы
    (рис 17.2) Форма frm_In

    В табл. 17.4. вы можете видеть информацию об элементах управления формы frm_Out (рис. 17.3.)

    Элементы управления на форме frm_Out
    Имя и тип элемента управления Назначение
    lbl_Date Информация о дате записи
    lbl_RecNum Информация о номере записи
    lbl_Type Тип записи - доход или расход
    txt_Summ Сумма, в рублях
    txt_Info Примечание
    cmd_Rec Запись исправленных данных по текущей записи в файл
    cmd_Exit Выход из формы
    сmd_First Перейти на первую запись в таблице
    сmd_Last Перейти на последнюю запись в таблице
    сmd_Forward Перейти на следующую запись
    сmd_Backward Перейти на предыдущую запись
    сld_First Установить дату для вывода первой записи на эту дату
    (рис 17.3) Форма frm_Out

    В табл. 17.5. вы можете найти информацию об элементах управления формы frm_Balance (рис. 17.4.)

    Элементы управления на форме frm_Balance
    Имя и тип элемента управления Назначение
    lbl_Balance Баланс доходов и расходов на текущую дату
    lbl_Msg Сообщение системы после анализа баланса
    cmd_OK Кнопка OK
    (рис 17.4) Форма frm_Balance

    После того, как созданы формы, подготовим книгу Microsoft Excel для записи материалов.

    17.1.3. Подготовка книги Microsoft Excel

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

    (рис 17.5) Структура данных для хранения информации

    В строках таблицы "Данные о доходах и расходах" будут храниться записи, введенные пользователем с помощью формы frm_In.

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

  • Ширина таблицы составляет 5 ячеек.
  • Номер записи - ячейка №1
  • Дата - ячейка №2
  • Тип - ячейка №3
  • Сумма - ячейка №4
  • Примечание - ячейка №5
  • Например, для того, чтобы узнать тип операции, записанной в строку с номером n нам понадобится проанализировать третью ячейку строки.

    Для того, чтобы перемещаться по отдельным строкам таблицы, нам нужно знать, адреса первой и последней строк в таблице. Обратите внимание на то, что данные, которые будет вводить пользователь, будут располагаться начиная со строки №5, четыре первых строки заняты служебной информацией. То есть, первая строка таблицы будет располагаться в пятой строке листа Excel. Адресовать эту строку можно по-разному. Мы выбрали следующий способ: строка будет адресоваться собственным номером и постоянным смещением.

    В ячейке листа B2 будем хранить информацию о постоянном смещении нашей таблицы. Там записано 4. Для того, чтобы получить номер строки листа, в котором хранится строка нашей таблицы с номером n, нужно n прибавить к значению постоянного смещения. То есть, для первой строки мы получим 4+1=5, для второй - 4+2=6.

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

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

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

    17.1.4. Код формы frm_Main

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

    Private Sub cmd_Exit_Click()
        When_Exit
    End Sub
    
    Private Sub cmd_frm_Balance_Click()
        frm_Balance.Show
    End Sub
    
    Private Sub cmd_frm_In_Click()
        frm_In.Show
    End Sub
    
    Private Sub cmd_frm_Out_Click()
        frm_Out.Show
    End Sub
    
    Private Sub cmd_frm_Report_Click()
        frm_Report.Show
    End Sub
    
    Private Sub UserForm_Terminate()
        When_Exit
    End Sub
    
    Sub When_Exit()
        ThisWorkbook.Save
        ThisWorkbook.Close
    End Sub

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

    При открытии книги мы отображаем на экране главную форму программы. Для этого мы добавили обработчик события Open для объекта Workbook (листинг 17.2.). Напомню, что в браузере проектов объект Workbook называется ЭтаКнига.

    Private Sub Workbook_Open()
        frm_Main.Show
    End Sub

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

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

    Теперь давайте рассмотрим код элементов управления формы frm_In.

    17.1.5. Код формы frm_In

    Листинг 17.3 содержит код формы frm_In.

    Private Sub cmd_Exit_Click()
        frm_In.Hide
        'Скрывая frm_In мы автоматически
        'переходим к frm_Main
    End Sub
    
    Private Sub cmd_Rec_Click()
        'Адрес строки для записи
        Dim num_Address
        'Вычисляем номер строки для записи
        num_Address = ActiveSheet.Range("B1") + _
            ActiveSheet.Range("B2")
        'Записываем номер в первую ячейку строки
        ActiveSheet.Cells(num_Address, 1) = _
            ActiveSheet.Range("B1")
        'Запишем дату во вторую ячейку
        ActiveSheet.Cells(num_Address, 2) = _
            Date
        'В третьей ячейке - тип операции
        ActiveSheet.Cells(num_Address, 3) = _
            cbo_Type.Value
        'В четвертой - сумма
        ActiveSheet.Cells(num_Address, 4) = _
            Val(txt_Sum)
        'В пятой - примечание
        ActiveSheet.Cells(num_Address, 5) = _
            txt_Info
        'Запишем новый номер строки
        ActiveSheet.Range("B1") = _
            ActiveSheet.Range("B1") + 1
        'Сбросим все установки на форме
        Initial
    End Sub
    
    Private Sub UserForm_Activate()
        'При активации формы
        'инициализируем элементы управления
        Initial
    End Sub
    
    Sub Initial()
        'Инициализация элементов управления
        lbl_Date = Date
        lbl_RecNum = ActiveSheet.Range("B1")
        cbo_Type.Clear
        cbo_Type.AddItem "Доход"
        cbo_Type.AddItem "Расход"
        cbo_Type.Value = "Доход"
        txt_Info = ""
        txt_Sum = ""
    End Sub

    Рассмотрим код формы frm_Out

    17.1.6. Код формы frm_Out

    Листинг 17.4 содержит код формы frm_Out. Обратите внимание на пользовательскую процедуру Load_Data(). Мы передаем ей параметр num_Index - номер строки, который должен быть отображен. Работа обработчиков нажатия на кнопки перемещения и обработчика, выполняющегося при выборе даты на календаре сводится к вычислению нужного номера строки и вызову этой процедуры.

    Private Sub UserForm_Initialize()
        'Загружаем первую строку
        Load_Data (1)
    End Sub
    
    Private Sub cmd_Backward_Click()
        'Предыдущая строка
        If Val(lbl_RecNum) > 1 Then
            Load_Data (Val(lbl_RecNum) - 1)
        End If
    End Sub
    
    Private Sub cmd_Exit_Click()
        frm_Out.Hide
    End Sub
    
    Private Sub cmd_First_Click()
        'Загружаем первую строку
        Load_Data (1)
    End Sub
    
    Private Sub cmd_Forward_Click()
        'Следующая строка
        If Val(lbl_RecNum) < ActiveSheet.Range("B1") Then
            Load_Data (Val(lbl_RecNum) + 1)
        End If
    End Sub
    
    Private Sub cmd_Last_Click()
        'Загружаем последнюю строку
        Load_Data (ActiveSheet.Range("B1") - 1)
    End Sub
    
    Private Sub cld_First_Click()
        'Просматриваем таблицу,
        'находим первую запись
        'за выбранную дату и выводим эту запись
        For i = 1 To ActiveSheet.Range("B1") - 1
            If ActiveSheet.Cells _
            (i + ActiveSheet.Range("B2"), 2) = _
            cld_First.Value Then
                Load_Data (i)
                Exit For
            End If
        Next i
    End Sub
    
    Private Sub cmd_Rec_Click()
        'Адрес строки для записи
        Dim num_Address
        'Вычисляем номер строки для записи
        num_Address = Val(lbl_RecNum + _
            ActiveSheet.Range("B2"))
        'Так как мы разрешили модифицировать
        'лишь сумму и примечание - запишем их
        'в текущую строку
        'Запишем сумму
        ActiveSheet.Cells(num_Address, 4) = _
            Val(txt_Sum)
        'Запишем примечание
        ActiveSheet.Cells(num_Address, 5) = _
            txt_Info
    End Sub
    
    Sub Load_Data(num_Index As Integer)
        'Принимает номер строки и выводит
        'Данные из этой строки
        'Адрес строки для чтения
        Dim num_Address
        'Вычисляем номер строки для чтения
        num_Address = num_Index + _
            ActiveSheet.Range("B2")
        'Выводим номер записи
        lbl_RecNum = _
            ActiveSheet.Cells(num_Address, 1)
        'Выводим дату
        lbl_Date = _
            ActiveSheet.Cells(num_Address, 2)
        'Выводим тип операции
        lbl_Type = _
            ActiveSheet.Cells(num_Address, 3)
        'Выводим сумму
        txt_Sum = _
            ActiveSheet.Cells(num_Address, 4)
        'Выводим примечание
        txt_Info = _
            ActiveSheet.Cells(num_Address, 5)
    End Sub

    Теперь рассмотрим код модуля формы frm_Balance

    17.1.7. Код формы frm_Balance

    В листинге 17.5. вы можете найти код модуля формы frm_Balance. Здесь мы вычисляем баланс доходов и расходов по всей таблице. Вычисления ведутся в коде обработчика события Activate.

    Private Sub cmd_OK_Click()
        frm_Balance.Hide
    End Sub
    
    Private Sub UserForm_Activate()
        'Адрес строки
        Dim num_Address
        'Переменная для хранения суммы доходов
        Dim num_Earn
        'Переменная для хранения суммы расходов
        Dim num_Spend
        For i = 1 To ActiveSheet.Range("B1") - 1
            num_Address = i + ActiveSheet.Range("B2")
            'Если в строке хранится значение дохода
            'добавим его в num_Earn
            If ActiveSheet.Cells(num_Address, 3) = "Доход" _
                Then
                    num_Earn = num_Earn + _
                        ActiveSheet.Cells(num_Address, 4)
                End If
            'Если в строке хранится значение расхода
            'добавим его в num_Spend
            If ActiveSheet.Cells(num_Address, 3) = "Расход" _
                Then
                    num_Spend = num_Spend + _
                        ActiveSheet.Cells(num_Address, 4)
                End If
        Next i
        lbl_Balance = num_Earn - num_Spend
        If num_Earn > num_Spend Then _
            lbl_Msg = "Доходы больше расходов."
        If num_Earn = num_Spend Then _
            lbl_Msg = "Доходы равны расходам."
        If num_Earn < num_Spend Then _
            lbl_Msg = "Доходы меньше расходов."
    End Sub

    17.2. Задача об обмене значениями

    17-02-Обмен значений.xlsm - пример к п. 17.2.

    17.2.1. Условие

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

    17.2.2. Решение

    Предположим, что имеются 2 переменные (А и В), содержащие числа. Для обмена значениями этих переменных достаточно произвести следующие действия:

  • Сложить А и В и результат записать в А
  • Вычесть из А переменную В и записать результат в В.
  • Вычесть из А переменную В и записать результат в А.
  • Для решения задачи будем считать, что число A записано в ячейку B2, число В - в ячейку C2. Подпишем соответствующим образом эти ячейки и разместим на рабочем листе кнопку с именем cmd_Change и надписью Обменять А и В (рис. 17.6.)

    (рис 17.6) Рабочий лист, подготовленный для решения задачи

    В листинге 17.6. вы можете найти программный код для решения задачи, размещенный в обработчике события Click для кнопки cmd_Change

    'Сохраняем сумму ячеек в B2
        ActiveSheet.Range("B2") = _
            ActiveSheet.Range("B2") + _
            ActiveSheet.Range("C2")
        'Разность сохраняем в С2
        ActiveSheet.Range("C2") = _
            ActiveSheet.Range("B2") - _
            ActiveSheet.Range("C2")
        'И еще раз разность в B2
        ActiveSheet.Range("B2") = _
            ActiveSheet.Range("B2") - _
            ActiveSheet.Range("C2")

    17.3. Перевод чисел из одной системы счисления в другую

    17-03-Системы счисления.xlsm - пример к п. 17.3.

    17.3.1. Условие

    Перевести заданное пользователем целое число A из одной системы счисления ( P ) в другую ( Q ). P и Q могут изменяться от 2 до 10.

    17.3.2. Решение

    MS Excel содержит функции для преобразования чисел между различными системами счисления, однако здесь мы создадим универсальное решение. Вы сможете встроить этот код в свои проекты. При необходимости вы сможете доработать его так, чтобы он смог работать с системами счисления, основание которых превышает 10.

    В данном случае наиболее очевидным является перевод введенного числа сначала из системы счисления с основанием P в систему с основанием 10, а потом уже из системы с основанием 10 в систему с основанием Q.

    Перевод в десятичную систему счисления осуществляется в два этапа:

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

    Перевод из двоичной системы в десятичную:

    1101 =1*2^3+1*2^2+0*2^1+1*2^0=8+4+0+1=13

    Перевод из пятеричной системы в десятичную:

    1042=1*5^3+0*5^2+4*5^1+2*5^0=125+0+20+2=147

    Перевод в систему счисления с основанием Q из системы с основанием 10 осуществляется путем накапливания остатков от деления этого числа на Q с последующим изменением этого числа целочисленным делением его на Q до тех пор, пока переводимое число не станет равным 0.

    Для решения этой задачи нам понадобится форма, содержащая следующие элементы управления (табл. 17.6.). У текстовых полей свойство AutoSize установлено в True.

    Элементы управления
    Имя элемента управления Подпись и примечания
    cmd_OK Перевести. Кнопка для перевода чисел
    txt_P Из системы P. Текстовое поле для хранения основания системы счисления P.
    txt_Q В систему Q. Поле для хранения основания системы счисления Q
    txt_A Число для перевода. Число, заданное для перевода из системы P в Q
    txt_B Результат. Текстовое поле для вывода результата перевода

    На рис. 17.7. вы можете увидеть форму программы.

    (рис 17.7) Форма программы для перевода чисел из одной системы счисления в другую

    В листинге 17.7. вы можете найти код события Click для кнопки cmd_OK.

    'Для хранения основания системы P
        Dim num_P
        'Для хранения основания системы Q
        Dim num_Q
        'Для хранения числа в 10-й системе
        Dim num_10
        'Для хранения очередного числа в
        'системе счисления Q
        Dim num_S
        num_P = Val(txt_P)
        num_Q = Val(txt_Q)
        'Переводим введенное число из
        'системы счисления P
        'в десятичную систему
        For i = 1 To Len(txt_A)
            num_10 = num_10 + Val(Mid(txt_A, i, 1)) * _
                num_P ^ (Len(txt_A) - i)
        Next i
        'Переводим число из десятичной системы
        'в систему с основанием Q
        txt_B = ""
        While num_10 <> 0
            'Остаток от деления запишем в str_S
            num_S = num_10 Mod num_Q
            'Запишем очередное число в
            'окно для вывода результата
            txt_B = Mid(Str(num_S), 2, 1) + txt_B
            'Запишем в num_10 результат
            'целочисленного деления
            'num_10 на основание системы
            'счисления Q
            num_10 = num_10 \ num_Q
        Wend

    17.4. Выводы

    В этой лекции мы рассмотрели несколько практических примеров решения задач для MS Excel.

    Страницы:

    17.1. Система учета домашних финансов

    17-01-Система учета домашних финансов.xlsm - пример к п. 17.1.

    MS Excel - это отличная среда для создания программ, автоматизирующих разного рода расчеты, для математического моделирования и т.д.. Давайте рассмотрим пример реализации простой системы учета домашних финансов.

    17.1.1. Условие

    Создадим в Excel простую систему учета домашних финансов. Она должна выполнять следующие функции:

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

    17.1.2. Решение: создаем формы

    Создадим в проекте Microsoft Excel следующие формы (табл. 17.1.)

    Формы в проекте
    Имя формы Назначение
    frm_Main Организация доступа к другим формам программы
    frm_In Ввод информации о доходах и расходах
    frm_Out Построчный вывод информации о доходах и расходах
    frm_Balance Вывод баланса доходов и расходов на текущую дату

    В табл. 17.2 вы можете найти информацию об элементах управления на форме frm_Main. На рис. 17.1. приведен внешний вид формы.

    Элементы управления на форме frm_Main
    Имя и тип элемента управления Назначение
    lbl_Info Информация о программе
    cmd_frm_In Вызов формы frm_In
    cmd_frm_Out Вызов формы frm_Out
    cmd_frm_Info Вызов формы frm_Info
    cmd_Exit Выход из программы
    (рис 17.1) Форма frm_Main

    В табл. 17.3. вы можете видеть информацию об элементах управления формы frm_In (рис. 17.2.)

    Элементы управления на форме frm_In
    Имя и тип элемента управления Назначение
    lbl_Date Информация о текущей дате
    lbl_RecNum Информация о номере записи
    cbo_Type Тип записи - доход или расход
    txt_Sum Сумма, в рублях
    txt_Info Примечание
    cmd_Rec Запись новой строки в файл
    cmd_Exit Выход из формы
    (рис 17.2) Форма frm_In

    В табл. 17.4. вы можете видеть информацию об элементах управления формы frm_Out (рис. 17.3.)

    Элементы управления на форме frm_Out
    Имя и тип элемента управления Назначение
    lbl_Date Информация о дате записи
    lbl_RecNum Информация о номере записи
    lbl_Type Тип записи - доход или расход
    txt_Summ Сумма, в рублях
    txt_Info Примечание
    cmd_Rec Запись исправленных данных по текущей записи в файл
    cmd_Exit Выход из формы
    сmd_First Перейти на первую запись в таблице
    сmd_Last Перейти на последнюю запись в таблице
    сmd_Forward Перейти на следующую запись
    сmd_Backward Перейти на предыдущую запись
    сld_First Установить дату для вывода первой записи на эту дату
    (рис 17.3) Форма frm_Out

    В табл. 17.5. вы можете найти информацию об элементах управления формы frm_Balance (рис. 17.4.)

    Элементы управления на форме frm_Balance
    Имя и тип элемента управления Назначение
    lbl_Balance Баланс доходов и расходов на текущую дату
    lbl_Msg Сообщение системы после анализа баланса
    cmd_OK Кнопка OK
    (рис 17.4) Форма frm_Balance

    После того, как созданы формы, подготовим книгу Microsoft Excel для записи материалов.

    17.1.3. Подготовка книги Microsoft Excel

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

    (рис 17.5) Структура данных для хранения информации

    В строках таблицы "Данные о доходах и расходах" будут храниться записи, введенные пользователем с помощью формы frm_In.

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

  • Ширина таблицы составляет 5 ячеек.
  • Номер записи - ячейка №1
  • Дата - ячейка №2
  • Тип - ячейка №3
  • Сумма - ячейка №4
  • Примечание - ячейка №5
  • Например, для того, чтобы узнать тип операции, записанной в строку с номером n нам понадобится проанализировать третью ячейку строки.

    Для того, чтобы перемещаться по отдельным строкам таблицы, нам нужно знать, адреса первой и последней строк в таблице. Обратите внимание на то, что данные, которые будет вводить пользователь, будут располагаться начиная со строки №5, четыре первых строки заняты служебной информацией. То есть, первая строка таблицы будет располагаться в пятой строке листа Excel. Адресовать эту строку можно по-разному. Мы выбрали следующий способ: строка будет адресоваться собственным номером и постоянным смещением.

    В ячейке листа B2 будем хранить информацию о постоянном смещении нашей таблицы. Там записано 4. Для того, чтобы получить номер строки листа, в котором хранится строка нашей таблицы с номером n, нужно n прибавить к значению постоянного смещения. То есть, для первой строки мы получим 4+1=5, для второй - 4+2=6.

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

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

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

    17.1.4. Код формы frm_Main

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

    Private Sub cmd_Exit_Click()
        When_Exit
    End Sub
    
    Private Sub cmd_frm_Balance_Click()
        frm_Balance.Show
    End Sub
    
    Private Sub cmd_frm_In_Click()
        frm_In.Show
    End Sub
    
    Private Sub cmd_frm_Out_Click()
        frm_Out.Show
    End Sub
    
    Private Sub cmd_frm_Report_Click()
        frm_Report.Show
    End Sub
    
    Private Sub UserForm_Terminate()
        When_Exit
    End Sub
    
    Sub When_Exit()
        ThisWorkbook.Save
        ThisWorkbook.Close
    End Sub

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

    При открытии книги мы отображаем на экране главную форму программы. Для этого мы добавили обработчик события Open для объекта Workbook (листинг 17.2.). Напомню, что в браузере проектов объект Workbook называется ЭтаКнига.

    Private Sub Workbook_Open()
        frm_Main.Show
    End Sub

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

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

    Теперь давайте рассмотрим код элементов управления формы frm_In.

    17.1.5. Код формы frm_In

    Листинг 17.3 содержит код формы frm_In.

    Private Sub cmd_Exit_Click()
        frm_In.Hide
        'Скрывая frm_In мы автоматически
        'переходим к frm_Main
    End Sub
    
    Private Sub cmd_Rec_Click()
        'Адрес строки для записи
        Dim num_Address
        'Вычисляем номер строки для записи
        num_Address = ActiveSheet.Range("B1") + _
            ActiveSheet.Range("B2")
        'Записываем номер в первую ячейку строки
        ActiveSheet.Cells(num_Address, 1) = _
            ActiveSheet.Range("B1")
        'Запишем дату во вторую ячейку
        ActiveSheet.Cells(num_Address, 2) = _
            Date
        'В третьей ячейке - тип операции
        ActiveSheet.Cells(num_Address, 3) = _
            cbo_Type.Value
        'В четвертой - сумма
        ActiveSheet.Cells(num_Address, 4) = _
            Val(txt_Sum)
        'В пятой - примечание
        ActiveSheet.Cells(num_Address, 5) = _
            txt_Info
        'Запишем новый номер строки
        ActiveSheet.Range("B1") = _
            ActiveSheet.Range("B1") + 1
        'Сбросим все установки на форме
        Initial
    End Sub
    
    Private Sub UserForm_Activate()
        'При активации формы
        'инициализируем элементы управления
        Initial
    End Sub
    
    Sub Initial()
        'Инициализация элементов управления
        lbl_Date = Date
        lbl_RecNum = ActiveSheet.Range("B1")
        cbo_Type.Clear
        cbo_Type.AddItem "Доход"
        cbo_Type.AddItem "Расход"
        cbo_Type.Value = "Доход"
        txt_Info = ""
        txt_Sum = ""
    End Sub

    Рассмотрим код формы frm_Out

    17.1.6. Код формы frm_Out

    Листинг 17.4 содержит код формы frm_Out. Обратите внимание на пользовательскую процедуру Load_Data(). Мы передаем ей параметр num_Index - номер строки, который должен быть отображен. Работа обработчиков нажатия на кнопки перемещения и обработчика, выполняющегося при выборе даты на календаре сводится к вычислению нужного номера строки и вызову этой процедуры.

    Private Sub UserForm_Initialize()
        'Загружаем первую строку
        Load_Data (1)
    End Sub
    
    Private Sub cmd_Backward_Click()
        'Предыдущая строка
        If Val(lbl_RecNum) > 1 Then
            Load_Data (Val(lbl_RecNum) - 1)
        End If
    End Sub
    
    Private Sub cmd_Exit_Click()
        frm_Out.Hide
    End Sub
    
    Private Sub cmd_First_Click()
        'Загружаем первую строку
        Load_Data (1)
    End Sub
    
    Private Sub cmd_Forward_Click()
        'Следующая строка
        If Val(lbl_RecNum) < ActiveSheet.Range("B1") Then
            Load_Data (Val(lbl_RecNum) + 1)
        End If
    End Sub
    
    Private Sub cmd_Last_Click()
        'Загружаем последнюю строку
        Load_Data (ActiveSheet.Range("B1") - 1)
    End Sub
    
    Private Sub cld_First_Click()
        'Просматриваем таблицу,
        'находим первую запись
        'за выбранную дату и выводим эту запись
        For i = 1 To ActiveSheet.Range("B1") - 1
            If ActiveSheet.Cells _
            (i + ActiveSheet.Range("B2"), 2) = _
            cld_First.Value Then
                Load_Data (i)
                Exit For
            End If
        Next i
    End Sub
    
    Private Sub cmd_Rec_Click()
        'Адрес строки для записи
        Dim num_Address
        'Вычисляем номер строки для записи
        num_Address = Val(lbl_RecNum + _
            ActiveSheet.Range("B2"))
        'Так как мы разрешили модифицировать
        'лишь сумму и примечание - запишем их
        'в текущую строку
        'Запишем сумму
        ActiveSheet.Cells(num_Address, 4) = _
            Val(txt_Sum)
        'Запишем примечание
        ActiveSheet.Cells(num_Address, 5) = _
            txt_Info
    End Sub
    
    Sub Load_Data(num_Index As Integer)
        'Принимает номер строки и выводит
        'Данные из этой строки
        'Адрес строки для чтения
        Dim num_Address
        'Вычисляем номер строки для чтения
        num_Address = num_Index + _
            ActiveSheet.Range("B2")
        'Выводим номер записи
        lbl_RecNum = _
            ActiveSheet.Cells(num_Address, 1)
        'Выводим дату
        lbl_Date = _
            ActiveSheet.Cells(num_Address, 2)
        'Выводим тип операции
        lbl_Type = _
            ActiveSheet.Cells(num_Address, 3)
        'Выводим сумму
        txt_Sum = _
            ActiveSheet.Cells(num_Address, 4)
        'Выводим примечание
        txt_Info = _
            ActiveSheet.Cells(num_Address, 5)
    End Sub

    Теперь рассмотрим код модуля формы frm_Balance

    17.1.7. Код формы frm_Balance

    В листинге 17.5. вы можете найти код модуля формы frm_Balance. Здесь мы вычисляем баланс доходов и расходов по всей таблице. Вычисления ведутся в коде обработчика события Activate.

    Private Sub cmd_OK_Click()
        frm_Balance.Hide
    End Sub
    
    Private Sub UserForm_Activate()
        'Адрес строки
        Dim num_Address
        'Переменная для хранения суммы доходов
        Dim num_Earn
        'Переменная для хранения суммы расходов
        Dim num_Spend
        For i = 1 To ActiveSheet.Range("B1") - 1
            num_Address = i + ActiveSheet.Range("B2")
            'Если в строке хранится значение дохода
            'добавим его в num_Earn
            If ActiveSheet.Cells(num_Address, 3) = "Доход" _
                Then
                    num_Earn = num_Earn + _
                        ActiveSheet.Cells(num_Address, 4)
                End If
            'Если в строке хранится значение расхода
            'добавим его в num_Spend
            If ActiveSheet.Cells(num_Address, 3) = "Расход" _
                Then
                    num_Spend = num_Spend + _
                        ActiveSheet.Cells(num_Address, 4)
                End If
        Next i
        lbl_Balance = num_Earn - num_Spend
        If num_Earn > num_Spend Then _
            lbl_Msg = "Доходы больше расходов."
        If num_Earn = num_Spend Then _
            lbl_Msg = "Доходы равны расходам."
        If num_Earn < num_Spend Then _
            lbl_Msg = "Доходы меньше расходов."
    End Sub

    17.2. Задача об обмене значениями

    17-02-Обмен значений.xlsm - пример к п. 17.2.

    17.2.1. Условие

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

    17.2.2. Решение

    Предположим, что имеются 2 переменные (А и В), содержащие числа. Для обмена значениями этих переменных достаточно произвести следующие действия:

  • Сложить А и В и результат записать в А
  • Вычесть из А переменную В и записать результат в В.
  • Вычесть из А переменную В и записать результат в А.
  • Для решения задачи будем считать, что число A записано в ячейку B2, число В - в ячейку C2. Подпишем соответствующим образом эти ячейки и разместим на рабочем листе кнопку с именем cmd_Change и надписью Обменять А и В (рис. 17.6.)

    (рис 17.6) Рабочий лист, подготовленный для решения задачи

    В листинге 17.6. вы можете найти программный код для решения задачи, размещенный в обработчике события Click для кнопки cmd_Change

    'Сохраняем сумму ячеек в B2
        ActiveSheet.Range("B2") = _
            ActiveSheet.Range("B2") + _
            ActiveSheet.Range("C2")
        'Разность сохраняем в С2
        ActiveSheet.Range("C2") = _
            ActiveSheet.Range("B2") - _
            ActiveSheet.Range("C2")
        'И еще раз разность в B2
        ActiveSheet.Range("B2") = _
            ActiveSheet.Range("B2") - _
            ActiveSheet.Range("C2")

    17.3. Перевод чисел из одной системы счисления в другую

    17-03-Системы счисления.xlsm - пример к п. 17.3.

    17.3.1. Условие

    Перевести заданное пользователем целое число A из одной системы счисления ( P ) в другую ( Q ). P и Q могут изменяться от 2 до 10.

    17.3.2. Решение

    MS Excel содержит функции для преобразования чисел между различными системами счисления, однако здесь мы создадим универсальное решение. Вы сможете встроить этот код в свои проекты. При необходимости вы сможете доработать его так, чтобы он смог работать с системами счисления, основание которых превышает 10.

    В данном случае наиболее очевидным является перевод введенного числа сначала из системы счисления с основанием P в систему с основанием 10, а потом уже из системы с основанием 10 в систему с основанием Q.

    Перевод в десятичную систему счисления осуществляется в два этапа:

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

    Перевод из двоичной системы в десятичную:

    1101 =1*2^3+1*2^2+0*2^1+1*2^0=8+4+0+1=13

    Перевод из пятеричной системы в десятичную:

    1042=1*5^3+0*5^2+4*5^1+2*5^0=125+0+20+2=147

    Перевод в систему счисления с основанием Q из системы с основанием 10 осуществляется путем накапливания остатков от деления этого числа на Q с последующим изменением этого числа целочисленным делением его на Q до тех пор, пока переводимое число не станет равным 0.

    Для решения этой задачи нам понадобится форма, содержащая следующие элементы управления (табл. 17.6.). У текстовых полей свойство AutoSize установлено в True.

    Элементы управления
    Имя элемента управления Подпись и примечания
    cmd_OK Перевести. Кнопка для перевода чисел
    txt_P Из системы P. Текстовое поле для хранения основания системы счисления P.
    txt_Q В систему Q. Поле для хранения основания системы счисления Q
    txt_A Число для перевода. Число, заданное для перевода из системы P в Q
    txt_B Результат. Текстовое поле для вывода результата перевода

    На рис. 17.7. вы можете увидеть форму программы.

    (рис 17.7) Форма программы для перевода чисел из одной системы счисления в другую

    В листинге 17.7. вы можете найти код события Click для кнопки cmd_OK.

    'Для хранения основания системы P
        Dim num_P
        'Для хранения основания системы Q
        Dim num_Q
        'Для хранения числа в 10-й системе
        Dim num_10
        'Для хранения очередного числа в
        'системе счисления Q
        Dim num_S
        num_P = Val(txt_P)
        num_Q = Val(txt_Q)
        'Переводим введенное число из
        'системы счисления P
        'в десятичную систему
        For i = 1 To Len(txt_A)
            num_10 = num_10 + Val(Mid(txt_A, i, 1)) * _
                num_P ^ (Len(txt_A) - i)
        Next i
        'Переводим число из десятичной системы
        'в систему с основанием Q
        txt_B = ""
        While num_10 <> 0
            'Остаток от деления запишем в str_S
            num_S = num_10 Mod num_Q
            'Запишем очередное число в
            'окно для вывода результата
            txt_B = Mid(Str(num_S), 2, 1) + txt_B
            'Запишем в num_10 результат
            'целочисленного деления
            'num_10 на основание системы
            'счисления Q
            num_10 = num_10 \ num_Q
        Wend

    17.4. Выводы

    В этой лекции мы рассмотрели несколько практических примеров решения задач для MS Excel.

    Вернуться к учебному плану