Textbox vba excel как очистить

Lexa13

0 / 0 / 0

Регистрация: 23.10.2012

Сообщений: 6

1

29.10.2012, 19:23. Показов 33978. Ответов 20

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

VB.NET
1
2
3
4
5
6
7
8
  Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        TextBox1.Clear() 
        TextBox2.Clear()
        TextBox3.Clear()
        TextBox4.Clear()
        TextBox5.Clear()
        TextBox6.Clear()
    End Sub

Как уменьшить объём данного кода. Подразумевается что чем дальше тем больше окон надо будет очистить.



0



Памирыч

Почетный модератор

21371 / 9105 / 1082

Регистрация: 11.04.2010

Сообщений: 11,014

29.10.2012, 19:47

2

Лучший ответ Сообщение было отмечено как решение

Решение

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

VB.NET
1
2
3
4
5
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        For I As Integer = 1 To 6
            Me.Controls("TextBox" & I).Text = ""
        Next
    End Sub

Вариант 2: Компоненты могут называться как угодно, и их может быть сколько угодно. Недостаток: они все должны находиться на одном контейнере (форме, а не GroupBox, Panel, etc.)

VB.NET
1
2
3
4
5
        For Each C As Control In Me.Controls
            If TypeOf C Is TextBox Then
                C.Text = ""
            End If
        Next



9



0 / 0 / 0

Регистрация: 23.10.2012

Сообщений: 6

29.10.2012, 19:49

 [ТС]

3

Я знаю сколько их всего. Так что пожалуй вариант 1.
Буду признательна ссылке на теорию по этим двум методам.
Спасибо большое.

PS только там было Button 2)))



0



Почетный модератор

21371 / 9105 / 1082

Регистрация: 11.04.2010

Сообщений: 11,014

29.10.2012, 20:01

4

Цитата
Сообщение от Lexa13
Посмотреть сообщение

Буду признательна ссылке на теорию по этим двум методам

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

Пользуйтесь форумом, задавайте вопросы, не стесняйтесь . Загляните в Готовые решения и полезные коды на Visual Basic .NET (Часть-1) там кое-что есть.



0



0 / 0 / 0

Регистрация: 23.10.2012

Сообщений: 6

29.10.2012, 22:57

 [ТС]

5

Цитата
Сообщение от Памирыч
Посмотреть сообщение

Я даже не знаю.

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



0



Юпатов Дмитрий

1706 / 1194 / 227

Регистрация: 23.12.2010

Сообщений: 1,526

29.10.2012, 23:28

6

Лучший ответ Сообщение было отмечено как решение

Решение

Цитата
Сообщение от Lexa13
Посмотреть сообщение

Ну хотя бы своими словами

Способ 1:

VB.NET
1
2
3
For I As Integer = 1 To 6
      Me.Controls("TextBox" & I).Text = ""
Next

Тут все в цикле с 1 по 6. В теле цикла мы вызываем элементы управления по имени:

VB.NET
1
Me.Controls("TextBox" & I)

т.е. вызываем TextBox с 1 по 6. Ну и после вызова изменяем их свойство Text на пустую строку («»).
Подробнее о Me.Controls
Способ 2:

VB.NET
1
2
3
4
5
For Each C As Control In Me.Controls
            If TypeOf C Is TextBox Then
                C.Text = ""
            End If
Next

Перебираем коллекцию элементов управления, расположенных в контейнере (в данном случае — непосредственно на форме). В процессе перебора при каждой итерации переменной С присваивается ссылка на некоторый элемент управления. В теле цикла проверяем тип элемента управления (в переменной С) и, если тип соответствует типу TextBox, то меняем свойство элемента управления Text на пустую строку.



9



20 / 20 / 0

Регистрация: 05.07.2011

Сообщений: 134

30.10.2012, 22:43

7

Юпатов Дмитрий,
а если необходимо очистить Lebel c формы?
С уважением, Akiva



0



edward_freedom

1568 / 1447 / 303

Регистрация: 01.10.2011

Сообщений: 2,636

30.10.2012, 22:49

8

Akiva,

VB.NET
1
2
3
4
5
For Each label As Control In Me.Controls
            If TypeOf label Is Label Then
                label.Text = ""
            End If
Next



2



29 / 29 / 1

Регистрация: 01.10.2010

Сообщений: 171

30.10.2012, 23:22

9

очень полезная тема вышла, побольше бы таких)



1



20 / 20 / 0

Регистрация: 05.07.2011

Сообщений: 134

31.10.2012, 01:36

10

Не пашет…



0



1706 / 1194 / 227

Регистрация: 23.12.2010

Сообщений: 1,526

31.10.2012, 02:21

11

Цитата
Сообщение от Akiva
Посмотреть сообщение

Не пашет…

1. Имя переменной совпадает с типом. Не хорошо.
2. А лейблы НЕПОСРЕДСТВЕННО на форме, или может, в групбоксе?



0



20 / 20 / 0

Регистрация: 05.07.2011

Сообщений: 134

31.10.2012, 17:02

12

На форме.



0



34 / 34 / 12

Регистрация: 29.07.2010

Сообщений: 413

22.06.2015, 21:21

13

У меня при таком цикле появляется ошибка

Миниатюры

Как очистить все TextBox на форме
 



0



Почетный модератор

21371 / 9105 / 1082

Регистрация: 11.04.2010

Сообщений: 11,014

22.06.2015, 21:22

14

vova_king, так, поди, текстбоксы лежат не на форме, а на каких-нибудь панелях, Групбоксах?



0



34 / 34 / 12

Регистрация: 29.07.2010

Сообщений: 413

22.06.2015, 21:46

15

Только одна 13 лежит в groupbox
Тут же в верху не написано что он не работает в groupbox (только про второй вариант написано)

Добавлено через 17 минут
Переместил их в загрузку форму при повторном запуске ругается.
Можно ли как нибудь очистить все в groupbox?



0



Юпатов Дмитрий

1706 / 1194 / 227

Регистрация: 23.12.2010

Сообщений: 1,526

22.06.2015, 22:31

16

У тебя переменная I взята в кавычки:

VB.NET
1
Me.Controls("TextBox" & "I").Text = ""

А надо так:

VB.NET
1
Me.Controls("TextBox" & I).Text = ""

Добавлено через 1 минуту
а если в групбоксе, то надо бы

VB.NET
1
имя_групбокса.Controls("TextBox" & "I").Text = ""



1



vova_king

34 / 34 / 12

Регистрация: 29.07.2010

Сообщений: 413

23.06.2015, 02:13

17

Решили сделать в GroupBox сделать так

VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
        ' чистим все поля в textbox
        Dim ss = Me.Controls ' массив со всеми компонентами гроупбокса
        For i = 0 To ss.Count - 1 ' прокручиваем все компоненты по одному
            If ss.Item(i).Controls.Count > 0 Then
                For a = 0 To ss.Item(i).Controls.Count - 1
                    If ss.Item(i).Controls.Item(a).Name.ToString.Substring(0, 4) = "Text" Then  ' свойство компонента text = ""
                        ss.Item(i).Controls.Item(a).Text = ""
                    End If
                Next
            End If
 
            If ss.Item(i).Name.ToString.Substring(0, 4) = "Text" Then ss.Item(i).Text = "" ' свойство компонента text = ""
        Next

А вот если используется CheckBox придется пладить или подумать и сделать так же как и для groupbox

VB.NET
1
2
3
4
5
6
7
Dim ss1 = GroupBox2.Controls
        For i = 0 To ss1.Count - 1 ' прокручиваем все компоненты по одному
            If ss1.Item(i).Name.ToString.Substring(0, 5) = "Check" Then
                Dim dd As Windows.Forms.CheckBox = ss1.Item(i)
                dd.CheckState = CheckState.Unchecked  ' сняли галочку = ""
            End If
        Next

Может быть кому нибудь пригодится!



1



MrCrown

1505 / 1417 / 319

Регистрация: 03.10.2012

Сообщений: 1,471

24.06.2015, 02:31

18

Лучший ответ Сообщение было отмечено Памирыч как решение

Решение

Ребят, а как вам такое: простая рекурсивная функция — очищает все текстбоксы во всех контейнерах на форме,
независимо от количества, уровня вложенности контейнеров и названий.

VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Clr(Me)
    End Sub
Private Sub Clr(ByVal ct As Control)
        For Each c As Control In ct.Controls
            If TypeOf c Is TextBox Then
                c.Text = ""
            Else
                Clr(c)
            End If
        Next
    End Sub



10



Тамахоме

0 / 0 / 0

Регистрация: 12.01.2018

Сообщений: 1

12.01.2018, 22:37

19

VB.NET
1
2
3
4
5
6
7
8
  Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        TextBox1.Clear() 
        TextBox2.Clear()
        TextBox3.Clear()
        TextBox4.Clear()
        TextBox5.Clear()
        TextBox6.Clear()
    End Sub

Данный вариант не работает. Сам искал решение данной проблеммы, так как PictureBox, Label и прочее чистит, а текстовое нет. Так как нету такого метода для ТекстБокса. Решение проблемы может быть таким (название поля естественно у Вас будет свое):

VB.NET
1
2
3
4
5
6
7
8
9
10
Private Sub cmdClearData_Click()
    txtParA1.Text = ""
    txtParA2.Text = ""
    txtParA3.Text = ""
    txtParA4.Text = ""
    txtParB1.Text = ""
    txtParB2.Text = ""
    txtParB3.Text = ""
    txtParB4.Text = ""
End Sub



0



TG59

0 / 0 / 0

Регистрация: 10.10.2019

Сообщений: 1

24.09.2021, 23:52

20

Попробуете этот вариант.

VB.NET
1
2
3
For Each tb As TextBox In Me.Controls.OfType(Of TextBox)()
            tb.Clear()
 Next



0



Обычно для очистки старого содержимого текстового поля (элемент управления ActiveX) вы должны войти в текстовое поле, выбрать все содержимое и затем нажать клавишу Backspace или Delete. Как быстро очистить все содержимое текстового поля? Эта статья покажет вам метод VBA для быстрой очистки содержимого текстового поля, просто дважды щелкнув по нему.

Очистить содержимое текстового поля при нажатии с кодом VBA


Очистить содержимое текстового поля при нажатии с кодом VBA

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

1. Если текстовое поле уже существует на листе, включите режим «Дизайн», нажав Застройщик > Режим проектирования. Смотрите скриншот:

Или вы также можете вставить текстовое поле, нажав Застройщик > Вставить > Текстовое поле (элемент управления ActiveX). Смотрите скриншот:

2. Щелкните текстовое поле правой кнопкой мыши и выберите Просмотреть код из контекстного меню. Смотрите скриншот:

3. В дебюте Microsoft Visual Basic для приложений В окне кода замените исходный код VBA в окне кода приведенным ниже кодом VBA.

Код VBA: очистить содержимое текстового поля при двойном щелчке по нему

Private Sub TextBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
  If Not iGblInhibitTextBoxEvents Then
    TextBox1.Value = ""
  End If
End Sub

Внимание: В коде TextBox1 — это имя текстового поля, из которого вы очищаете содержимое. Пожалуйста, измените его на свой собственный.

4. нажмите другой + Q ключи для выхода из Microsoft Visual Basic для приложений окно.

5. Выключите режим дизайна.

С этого момента при двойном щелчке по текстовому полю его содержимое будет немедленно очищено.


Статьи по теме:

  • Как автоматически выбрать текст текстового поля, когда он выбран в Excel?
  • Как автозаполнить текстовое поле при вводе в Excel?
  • Как объединить тексты из нескольких ячеек в текстовое поле в Excel?
  • Как отключить редактирование в текстовом поле, чтобы пользователь не вводил данные в Excel?
  • Как отформатировать текстовое поле в процентах в Excel?

Лучшие инструменты для работы в офисе

Kutools for Excel Решит большинство ваших проблем и повысит вашу производительность на 80%

  • Снова использовать: Быстро вставить сложные формулы, диаграммы и все, что вы использовали раньше; Зашифровать ячейки с паролем; Создать список рассылки и отправлять электронные письма …
  • Бар Супер Формулы (легко редактировать несколько строк текста и формул); Макет для чтения (легко читать и редактировать большое количество ячеек); Вставить в отфильтрованный диапазон
  • Объединить ячейки / строки / столбцы без потери данных; Разделить содержимое ячеек; Объединить повторяющиеся строки / столбцы… Предотвращение дублирования ячеек; Сравнить диапазоны
  • Выберите Дубликат или Уникальный Ряды; Выбрать пустые строки (все ячейки пустые); Супер находка и нечеткая находка во многих рабочих тетрадях; Случайный выбор …
  • Точная копия Несколько ячеек без изменения ссылки на формулу; Автоматическое создание ссылок на несколько листов; Вставить пули, Флажки и многое другое …
  • Извлечь текст, Добавить текст, Удалить по позиции, Удалить пробел; Создание и печать промежуточных итогов по страницам; Преобразование содержимого ячеек в комментарии
  • Суперфильтр (сохранять и применять схемы фильтров к другим листам); Расширенная сортировка по месяцам / неделям / дням, периодичности и др .; Специальный фильтр жирным, курсивом …
  • Комбинируйте книги и рабочие листы; Объединить таблицы на основе ключевых столбцов; Разделить данные на несколько листов; Пакетное преобразование xls, xlsx и PDF
  • Более 300 мощных функций. Поддерживает Office/Excel 2007-2021 и 365. Поддерживает все языки. Простое развертывание на вашем предприятии или в организации. Полнофункциональная 30-дневная бесплатная пробная версия. 60-дневная гарантия возврата денег.

вкладка kte 201905


Вкладка Office: интерфейс с вкладками в Office и упрощение работы

  • Включение редактирования и чтения с вкладками в Word, Excel, PowerPoint, Издатель, доступ, Visio и проект.
  • Открывайте и создавайте несколько документов на новых вкладках одного окна, а не в новых окнах.
  • Повышает вашу продуктивность на 50% и сокращает количество щелчков мышью на сотни каждый день!

офисный дно

Комментарии (0)


Оценок пока нет. Оцените первым!

Хитрости »

5 Май 2011              115239 просмотров


Очень часто при работе с формами(UserForm) приходится заполнять значениями КомбоБоксы(ComboBox) и ТекстБоксы(TextBox). Иногда однотипными данными. Или очистить их все после выполнения какого-либо действия. А может проверить, все ли элементы заполнены, прежде чем продолжать действие. Если КомбоБоксов/ТекстБоксов пару штучек — не проблема

TextBox1 = ""
TextBox2 = ""

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

Sub All_TextBoxes()
    Dim oControl As Control
    For Each oControl In UserForm1.Controls
        If TypeOf oControl Is MSForms.TextBox Then
            oControl.Value = ""
        End If
    Next oControl
End Sub

В примере элементы формы очищаются, но в код можно подставить любое действие — добавление нового элемента списка(для ComboBox), поменять представление данных в TextBox, проверить наличие данных в проверяемом элементе и т.д. Тут уж зависит от поставленной задачи. Конечно, подобным способом можно проделать разные действия и с остальными элементами формы. Только надо будет заменить тип для проверки элементов:

ComboBox - MSForms.ComboBox
CheckBox - MSForms.CheckBox
CommandButton - MSForms.CommandButton
Frame - MSForms.Frame
Image - MSForms.Image
Label - MSForms.Label
ListBox - MSForms.ListBox
MultiPage - MSForms.MultiPage
SpinButton - MSForms.SpinButton
TabStrip - MSForms.TabStrip
ToggleButton - MSForms.ToggleButton

Это не единственный способ проделывания однотипных действий с элементами формы. Код ниже использует имена элементов для обращения к ним:

Sub All_TextBoxes()
    Dim li As Long
    For li = 1 To 10
        UserForm1.Controls("TextBox" & li).Value = li
    Next li
End Sub

Недостаток данного метода: имена элементов должны строго соответствовать используемым в коде и лишь нумерация на конце имени должна различаться. За нумерацию отвечает переменная li и, конечно, цикл, в котором задается начальное и конечные значения. В примере ТекстБоксам с именами от «TextBox1» до «TextBox10» будут подставлены значения номеров самих ТекстБоксов. Но такой недостаток может быть очень полезным. Например, если необходимо проделать действия не над всеми ТекстБоксами, а лишь над некоторыми из них. Тогда все, что необходимо дать ТекстБоксам определенные имена с нумерацией(«ToDB1″,»ToDB2» и т.д.) и в зависимости от имени можно проделывать различные действия: стирать значения, менять свойства элементов и т.д.
И есть еще один плюс такого подхода: когда необходимо заполнить значения ТекстБоксов значениями ячеек. Скажем надо заполнить 10 ТекстБоксов(с именами TextBox1, TextBox2, TextBox3 и т.д.) из ячеек диапазона A2:A11 листа с именем «Лист2″(т.е. из 10 ячеек, начиная с ячейки A2). Код будет выглядеть так:

Sub Fill_TextBoxes_FromCells()
    Dim li As Long
    For li = 1 To 10
        UserForm1.Controls("TextBox" & li).Value = Sheets("Лист2").Range("A" & li).Value
        'или применить Cells вместо Range
        'UserForm1.Controls("TextBox" & li).Value = Sheets("Лист2").Cells(li, 1).Value
    Next li
End Sub

Подробнее про обращение к диапазонам из VBA можно узнать из этой статьи: Как обратиться к диапазону из VBA

Скачать пример

  Tips_Macro_WorkWithGroupControls.xls (51,5 KiB, 4 052 скачиваний)

P.S. Небольшое дополнение: нужные элементы можно просто помещать внутрь объекта Frame. Тогда можно будет применять цикл исключительно по элементам внутри этого Frame(предположим, что Frame называется Frame1):

Sub All_TextBoxes_InFrame()
    Dim oControl As Control
    For Each oControl In Frame1.Controls
        If TypeOf oControl Is MSForms.TextBox Then
            oControl.Value = ""
        End If
    Next oControl
End Sub

Кстати говоря, примерно так же можно перебрать элементы ActiveX не на форме, а на листе(вставляются на лист через вкладку Разработчик(Developer)Вставить(Insert)Элементы ActiveX(ActiveX Controls)). Например, снимем флажки со всех CheckBox-ов:

Sub Off_ActiveXCheckBoxes()
    Dim oControl
    'цикл по всем объектам на листе
    For Each oControl In ActiveSheet.DrawingObjects
        'определяем тип объекта - должен быть OLEObject(так определяется ActiveX)
        If TypeName(oControl) = "OLEObject" Then
            'необходимо дополнительно проверить тип элемента
            If TypeOf oControl.Object Is MSForms.CheckBox Then
                oControl.Object.Value = 0
            End If
        End If
    Next oControl
End Sub

Для этих элементов на листе в строке TypeOf oControl.Object Is MSForms.CheckBox для проверки типа(MSForms.CheckBox) используются те же значения, что и для контролов на форме. Перечень приведен выше.
Но помимо ActiveX(к слову устаревших и не рекомендованных к использованию) на листе могут быть и другие, более новые флажки — элементы форм(вставляются на лист через вкладку Разработчик(Developer)Вставить(Insert)Элементы управления формы(Form Controls)). К ним подход уже другой:

Sub Off_ShapeCheckBoxes()
    Dim oControl
    'цикл по всем объектам на листе
    For Each oControl In ActiveSheet.DrawingObjects
        'определяем тип объекта - если это Элемент форм, то будет указание на конкретный тип
        If TypeName(oControl) = "CheckBox" Then
            oControl.Value = 0
        End If
    Next oControl
End Sub

В данном случае для определения конкретного типа контрола используется TypeName. В коде выше нам нужны CheckBox-ы и на них и проверяем. А вот список основных элементов форм, которые доступны по умолчанию для всех версий для вставки на лист:
Button — кнопка
DropDown — поле со списком
CheckBox — флажок
Spinner — счетчик
ListBox — список
OptionButton — радиокнопка
GroupBox — группа(рамка)
Label — надпись
ScrollBar — полоса прокрутки

Если совместить, то можно снять флажки со всех checkBox-ов — и ActiveX и Элементов форм:

Sub Off_AllCheckBoxes()
    Dim oControl
    'цикл по всем объектам на листе
    For Each oControl In ActiveSheet.DrawingObjects
        'определяем тип флажка: ActiveX или Элемент форм
        Select Case TypeName(oControl)
        Case "OLEObject"    'ActiveX - необходимо дополнительно проверить тип элемента
            If TypeOf oControl.Object Is MSForms.CheckBox Then
                oControl.Object.Value = 0
            End If
        Case "CheckBox"     'Элемент форм CheckBox
            oControl.Value = 0
        End Select
    Next oControl
End Sub

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


Статья помогла? Поделись ссылкой с друзьями!

  Плейлист   Видеоуроки


Поиск по меткам



Access
apple watch
Multex
Power Query и Power BI
VBA управление кодами
Бесплатные надстройки
Дата и время
Записки
ИП
Надстройки
Печать
Политика Конфиденциальности
Почта
Программы
Работа с приложениями
Разработка приложений
Росстат
Тренинги и вебинары
Финансовые
Форматирование
Функции Excel
акции MulTEx
ссылки
статистика

Even after all this time, this is one of the main results in google, so I’d like to share information about the matter that might make things easier for people who could reach the page in the future after a couple of hours on the matter:

The method below works only for unbounded controls:

Private Sub Text1_GotFocus()
If Me.Text1.Value = "First" Then
    Me.Text1.Value = ""
End If 
End Sub 

What I did was to create a function that goes through all controls, checks if they are bounded, and if not bounded, attributes the default value:

NOTES ON THE FUNCTION BELOW:
1- I think «DefaultValue» is better then «», but that would work too.
2- The «Select case» is needed otherwise the .ControlSource property is not found.
3- You could check the bound of the control in each type if needed, I only had textboxes with bound.
4- The «Me.Refresh» makes bounded controls to be set to default, as long the bound is related to controls in the same form.

Function ClearControls(frm As Form)
Dim ctrl As Control
For Each ctrl In frm.Controls
    Select Case ctrl.ControlType
            Case acTextBox
                If ctrl.ControlSource = Null Then
                    ctrl.Value = ctrl.DefaultValue
                End If
            Case acOptionGroup, acComboBox, acListBox
                ctrl.Value = Null
            Case acCheckBox
                ctrl.Value = False
        End Select
Next
Me.Refresh
End Sub

So, on the click event code I just called the ClearControls function as follows:

ClearControls Me

This also makes possible to re-use the function in other controls/events.

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 201


Репутация:

9

±

Замечаний:
0% ±


Excel 2010

Приветствую всех!

Очередная сложность, с которой столкнулся — ох тяжко идут формы пока что. :))
Есть текстбокс. Изначально в нем текст, дабы люди понимали, что туда вводить. При клике на текстбокс текст никуда не исчезает — оно и понятно.
Как сделать так, чтобы исчезал? :)

Думаю, пример тут не нужен, но если надо, могу набросать.

Буду признателен! :)


e-mail: akobir.ismailov@gmail.com

Понравилась статья? Поделить с друзьями:
  • Text options in excel
  • Textbox vba excel value
  • Text only in excel cell
  • Textbox text excel vba
  • Textbox setfocus vba excel