Страницы

четверг, 1 октября 2015 г.

Создание формы в Excel VBA

Вариант 5
Создать пользовательскую форму вида:


Создать в модуле формы частную процедуру-подпрограмму, запускающуюся при щелчке по кнопке с надписью «Расчет». Процедура должна вычислять максимальную сумму, начисленную за дневную работу какому-либо из сотрудников должности, название которой вводится в текстовое поле  Поле1, в день недели, номер которого вводится в Поле2. Начисленная сумма вычисляется как произведение отработки на расценку. Результат вычисления процедура должна поместить в Поле3.
Для создания пользовательской формы нужно перейти в редактор кода Visual Basic (Alt+F11) и в меню выбрать Insert->UserForm. Затем нужно добавить нужные компоненты и настроить все параметры формы и компонентов – размер, шрифт, названия.
В данном случае нужны три элемента TextBox (TextDolgn – должность, TextDen – день недели, TextMaks – максимальная начисленная сумма), две кнопки (Расчет и Выход) и 4 надписи. Все свойства можно установить на панели Properties.
Если нажать два раза на кнопку Расчет, то редактор создаст заготовку процедуры. Внесем в нее текст:

Private Sub btnCalc_Click()
Dim r As Integer        'номер строки
Dim c As Integer        'номер столбца
Dim maxSum As Integer   'максимальная начисленная сумма
Dim rng As Range        'пользовательский диапазон
textMaks.Text = ""      'очистка поля от предыдущего поиска
'если не введено название должности, то сообщение и выход из процедуры
If textDolgn.Text = Empty Then
    MsgBox "Введите название должности!"
    textDolgn.SetFocus   'фокус на поле ввода
    Exit Sub
End If
'если не введен номер дня, то сообщение и выход из процедуры
If textDen.Text = Empty Then
    MsgBox "Введите номер дня недели (от 1 до 7)!"
    textDen.SetFocus
    Exit Sub
End If
'введено нечисловое значение дня
If Not (IsNumeric(textDen.Text)) Then
    MsgBox "Нечисловое значение дня недели (нужно от 1 до 7)!"
    textDen.SetFocus
    textDen.Text = ""   'очистка поля
    Exit Sub
    'введен неправильный номер дня недели
ElseIf (CInt(textDen.Text) < 1) Or (CInt(textDen.Text) > 7) Then
    MsgBox "Неверное значение дня недели (нужно от 1 до 7)!"
    textDen.SetFocus
    textDen.Text = ""   'очистка поля
    Exit Sub
End If
'начинаем цикл с 3 строки
r = 3
'номер дня из поля ввода
c = CInt(textDen.Text)
Set rng = Sheets(1).UsedRange
maxSum = -1
For r = 3 To rng.Rows.Count
    'если в ячейке найдено указанное название должности
    If InStr(1, Cells(r, 2), textDolgn.Text, vbTextCompare) > 0 Then
    'если сумма больше чем максимум, то меняем значение максимума на новое
        If CInt(Cells(r, 3)) * CInt(Cells(r, c + 3)) > maxSum Then maxSum = CInt(Cells(r, 3)) * CInt(Cells(r, c + 3))
    End If
Next r
If maxSum = -1 Then
    MsgBox "Указанная должность не найдена"
    textMaks.Text = "-"
Else
    textMaks.Text = CStr(maxSum)
End If
Set rng = Nothing 'освобождение памяти
End Sub
Тут куча всяких проверок. Сначала проверим, все ли данные внесены. Если нет – сообщим пользователю об этом, установим фокус ввода на чистом поле (для удобства пользователя, чтобы ему лишний раз мышью не тыкать) и выйдем из процедуры.
Затем проверим, правильно ли введен номер дня. Во-первых, это должно быть число, а во-вторых – число от 1 до 7. Если что-то не так – очищаем поле ввода, устанавливаем фокус на него и выходим из процедуры, опять же сообщив пользователю о неудачной попытке.
Если все путем, начинаем поиск нужных значений. Определим пользовательский диапазон, чтобы не зависеть от числа строк. Затем нужно в цикле найти максимальную сумму. Значения ячеек нужно с чем-то сравнивать. Здесь мы не можем просто подставить первую ячейку в строке или столбце, потом что необходимо отобрать по параметру – должности. Но мы видим, что начисленная сумма не может быть меньше нуля – расценка не может быть отрицательной, и число часов отработки тоже. Ну, в данном случае мы не рассматриваем возможность «красного сторно» - то есть исправления за предыдущие периоды. Так что возьмем начальную максимальную сумму равной -1 (минус один).
Начинаем цикл перебора ячеек столбца с указанным номером дня (это значение поля ввода плюс 3).
Смотрим, содержится ли в ячейке указанное название должности. Можно просто сравнить две строки, но это неудобно, поскольку надо будет вводить должность целиком и правильно. Поэтому используем функцию InStr, которая возвращает значение больше 0, если указанная подстрока найдена в строке. Можно было использовать функцию Like, которая тоже сравнивает две строки. Это на выбор разработчика.
Если должность в ячейке найдена, перемножаем расценку на число часов отработки и сравниваем результат с максимальной суммой. Если результат больше, то меняем его на новое значение.
Не забываем конвертировать строковые значения в числовые и наоборот там, где это нужно. Даже если Excel и сам понимает, где что содержится, лучше это делать для надежности.
После прохождения цикла смотрим, если максимальная сумма равна -1 (начальное значение), значит, нет такой должности. Выводим сообщение, а в поле помещаем прочерк для наглядности.
Если сумма не равна -1, то помещаем найденное значение в поле textMaks.
Освобождаем память объекта в конце программы.
Для кнопки Выход тоже есть текст:
Private Sub btnExit_Click()
'выгрузка формы
    Unload Me
End Sub
Для запуска формы помещаем на лист с данными кнопку (вкладка «Разработчик», раздел «Элементы управления», список «Вставить» - выбрать кнопку из элементов управления формы) и назначим ей макрос Кнопка1_Щелчок. Затем в редакторе напишем код для этой кнопки:
Sub Кнопка1_Щелчок()
UserForm1.Show
End Sub
Все, можно проверять работу формы.
Я привел здесь только 5 вариант. Если нужно другой, то можно спросить в группе ВК (см. страницу с контактами). Но вообще, все варианты похожие. Есть только небольшие отличия, особенно, если нужно вывести строку с несколькими текстовыми значениями. Тогда можно использовать свойство текстбокса – Multiline для вывода нескольких строк, а для разделения использовать символы переноса на новую строку.

Дополнительные материалы


Общий список всех сообщений по этой работе