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

Страницы: 1 2 След.
VBA. Создание события для Control UserForm программным методом, Активировать созданное событие для Conrol UserForm из исполняемого кода
 
наверное, правильно будет перейти в ту тему.
По этой получил исчерпывающий ответ, за что еще раз нижайший поклон! Проверил, работает безукоризненно.
Но эта тема частично связана с той, поэтому эту закрываем, а там я попытаюсь разъяснить, чего я хочу
VBA. Создание события для Control UserForm программным методом, Активировать созданное событие для Conrol UserForm из исполняемого кода
 
Спасибо огромное!

Вот я, дурень, заморочился(
Все так просто оказалось.

А материал великолепен!
Разжевано по буквам для последнего чайника

Простите за наглость, а случайно по теме "VBE Элементы управления панели Toolbox" таких же полезных советов не найдется?
VBA. Создание события для Control UserForm программным методом, Активировать созданное событие для Conrol UserForm из исполняемого кода
 
Здравствуйте!

Никак не могу справиться со следую щей задачкой.
Создал форму, назвал ее UserFormMy.
Добавил на форму в режиме работы с редактором несколько кнопок.
Придал им некую единообразность в наименовании: каждая кнопка объявляется начальным именем "cmbBtm" и содержит номер на конце.
Создал Модуль в книге, переименовал его "General".
Как выше написано, создал форму "UserFormMy"  и разместил на ней три кнопки; "cmbBtm5", "cmbBtm3", "cmbBtm6".
В модуле "General". создал основной исполняемый код, который предварительно исследует имеющуюся форму.
В коде проверяется, имеются ли на форме интересующие кнопки, и, если таковые находятся, то проверяется, а имеются ли для них события нажатия на них (событие "Click").
Если такое событие не обнаружено, то программно создается.
После проверки всех объектов (Control) на исследуемой UseForm, в исполняемом коде загружается форма и выводится на экран.
Ожидаемый результат - при нажатии на интересующую кнопку ожидается вызов события "Click".
Однако этого не происходит.
При этом созданные события замечательно записываются в коды формы.
Но лишь завершив основной исполняемый код и заново его запустив, тогда только начинают работать события для кнопок.
А почему сразу не срабатывают, если я только после всех предварительных подготовок загружаю форму?
Полный код приведен в прилагаемом файле.
Изменено: Владимир Баукин - 26.02.2025 10:42:30
VBE Элементы управления панели Toolbox, Добавление пользовательского объекта, описанного в файле формата .xlsm, в Toolbox
 
Здравствуйте!

Характеристики системы; Windows 10 Pro 64-bit, Microsoft Office: Microsoft Project профессиональный 2019 - ru - ru

Подскажите, пожалуйста, существует ли какая-то возможность объект, описанный в созданном файле формата .xlsm, добавить в панель управления Toolbox редактора VBE?
Возможно нужно мой файл сконвертировать/переместить в какую-то специальную папку, где хранятся физические файлы уже созданных элементов управления, таких. как кнопка, текстовое поле, переключатели, флажки и т.п., отображаемых в этой панели?
Или следует использовать какой-то другой метод?

Есть у меня созданный файлик, который выполняет функцию вставки на рабочий лист кнопочки, при нажатии на которую открывается форма с нарисованным календарем, где можно выбрать любую дату и вставить ее в любую ячейку в активный лиcт excel, выбранную пользователем.
Он прекрасно работает как самостоятельный файл, так и на его основе создана надстройка. которая также прекрасно работает.
Абсолютно бесполезная приблуда, но задел был именно в том, чтобы впоследствии иметь возможность использовать этот скрипт в качестве элемента управления.

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

Пока мои исследования по этому направлению, увы, не привели к возможности решить эту задачу
Программно растянуть столбец А до установленных границ листа
 
grh1, попробуйте поизучать рекомендации по прилагаемой ссылке https://excelvba.ru/code/ColumnWidth
Идентификация типа объекта ActiveX, внедренного в лист книги Excel
 
Игорь, СПАСИБО ОГРОМНОЕ!
Именно то, что надо!
Идентификация типа объекта ActiveX, внедренного в лист книги Excel
 
Здравствуйте!

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

Код
Sub Test()
    Dim ExistOLEObj As OLEObject
    With ThisWorkbook.ActiveSheet
        For Each ExistOLEObj In .OLEObjects
            Debug.Print ExistOLEObj.Name
        Next
    End With
End Sub

А можно каким-то свойством определить не имя, а тип объекта ActiveX?
Что если это текстовое поле, то возвращался бы конкретный идентификатор, что это именно текстовое поле, а если кнопка, то это именно кнопка, а не что-то иное.
Изменено: Владимир Баукин - 15.07.2021 02:06:20
Принудительное изменение средствами VBA внешнего вида указателя курсора мыши при нажатии на кнопку подключенной надстройки, Подключение файла вида курсора мыши из списка, расположенного в каталоге C:\Windows\Cursors
 
Возвращаясь к теме, предварительно всех приветствую!

В принципе, удалось найти подход для решения данной задачи.
Суть решения заключается в заполнении видимой области клиентской части книги Excel полностью прозрачной формой.
Безусловно, я не перехватываю управление курсором самого приложения, а лишь визуально обманываю пользователя, когда он перемещает курсор в клиентской части, и курсор имеет форму, который задан разработчиком.
И только после того, как пользователь выбирает какую-то ячейку, кликнет на ней мышью, форма курсора изменится на стандартную левонаправленную вверх стрелку.
При этом, в координаты, в которых располагался курсор на момент клика левой кнопкой мыши пользователем будет вставлен объект ActiveV, которому будет прописано действие при последующей инициации пользователем его события Click (то есть пользователь, увидев появившийся объект кликнет по нему мышкой).

Следует отметить следующие  недостатки данного способа решения задачи.
1. В конечном итоге форма курсора восстанавливается до стандартной левонаправленной  вверх стрелки, что может не соответствовать изначально установленной форме курсора и поэтому привести в замешательство пользователя, заставив его вручную через параметры заново переопределять удобную для него форму курсора.
Но, к сожалению, я не сумел пока понять как запомнить изначальную форму, где ее хранить, поскольку архитектура исполняемого кода не является непрерывной процедурой.
2. Возникновение передергивания экрана в процессе выполнения кода.

Также стоит обратить внимание, что при использовании данного способа решения задачи, для предотвращения ошибок, связанных с программным обращениям к компонентам VBAProject, необходимо предварительно произвести некоторые модификации установок в центре управления безопасностью приложения Excel и в самом VBAProject, а именно:
1.  Подключаем в VBProject основного файла с исполняем кодом библиотеку VBIDE (Tools -> Referense ->  Microsoft Visual Basic  for Application Exctensibility 5.3.
2. В Центре управления безопасностью параметров приложения Excel устанавливаем ссылку на вышеуказанную библиотеку.
(Файл -> Параметры -> Центр управления безопасностью -> Параметры центра управления безопасностью -> Надежные расположения -> Добавить новое расположение -> выбираем путь к библиотеке WBEGEXT.OLB (VBE6)
(у меня она располагается по адресу: C:\Program Files (x86)\Common Files\Microsoft Shared\VBA\VBA6\)
3. Очень важно не забыть перейти потом на вкладку "Параметры макросов" в "Параметрах центра управления безопасностью" и убедиться, что в разделе "Параметры макросов для разработчика" активирован флажок "Доверять доступ к объектной модели проектов VBA".
4. Рекомендую сохранить настройки и перезапустить приложение.
Доступ к компонентам VBProject открыт.

Теперь выкладываю полный исполняемый код при тестировании решения со своими комментариями.

Код основного модуля:
Код
Option Explicit

Sub Proba()
    Dim RngVis As Range
    Dim PosLeftObj As Integer, PosTopObj As Integer, WDTHObj As Integer, HGHTObj As Integer
    
    'Определяем объект Range, представляющий видимый диапазон клиентской области книги Excel
    Set RngVis = Application.ActiveWindow.VisibleRange
    'Считываем из него необходимые координаты и размеры в пунктах для определения стартовых координат и размера UserForm, которая заполнит виlимую область клиентской части рабочей книги
    With RngVis
        PosLeftObj = .Cells(1, 1).Left
        PosTopObj = .Cells(1, 1).Top
        WDTHObj = .Cells(.Rows.Count, .Columns.Count).Left + .Cells(.Rows.Count, .Columns.Count).Width - PosLeftObj
        HGHTObj = .Cells(.Rows.Count, .Columns.Count).Top + .Cells(.Rows.Count, .Columns.Count).Height - PosTopObj
    End With
    MyForm.Left = PosLeftObj
    MyForm.Top = PosTopObj
    MyForm.Width = WDTHObj
    MyForm.Height = HGHTObj
    MyForm.Show
End Sub

Код копируемого в нужную книгу модуля, содержащего процедуры/функции, которые задействуются при клике на добавленном в интересуемую книгу объекте ActiveX:
Код
Option Explicit

Sub Res()
    MsgBox "Макрос скопирован и работает"
End Sub

Код вспомогательной формы:
Предварительные настройки формы с использованием окна свойств следующие:
BackColor = &H80000005&
Caption =""
PictureAligment=fmPictureAligmentCenter
ShowModal=False
Код
Option Explicit

Private Const OCR_NORMAL As Long = 32512
Private Const IDC_APPSTARTING As Long = 32650
Private Const IMAGE_CURSOR As Long = 2
Private Const PathCursor As String = "c:\Windows\Cursors\"
Private Const GenNameMacros As String = "Res"

#If VBA7 Then
    'Функция копирования текущего значка указателя курсора мыши
    Private Declare PtrSafe Function CopyCursor Lib "user32" Alias "CopyIcon" (ByVal hcur As LongPtr) As LongPtr
    'Функция создания значка указателя курсора мыши на основе данных из файла, к которому обращается функция
    Private Declare PtrSafe Function LoadCursorFromFile Lib "user32" Alias "LoadCursorFromFileA" (ByVal lpFileName As String) As LongPtr
    'Функция извлечения дескриптора (ручки) текущего курсора
    Private Declare PtrSafe Function GetCursor Lib "user32" () As LongPtr
    'Функция настройки системного курсора. Заменяет содержимое системного курсора, определенного параметром ID содержимым курсора, определенным его дескриптором (ручкой)
    Private Declare PtrSafe Function SetSystemCursor Lib "user32" (ByVal hcur As LongPtr, ByVal id As Long) As Long
    'Функция считывания положения курсора в указанных координаты экрана (результат в пикселях)
    Private Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
    'Функция извлечения дескриптора (ручки) интересуемого окна
    Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal ClassName As String, ByVal WindowName As String) As LongPtr
    'Функция считывания информации об интересуемом окне
    Private Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr
    'Функция изменения атрибутов интересуемого окна
    Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
    'Функция регулирования прозрачности окна
    Private Declare PtrSafe Function SetLayeredWindowAttributes Lib "user32" (ByVal hwnd As LongPtr, ByVal crKey As Integer, ByVal bAlpha As Integer, ByVal dwFlags As Long) As Long
    'Функция подавления визуализации окна стороннего задействуемого в коде приложения другого приложения
    Private Declare PtrSafe Function LockWindowUpdate Lib "user32" (ByVal hWndLock As LongPtr) As Long
    
    'Переменные, используемые для преобразования вспомогательной формы в прозрачную
    Private hwnd As LongPtr
    Private lStyle As LongPtr
    'Объявляем 3 переменные
    Private NewCur As LongPtr, OldCursor As LongPtr, VBEHwnd As LongPtr
    'Определяем файл, соответствующий виду конечного курсора мыши
    Private Const NameFileCurEnd As String = "aero_arrow.cur"
    'Определяем файл, соответствующий виду промежуточного курсора мыши
    Private Const NameFileCurTMP As String = "lperson.cur"
#Else
    Private Declare Function CopyCursor Lib "user32" Alias "CopyIcon" (ByVal hcur As Long) As Long
    Private Declare Function LoadCursorFromFile Lib "user32" Alias "LoadCursorFromFileA" (ByVal lpMyFileName As String) As Long
    Private Declare Function GetCursor Lib "user32" () As Long
    Private Declare Function SetSystemCursor Lib "user32" (ByVal hcur As Long, ByVal id As Long) As Long
    Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal ClassName As String, ByVal WindowName As String) As Long
    Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
    Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    Private Declare Function SetLayeredWindowAttributes Lib "user32" (ByVal hwnd As Long, ByVal crKey As Integer, ByVal bAlpha As Integer, ByVal dwFlags As Long) As Long
    Private Declare Function LockWindowUpdate Lib "user32" (ByVal hWndLock As Long) As Long
    
    Private hwnd As Long
    Private lStyle As Long
    Private NewCur As Long, OldCursor As Long, VBEHwnd As Long
    Private Const NameFileCurEnd As String = "arrow_l.cur"
    Private Const NameFileCurTMP As String = "handapst.ani"
    
#End If

'Тип данных - координаты курсора в пунктах
Private Type POINTAPI
    X As Long
    Y As Long
End Type

Private pntPos As POINTAPI

'Значение константы пересчета значения в пунктах в значение в пикселях
Private Const PNTINPX As Single = 1.3281472327365
'Значение константы пересчета значения в пикселях в значение в пунктах
Private Const PXINPNT As Single = 0.75292857248934

'Константы, используемые для преобразования вспомогательной формы в прозрачную
Private Const WS_EX_LAYERED = &H80000
Private Const LWA_ALPHA = &H2
Private Const GWL_EXSTYLE = &HFFEC

Private Sub UserForm_Click()
    Dim ButtonOLEObj As OLEObject, LeftPos As Integer, TopPos As Integer
    Dim lLineNum As Long
    'Переменные значении смещения координат объектов клиентской области относительно координат окна приложения
    Dim SHFTX As Long, SHFTY As Long
    
    'Определяем координаты (в пикселях) смещения расположения первой ячейки клиентской области относительно координат окна приложения
    SHFTX = ActiveWindow.PointsToScreenPixelsX(0)
    SHFTY = ActiveWindow.PointsToScreenPixelsY(0)
    'Считываем координаты (в пикселях) текущего положения указателя мыши
    GetCursorPos pntPos
    'Определяем координаты (в пунктах) расположения добавляемого объекта ActiveX
    If Round((pntPos.X - SHFTX) * PXINPNT) - 20 <= 0 Then
        LeftPos = 0
    Else
        LeftPos = Round((pntPos.X - SHFTX) * PXINPNT) - 20
    End If
    If Round((pntPos.Y - SHFTY) * PXINPNT) - 20 <= 0 Then
        TopPos = 0
    Else
        TopPos = Round((pntPos.Y - SHFTY) * PXINPNT) - 20
    End If
    'Добавляем в лист дополнительный объект ActiveX (кнопку)
    Set ButtonOLEObj = ActiveWorkbook.ActiveSheet.OLEObjects.Add( _
        ClassType:="Forms.CommandButton.1", _
        DisplayAsIcon:=False, _
        Left:=LeftPos, _
        Top:=TopPos, _
        Width:=40, _
        Height:=40 _
    )
    With ButtonOLEObj
        .Object.Caption = ""
        'Вставляем в добавленный в активный лист объект ActiveX изображение и центрируем ее относительно размера объекта
        If Dir(ThisWorkbook.Path & "\Smiling face.jpg") <> "" Then .Object.Picture = LoadPicture(ThisWorkbook.Path & "\Smiling face.jpg")
        .Object.PicturePosition = fmPicturePositionCenter
    End With
    'Активируем ячейку активного листа, которая включает в свой размер левую и верхнюю координату добавленного объекта ActiveX
    ActiveWorkbook.ActiveSheet.Range(ButtonOLEObj.TopLeftCell.Address).Select
    'Отключаем переключение на окно VBAProject
    On Error GoTo ErrH:
    Application.VBE.MainWindow.Visible = False
    VBEHwnd = FindWindow("wndclass_desked_gsk", Application.VBE.MainWindow.Caption)
    If VBEHwnd Then
        LockWindowUpdate VBEHwnd
    End If
    'Вызываем функцию проверки наличия в активной книге необходимых модулей, требуемых для корректного срабатывания события Click добавленного объекта ActiveX ButtonOLEObj
    'и копирования этих модулей в активную книгу при их отсутствии
    Dim RunReplace As Boolean, Res As Integer, TextErr As String, NumbErr As Integer
    'Функции передан аргумент, определяющий, требуется ли замена содержимого модуля, предназначенного для вставки в активную книгу, при его обнаружении в активной книге
    RunReplace = False
    Res = CopyVBComponent("ModuleRun", "", ThisWorkbook, ActiveWorkbook, RunReplace)
    'Если необходимый модуль обнаружен в активной книге
    If Res = 0 Or Res = 1 Then
        'Определяем количество заполненных строк в интересуемом модуле
        lLineNum = ActiveWorkbook.VBProject.VBComponents(ActiveWorkbook.ActiveSheet.Name).CodeModule.CountOfLines + 1
        'Для нового добавленного объекта ActiveX создаем событие Click
        With ActiveWorkbook.VBProject.VBComponents(ActiveWorkbook.ActiveSheet.Name).CodeModule
            lLineNum = .CreateEventProc("Click", ButtonOLEObj.Name)
            lLineNum = lLineNum + 1
            .InsertLines lLineNum, GenNameMacros
        End With
    'Если в процессе выполнения функции произошла ошибка
    Else
        Select Case NumbErr
            Case 2
                TextErr = "Код ошибки 2: в книге исполняемого кода " & ThisWorkbook.Name & " не обнаружен проект VBA"
            Case 3
                TextErr = "Код ошибки 3: книга с исполняемым кодом " & ThisWorkbook.Name & " запаролирована"
            Case 4
                TextErr = "Код ошибки 4: Активная книга не содержит проект VBA"
            Case 5
                TextErr = "Код ошибки 5: проект VBA активной книги запаролирован"
            Case 6
                TextErr = "Код ошибки 6: не задано/неверно задано имя копируемого модуля"
            Case 7
                TextErr = "Код ошибки 7: в книге исполняемого кода не обнаружен заданный модуль"
            Case 8
                TextErr = "Код ошибки 8: ошибка удаления экспортированного файла модуля из временной папки"
            Case 9
                TextErr = "Код ошибки 9: неизвестная ошибка"
        End Select
        MsgBox "В процессе выполнения произошла ошибка на этапе модификации данных VBAProject" & Chr(13) & _
                TextErr, vbInformation + vbOKOnly, "Ошибка"
        'Удаляем добавленный объект ActiveX
        ButtonOLEObj.Delete
    End If
    Application.VBE.MainWindow.Visible = False
    'Устанавливаем форму стандартного системного курсора
    If Dir(PathCursor & NameFileCurEnd) <> "" Then
        NewCur = LoadCursorFromFile(PathCursor & NameFileCurEnd)
        SetSystemCursor NewCur, OCR_NORMAL
    End If
ErrH:
    LockWindowUpdate 0&
    Unload Me
End Sub

Private Sub UserForm_Initialize()
'    'Запоминаем прежний курсор и загружаем свой
'    OldCursor = GetCursor()
'    OldCursor = CopyCursor(OldCursor)
    If Dir(PathCursor & NameFileCurTMP, vbNormal) <> "" Then
        NewCur = LoadCursorFromFile(PathCursor & NameFileCurTMP)
        SetSystemCursor NewCur, OCR_NORMAL
    End If
    'Устанавливаем окно формы полностью прозрачным
    hwnd = FindWindow(vbNullString, Me.Caption)
    lStyle = GetWindowLong(hwnd, GWL_EXSTYLE)
    SetWindowLong hwnd, GWL_EXSTYLE, lStyle Or WS_EX_LAYERED
    SetLayeredWindowAttributes hwnd, 0, 2.55, LWA_ALPHA
End Sub

'Функция копирования компонента VBAProject из одной книги в другую
'Параметры функции:
'wbFromFrom - Книга, компонент из VBA-проекта которой необходимо копировать
'wbFromTo - Книга, в VBA-проект которой необходимо копировать компонент
'sModuleName - Имя модуля, который необходимо копировать
'sModuleToName - Имя модуля, в который необходимо копировать
'bOverwriteExistModule: Если True или 1, то при наличии в конечной книге компонента с именем sModuleName - он будет удален, а вместо него импортирован копируемый
                        'Если False, то при наличии в конечной книге компонента с именем sModuleName сам компонент не будет скопирован в VBAProject конечной книги
'Возвращаемые значения: 0 - Модуль успешно добавлен в VBAProject конечной (активной) книги;
                        '1 - интересуемый модуль обнаружен в конечной книге и его принудительная замена не требуется
                        'Ошибки, выявленные в ходе выполнения функции, не позволяющие дальнейшее ее корректное выполнение
                        '2 - в книге, из которой копируем, нет проекта VBA
                        '3 - в книге, из которой копируем, для проекта VBA установлен пароль
                        '4 - в книге, в которую копируем, нет проекта VBA
                        '5 - в книге, в которую копируем, для проекта VBA установлен пароль
                        '6 - не задано/неверно задано имя копируемого модуля
                        '7 - в книге, из которой копируем, не найден заданный модуль
                        '8 - ошибка удаления экспортированного файла модуля из временной папки
                        '9 - неизвестная ошибка
Private Function CopyVBComponent(sModuleName As String, ByVal sModuleToName As String, wbFromFrom As Workbook, wbFromTo As Workbook, bOverwriteExistModule As Boolean) As Integer

    Dim objVBProjFrom As Object, objVBProjTo As Object
    Dim objVBComp As Object, objTmpVBComp As Object
    Dim sTmpFolderPath As String, sVBCompName As String, sModuleCode As String
    
    'Проверяем корректность указанных параметров
    On Error Resume Next
    Set objVBProjFrom = wbFromFrom.VBProject
    Set objVBProjTo = wbFromTo.VBProject
    
    'если в книге, из которой копируем, нет проекта VBA
    If objVBProjFrom Is Nothing Then
        CopyVBComponent = 2: Exit Function
    End If
    'если в книге, из которой копируем, для проекта VBA установлен пароль
    If objVBProjFrom.Protection = 1 Then
        CopyVBComponent = 3: Exit Function
    End If
    
    'если в книге, в которую копируем, нет проекта VBA
    If objVBProjTo Is Nothing Then
        CopyVBComponent = 4: Exit Function
    End If
    'если в книге, в которую копируем, для проекта VBA установлен пароль
    If objVBProjTo.Protection = 1 Then
        CopyVBComponent = 5: Exit Function
    End If
    
    'если не задано имя копируемого модуля
    If Trim(sModuleName) = "" Then
        CopyVBComponent = 6: Exit Function
    End If
    'если не задано имя модуля для вставки кода, используем имя копируемого
    If Trim(sModuleToName) = "" Then
        sModuleToName = sModuleName
    End If
    
    'проверяем, существует ли в книге, из которой копируем, заданный модуль
    Set objVBComp = objVBProjFrom.VBComponents(sModuleName)
    'модуля нет, выходим из функции
    If objVBComp Is Nothing Then
        CopyVBComponent = 7: Exit Function
    End If
    
    'полный путь для экспорта/импорта модуля. К папке должен быть доступ на запись/чтение
    sTmpFolderPath = Environ("Temp") & "\" & sModuleToName & ".bas" '"
    'Если bOverwriteExistModule = True (принудительная замена модуля в конечной книге на новую версию), удаляем из временной папки и из конечного проекта модуль с указанным именем
    If bOverwriteExistModule Then
        'удаляем файл модуля из временной папки
        If Dir(sTmpFolderPath, 6) <> "" Then
            Err.Clear
            Kill sTmpFolderPath
            'удалить не удалось, модуль не сохранен. Выход из функции
            If Err.Number <> 0 Then
                CopyVBComponent = 8: Exit Function
            End If
        End If
        'удаляем модуль из конечной книги
        With objVBProjTo.VBComponents
            Set objVBComp = Nothing
            Set objVBComp = .Item(sModuleToName)
            'только если это не модуль листа или книги(их можно только очистить, но не удалять)
            If objVBComp.Type <> 100 Then
                .Remove .Item(sModuleToName)
            End If
        End With
    'Если установлен параметр bOverwriteExistModule, обозначающий, что принудительное обновление содержимого интересуемого модуля не требуется
    Else
        Err.Clear
        Set objVBComp = objVBProjTo.VBComponents(sModuleToName)
        'Если интересуемого модуля в конечной книге не обнаружено
        If Err.Number <> 0 Then
            'Err.Number 9 - отсутствие указанного компонента, что нам не мешает.
            'Если ошибка другая - выход из функции
            If Err.Number <> 9 Then
                CopyVBComponent = 9: Exit Function
            End If
        'если интересуемый модуль в конечной книге обнаружен
        Else
            CopyVBComponent = 1: Exit Function
        End If
    End If
    
    'Экспорт/Импорт компонента во временную директорию
    objVBProjFrom.VBComponents(sModuleName).Export sTmpFolderPath
    'копируем
    Set objVBComp = Nothing
    Set objVBComp = objVBProjTo.VBComponents(sModuleToName)
    If objVBComp Is Nothing Then
        objVBProjTo.VBComponents.Import sTmpFolderPath
    Else
        'Если компонент - модуль листа или книги, его нельзя удалить. Поэтому удаляем из него весь код и добавляем код из копируемого компонента
        If objVBComp.Type = 100 Then
            'для простоты обращения в коде делаем ссылку на копируемый модуль
            Set objTmpVBComp = objVBProjFrom.VBComponents(sModuleName)
            'копируем из него код
             With objVBComp.CodeModule
                .DeleteLines 1, .CountOfLines
                sModuleCode = objTmpVBComp.CodeModule.Lines(1, objTmpVBComp.CodeModule.CountOfLines)
                .InsertLines 1, sModuleCode
            End With
        End If
    End If
    'удаляем временный файл компонента
    Kill sTmpFolderPath
    CopyVBComponent = 0
End Function

Если абстрагироваться от вышеуказанных недостатков, то в системах 64-bit и 32-bit с установленным офисом 64-bit данное решение работает вполне корректно и при желании, если файл с исполняемым кодом оформить в виде надстройки, поместить ее в группу на ленте, где располагаются элементы Active X отдельной дополнительной группой, получится вполне приемлемый для использования уникальный пользовательский объект.
Прилагаю для ознакомления пример с описанным исполняемым кодом. Достаточно загрузить приложение Excel, открыть любую книгу Excel или просто создать новую и вызвать на исполнение макрос из прилагаемого файла формата .xlsm Proba.

Спасибо за внимание!
Любые замечания, идеи, конструктивная критика приветствуются.

С Уважением!  
Изменено: Владимир Баукин - 11.07.2021 06:01:56
Идентификация средствами VBA координат или адреса ячейки, которая отображается первой в клиентской области загруженной книги Excel
 
БМВ, спасибо ОГРОМНЕЙШЕЕ!!!!
То, что надо!

P.S. Второй раз уже здорово выручаете.
Идентификация средствами VBA координат или адреса ячейки, которая отображается первой в клиентской области загруженной книги Excel
 
Здравствуйте!

Суть вопроса заключается в следующем.
Пользователь загружает книгу Excel.
При этом размер окна самого приложения Excel может занимать как все экранное пространство монитора, так размеры могут быть  установлены самим пользователем, что для решения данной задачи не  является принципиальным.
После отображения загруженной книги на экране пользователь, не воздействуя на клиентскую область окна,  вызывает на запуск определенный макрос, управляя мышью (выбирает пункт меню "Разработчик", далее на ленте выбирает иконку "Макросы" в группе "Код", выбирает имя нужного макроса и запускает команду "Выполнить").
Задача макроса заключается в заполнении видимой на экране области клиентской части объектом ActiveX, например, Image.
Для этого всего лишь надо узнать координаты (левую и верхнюю) или адрес ячейки активного листа, которая является первой в этой видимой клиентской области.
Для наглядности прилагаю графический файл, на примере которого хочется понять как мне узнать координаты или адрес ячейки I49, которая является первой ячейкой в отображаемой клиентской области.
При этом совершенно не факт, что данная ячейка является активной, она просто первая отображаемая.
Существуют ли свойства, методы, функции, которые можно задействовать в запускаемом исполнительном коде, чтобы вычислить координаты или адрес этой ячейки?
Причем средствами VBA я запросто могу четко переместить курсор мыши в пределы интересуемой меня ячейки.  
Изменено: Владимир Баукин - 06.07.2021 04:26:48
Изменение свойства встраиваемого объекта ActiveX в лист Excel средствами VBA, Управление свойствами встраиваемых объектов
 
Ай, да спасибо!
Мало того, что мне объяснили, что в моем коде не хватало установки значения прозрачности внедряемого интересуемого меня объекта ActiveX , так еще и  ненавязчиво продемонстрировали альтернативный вариант используемого мною кода, который является более наглядным, эргономичным, а соответственно, более профессиональным.
Возьму этот вариант на вооружение.
Еще раз ОГРОМНОЕ СПАСИБО!
Все работает корректно, решение можно считать исчерпывающим.  
Изменение свойства встраиваемого объекта ActiveX в лист Excel средствами VBA, Управление свойствами встраиваемых объектов
 
Здравствуйте!

Система  64-bit с версией офиса 64-bit.
Вставляю. в  лист Excel объект Image из предлагаемой коллекции объектов ActiveX.
Изменяю значения свойств внедренного объекта через использование окна "Свойства" в режиме конструктора в опции меню "Разработчик":
1. Устанавливаю свойству BackStyle значение fmBackStyleTransparent (прозрачный фон)
2. Устанавливаю свойству BorderStyle значение fmBorderStyleNone (обрамления объекта невидимы) .
Все замечательно, объект становится прозрачным без рамок!
Теперь делаю тоже самое, но с использованием макроса.
Код макроса;
Код
Sub Proba()
    Dim I As Integer, EistOLEObj As OLEObject
    I = 1
    'Определяем количество имеющихся на активном листе объектов ActiveX
    With ThisWorkbook.ActiveSheet
        For Each EistOLEObj In .OLEObjects
            I = I + 1
        Next
        'Добавляем на лист дополнительный объект ActiveX Image
        .OLEObjects.Add ClassType:="Forms.Image.1", _
                        DisplayAsIcon:=False, _
                        Left:=0, _
                        Top:=0, _
                        Width:=175, _
                        Height:=320
        'Переопределяем имя добавленного объекта для последующего удобства обращения к нему
        .OLEObjects(I).Name = "TempImage"
        'Устанавливаем свойства объекту, чтобы он был невиден пользвателю
        With .OLEObjects("TempImage")
            .Object.BackStyle = fmBackStyleTransparent
            .Object.BorderStyle = fmBorderStyleNone
        End With
    End With
End Sub
Не работает корректно! Границы объекта успешно не выделяются, но при этом фон объекта не становится прозрачным.
Почему?
Принудительное изменение средствами VBA внешнего вида указателя курсора мыши при нажатии на кнопку подключенной надстройки, Подключение файла вида курсора мыши из списка, расположенного в каталоге C:\Windows\Cursors
 
Александр Моторин, спасибо!

Пример действительно рабочий и для 32-х версии офиса и для 64-х битной, при правильной адаптации API функций.
Немного видоизменил код Вашего примера, сделав его универсальным как как для 64-bit версии офиса, так и для 32-bit системы, чтобы не распыляться между версиями.
Универсальный код для вышеприложенного примера:
Код
Option Explicit

Private Const OCR_NORMAL As Long = 32512
#If VBA7 Then
    'Загружаем функции для просмотра курсора
    Private Declare PtrSafe Function CopyCursor Lib "user32" Alias "CopyIcon" (ByVal hcur As LongPtr) As LongPtr
    Private Declare PtrSafe Function LoadCursorFromFile Lib "user32" Alias "LoadCursorFromFileA" (ByVal lpFileName As String) As LongPtr
    Private Declare PtrSafe Function GetCursor Lib "user32" () As LongPtr
    Private Declare PtrSafe Function SetSystemCursor Lib "user32" (ByVal hcur As LongPtr, ByVal id As Long) As Long
    Public Declare PtrSafe Function DestroyCursor Lib "user32" (ByVal hcur As LongPtr) As Long
#Else
    'Загружаем функции для просмотра курсора
    Private Declare Function CopyCursor Lib "user32" Alias "CopyIcon" (ByVal hcur As Long) As Long
    Private Declare Function LoadCursorFromFile Lib "user32" Alias "LoadCursorFromFileA" (ByVal lpMyFileName As String) As Long
    Private Declare Function GetCursor Lib "user32" () As Long
    Private Declare Function SetSystemCursor Lib "user32" (ByVal hcur As Long, ByVal id As Long) As Long
    Public Declare PtrSafe Function DestroyCursor Lib "user32" (ByVal hcur As Long) As Long

#End If
'Объявляем 2 переменные
Public NewCur As LongPtr, OldCursor As LongPtr



Sub Солнце1_Щелчок()
'Пишем откуда мы берем новый курсор
NewCur = LoadCursorFromFile(ActiveWorkbook.Path & "\Cursor.cur")
'Запоминаем прежний курсор и загружаем свой
'OldCursor = GetCursor()
'OldCursor = CopyCursor(OldCursor)
SetSystemCursor NewCur, OCR_NORMAL
End Sub

Sub Улыбающеесялицо3_Щелчок()
'Пишем откуда мы берем новый курсор
NewCur = LoadCursorFromFile(ActiveWorkbook.Path & "\check.cur")
'Запоминаем прежний курсор и загружаем свой
'OldCursor = GetCursor()
'OldCursor = CopyCursor(OldCursor)
SetSystemCursor NewCur, OCR_NORMAL
End Sub
Однако, экспериментируя, я не до конца сумел разобраться в целях использования переменной OldCursor.
Если закомментировать строки кода с параметром OldCursor, как в приведенном мною примере, то результат получится абсолютно таким же
Подсознательно понимаю, что она, скорее всего, необходима для возвращения стандартного вида указателя мыши, но не до конца понял, как ей правильно пользоваться, в связи с чем и соответствующий вопрос, а как вернуть при необходимости стандартный вид указателя курсора, например, используя событие листа Worksheet_SelectionChange?
То есть, пользователь нажал на кнопку вышеупомянутой в теме надстройки.
Курсор при использовании кода в приложенным Александром Моториным примере изменяет внешний вид, какой ему заложил разработчик.
Пользователь переводит курсор в границы сетки таблицы Excel.
Курсор преобразуется в курсоры самого Excel (да и бог с ним, потом разберемся...)
При выборе пользователем любой ячейки таблицы листа (срабатывание события Worksheet_SelectionChange) кликанием на ней левой клавишей мыши или задействованием клавиш навигации клавиатуры, вид курсора нужно вернуть к стандартной стрелке.
Из справочного материала самого Microsoft я понял, что для этих целей необходимо использовать функцию DestroyCursor.
Но как ее правильно применить в VBA из скудного справочного материала я решения не нашел.
Все эксперименты на авось по типу кода:
Код
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    DestroyCursor NewCur
End Sub
естественно, с треском провалились.

Как это корректно сделать?
(Прикладываю видоизмененный пример Александра Моторина)
Изменено: Владимир Баукин - 14.06.2021 19:19:13
макрос поиска строки и замены текста в нескольких столбцах
 
А каким способом Вы хотите достичь желаемого результата, использованием формул или применением макроса?
Принудительное изменение средствами VBA внешнего вида указателя курсора мыши при нажатии на кнопку подключенной надстройки, Подключение файла вида курсора мыши из списка, расположенного в каталоге C:\Windows\Cursors
 
Здравствуйте!
64-bit операционная система с 64-bit версией офиса (хотя, особо пока без разницы, ибо прилагающая ниже ссылка на найденный пример также выдает безуспешный результат и в 32-bit системе).
Итак, есть подключенная надстройка, представляющая из себя отдельную вкладку на ленте и содержащая кнопку.
Хочется, чтобы при нажатии на эту кнопку внешний вид курсора менялся со стандартной левонаправленной вверх стрелки на, например, вид руки с вытянутым указательным пальцем.
Вполне стандартный курсор, который можно найти в каталоге "C:\WINDOWS\Cursors\aero_link_il.cur"
Найденный в интернете пример по ссылке: http://rusproject.narod.ru/winapi/l/loadcursorfromfile.html показал на необходимость применения функций API LoadCursorFromFileA и SetCursor.
Однако ни адаптация этих функций под операционную систему 64-bit, ни прямое применение кода примера в системе 32-bit к желаемому результату не привело.
Иные поиски в инете с моделированием различных вариантов запросов по данному вопросу также не пролили свет на решение проблемы.
Предварительный код получается таким:

Код для системы 64-bit:
Код
Declare PtrSafe Function LoadCursorFromFile Lib "user32" Alias "LoadCursorFromFileA" (ByVal lpFileName As String) As LongPtr
Declare PtrSafe Function SetCursor Lib "user32" (ByVal hCursor As LongPtr) As LongPtr

Sub proba()
Dim hCursor As LongPtr

hCursor = LoadCursorFromFile("C:\WINDOWS\Cursors\aero_link_il.cur")
If hCursor = 0 Then End
SetCursor hCursor
End Sub 

Код для системы 32-bit:

Код
Declare Function LoadCursorFromFile Lib "user32" Alias "LoadCursorFromFileA" (ByVal lpFileName As String) As Long
Declare PtrSafe Function SetCursor Lib "user32" (ByVal hCursor As LongPtr) As Long

Sub proba()
Dim hCursor As Long

hCursor = LoadCursorFromFile("C:\WINDOWS\Cursors\aero_link_il.cur")
If hCursor = 0 Then End
SetCursor hCursor
End Sub 

Кто-нибудь сможет подсказать, как добиться желаемого результата?
Изменено: Владимир Баукин - 14.06.2021 07:22:43
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Цитата
Ігор Гончаренко написал:
см.вложение
Посмотрел.
На используемой мною рабочей станции используемый код не приводит к нужному результату, но все равно спасибо!
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Всех приветствую!

Мда... Не удалось победить модальный вариант формы даже с помощью API функции TrackMouseEvent.
Раскопал в загашнике 32-х битную версию винды, посмотрел, как работает эта функция на примере, упомянутом в ссылке вышеизложенного поста и понял, что все равно, как не трудись, а все упирается в событие MouseMove, которое при определенных ситуациях срабатывает, к сожалению, далеко не всегда.
Удалось это даже реализовать "костыльным" методом в 64-х разрядной операционной среде
Однако не сожалению о приобретенных знаниях, изучая справочные материалы, к адаптации API функций к 64-bit системе.
Задачку все-таки удалось решить, то есть достигнуть желаемого результата пусть и не совсем так, как это изложено в теме.
Сосредоточился на использование немодального варианта UserForm.
Если в листе книги Excel вызывается подобного рода форма и этот лист не обременен необходимостью обрабатывать свои события, то решение простенькое, наглядное, с которым можно ознакомиться в прилагаемом примере (Пример 1.zip)
Другое дело, если в листе книги Excel, в котором вызывается форма, задействуются события, такие как, например, SelectionChange.
В этом случае, особенно если для последующих вычислений, переадресации результирующих данных активного листа книги в другие области, организации ссылок и т.п. используются данные из вызванной формы, которые изменяют свойства объектов активного листа, то применение немодальной формы, когда возможно прямое изменение свойств объектов листа  книги Excel пользователем  в обход вызванного на экран диалогового окна, чревато непредсказуемыми последствиями.
Соответственно, пользователя нужно попытаться оградить от случайных "нежданчиков", когда у него случайно дернется рука, находящаяся на мышке, или просто обернувшись, случайно заденет мышь локтем, чтобы он визуально увидел, что диалог прервался. Много различных вариантов можно придумать
Либо, если это злоумышленник, то не позволить ему совершить свое коварное дело изменить результат путем ручного (не через форму) изменения ключевых данных листа книги Excel
Но машине-то по фигу, она реагирует на событие, созданное пользователем.
Поэтому, в результате упорных поисков и экспериментов, пришел к альтернативному варианту использования немодальной формы и принудительного контроля курсора мыши.
При этом управление курсором мыши я захватываю уже на этапе загрузки формы.
Желающие могут ознакомиться с решением в прилагаемом файле Пример 2.zip

Всем спасибо за внимание!
С Уважением
Изменено: Владимир Баукин - 29.05.2021 23:54:26
Есть ссылка на столбец умной таблицы. Как взять это название столбца из другой ячейки ?, Как правильно сослаться ?
 
Не совсем понял суть вопроса, но попробую ответить как понял.
Если нужно иметь возможность использовать значение конкретной ячейки из любой другой или обращения к ней по ее адресу, задайте нужной ячейке конкретное имя, как, например, в Вашем случае, задаем ячейке G1 имя "ПЕТЯ".
И, например, в ячейке А17 обращаемся к этому имени: =ПЕТЯ
Результатом показа в ячейке А17 будет "Петя".
Даже похулиганим немножко.
Установим ячейке G1 имя "ПЕТЯ", а ячейке H1 имя "ВАСЯ".
Введем в ячейку A17 формулу:
=ЕСЛИ(СМЕЩ(ПЕТЯ;1;0;1;1)<СМЕЩ(ВАСЯ;1;0;1;1); "Вася молодец!";"Петя молодец!")
И теперь поглумимся.
Оставив данные как есть в исходном примере, у нас получится, что Вася молодец!
Изменив значение в ячейке  В5 с 12 на 60, получим, что Петя молодец!
Изменено: Владимир Баукин - 22.05.2021 19:35:07
Как собрать данные в нужную ячейку, при соблюдения условия равенства данных в столбцах
 
Согласен с модератором - это тема отдельного разговора, что мы собираемся получить в результате.
Лучше создать отдельную тему, где мы сможем воспользоваться сочетанием функций Excel ПОИСКПОЗ и ИНДЕКС при правильной сортировке данных в КНИГА2.xls
Как собрать данные в нужную ячейку, при соблюдения условия равенства данных в столбцах
 
Здравствуйте!

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

В своей таблице в Книге1.xls в ячейку "В2"  введите формулу:
=ВПР(RC[-1];'[КНИГА 2.xlsx]БД'!C1:C2;2;0)
Скопируйте ее на все все ячейки столбца "В", где в ячейке столбца "А" имеются значения.
По мере заполнения ячеек столбца "А" продолжайте копирование формулы в соответствующую ячейку столбца "В".
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Снова всем здравия!

Тема по-прежнему для меня актуальна.

Вниманию модераторов!
Прошу переформулировать тему в окончательный правильный вариант:
Изменение свойств объектов (Controls) загруженной и показанной на экране пользовательской формы (UserForm) при перемещении указателя курсора мыши по экрану пользователем.

Предварительно отдельно хочу поблагодарить БМВ, что не позволил сойти с пути истинного.
На этом лирику закончим и перейдем к конкретике.

Никак не могу найти ошибку в своем коде  в силу недостаточности уровня знаний в понимании правил использования обратного вызова с использованием API функций.
Начнем по порядку.
Итак, есть задача - изменять для визуальной наглядности пользователю состояние свойств объектов (Controls) загруженной и выведенной на экран формы (UserForm) при перемещении пользователем мыши по экрану окна.
Возьмем для простоты простейшую форму, содержащую объект Image.
Желаемое:
Если пользователь навел курсор мыши на форму (курсор мыши внутри координат формы), то фон Image зеленый.
Если пользователь перевел курсор мыши за пределы координат формы , то фон Image становится красный.
Все это я пытаюсь реализовать в 64-bit операционной системе с установленной версией Office, использующего 64-разрядную версию VBA.
Создавая различного рода запросы в поисковике для решения своей задачи я выяснил, что в помощь мне функция API TRACKMOUSEEVENT.
И даже нашел практический пример по ссылке: http://rusproject.narod.ru/winapi/t/trackmouseevent.html
Изучив его, я понял, что мне его необходимо адаптировать в свою операционную среду.
И тут снова мне в помощь пришел найденный справочный материал:  https://codekabinett.com/rdumps.php?Lang=2&targetDoc=windows-api-declaration-vba-64-bit
Изучив на его основании типы аргументов необходимых мне API функций,  я адаптировал их декларацию под версию VBA 64-bit.
При проверке компиляции кода в среде VBA.Project все хорошо.
Однако результат выполнения кода не дает нужного результата.
Более того, при пошаговом выполнении наблюдается серьезный сбой, когда приложение Excel  просто перезагружается или даже закрывается.
И это происходит именно на этапе срабатывания функции обратного вызова.
Теперь конкретно о коде.

Вот код основного модуля
Код
Option Explicit

Public Const WM_MOUSELEAVE As Long = &H2A3&
Public Declare PtrSafe Function TRACKMOUSEEVENT Lib "user32" Alias "TrackMouseEvent" ( _
          lpEventTrack As TRACKMOUSEEVENT) As Long

Public Type TRACKMOUSEEVENT
    cbSize As Long
    dwFlags As Long
    hwndTrack As LongPtr
    dwHoverTime As Long
End Type

Public Const TME_LEAVE As Long = &H2

Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr

Declare PtrSafe Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As LongPtr, ByVal hWnd As LongPtr, ByVal Msg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr

Private Const GWLP_WNDPROC = (-4)
Dim PrevProc As LongPtr
Public Track As TRACKMOUSEEVENT
Public NoRecursForm As Boolean

Public Sub Hook(ByVal frmHWnd As LongPtr)
    PrevProc = SetWindowLong(frmHWnd, GWLP_WNDPROC, AddressOf WindowProc)
End Sub

Public Sub UnHook(ByVal frmHWnd As LongPtr)
    SetWindowLong frmHWnd, GWLP_WNDPROC, PrevProc
End Sub

Public Function WindowProc(ByVal hWnd As LongPtr, ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
    
    If uMsg = WM_MOUSELEAVE Then

        If UserForm1.Image1.BackColor = vbGreen Then
           UserForm1.Image1.BackColor = vbRed
        Else
           UserForm1.Image1.BackColor = vbGreen
        End If
        
    End If
    
    WindowProc = CallWindowProc(PrevProc, hWnd, uMsg, wParam, lParam)
End Function

Sub Example()
    Load UserForm1
    UserForm1.Show
End Sub

В процедуре Hook основного модуля используется параметр дескриптора окна пользовательской формы frmHwnd.
Я знаю, что у UserForm и его Controls нет свойства hwnd, поэтому мне опять же в помощь пришел справочный материал: https://colinlegg.wordpress.com/2016/05/06/getting-a-handle-on-userforms-vba/, изучив который я научился считывать дескриптор пользовательской формы.

Соответственно, код класса оговоренной для примера формы приобрел следующий вид:
Код
Option Explicit

Private Declare PtrSafe Function FindWindowA Lib "user32.dll" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
 
Private mlnghWnd As LongPtr
 
Public Property Get hWnd() As LongPtr
    hWnd = mlnghWnd
End Property
 

Private Sub UserForm_Initialize()
   StorehWnd
   Hook Me.hWnd
   With Track
       .cbSize = Len(Track)
       .dwFlags = TME_LEAVE
       .hwndTrack = Me.hWnd
       .dwHoverTime = 400
   End With
End Sub
 
Private Sub StorehWnd()
 
    Dim strCaption As String
    Dim strClass As String
 
    'class name changed in Office 2000
    If Val(Application.Version) >= 9 Then
        strClass = "ThunderDFrame"
    Else
        strClass = "ThunderXFrame"
    End If
 
    'remember the caption so we can
    'restore it when we're done
    strCaption = Me.Caption
 
    'give the userform a random
    'unique caption so we can reliably
    'get a handle to its window
    Randomize
    Me.Caption = CStr(Rnd)
 
    'store the handle so we can use
    'it for the userform's lifetime
    mlnghWnd = FindWindowA(strClass, Me.Caption)
 
    'set the caption back again
    Me.Caption = strCaption
 
End Sub

Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    TRACKMOUSEEVENT Track
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    UnHook Me.hWnd
End Sub

Однако не работает(
При пошаговом исполнении при обращении к функции WindowProc, я заметил, что параметр uMsg вообще даже близко не сопоставляется с установленной константой WM_MOUSELEAVE.
При этом происходит рекурсивное обращение к указанной функции, параметр uMsg меняется каждый раз, а после раза 4-5 рекурсивного вызова, приложение просто перезапускается или выгружается.

Уважаемые знатоки темы, подскажите, где у меня ошибка и/или чего мне не хватает (кроме ума и знаний, тут, надеюсь, понятно, шутки будут неуместны).  
Изменено: Владимир Баукин - 22.05.2021 03:25:42
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Хороший вопрос... Еще сильнее озадачил

Цитата
_Igor_61 написал: И сколько их потребуется?
всего 4

Цитата
БМВ написал:  так как быстрое перемещение не вызовет событие
Спасибо за замечание, учту!
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Цитата
RAN написал:
и как оно выглядит?
Курсор внутри формы - объект формы красный.
Курсор вне формы - объект формы зеленый  
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Есть, конечно, одна идея.
Например, обрамить границы формы объектами Label.
Тогда в любых вариантах передвижения курсора пользователем, используя событие MoseMove этих пограничных объектов, приводить вид объектов внутри формы к задуманному состоянию, которое хочется визуально получить, когда курсор переводится за границы формы.
Но может есть предложения поинтереснее?

Цитата
_Igor_61 написал: Это Вы так просто количество сообщений набираете?
Я бы с радостью перешел скорее к реализации следующего этапа своей задачи, решив эту.
Но проблема этого этапа пока не решена.
Да, я знаю координаты формы, могу определить координаты курсора.
Но не понимаю пока, как это объединить воедино, чтобы как только курсор получил координаты, находящимися за пределами границы формы произошел бы вызов какой-либо процедуры, которая бы изменила визуальное представление объектов формы
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Цитата
vikttur написал:
Вы бы озвучили конечную цель - для чего это?
Цель - визуальное предоставление пользователю состояния формы при нахождении курсора вне ее координат
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Цитата
БМВ написал:
Модельная форма не позволит ничего сделать с приложением за её пределами.
Не сможет и пес с ним. Важно, что пользователь увидит изменения, которые произошли в форме, когда он перевел курсор за ее пределы
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Цитата
Такого идиотского странного способа запуска макроса встречать еще не доводилось

Не вопрос.
Не претендую на безукоризненность.
Если резюме относится именно к формулировке, то можно переформулировать, как "Создание события отслеживания покидания курсором предела пользовательской форме на экране". Если резюме относится к сути самой задачи, то не вижу в ней ничего идиотского.
Более того, именно поэтому и обратился за помощью. Возможно, не спорю, есть идеи и получше. С удовольствием выслушаю рекомендации, предложения.
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Цитата
_Igor_61 написал: Вы же хотите просто определять положение (координаты) мыши
Да в том-то и дело, что координаты я прекрасно научился считывать.
Не получается вот что.
Попробую пояснить простеньким примером.
Предположим, есть пустая форма, в которой расположен, ну, пусть будет 'элементарный Label, при наведении на который цвет фона становится красный.
Теперь пользователь переводит курсор за границы формы. Как только курсор покинет пределы координат формы визуально хочется получить, чтобы цвет фона этого Label стал, например, зеленым.

Цитата
БМВ написал: она нужна не модальная?
Да без разницы какой тип самой формы.  
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Предлагаю такой вариант названия темы: "Запуск процедуры (макроса) при перемещении курсора мыши за пределы границ пользовательской формы, показанной на экране".

Цитата
БМВ написал: Если форма запущена как модальная, то я с трудом понимаю как нарушены границы.
Элементарно. Форма загружена, показана пользователю на экране в определенных координатах. Ничто не мешает пользователю, управляя мышью, перемещать курсор по всему экрану. Важно отловить момент, когда курсор, находящийся в пределах координат формы, затем переводится пользователем в координаты, находящимися за пределами этой формы.    
Изменение свойств объектов (Controls) загруженной и показанной на экране UserForm при перемещении указателя курсора мыши по экрану пользователем.
 
Здравствуйте, Уважаемые!

Понимаю, тема изъезженная, однако, блуждая по бесконечным просторам инета, на текущий момент не сумел найти ответа  на вот какой вопрос.
Есть форма (UserForm), напичканная множеством объектов.
Контроль внутри происходящего в форме, как в муравейнике - четко и жестко, мышь не проскользнет.
Но вот засада.
Мерзкий пользователь, работая с формой, вдруг по непонятно каким соображениям перемещает курсор мыши за границы формы.
И вот тут как раз и требуется просигнализировать, так сказать, дать понять исполняемому коду, что нарушена граница, пересечена "точка события", если уж совсем увлекаться в эпитеты, анализируя структуры объектов, аналогичных Черным дырам.
Пусть это даже будет вызов простейшего макроса, содержащего всего лишь вывод на экран предупреждающего сообщения, не важно.
Важно понять как вызвать этот макрос, к какому событию какого объекта формы обратиться.
Я скрупулезно исследовал.
Использование события формы UserForm_MouseMove не помогает.
И даже пытался зайти с другой стороны
Изучил возможности функции API GetCursorPos, определяющей координаты текущего расположения курсора на экране, в результате чего научился дрессировать UserForm, как в цирке на арене, располагая ее где захочу и как захочу.
Пытался даже комбинировать, но безрезультатно.
Чувствую, что решение где-то рядом, но найти пока не могу.
Люди добрые, "поможите" чем можете!  
Страницы: 1 2 След.
Наверх