Выбрать дату в календареВыбрать дату в календаре

Страницы: 1 2 3 4 5 6 7 8 9 10 11 ... 29 След.
Извлечь дополнительные данные из функции пользователя
 
Спасибо, МатросНаЗебре за ваши варианты, буду посмотреть ;) , но скорее всего остановлюсь на варианте публичной переменной, ведь все прочие влияют (своей переделкой) на работу функции в других местах, надо будет там что-то изменять, верно ведь? Кстати, проверяя свое предложение из поста №6, додумался, что эту переменную еще стоит очищать где-либо выше, сама ведь она не очистится
Извлечь дополнительные данные из функции пользователя
 
Спасибо всем откликнувшимся, прошу прощения за запоздалый отклик - не было доступа к ПК, а со смарта не наотвечаешься 8-0 . По просьбе уважаемого Sanja прилагаю пример и описываю задачу более подробно. Итак, есть диапазон с данными по реестрам за достаточно длинный период, номера реестров ежегодно обнуляются, это важно. Необходимо при выполнении условия (не относящегося к задаче) окрасить ячейки определенного реестра. Сейчас это реализовано приблизительно так:
Код
x = Range("A1:J" & Cells(Rows.Count, 1).End(xlUp).Row).Value
    
    For i = 1 To UBound(x) 'расчет номера 1 строки реестра
        If x(i, 1) = "ГНН-0001" And CDate(x(i, 3)) = #1/1/2023# Then Exit For
    Next i
                    
    With Cells(i, 1).Resize(UBound(ArrAutofilterNew(x, "1=" & "ГНН-0001", "3=" & #1/1/2023#)), 10).Interior
    'раскраска ячеек
    End With
циклом вычисляю начало диапазона (просто поиск номера не подойдет из-за ежегодного обнуления), далее с помощью искомой функции определяю размер массива (в данном случае только для этого) ну и далее по задаче. Подумал о том, что код функции, отрабатывая, вычисляет положение отфильтрованного массива в исходном и хорошо было бы иметь возможность вытащить эти данные. Ни для чего другого, просто для исключения цикла и все. Уфф, вроде объяснил. Собственно, пока не было доступа к ПК, 2 "кривых" способа решения я придумал: во-первых можно сделать копию функции (изменив, разумеется имя) и вместо ArrAutofilterNew = newarr написать что-то типа ArrAutofilterNew2 = r & " " & Ubound(newarr), где r это вычисленное значение i как в посте №1, а далее использовать через Split, но разве это дело "модифицировать" функцию под узкую задачу? Или объявить публичную переменную в коде функции и использовать ее, предварительно запустив функцию ad=ArrAutofilterNew (...) . Чуть лучше, но наверняка с точки зрения гуру не то 8-0. Надеюсь, объяснил понятно и подробно, если есть более красивый и, самое главное, более грамотный вариант, буду рад его увидеть
Извлечь дополнительные данные из функции пользователя
 
Доброго времени суток, уважаемые форумчане. Пытаюсь использовать функцию пользователя, взятую с сайта:https://excelvba.ru
Код
Function ArrAutofilterNew(ByRef arr, ParamArray args() As Variant) As Variant    ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru
    ' Получает по ссылке массив ARR для фильтрации
    ' и список критериев фильтрации в формате "3=маска текста" (номер столбца, "=", искомое значение)
    ' Возвращает двумерный массив с подходящими строками
    
    On Error Resume Next
    ArrAutofilterNew = False ' возвращаемое значение в случае ошибки
    If UBound(args) = -1 Then Debug.Print "Array filtering error: filters required": Exit Function
    ReDim Filters(1 To UBound(args) + 1, 1 To 2)
 
    Dim i&, ColumnToCheck&, FiltersCount&, j&, ro&, RowsCount&:  Err.Clear: i& = UBound(arr, 2)
    If Err.Number > 0 Then Debug.Print "Array filtering error: two dimensional array required": Exit Function
 
    For i& = LBound(args) To UBound(args)    ' перебираем все параметры фильтрации
        If Not IsMissing(args(i&)) Then
            If args(i&) Like "#*=*" Then ' распознаем параметры фильтрации
                FiltersCount& = FiltersCount& + 1
                Filters(FiltersCount&, 1) = Val(Split(args(i&), "=")(0)) ' столбец массива
                Filters(FiltersCount&, 2) = Split(args(i&), "=", 2)(1) ' маска для значения
            Else ' неверно заданный фильтр
                Debug.Print "ArrAutofilterNew error: invalid filter «" & args(i&) & "»"
            End If
        End If
    Next i&
    If FiltersCount& = 0 Then Debug.Print "Array filtering error: all filters are empty": Exit Function
 
    ReDim arrCheck(LBound(arr, 1) To UBound(arr, 1)) As Boolean ' для результатов проверки
    For i = LBound(arr, 1) To UBound(arr, 1)    ' перебираем все строки массива, и проверяем их
        arrCheck(i) = True
        For j& = 1 To FiltersCount&    ' перебираем все параметры фильтрации
            If Not (arr(i, Filters(j&, 1)) Like Filters(j&, 2)) Then arrCheck(i) = False: Exit For
        Next j&
        RowsCount& = RowsCount& - arrCheck(i) ' увеличиваем счётчик подходящих строк на 1
    Next i
    If RowsCount& = 0 Then Exit Function ' выход, если нет ни одной подходящей строки в массиве
    
    ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)) ' формируем новый массив
    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
            For j = LBound(arr, 2) To UBound(arr, 2)
                newarr(ro&, j) = arr(i, j) ' заполняем массив значениями из исходного
            Next j
        End If
    Next i
    ArrAutofilterNew = newarr ' возвращаем результат
    Erase arrCheck
End Function

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

Код
If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
...

ну и далее. Так вот, как можно в некую переменную передать в этот момент значение i ? Так-то понятно, дописать типа: if r=empty then r=i, но как и что нужно написать, чтобы наряду с полученным значением функции ArrAutofilterNew = newarr иметь доступ к этому дополнительному значению r? Фактически, мне необходимо знать положение отфильтрованного массива (в моем случае он непрерывный) в исходном массиве и я надеюсь получить это значение вышеописанным методом.

P.S. Заранее спасибо всем откликнувшимся

Изменено: OlegO - 14.02.2026 19:31:10
Запуск макроса при изменении ListBox
 
Цитата
написал:
У Вас там ComboBox, а не ListBox
Теперь дошло, но это просто описка, извините на невнимательность
Запуск макроса при изменении ListBox
 
А теперь я немного не понял, MikeVol. В прилагаемом файле есть лист, на нем здоровенная кнопка, нажатие на которую запускает UserForm с искомым ListBox. Мог бы конечно на открытие файлы повесить запуск UserForm или на двойной или правый клик, но какая разница? Или вы не это имели ввиду?
Запуск макроса при изменении ListBox
 
МатросНаЗебре, приношу извинения, но почему-то при первой проверке вашего кода отработалось с указанной "неправильностью", не знаю почему. А вот теперь, когда формировал файл по вашей просьбе и проверил, все сработало как надо. Еще раз извините за критику.

P.S. кстати понял почему не получилось с первого раза, я не заметил того, что вы закавычили имена макросов и оставил сначала свою строку
Изменено: OlegO - 20.01.2026 19:47:28
Запуск макроса при изменении ListBox
 
Дмитрий(The_Prist) Щербаков, а вот ваш код работает как задумывалось, спасибо большое за пример решения
Запуск макроса при изменении ListBox
 
МатросНаЗебре, спасибо за отклик, но ваш код проявляет свою "неправильность" так же как и мой уже на 6 строке, можно закомментировать 7 строку, попытаться вызвать любой макрос и отработают все 4. Увы.
Запуск макроса при изменении ListBox
 
Доброго времени суток, уважаемые форумчане. Скажу сразу, нынешний вопрос уже имеет решение, мне просто хочется узнать имеется ли другое. Итак, на форме есть листбокс с прописанным содержанием:
Код
Me.Service_macros.List = Array("восс-е исходных значений ДИ", "восс-е контекст. меню листа", "визуал-я 1 строки прихода", "отображение скрытых имен")
Задумывался запуск нужного макроса при его выборе, макросы разумеется сформированы и находятся в отдельном модуле. Сначала я попытался сделать это так:
Код
Private Sub Service_macros_Change()
    ad = Array(Func_RecNM, Func_RecCM, Func_RecViz, Func_ShowImen)(Service_macros.ListIndex)
End Sub
потом Choose, потом Switch, но всегда в этих случаях получалось одно и тоже: макросы запускались все по очереди (можно убедиться в прилагаемом примере выбрав любой макрос, а отработают все, что неприемлемо для меня). Я так понимаю, что согласно логике кода встроенных функций, они проверяют правильность всех вариантов, при этом запуская их в данном случае. Решением стало использование Select Case:
Код
Private Sub Service_macros_Change()
    Select Case Service_macros.ListIndex
         Case 0: ad = Func_RecNM
         Case 1: ad = Func_RecCM
         Case 2: ad = Func_RecViz
         Case 3: ad = Func_ShowImen
     End Select
End Sub
Повторюсь, все работает, просто хотелось бы знать, можно ли было решить вопрос иначе
Заранее спасибо всем откликнувшимся
Поиск Даты методом .Find() с конца диапазона
 
Цитата
написал:
забрать в него (в массив) сразу весь диапазон
Заранее уверен, что рассмешу всех гуру форума своим предположением, но, чисто для хорошего настроения перед Новым Годом, выскажу его. Ведь, если отобранный массив из которого в дальнейшем коде отбираются нужные данные будет в "высоту" из скажем 100 строк, а не в 1000, он же будет обрабатываться чуть-чуть быстрее, пусть неуловимо по времени, но хотя бы с формальной точки зрения?
Поиск Даты методом .Find() с конца диапазона
 
Цитата
написал:
даты в диапазоне лучше искать в цикле
Спасибо за отклик, Sania, но в данном конкретном случае, несмотря на смехотворность причины, я хотел бы обойтись без цикла. Как Вы наверное догадались этот код будет использоваться для расчета диапазона с нужными датами: x = .Range(.Cells(начало, 1), .Cells(конец, 28)).Value. Начало могу вычислить по другому диапазону, данные в котором имеют вид 2020, 2021 и т.д. Для предыдущих, относительно текущего, годов конец могу вычислить, задав для поиска следующий год, но при его отсутствии (сейчас это 2026) поиск выпадет с ошибкой. Пытался использовать IIf, но там код проверяет все варианты и выпадает разумеется также. Просто хочется попробовать (повторюсь безотносительно задачи) обойтись 1 строкой, чисто для интереса, в любом случае при невозможности этого, укажу на последнюю занятую ячейку.  
Поиск Даты методом .Find() с конца диапазона
 
Доброго времени суток, уважаемые форумчане, всех с наступающим! Очень давно не обращался за помощью на наш форум, но вот опять вылез вопрос. И, самое главное, понимаю, что проблема скорее всего крошечная, а сам никак не могу разобраться :oops: . Итак, в диспетчере имен задан диапазон, в коде требуется найти значение, начиная с конца диапазона. Делать я это пытаюсь так:
Код
f =  45962 '"декабрь" '
r = [Dt].Find(f, , , , , xlPrevious).Row
MsgBox r
В искомом диапазоне в ячейках находятся даты, вычисляемые по формуле =ДАТА($D$14;11;1). Если я указываю для поиска например 45962 (значение ячейки для ноября 2025), то выпадает ошибка 91. А вот если (для проверки) в ячейках В21 и В37 внести "декабрь" и соответственно его искать, то все проходит правильно, вычисляя значение 37. Что сейчас написано у меня не так и как это поправить?
Заранее спасибо всем откликнувшимся.
Изменено: Sanja - 27.12.2025 17:35:37
Сохранение значения UDF
 
Еще раз прошу прощения, просто как то, в одном из обсуждений меня немного упрекнули на некоторую как выразились "многобуквенность", вот я постарался, в меру своих возможностей, написать лапидарно
Сохранение значения UDF
 
Дмитрий, спасибо за ответ, буду изучать. А что качается логики моей задумки, то не стал грузить форумчан, посчитал ненужным подробное объяснение. А было оно таким: Для проверки запускать ли заново нумерацию я применил словарь dicNum, если есть ключ - нумерация продолжается, если нет - добавить ключ (сформированный в цикле) + сбросить значение до 1. А вот как победить стремление функции сбрасывать значение на 0 я и задал главный вопрос, мне казалось тогда, что как-то по аналогии со Static можно это соорудить. Еще раз спасибо.
Присвоение уникального значения, Нужна формула для присвоение уникального значения
 
Цитата
написал:
Спасибо! а как пользоваться?)
Ну не знаю 8-0 , этот кусок кода выдает верное значение I (в данном примере =3), а что дальше это вам решать.  
Изменено: OlegO - 27.02.2025 13:17:07
Присвоение уникального значения, Нужна формула для присвоение уникального значения
 
Тогда вот файл. Обратите внимание, что код проверяет на пропущенные номера (например удалили что-либо) и предлагает сначала их
Сохранение значения UDF
 
Прошу прощения, Дмитрий, но нет. dicNum в реальном файле у меня объявлен как Private, а вот в примере не указал, каюсь. Но, еще раз извиняюсь, дело не в этом, как мне кажется. Когда я прохожу код пошагово, я получаю при первой итерации верное значение n. Далее изменяется i, заново отрабатывается функция и я сразу вижу, что значение  Calc_NR = 0. Естественно функция дает ответ 1, при этом словарь dicNum, как ему и положено содержит первый ключ. Ваш код (я скопировал его без изменений) приводит к аналогичному результату. А что касается второго вопроса, то дело в том, что я встречал код в котором проверялось значение функции типа If функция>0 then, именно функции, а не переменной принимающей ее значение. Вот по аналогии, я и хотел бы не рассчитывать значение n, а напрямую указывать функцию как один из аргументов.
Присвоение уникального значения, Нужна формула для присвоение уникального значения
 
kse-solo1, вам необходимо именно формулой, а как сделать макросом вы в курсе или все-равно? Макросом очень похожее решение у меня есть
Сохранение значения UDF
 
Доброго времени суток, уважаемые форумчане. Вновь обращаюсь к вам за помощью в написании кода, ситуация такая: имеется код наполнения словаря:  
Код
 For i = 1 To UBound(xF)
    n = Calc_NR(dicNum, xF(i, 1) & "|" & xF(i, 4))
    dicData.Item(Join(Array(n, xF(i, 6), xF(i, 3)), "|")) = xF(i, 2)
 Next i
в силу определенных обстоятельств, мне требуется расчет для нумерации по строкам (n) для каждого расходного документа, делать я это попытался с помощью функции пользователя:
Код
Function Calc_NR(dicNum As Object, key As String) As Long 'расчет нумерации реестра
    If dicNum.Exists(key) Then
        Calc_NR = Calc_NR + 1
    Else
        dicNum.Item(key) = 1: Calc_NR = 1
    End If
End Function
Частично получилось, но возникли 2 вопроса: функция верно рассчитывает номер для первой позиции, но не сохраняет значение Calc_NR для 2-ой и последующих позиций, все они нумеруются как 1. Можно ли, и как, если можно, это исправить? и второй вопрос (с разрешения модераторов) можно ли и как, если можно, напрямую использовать функцию при формировании ключа словаря, т.е. записывать не  
Код
dicData.Item(Join(Array(n, xF(i, 6)...
а так:
Код
dicData.Item(Join(Array(Calc_NR, xF(i, 6)...
при условии конечно, что есть решение для первого вопроса, а иначе зачем?
Заранее спасибо всем откликнувшимся
Пакетная отправка файлов через CDO
 
Вроде бы разобрался, еще раз перепроверив исходный образец кода отправки. Код теперь выглядит так:
Код
                    For Each att In dicMail.Item(k)
                        .AddAttachment ThisWorkbook.Path & "\" & att
                        Kill ThisWorkbook.Path & "\" & att
                    Next att
БМВ, команда на прикрепление файла, наверное копирует файл в оперативную память или еще куда-либо, в любом случае команда на удаление отрабатывает, но ни Count прикрепленных не уменьшается, ни item-ы. Во всяком случае письмо на свой ящик ушло, файлы там есть. Всем спасибо.
Пакетная отправка файлов через CDO
 
БМВ, да, если что, я перенесу команду удаления, почему не прикрепляется-то?  
Изменено: OlegO - 16.02.2025 20:58:33
Пакетная отправка файлов через CDO
 
Доброго времени суток, уважаемые форумчане. Я уже поднимал тему отправки файлов через  CDO на нашем форуме, но вопрос возник снова. Итак, в функцию отправки письма передается словарь, ключом которого является адрес, а итемом - массив наименований документов к тому времени уже созданных. Словарь (для примера конечно) наполняется так:
Код
        For i = 1 To 2
            If Not dicMail.Exists(Key) Then
                dicMail.Item(Key) = Cells(i, 1).Value & ".pdf"
            Else:
                dicMail.Item(Key) = Array(dicMail.Item(Key), Cells(i, 1).Value & ".pdf")
            End If
        Next i
ad = Func_SendMailCDO(dicMail)
далее вызов функции, инфа по логину-паролю, разумеется левая, для примера:
Код
Function Func_SendMailCDO(dicMail As Object) 'отправка на e-mail покупателя
    Dim objCDOCnf As Object, objCDOMsg As Object, att As Variant, k As Variant
        Const CDO_Cnf = "http://schemas.microsoft.com/cdo/configuration/"
        Set objCDOCnf = CreateObject("CDO.Configuration") 'назначаем конфигурацию CDO
        
            With objCDOCnf.Fields
...
                .Item(CDO_Cnf & "sendusername") = "login@mail.ru" 'учетная запись на сервере
                .Item(CDO_Cnf & "sendpassword") = "pass" 'пароль к почтовому аккаунту
                .Update
            End With
                    
            On Error Resume Next
            For Each k In dicMail.keys
                Set objCDOMsg = CreateObject("CDO.Message") 'создаем сообщение
                With objCDOMsg
...
                    .Subject = "Копии документов" 'тема письма
Далее я пытаюсь прикрепить аттач и вот с этим у меня и возникают проблема, т.к. само письмо уходит по адресу и вообще, кроме аттача, код отрабатывает на ОК:                    
Код
For Each att In dicMail.Item(k)
         .Attachments.Add ThisWorkbook.Path & "\" & att
         Kill ThisWorkbook.Path & "\" & att
Next att
       .Send
значение att верное, файлы pdf в наличии, а значение objCDOMsg.Attachment.Count как было =0 так и остается. Повторюсь, письмо уходит, но пустое без нужного вложения. Что сейчас написано не так и как это исправить?
Заранее спасибо всем откликнувшимся.
Функция пользователя: ввод параметров
 
Ага, вона оно как :) Ясно. Спасибо большое за консультацию и терпение.
Функция пользователя: ввод параметров
 
Цитата
написал:
Ваше обучение VBA идёт странным маршрутом.
Вы бы знали каким :D . Нет так-то я и сам мог, мне хотелось иного ;) . Хотелось, чтобы при ПОПЫТКЕ ввести неверные данные как минимум с листа, Excel сразу указывал на это (MsgBox например), а в "идеальном" варианте, чтобы и по ходу применения ф-и в коде в этом случае выскакивало какое либо сообщение (я понимаю, что это уж наверное совсем нереально, но так и это не условие, а просто вопрос о возможности).  
Функция пользователя: ввод параметров
 
Дмитрий(The_Prist) Щербаков, МатросНаЗебре, спасибо за ответы. Буду думать 8-0

P.S. прочитал статью Дмитрия, подумал, многое стало понятнее. НО можно еще немного обнаглеть и  узнать еще одну вещь? Сейчас в моей ф-и это не слишком важно, но вдруг возможна иная ситуация в будущем  :oops: : можно ли как, если можно, ограничить допустимые значения для ввода параметра по аналогии с проверкой данных в ячейке? Конкретно в параметр CaseWord As Byte должны вводиться только числа от 2 до 6 и ничего иного. В ArgumentDescriptions у меня есть подсказка по этому поводу, но можно ли подстраховать корректную работу функции от неверных данных пользователя?
Изменено: OlegO - 11.02.2025 18:40:34
Функция пользователя: ввод параметров
 
Спасибо, МатросНаЗебре, вроде понял и получается, сейчас проверю в реальном коде. Подскажите на будущее, в чем разница параметров ParamArray SNP()  и SNP as Variant из заголовка функции.
Функция пользователя: ввод параметров
 
Наберусь смелости и возражу уважаемому Sanja 8). Возможно я недостаточно понятно обрисовал проблему, попробую еще раз. Измененный вариант функции правильно вызывается и отрабатывается кодом VBA, а вот как измененную ф-ю вызвать с листа неясно. Если указать в качестве аргументов диапазоны или даже диапазон (как в примере =DeclensionFIO_Arr(2;F1)), то я смогу наверное данные для ф-ии изменить на Split(SNP(0).Formula)(0), но ведь тогда данные не подойдут для варианта, вызываемого кодом, там у SNP(0) вообще нет свойства .Formula, а есть только значения. Получается, что не получится иметь вариант работающий как из-под кода так и с листа?
Функция пользователя: ввод параметров
 
Ну нельзя так, как мне захотелось, значит нельзя. Но позвольте еще один вопрос по этой функции. Чтобы вызвать ее с листа необходимо указать помимо номера падежа еще и отдельные ячейки с фамилией, именем и отчеством. Если эти данные будут в одной ячейке, то результат будет частично или полностью неверен. Если вызывать функцию кодом, то приходится сооружать примерно такую конструкцию:
Код
ad= DeclensionFIO(2, CStr(Split([F1])(0)), CStr(Split([F1])(1)), CStr(Split([F1])(2)))
немного длинновато и кстати почему приходится оборачивать Split в CStr, данные и так текстовые? (но это так, к слову, а не вопрос  ;) ). Для удобства ввода (в моем понимании) попробовал изменить параметры ф-и на следующие:
Код
Function DeclensionFIO_Arr(CaseWord As Byte, ParamArray SNP()) As String 
...
изменив, разумеется, Surname, Name и Patronymic на CStr(SNP(0)(1)), CStr(SNP(0)(2)) и CStr(SNP(0)(3)) соответственно. Ф-я работает, в коде вызываю ее :
Код
ad = DeclensionFIO_Arr(3, Split([F1]))
но не могу понять как ее запускать с листа Excel, если потребуется. Пробовал =DeclensionFIO_Arr(2;F1) - не получилось, по сути мне одновременно нужен аналог Array и Split, верно? А как это сделать формулами, если это возможно конечно?
Функция пользователя: ввод параметров
 
Цитата
написал:
Обрабатывайте каждый в отдельности, без Array()(i)
Здравствуйте, Sanja. Собственно, как вы предложили, у меня в текущем коде и работает. При склонении фамилии переменная = Mid(Surname, 1, Len(Surname)) - 1), при склонении имени соответственно Mid(Name, 1, Len(Name)) - 1) и т.д. Все ОК, просто хотелось узнать можно ли написать по иному, сэкономив строки (их разумеется не жалко, просто интересно). Просто не пойму почему не изменяется значение tmp при изменении i ?
Функция пользователя: ввод параметров
 
Просто мне хотелось, что бы при измении значения i переменная сама принимала новое значение, без доп. функций. Иначе какой смысл пытаться сократить 3 строки кода, написав отдельную функцию на n строк?  8-0  
Изменено: OlegO - 10.02.2025 20:18:05
Страницы: 1 2 3 4 5 6 7 8 9 10 11 ... 29 След.
Наверх