简体   繁体   English

将 ImageCombo-ActiveX 添加到工作表时出现 Excel VBA 问题

[英]Excel VBA Problem when adding an ImageCombo-ActiveX to a worksheet

I'm trying to add an ImageCombo-ActiveX control to an Excel worksheet by using the VBA-function.OLEObjects.Add(classtype:="MSComctlLib.ImageComboCtl.2", Top:=TopPos, Left:=LeftPos, Height:=0, Width:=0).我正在尝试使用 VBA-function.OLEObjects.Add(classtype:="MSComctlLib.ImageComboCtl.2", Top:=TopPos, Left:=LeftPos, Height:= 将 ImageCombo-ActiveX 控件添加到 Excel 工作表0,宽度:=0)。

When doing so, the ImageCombo control is displayed on the worksheet in a preloaded state: ImageCombo Preloaded State这样做时,ImageCombo 控件以预加载状态显示在工作表上: ImageCombo 预加载状态

When doing a check with Winspector Spy, it turned out then the ActiveX-Window is loaded as a child-window of an invisible window within Excel named as 'CtlFrameworkParking': ActiveX control window当使用 Winspector Spy 进行检查时,结果发现 ActiveX-Window 被加载为 Excel 中名为“CtlFrameworkParking”的不可见窗口的子窗口: ActiveX 控制窗口

instead of being diplayed as an ImageCombo-control.而不是作为 ImageCombo 控件显示。 To force this, I first have to make the worksheet window invisble and then redisplay it: Status after Re-displaying the worksheet window为了强制执行此操作,我首先必须使工作表窗口不可见,然后重新显示它:重新显示工作表窗口后的状态

Finally, after manually scrolling down a line, the ImageCombo-control is diplayed at the desired location with the desired size.最后,在手动向下滚动一行后,ImageCombo 控件将以所需大小显示在所需位置。 Status after worksheet scroll工作表滚动后的状态

Reinspecting with Winspector Spy the ActiveX-Window now is located within the worksheet window: final correct status使用 Winspector Spy 重新检查 ActiveX-Window 现在位于工作表窗口内:最终正确状态

Is there any way to programatically force the ActiveX-Window to show in final state on the worksheet window, probably with some api calls?有没有办法以编程方式强制 ActiveX-Window 在工作表窗口中以最终状态显示,可能有一些 api 调用?

I Solved the problem doing it the dirty way by adding the following lines:我通过添加以下行以肮脏的方式解决了这个问题:

Function ShowLanguageDropDown(TargetSheetName As String, Optional TopPos As Single = 0#, Optional LeftPos As Single = 0#, Optional SetVisible As Boolean = False) As MSComctlLib.ImageCombo
'---------------------------------------------------------------------------------------
' Procedure : ShowLanguageDropDown
' Author    : Bernd Birkicht
' Date      : 05.11.2022
' Purpose   : inserts an image dropdown on the target sheet, requires prelodad OLE-objects on a SourceSheet
'             containing the ImageDropdown and the to be associated pre-set ImageList-activeX control
'---------------------------------------------------------------------------------------
'
'........
Set TargetSheet = ActiveWorkbook.Sheets(TargetSheetName)
'........

With TargetSheet
  .Visible = xlSheetHidden
  .Visible = xlSheetVisible
  .Activate
End With
Set TargetSheet = Nothing

CurrentScrollRow = ActiveWindow.ScrollRow
ActiveWindow.ScrollRow = 2
ActiveWindow.ScrollRow = CurrentScrollRow
End function

These commands now do programmatically what I did manually before resulting in now correctly displaying the ImageDropdown control at the desired location on the worksheet.这些命令现在以编程方式执行我之前手动执行的操作,导致现在在工作表上的所需位置正确显示 ImageDropdown 控件。

I would welcome a more elegant solution.我会欢迎一个更优雅的解决方案。

I finally decided to to drop the approach of using an ImageCombo-ActiveX control directly on an Excel worksheet due to i encounterd a big bunch of problems with the ImageCombo-control further on.我最终决定放弃直接在 Excel 工作表上使用 ImageCombo-ActiveX 控件的方法,因为我进一步遇到了 ImageCombo-控件的一大堆问题。

When stopping the screen update, the Drop-down arrow within the control occasionally disappears and the control repaints not always fully.停止屏幕更新时,控件内的下拉箭头偶尔会消失,并且控件并不总是完全重绘。 I was not able to fix this.我无法解决这个问题。

At the end of the day, I used the ImageCombo-ActiveX control within a modeless userform which is not affected at all from application screen updating or events processed by the application while the userform is displayed.最后,我在无模式用户窗体中使用了 ImageCombo-ActiveX 控件,它完全不受应用程序屏幕更新或显示用户窗体时应用程序处理的事件的影响。

To prevent the userform from floating on the windows screen, I now attached the userform to the Excel-application window and cropped the userform frame around the ImageCombo-control.为了防止用户窗体在 Windows 屏幕上浮动,我现在将用户窗体附加到 Excel 应用程序窗口并裁剪 ImageCombo 控件周围的用户窗体框架。

Please find below the code:请在下面找到代码:

Private Sub UserForm_Initialize()
'---------------------------------------------------------------------------------------
' Procedure : UserForm_Initialize
' Author    : Bernd Birkicht
' Date      : 10.11.2022
' Purpose   : fills the image-Dropdownbox valid lnaguage entries
'---------------------------------------------------------------------------------------
'
  Static BasicInit As Boolean

  On Error GoTo UserForm_Initialize_Error

  If BasicInit Then Exit Sub    'already initialised?

....
  'adapt userform window to  Dropbox size
  Me.Height = Me!LanguageDropBox.Height
  Me.Width = Me!LanguageDropBox.Width

  With Me.LanguageDropBox
    Set .ImageList = Nothing          'delete image list and import again
    If .ImageList Is Nothing Then Set .ImageList = Me.LanguageSmallIconImageList
    mlngptrCtlHwnd = .hwnd
    .Locked = True
  End With

  PopulateComboItems Translate:=bTranslate

UserForm_Initialize_Exit:
  Crop_UF_Frame
  BasicInit = MakeChild(Me)
  
  Exit Sub

UserForm_Initialize_Error:
  Select Case Err.Number

  Case Else
    'MsgBox "Error " & Err.Number & " (" & Err.Description & ") in Prozedur UserForm_Initialize aus Formular LanguageDropBoxForm"
    'LogError Err.Number, Err.Description, "in Prozedur UserForm_Initialize aus Formular LanguageDropBoxForm"
    ErrEx.CallGlobalErrorHandler        ' Call the global error handler to deal with unhandled errors
    Resume UserForm_Initialize_Exit:
  End Select

End Sub



Private Sub Crop_UF_Frame()
'---------------------------------------------------------------------------------------
' Procedure : Crop_UF_Frame
' Author    : Nepumuk https://www.herber.de/forum/archiv/1456to1460/1459854_Userform_komplett_ohne_Rand.html
' Date      : 21.11.2015
' Purpose   : crop the userform frame
' geändert  : 11.11.2022 Bernd Birkicht
'             ergänzt: Region eingrenzen auf einzelnes Control in der Userform
'---------------------------------------------------------------------------------------
'
  Dim udtRect As RECT, udtPoint As POINTAPI
  Dim lngptrStyle As LongPtr, lngptrRegion As LongPtr, lngParenthWnd As LongPtr
  Static BasicInit As Boolean

  On Error GoTo Crop_UF_Frame_Error

  mlngptrHwnd = FindWindowA(GC_CLASSNAMEMSFORM, Caption)

  lngptrStyle = GetWindowLongA(mlngptrHwnd, GWL_STYLE)
  Call SetWindowLongA(mlngptrHwnd, GWL_STYLE, lngptrStyle And Not WS_CAPTION)
  Call DrawMenuBar(mlngptrHwnd)

  Call GetWindowRect(mlngptrHwnd, udtRect)
  udtPoint.x = udtRect.right
  udtPoint.y = udtRect.bottom

  Call ScreenToClient(mlngptrHwnd, udtPoint)

  '11.11.2022 set region
  If mlngptrCtlHwnd = 0 Then  'Control in Userform gewählt?
    'remove userform frame
    With udtRect
      .bottom = udtPoint.y
      .left = 4
      .right = udtPoint.x
      .top = 4
    End With
  Else
    'set region to WindowRect of the selected control
    Call GetWindowRect(mlngptrCtlHwnd, udtRect)
  End If

  lngptrRegion = CreateRectRgnIndirect(udtRect)
  Call SetWindowRgn(mlngptrHwnd, lngptrRegion, 1&)

Crop_UF_Frame_Exit:
  Exit Sub

Crop_UF_Frame_Error:
  Select Case Err.Number

  Case Else
    ErrEx.CallGlobalErrorHandler        ' Call the global error handler to deal with unhandled errors
    Resume Crop_UF_Frame_Exit:
  End Select
End Sub


Private Function MakeChild(ByVal UF As UserForm) As Boolean
  Dim DeskHWnd As LongPtr
  Dim WindowHWnd As LongPtr
  Dim UFhWnd As LongPtr

  MakeChild = False

  ' get the window handle of the Excel desktop
  DeskHWnd = FindWindowEx(Application.hwnd, 0&, "XLDESK", vbNullString)
  If DeskHWnd > 0 Then
    ' get the window handle of the ActiveWindow
    WindowHWnd = FindWindowEx(DeskHWnd, 0&, "EXCEL7", ActiveWindow.Caption)
    If WindowHWnd > 0 Then
      ' ok
    Else
      MsgBox "Unable to get the window handle of the ActiveWindow."
      Exit Function
    End If
  Else
    MsgBox "Unable to get the window handle of the Excel Desktop."
    Exit Function
  End If

' get the window handle of the userform
  Call IUnknown_GetWindow(UF, VarPtr(UFhWnd))
  mlngptrOldParenthWnd = GetParent(UFhWnd)
  If mlngptrOldParenthWnd = WindowHWnd Then Exit Function  'Assignment to Excel window already done

  'make the userform a child window of the MDIForm
  If (UFhWnd > 0) And (WindowHWnd > 0) Then
    ' make the userform a child window of the ActiveWindow
    If SetParent(UFhWnd, WindowHWnd) = 0 Then
      ''''''''''''''''''''
      ' an error occurred.
      ''''''''''''''''''''
      MsgBox "The call to SetParent failed."
      Exit Function
    End If
  End If

  MakeChild = True
End Function

call:称呼:

    If Wb.ActiveSheet.Name = Translate_To_OriginalText(InitSheetName) And LanguageDropBoxUForm Is Nothing Then
      LanguageDropBoxForm.Hide        'Lädt das Window ohne es anzuzeigen
      If UserForms.count > 0 Then Set LanguageDropBoxUForm = UserForms(UserForms.count - 1)
      LanguageDropBoxForm.Move 660#, 85#
      LanguageDropBoxForm.Show vbModeless     'show Language-Select-Window modeless
    endif

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM