Ответы пользователя по тегу Visual Basic
  • Как запретить изменять тему письма и список адресатов в MS Outlook?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Видимо, не всё так просто.
    Если открыть вкладку "Разработчик", то можно увидеть конструктор форм. Или как-то так перед отправкой письма:
    If TypeOf Application.ActiveWindow Is Outlook.Inspector Then _
      Set obj = Application.ActiveInspector.CurrentItem
    
    If Not obj Is Nothing Then
      If Not obj.Subject = NewSubject Then
        obj.Subject = NewSubject
        obj.Save
      End If
    End If
    Ответ написан
    Комментировать
  • Как на VBA написать массив?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Так объявляются статические массивы (границы массива изменять нельзя):
    ' 1 - нижняя граница массива, 5 - верхняя граница массива
    Dim arr(1 To 5) As Integer
    ' Если не объявлять нижнюю границу,
    ' то по умолчанию в Excel нижняя граница массива будут начинаться с 0 до 5

    Динамические массивы объявляются безразмерными, затем для изменения границ массива используется оператор ReDim. Параметр Preserve можно опустить:
    Dim arr() As Integer
    b = 5
    ' Параметр Preserve нужен для сохранения значений в массиве при изменении верхней границы
    ReDim Preserve arr(1 To b)

    ЗЫ: Если всё понятно, внизу ответа нужно нажать кнопку "Отметить решением" :)
    Ответ написан
    Комментировать
  • Как правильно составить запрос с датой в vba access?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Создавал дату в виде dt = DateSerial(2015, 12, 31), затем в запросе SQL обращался: "SELECT ... #" & Format(dt, "yyyy-mm-dd") & "#". С другими разделителями эффекта не достиг.
    Ответ написан
    Комментировать
  • Как создать универсальный шаблон письма в Word'е?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    1. Можно промаркировать жёлтый текст и сделать замену прямо в Word (в примере 1 замена во всём тексте), или использовать закладки (Вставка (меню) -> Ссылки (группа) -> Закладки), или использовать инструмент Слияние и брать данные из файла Excel (без VBA). При слиянии связи могут глючить + конечный документ необходимо Объединить (как текущую запись), чтобы при работе с документом поля не обновлялись (Слияние использовать не советую). К тому же поля не поддерживают неразрывные символы Word'а Chr(160) и Chr(30).
      Примечание к документам слияния

      В таблице Excel есть поле Дата_1 (тип Дата) и поле Дата_2 (тип Дата). Если значение Дата_1 равно 43003 и значение Дата_2 равно 44764, то в формула ниже посчитается с ошибкой (будет значение ИСТИНА):
      { IF { MERGEFIELD Дата_1 \@"DD.MM.YYYY' г.'"  \* MERGEFORMAT } = { MERGEFIELD Дата_2 \@"DD.MM.YYYY' г.'"  \* MERGEFORMAT } "ИСТИНА" "ЛОЖЬ" }

      Option Explicit
      '123456789012345678901234567890123456h8nor@ya567890123456789012345678toster56789
      
      Sub Replacement_tags()
        Dim Content_Find As Find ' Объект Find
        
        Set Content_Find = ActiveDocument.Content.Find
        With Content_Find ' Найти маркер
          .ClearFormatting: .Replacement.ClearFormatting ' Очистить формат
          .MatchWildcards = False ' ВАЖНО! Отключить Подстановочные знаки
          
          .Text = "[Шапка]": .Replacement.Text = "Начальнику управления..."
          .Execute Forward:=True, Replace:=wdReplaceAll ' Заменить все маркеры [Шапка]
          
          ' Хитрость: перемещение курсора в конец заменённого текста
          .Execute FindText:=.Replacement.Text, _
            Forward:=True, Wrap:=wdFindStop, Replace:=wdReplaceNone
          .Parent.Select ' Выделяем текст для управления курсором
          'Selection.Collapse Direction:=wdCollapseEnd ' Курсор в конец найденного
        End With
      End Sub
    2. Можно сразу заменить на дублированный текст:
      .Replacement.Text = "Начальнику управления..." & String(3, Chr(13)) & "Начальнику управления..."
      или вводить количество дублей в переменную Text перед заменой:
      ' Chr(13) - код символа возврата каретки. В других языках более привычная запись "\r"
      
        CapText = "Начальнику управления..."
        CapСount = InputBox("Введите количество 'Шапок'", , 1)
        If Not CInt(Val(CapСount)) = CapСount Then _
          MsgBox "Введите целое число", vbCritical: Exit Sub _
        Else Text = CapText
        
        While CapСount > 1
          Text = Text & String(3, Chr(13)) & CapText
          CapСount = CapСount - 1
        Wend
    3. Таблицу можно также подтягивать через Слияние (точнее там создаётся объект OLE, которой глючит больше чем обычные поля - в основном это удержание файла Excel, откуда берутся данные). Удобнее программно создавать таблицу:
      ' Используем хитрость из п.1, если планируем создать таблицу в месте маркера
        
        Set tblNew = ActiveDocument.Tables.Add(Selection.Range, 3, 2)
        With tblNew
          .Columns(1).PreferredWidth = CentimetersToPoints(4) ' Колонка 1, Ширина 4 см
          .Borders(wdBorderTop).LineStyle = wdLineStyleNone ' Границы таблицы, например
          .Borders(wdBorderHorizontal).LineStyle = wdLineStyleSingle
          .Borders(wdBorderVertical).LineStyle = wdLineStyleDot
          For i = 1 To 2
            .Cell(1, i).Range.Text = "Строка 1; #" & i
          Next i
          .Cell(1, 1).Range.InsertAfter Chr(13) & "Строка 2" ' Добавить текст
          .Cell(tblNew.Rows.count, tblNew.Columns.count).Range.InsertAfter "Последняя ячейка"
        End With
    4. Чтобы основной текст нельзя было отредактировать, проще всего создать шаблон Word с поддержкой макросов, основную процедуру (автозапуск) разместить в модуле ThisDocument:
      Private Sub Document_Open()
        Replacement_tags ' Процедура из п.1
      End Sub
      Данные для заполнения шаблона можно поместить в отдельный файл.

    +
    Как использовать отладчик:
    1. Открыть MS Word, в тексте написать маркер [Шапка]
    2. Открыть VBA в приложении (Alt+F11)
    3. Выбирать в меню Insert -> Module
    4. Вставить процедуру (из п.1)
    5. Нажать F5 (запустится процедура, в которой установлен курсор)
    Ответ написан
    Комментировать
  • Быстрый поиск и замена в Word?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Вероятно, проблема в использовании объекта Selection. Код для VBA:
    Option Explicit
    '123456789012345678901234567890123456h8nor@ya567890123456789012345678toster56789
    
    Sub Replacement_tags()
      Dim Content_Find As Find ' Объект Find (в VBScript переменные объявляются без указания типа)
      Const wdFindContinue = 2 ' для VBScript
      Const wdReplaceAll = 1 ' для VBScript
      
      ' Set objWrd = CreateObject("Word.Application") ' В MS Word объявлять не нужно
      ' в VBScript всё равно придётся открывать файл, так что objDoc = objWrd.ActiveDocument
      ' Set objDoc = objWrd.Documents.Open(Filename:="C:\FullName.doc")
      Set Content_Find = ActiveDocument.Content.Find ' в VBScript - objDoc.Content.Find
      
      With Content_Find ' Найти метку
        .ClearFormatting: .Replacement.ClearFormatting ' Очистить формат
        .MatchWildcards = False ' ВАЖНО! Отключить Подстановочные знаки
        .Replacement.Font.Color = wdColorAutomatic ' wdColorAutomatic = -587137025
        
        .Text = "p***p": .Replacement.Text = "newText"
        .Execute2007 Forward:=True, Replace:=wdReplaceAll, Wrap:=wdFindContinue
      End With
    
      ' Подсветить ".Text" в документе Word 2007+ (визуальная отладка)
      With Content_Find ' Отменяется после метода "Execute" или "ClearHitHighlight"
        .Parent.HomeKey wdStory ' wdStory = 6
        .HitHighlight .Text, wdColorTan ' wdColorTan = &H99CCFF
      End With
    End Sub

    Думаю, что метод .Selection.EndKey не нужен, т.к. в вашем примере указана замена по всему тексту (.Replace = 1), а поиск начинается с позиции курсора, т.е. сначала. Цикла поиска по тексту нет, так что .Wrap можно не использовать.

    Вариант проще
    : можно перед заменой отключить обновление экрана приложения objWrd.ScreenUpdating = False.
    Ответ написан
    Комментировать
  • Excel VBA выделяющая ячейку со значением?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Вы усложняете задачу. Для этого нужен не VBA, а условное форматирование. Видео смотреть с 2:02. Особенности:
    • В примере указана ссылка на ячейку с текущей датой. Если необходимо привязаться к дате на ПК, то формула в 2:44 будет: =$E5<СЕГОДНЯ()
    • В Excel даты представляются в виде чисел. Поэтому для выделения цветом разницы в 30 дней (и старше) задаём формулу для условного форматирования: =$E5<СЕГОДНЯ()-29
    Ответ написан
    Комментировать
  • Написание макросов Excel, какой скилл нужен?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Как и в других высокоуровневых языках:
    1. Понимание основ программирования (переменные/операторы/логические операции/циклы)
    2. Понимание объектной структуры
    3. Понимание поставленной задачи

    Если есть время читайте книги "Книги, методички для изучения VBA с нуля?", если нет - ищите решение задачи в и-нете. Серьёзные задачи макрорекодор выполнять в принципе не может, - он не программист.
    Ответ написан
    Комментировать
  • Как объединить ячейки с одинаковыми значениями в Excel с помощью VBA?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Option Explicit
    Option Base 1
    '123456789012345678901234567890123456h8nor@ya567890123456789012345678toster56789
    
    Sub Merge_by_Rows() ' Без форматирования границ
      Dim i As Integer, j As Integer, cnt As Integer
      Dim arr() As Variant, s As String
      
      With ActiveSheet.UsedRange ' Кол-во столбцов определяется по 1-й строке
        arr = Range(Cells(1, 1), Cells(.Rows.Count + 1, Range("A1").End(xlToRight).Column))
      End With
      
      cnt = 1: s = get_Row(arr, cnt)
      For i = LBound(arr, 1) + 1 To UBound(arr, 1)
        If get_Row(arr, i) <> s Then
          For j = LBound(arr, 2) To UBound(arr, 2)
            With ActiveSheet.Range(Cells(cnt, j), Cells(i - 1, j)).Offset(, UBound(arr, 2))
              .Merge
              .HorizontalAlignment = xlCenter
              .VerticalAlignment = xlCenter
              .Value = arr(cnt, j)
            End With
          Next j
          cnt = i: s = get_Row(arr, cnt)
        End If
      Next i
    End Sub
    
    Function get_Row(ByVal arr As Variant, ByVal num_Row As Integer) As String
      Dim j As Integer
      
      For j = LBound(arr, 2) To UBound(arr, 2)
        get_Row = WorksheetFunction.Trim(get_Row & " " & arr(num_Row, j))
      Next j
    End Function

    Процедуру выполнять на активном листе.
    Ответ написан
    Комментировать
  • Excel 2010 и 2013 по разному кодируют цвета? И вообще где почитать про различия для разных версий офиса?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Начну с того, что не удачно привязываться к цветам в 99% (по праздникам на сайте github блок contributions заливался жёлтым, в обычные дни - зелёным).
    Каждая версия программы Excel имеет свою объектную структуру, в которой могут быть как нововведения, так и изменения. Нововведения в предыдущих версиях вообще не будут работать, а изменения могут работать криво (т.к. объектная структура может измениться). Различия между Excel 2010 и 2013 на вскидку указать сложно, - разве что числовые значения цветов и сводные таблицы. Различий между Excel 2003 и 2007 гораздо больше: начиная от записи формул условного форматирования и заканчивая объектной моделью ribbon-меню. В процессе отладки при выявлении конкретной проблемы можно просто сделать вилку:
    Select Case Val(Application.Version)
      Case 12
        ' Excel 2007
      Case 14
        ' Excel 2010, VB 7.0
      Case 15
        ' Excel 2013
      Case 16
        ' Excel 2016, VB 7.1
      Case 17
        ' Excel 2019
      Case Else
        ' Прочие
    End Select

    Куда большая пропасть при обработке кода на x86 и x86_64. В вашем конкретном случае посоветую заменить числовые цвета на индексы палитры.
    Cells(row, column).Interior.ColorIndex ' принимает значения от 0 до 56
    Ответ написан
    2 комментария
  • Как решить проблемы с кодировкой в VBA при работе на win и на mac?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    1. Сохраните в винде в текстовый файл с кодировкой UTF, затем на маке откройте и замените код (вручную)
    2. Поищите программу win2mac, типа CVT32
    3. Или Какой выбрать редактор кода для Mac с поддержкой Win-1251?
    Ответ написан
    6 комментариев
  • Как перейти на новую строку после заполнения предыдущей EXCEL VBA?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Во первых, чтобы не копировать иероглифы, нужно в окне с кодом переключиться на русский язык.
    Во вторых, в данном случае вместо Application лучше написать WorksheetFunction.
    В третьих, у вас в коде написано:
    ' НомерСтроки - Кол-во непустых ячеек в колонке "1" + 1, а не номер первой пустой строки

    Если в 1-й колонке таблицы есть хотя бы одна пустая строка, то намерения вставить новую запись в конец таблицы будут не выполнены. Поэтому замените на:
    ' НомерСтроки - Номер первой пустой строки на рабочем листе
    НомерСтроки = ActiveSheet.Cells.SpecialCells(xlLastCell).Row + 1


    UPD: Количество непустых ячеек (при их наличии) к колонке активной ячейки можно посчитать:
    КолНепустых = ActiveCell.SpecialCells(xlCellTypeLastCell).Row - _
      ActiveCell.EntireColumn.SpecialCells(xlCellTypeBlanks).Count
    Ответ написан
    Комментировать
  • Как обратиться к кастомному элементу на панели Excel?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Мне когда-то очень помог сайт: www.rondebruin.nl/win/s2/win003.htm, внизу этой страницы есть архив DropDown.zip с примерами создания списков.
    1. За формирование списка в файле Ron_DropDown.xlsm отвечает процедура DDListItem (все процедуры, связанные с Ribbon-меню, обязательно должны содержать параметр "control As IRibbonControl"; подсказки в своём проекте покажет RibbonXMLEditor).
    2. Элементы недостаточно задать параметрами, - их нужно нарисовать. Для обновления Ribbon-меню в файле Jim_DynDropDown.xlsm отвечает процедура RedoRib, которая содержит единственный метод "rib.Invalidate". Если возникнет ошибка (в процессе отладки) и объект примет значение "rib = Nothing", то лента станет недоступной.

    Для изучения примеров вам понадобится RibbonXMLEditor.

    0_1372fc_c4811587_XXXL
    На сайте: fluentui.blogspot.ru есть русскоязычная информация о Ribbon-меню.
    Ответ написан
    Комментировать
  • Как пронумировать ячейки по содержимому?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Чтобы найти подстроку в строке с помощью оператора Like (Примеры), необходимо подстроку выделить символом звёздочки "*" с обеих сторон. Нужно помнить, что регистр букв необходимо соблюдать.
    Рекомендую также в самом начале модуля вписать строку Option Explicit, что позволит избежать обращения к несуществующим переменным (все переменные должны быть объявлены через оператор Dim).
    Можете попробовать использовать регулярные выражения, как посоветовали ниже, но в данном контексте можно обойтись и без них.
    Проще всего использовать вариант #3 (который предложили ниже), но на слабом ПК будет тормозить.
    Ответ написан
    Комментировать
  • Excel VBA почему не выполняется поиск в объединенных ячейках?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Замените SearchOrder:=xlByColumns на SearchOrder:=xlByRows
    и удалите строки Cells.FindNext(After:=ActiveCell).Activate
    Ответ написан
  • Где могут помочь решить такую задачу?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Если 2-ю дробь принять за некую функцию f, то как уже написали, используем цикл для суммирования:
    Dim y as byte, f as double
    ' ... цикл "For y" будет вложен в цикл: For x = 2 To 6
    For y = 1 To 7
      f = f + y
    Next y
    Ответ написан
    Комментировать
  • VBA Как сохранить значение оператора в массив на каждом шаге цикла?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Надеюсь вы учитываете, что Me!ОрганРегУчета должен иметь тип String!
    Вот простой вариант выполнения задания:

    Option Explicit ' Обязательное объявление переменных
    ' чтобы избежать ошибок, и так удобнее пользоваться отладчиком
    '123456789012345678901234567890123456h8nor@ya567890123456789012345678toster56789
    
    Sub Save_in_avArr() ' Процедура сохранения в массив avArr
    ' значений из Me!ОрганРегУчета и присвоение массиву avArr1
    ' верхней границы массива avArr
      Dim i As Integer, avArr() As String, avArr1 As Variant
      
      ' По умолчанию функция Split использует разделитель "символ ПРОБЕЛ"
      avArr = Split(Me!ОрганРегУчета)
      ' Передаваемая строка Me!ОрганРегУчета стала массивом avArr
      ' Нижняя граница массива LBOUND(avArr) = 0
      
      ReDim avArr1(UBound(avArr)) ' Создаём массив avArr1 с верхней границей как у avArr
      ' Заполняем массив avArr1 от 0 до e (в вашем случае)
      For i = LBound(avArr1) To UBound(avArr1)
        ' ...
        ' avArr1(i) = i
      Next i
      
      ' Например, выводим на экран значения массива avArr1
      MsgBox "№ имеет значение: " & Join(avArr, vbCr & "№ имеет значение: ")
    End Sub

    Обратите внимание на объявление переменных:
    ' Иногда вместо объявления динамического массива текстового типа String
    Dim avArr() As String
    ' Удобнее использовать универсальный тип переменной Variant
    Dim avArr() As Variant
    ' Тогда в ходе выполнения можно удалить из массива, например, элементы с 0 по 2
    ReDim Preserve avArr(3 To UBound(avArr))
    ' Примечание: в многомерных массивах изменять можно только последнюю размерность
    
    ' Важно! Если не объявлять динамический массив, а поместить его в тип переменной
    Dim avArr As Variant
    ' то работа со значениями массива будет медленнее примерно в 18 раз
    Ответ написан
    Комментировать
  • Стоит ли серьезно изучать VBA?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    1) Да, особенно Excel. Думаю не стоит рассказывать о том, что Excel удобнее своих аналогов.
    2) Нет, вероятно это слухи. Можно даже сказать, что языки несовместимы.
    3) Нет. Для того чтобы работать во фрилансе, нужно уметь писать на тех языках, на которых предполагается выполнения задания. Как правило VBA там нет.

    В целом с помощью VBA можно решать другие задачи, например для AutoCAD. Можно подключать сторонние библиотеки и работать с их функциями. Да и в любой области, где производительность не играет особой роли, а важен результат. Неплохо его знать для того, чтобы придя за чужой компьютер, можно было не разворачивать среду программирования, а воспользоваться ей из установленного пакета MS Office (который есть на любом ПК под Windows).

    VBA можно понять самому (достаточно почитать справку в и-нете). Что мешает после VBA освоить другой инструмент (выучить ещё один язык)?

    Ах, да! Если действительно вас интересует перспективный язык - смотрите в сторону разработки мобильных приложений (каждая вторая компания их выпускает).
    Ответ написан
    Комментировать
  • Как использовать в vba функцию COUNTA?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Согласно линку...
    Ок, пишем. Получается
    MsgBox Application.WorksheetFunction.CountA("A1:F1")

    Вы передаёте функции значение A1:F1, а вам нужно передать диапазон ячеек Range("A1:F1"); также, как вы делали со строкой Rows(1).
    Ответ написан
    Комментировать
  • Книги, методички для изучения VBA с нуля?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Очень помогла разобраться со структурой Excel книга ISBN 5-8459-0921-Х (печатная версия досталась от друга). В главе 11 написано как подключаться к БД через ADO. Примеры из книги.
    Пишу для версии офиса 2007+ (от которого многие плюются, чтобы ковыряться в структуре файла необходимо разбираться в xml), но если требуется использовать возможности нового офиса, например ribbоn-меню, то тут только английская литература ISBN 978-0-470-04643-2. Примеры из книги.
    ЗЫ: Ещё советуют Уокенбаха, но лично я его не читал.
    ЗЫЫ: Для прочих приложений (Word, Outlook) толковых книг не искал, - было достаточно и-нета.
    Ответ написан
    Комментировать
  • Как отправить email с вложение из Outlook с помощью VBA?

    honor8
    @honor8
    Принципы быстродействия VBA в описании
    Макрос отправляет письмо на "Место события" при появлении оповещения о событии.

    ' Процедуру разместить в модуле ThisOutlookSession.
    ' Уровень безопасности макросов (без цифровой подписи) - низкая.
    Option Explicit
    '123456789012345678901234567890123456h8nor@ya567890123456789012345678toster56789
    
    Private Sub Application_Reminder(ByVal Item As Object)
      Dim objMsg As MailItem, sAttachment As String
      Set objMsg = Application.CreateItem(olMailItem)
      
      ' Путь к файлу вложения (Указанный файл "Текст.txt" находится на Рабочем столе)
      sAttachment = CreateObject("Wscript.Shell").SpecialFolders.Item("Desktop") & "\Текст.txt"
      
      If Item.MessageClass <> "IPM.Appointment" Then
        Exit Sub
      End If
      If Item.Categories <> "Automated Email Sender" Then
        Exit Sub ' Закомментировать, если у события не указана категория
      End If
      
      With objMsg
        .To = Item.Location ' Место события
        .Subject = Item.Subject
        .Body = Item.Body
        ' Если файл вложения существует, то добавить в письмо
        If Len(sAttachment) > 0 Then .Attachments.Add sAttachment
        '.Display '' Показать письмо (для отправки вручную; вместо '.Send)
        .Send
      End With: Set objMsg = Nothing
    End Sub

    Заметка: Могут быть проблемы при создании писем по просроченным событиям.
    Ответ написан
    2 комментария