简体   繁体   English

VBA Excel ListView 复选框不显示在用户窗体中

[英]VBA Excel ListView Checkboxes do not show in Userform

I have a UserForm with a MultipageControl (name Controller_MultiPage).我有一个带有 MultipageControl(名称 Controller_MultiPage)的用户窗体。 At runtime my code adds pages to the Multipage and creates a newListView on each page.在运行时,我的代码将页面添加到 Multipage 并在每个页面上创建一个 newListView。 Every ListView has:每个 ListView 都有:

      With newListView
        .MultiSelect = False
        .Width = Controller_MultiPage.Width - 10
        .Height = Controller_MultiPage.Height - 20
        .View = lvwReport
        .HideColumnHeaders = False
        .ColumnHeaders.Add Text:="Signal Name", Width:=.Width / 10 * 4
        .ColumnHeaders.Add Text:="Type", Width:=.Width / 10
        .ColumnHeaders.Add Text:="I/O", Width:=.Width / 10
        .ColumnHeaders.Add Text:="Description", Width:=.Width / 10 * 4
        .CheckBoxes = True
        .FullRowSelect = True
    End With

then I populate the newListView with data from an XML file:然后我用 XML 文件中的数据填充 newListView:

         For Each node In list
            With node.Attributes
                Set listItem = newListView.ListItems.Add(Text:=.getNamedItem("Name").Text)
                listItem.ListSubItems.Add = .getNamedItem("Type").Text
                listItem.ListSubItems.Add = IIf(.getNamedItem("Input").Text = "1", "IN", "OUT")
                listItem.ListSubItems.Add = .getNamedItem("Description").Text
                listItem.Checked = False
            End With
        Next

but the checkboxes do not show.但复选框不显示。 I can see the space for them in front of the first column and by clicking that space the checkbox of that particular row then appears.我可以在第一列前面看到它们的空间,然后单击该空间,然后出现该特定行的复选框。 What I also noticed is that if I change the property我还注意到,如果我更改属性

listItem.Checked = True

the behavior described above does not change, and when I click the free space in front of the first column (checkboxes space) the chsckbox that then shows up is still unchecked.上述行为没有改变,当我单击第一列(复选框空间)前面的可用空间时,然后显示的 chsckbox 仍然未选中。 Any idea?任何想法?

The problem seems to be in the behavior of the MultiPage control.问题似乎出在 MultiPage 控件的行为中。 What I noticed was that if I forced the checkboxes' status (checked or unchecked) from the code, using the MultiPage_Change event, then the checkboxes show up.我注意到的是,如果我使用MultiPage_Change事件从代码中强制复选框的状态(选中或未选中),那么复选框就会出现。

So what I did was to create a class that holds the status of all checkboxes of all listviews on a single page, instantiate the Class for each ListView and store everything into a Dictionary, using the newListView.Name as Key所以我所做的是创建一个 class 保存单个页面上所有列表视图的所有复选框的状态,为每个ListView实例化 Class 并将所有内容存储到字典中,使用newListView.Name作为键

Then when the user changes page, the MultiPage_Change event that fires resets all the values of the checkboxes according to the Dictionary stored values.然后,当用户更改页面时,触发的 MultiPage_Change 事件会根据 Dictionary 存储的值重置复选框的所有值。

In the Listview_N_ItemChecked event some other code updates the status of the item stored in the Dictionary.在 Listview_N_ItemChecked 事件中,一些其他代码会更新存储在 Dictionary 中的项目的状态。 Kind of cumbersome but it works.有点麻烦,但它有效。

the class ( updated ): class(更新):

' Class Name = ComponentsSignalsRecord
Option Explicit

Dim Name As String
' NOTE: Signals(0) will always be empty and status(0) will always be False
Dim Signals() As String
Dim Status() As Boolean
Dim Component As String

Property Let SetComponentName(argName As String)
    Component = argName
End Property

Property Get GetComponentName() As String
    GetComponentName = Component
End Property

Property Get getSignalName(argIndex) As String
    If argIndex >= LBound(Signals) And argIndex <= UBound(Signals) Then
        getSignalName = Signals(argIndex)
    Else
        getSignalName = vbNullString
    End If
End Property

Property Get dumpAll() As String()
    dumpAll = Signals
End Property

Property Get Count() As Long
    Count = UBound(Signals)
End Property

Property Get getStatus(argName As String) As Integer
    ' returns: -1 = Not Found; 1 = True; 0 = False
    getStatus = -1
    Dim i As Integer
    For i = 0 To UBound(Signals)
        If argName = Signals(i) Then getStatus = IIf(Status(i) = True, 1, 0): Exit For
    Next
End Property

Property Let setName(argName As String)
    Name = argName
End Property

Property Get getName() As String
    getName = Name
End Property

Public Sub UncheckAll()
    Dim i As Integer
    For i = 0 To UBound(Status)
        Status(i) = False
    Next
End Sub

Public Sub CheckAll()
    Dim i As Integer
    For i = 0 To UBound(Status)
        Status(i) = True
    Next
End Sub

Public Sub deleteSignal(argName As String)
    Dim spoolSignals() As String
    Dim spoolStatus() As Boolean
    Dim i As Integer
    spoolSignals = Signals
    spoolStatus = Status
    ReDim Signals(0)
    ReDim Status(0)
    For i = 1 To UBound(spoolSignals)
        If argName <> spoolSignals(i) Then
            ReDim Preserve Signals(UBound(Signals) + 1):    Signals(UBound(Signals)) = spoolSignals(i)
            ReDim Preserve Status(UBound(Status) + 1):      Status(UBound(Status)) = spoolStatus(i)
        End If
    Next
End Sub

Public Sub addSignal(argName As String, argValue As Boolean)
    Dim i As Integer
    For i = 0 To UBound(Signals)
        If argName = Signals(i) Then GoTo bye
    Next
    ReDim Preserve Signals(UBound(Signals) + 1)
    ReDim Preserve Status(UBound(Status) + 1)
    Signals(UBound(Signals)) = argName
    Status(UBound(Status)) = argValue
bye:
End Sub

Public Sub setStatus(argName As String, argValue As Boolean)
    Dim i As Integer
    For i = 0 To UBound(Signals)
        If argName = Signals(i) Then Status(i) = argValue: Exit For
    Next
End Sub

Private Sub Class_Initialize()
    ReDim Signals(0)
    ReDim Status(0)
End Sub

The Form relevant code.表单相关代码。 Module level:模块级别:

Dim myDict As New Dictionary                           ' the Dictionary
Dim ComponentsSignalsList As ComponentsSignalsRecord   ' the Class

for each ListView created, may be one or more for every single MultiPage page:对于创建的每个 ListView,每个 MultiPage 页面可能是一个或多个:

Set ComponentsSignalsList = New ComponentsSignalsRecord
ComponentsSignalsList.setName = newListView.name

while populating the listview(s) in a loop for each single item added:在为添加的每个单个项目循环填充列表视图时:

ComponentsSignalsList.addSignal List_Item.Text, List_Item.Checked

end of each loop, add the Class instance to the Dictionary:在每个循环结束时,将 Class 实例添加到 Dictionary 中:

myDict.Add ComponentsSignalsList.getName, ComponentsSignalsList

Now when changing Page in the MultiPage widget:现在在 MultiPage 小部件中更改页面时:

Private Sub Controller_MultiPage_Change()
    If isLoading Then Exit Sub   'avoid errors and undue behavior while initializing the MultiPage widget
    Dim locControl As Control
    Dim controlType As String: controlType = "ListView"
    With Controller_MultiPage
        For Each locControl In .Pages(.value).Controls
            If InStr(1, TypeName(locControl), controlType) > 0 Then
                Call Check_CheckBoxes(locControl)
            End If
        Next
    End With
End Sub

Private Sub Check_CheckBoxes(argListView As listView)
    If argListView.CheckBoxes = False Then Exit Sub   'some ListViews don't have checkboxes
    Dim myItem As ListItem
    For Each myItem In argListView.ListItems
        With myItem
            .Checked = myDict.Item(argListView.name).getStatus(.Text)
        End With
    Next
End Sub

when ticking/unticking a checkbox (note the the ItemChecked event handler is defined in another Class Public WithEvents , where the handler calls this method passing both the ListView ID and the Item object):当勾选/取消勾选复选框时(注意 ItemChecked 事件处理程序是在另一个 Class Public WithEvents中定义的,其中处理程序调用此方法传递 ListView ID 和 Item 对象):

Public Sub ListViewsEvents_ItemCheck(argListView As listView, argItem As MSComctlLib.ListItem)
    With argItem
        myDict.Item((argListView .name).setStatus argName:=.Text, argValue:=.Checked
    End With
End Sub

I just found the answer to the same problem that I also had and I feel so stupid.我刚刚找到了同样问题的答案,我觉得自己很愚蠢。 I had the first column of the Listview set to Width = 0... and thus the checkboxes would no longer show.我将 Listview 的第一列设置为 Width = 0...,因此复选框将不再显示。 I gave it a width and everithing is back to normal...我给了它一个宽度,一切都恢复了正常......

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

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