Sizing of Dynamically created ListView

pingel

New Member
Joined
May 23, 2022
Messages
4
Office Version
  1. 365
Platform
  1. Windows
Working on a vba module to dynamically create a form with two ListView components. Started out with ListBox components, but need to control color of individual items in the List, and therefore need to change to ListView components instead. For some reason the ListView can't be easily sized and positioned similarly to the ListBox component, and I have tried various options to no avail.

The Form looks something like this:
1665475200551.png


The ListViews are embedded in two frames, to at least position them appropriately, but I still can't get the size to work.

Below is some of the code to generate the form and add the first ListView

VBA Code:
Private Sub ModuleSelectForm()
    Dim myForm   As Object
    ' ListView Components
    Dim LFrame                 As Frame
    Dim SFrame                 As Frame
    Dim LoadedModuleListBox    As ListView
    ...
    Dim ListViewHandle         As Long
    Dim ListViewRect           As Rect
    ...
    ...

    ' Add The form
    Set myForm = ThisWorkbook.VBProject.VBComponents.Add(3)
    Set vbaModulesForm = myForm
    'Create the User Form
    With myForm
        .Properties("Caption") = "Manage Expense Files"
        .Properties("Width") = 410
        .Properties("Height") = 350
    End With
    'Create Load Module ListBox inside Frame
    Set LFrame = myForm.Designer.Controls.Add("Forms.Frame.1")
    With LFrame
        .Caption = ""
        .BorderStyle = fmBorderStyleNone
        .KeepScrollBarsVisible = fmScrollBarsNone
        .ScrollBars = fmScrollBarsNone
        .SpecialEffect = fmSpecialEffectFlat
        .Top = 5
        .Left = 10
        .Width = 150
        .Height = 150
  
        Set LoadedModuleListBox = LFrame.Controls.Add("MSComctlLib.ListViewCtrl.2", "LoadedModuleListBox")
        With LoadedModuleListBox
            .Visible = True
            .View = lvwList
            .MultiSelect = True
            .CheckBoxes = False
            .HideColumnHeaders = True
            .HideSelection = False
            .LabelEdit = False
            .BorderStyle = fmBorderStyleOpaque
           '.Top = 5          ' Doesn't work
           '.Left = 10        ' Commented out
           '.Width = 150
           '.Height = 150

        End With
    End With

...

End Sub

------

I of course tried to set .Left, .Top, .Height, and .Width - which are non existing for ListView
Interestingly enough, I found an example of a form with a ListView, and if I don't try to create it dynamically, but instead add a ListView to a form in the project, for some reason I am able to set width, height, etc. That off course doesn't help me either - as I want to be able to add this module to any project, without having to add the form.

I then tried to get the Window Handle of the ListView and use SetWindowPos to modify it:

VBA Code:
Private Sub UserForm_Initialize()
    Dim LstItem            As ListItem
    Dim ListViewHandle     As Long
    Dim ListViewRect       As Rect
    ' Size / Position of Listview
    With Me.LoadedModuleListBox
        ListViewHandle = .hWnd
        Call GetWindowRect(ListViewHandle, ListViewRect)
        SetWindowPos ListViewHandle, 0, ListViewRect.Left + 5, ListViewRect.Top + 10, 150, 150, &H40
        ..
    End With
...
End Sub

This doesn't give me any errors, but it also doesn't change anything either.


Does anyone out there have a good example of how to dynaically add a ListView to a form, and size it and position it on the form?
Any help would be greatly appreciated.

Thanks
 

Excel Facts

Who is Mr Spreadsheet?
Author John Walkenbach was Mr Spreadsheet until his retirement in June 2019.
I tried running your code and it seems to work fine. It first creates the userform, then it adds a frame to the userform, and then it adds a listview control within the frame with the properties set as specified. Note that the left and top positions are set relative to the frame, not the userform.

pingel.png
 
Upvote 0
Thanks for the quick response.
Instead of trying to figure out why the code works for you and not for me, I trimmed down the code and created a workbook with the example module included.

I can't find a way here to add the excel workbook, so I have included the entire module here:

VBA Code:
Private Const ThisModuleName = "ListViewTest"
'*************************************************

Public Type Rect
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Public Declare PtrSafe Function GetWindowRect Lib "user32" (ByVal hWnd As Long, Rect As Rect) As Long
Public Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long


Private vbaListViewForm As Object

' Routine to run the setup/management
Private Sub RunThis()
    Call vbaListViewFormCreate
End Sub


Private Sub vbaListViewFormCreate()
    Dim myForm   As Object
    Dim VBCode   As VBIDE.CodeModule
    Dim Module   As VBIDE.VBComponent
    Dim ProcKind As VBIDE.vbext_ProcKind
    Dim ProcName As String
    ' Center Button Components
    Dim LoadButton      As MSForms.CommandButton
    Dim CancelButton    As MSForms.CommandButton
    ' ListView Components
    Dim LFrame                 As Frame
    Dim LoadedModuleListBox    As ListView
    ' General variables
    Dim CreateLines As Boolean
    Dim CLine       As Long
    Dim MLine       As Long
    Dim x           As Integer
    Dim Line        As Integer
    Dim IDEVisible  As Boolean
    ' Was the vba editor open - i.e. the routine was called from the editor
    IDEVisible = Application.VBE.MainWindow.Visible
    'This is to stop screen flashing while creating form
    Application.VBE.MainWindow.Visible = False
    ' Add The form
    Set myForm = ThisWorkbook.VBProject.VBComponents.Add(3)
    Set vbaModulesForm = myForm
    'Create the User Form
    With myForm
        .Properties("Caption") = "ListView Form"
        .Properties("Width") = 250 ' Border is 2 on each side
        .Properties("Height") = 250
    End With
    'Create Load Module ListBox inside Frame
    Set LFrame = myForm.Designer.Controls.Add("Forms.Frame.1")
    With LFrame
        .Caption = ""
        .BorderStyle = fmBorderStyleNone
        .KeepScrollBarsVisible = fmScrollBarsNone
        .ScrollBars = fmScrollBarsNone
        .SpecialEffect = fmSpecialEffectFlat
        .Top = 5
        .Left = 10
        .Width = 150
        .Height = 150
    
        Set LoadedModuleListBox = LFrame.Controls.Add("MSComctlLib.ListViewCtrl.2", "LoadedModuleListBox")
            
        With LoadedModuleListBox
            .Visible = True
            .View = lvwList
            .MultiSelect = True
            .CheckBoxes = False
            .HideColumnHeaders = True
            .HideSelection = False
            .LabelEdit = False
            .BorderStyle = fmBorderStyleOpaque
        End With
    End With

    'Create CommandCenterButton Load
    Set LoadButton = myForm.Designer.Controls.Add("Forms.commandbutton.1")
    Call FormButtonSetup(LoadButton, "cmd_Load", "Load", "", 170, 100)
    'Create CommandButton Cancel
    Set CancelButton = myForm.Designer.Controls.Add("Forms.commandbutton.1")
    Call FormButtonSetup(CancelButton, "cmd_Cancel", "Cancel", "", 170, 170)


    ' Add the code to the form - dynamically
    ' The code below is dynaically added to the form, so that any component on the form as associated code
    'add code for Components
    CLine = 1
    ' Setup the import module (this module)
    Set VBProj = ThisWorkbook.VBProject
    On Error Resume Next
    Set Module = VBProj.VBComponents(ThisModuleName)
    On Error GoTo 0
    If Not Module Is Nothing Then
        ' Find all the functions needed
        Set VBCode = Module.CodeModule
        With VBCode
            ' Start after declarations
            MLine = .CountOfDeclarationLines + 1
            CreateLines = False
            ' Go thru all lines
            Do Until MLine >= .CountOfLines
                ProcName = .ProcOfLine(MLine, ProcKind)
                ' Check to see if we are at the start of the procedures
                If ProcName = "UserForm_Initialize" Then CreateLines = True
                ' Process lines if we have started
                If CreateLines Then
                    ' Add all the lines from producedure start thru End Sub
                    Do Until MLine >= .ProcStartLine(ProcName, ProcKind) + .ProcCountLines(ProcName, ProcKind) + 1 >= .CountOfLines
                        ProcLine = RTrim(.Lines(MLine, 1))
                        myForm.CodeModule.InsertLines CLine, ProcLine
                        CLine = CLine + 1
                        MLine = MLine + 1
                        If Left(ProcLine, 7) = "End Sub" Then Exit Do
                    Loop
                End If
                ' Check to see if we are done
                If ProcName = "cmd_Cancel_Click" Then CreateLines = False
                ' Get to the next procedure
                MLine = .ProcStartLine(ProcName, ProcKind) + .ProcCountLines(ProcName, ProcKind) + 1
            Loop
        End With
    End If
    'Show the form
    VBA.UserForms.Add(myForm.Name).Show
    'Delete the form (Dynamic)
    ThisWorkbook.VBProject.VBComponents.Remove myForm
    ' Can we re-open the vba editor?
    Application.VBE.MainWindow.Visible = IDEVisible

End Sub

Private Sub FormButtonSetup(Btn As MSForms.CommandButton, Name As String, Caption As String, Accelerator As String, Top As Long, Left As Long, Optional Width As Long = 50)
    With Btn
        .Name = Name
        .Caption = Caption
        .Accelerator = Accelerator
        .Top = Top
        .Left = Left
        .Width = Width
        .Height = 20
        .Font.Size = 8
        .Font.Name = "Tahoma"
        .BackStyle = fmBackStyleOpaque
    End With
End Sub


' ************************************************************************
' Form Code to load and insert into Dynamic Form
' This code is NOT used inside this module
' It is only used to create the dynamic form
' ************************************************************************

' add code for Initialization of Form
Private Sub UserForm_Initialize()
    Dim modName, modStr    As String
    Dim LoadMods, SaveMods As Long
    Dim LstItem            As ListItem
    Dim ListViewHandle     As Long
    Dim ListViewRect       As Rect
    ' Size / Position of Listview
    With Me.LoadedModuleListBox
        '.ColumnHeaders.Add Text:="Header", Width:=150
        ListViewHandle = .hWnd
        Call GetWindowRect(ListViewHandle, ListViewRect)
        ' MsgBox ListViewRect.Left & " - " & ListViewRect.Right & " | " & ListViewRect.Top & " - " & ListViewRect.Bottom
        SetWindowPos ListViewHandle, 0, ListViewRect.Left, ListViewRect.Top, 150, 150, &H40
    End With
End Sub

'add code for Comand Button
Private Sub cmd_Load_Click()
    Dim LstItem As ListItem
    ' Load Items into the ListView
    For i = 1 To 6
        Set LstItem = Me.LoadedModuleListBox.ListItems.Add(Text:="Item " & i)
    Next i

    
End Sub
    
  
'add code for Comand Button Clse
Private Sub cmd_Cancel_Click()
    Unload Me
End Sub


Create a new module in an empty workbook
Name the module: ListViewTest

Copy the above code into the module
Then run the routine: RunThis

What I get when I do that is the following:

1665513874153.png


Any idea what I might be doing wrong here?

Thanks
 
Upvote 0
The code that you've posted does not set the properties for Left, Top, Width, and Height. When I include it like this...

VBA Code:
        With LoadedModuleListBox
            .Visible = True
            .View = lvwList
            .MultiSelect = True
            .CheckBoxes = False
            .HideColumnHeaders = True
            .HideSelection = False
            .LabelEdit = False
            .BorderStyle = fmBorderStyleOpaque
            .Top = 5
            .Left = 10
            .Width = 150
            .Height = 150
        End With

...I get the following...

pingel.png


By the way, you're assigning your listview control to a variable called LoadedModuleListBox, which can get a bit confusing since the name incudes the word listbox, instead of listview.
 
Upvote 0
Solution
Don't I feel like an idiot!! :-)

Not sure what the difference was, but when I originally started out by setting the size and position the normal way, I got an error - like property not available.
When I look (and still do), size and position properties doesn' seem to be part of the ListView Class:

1665714592233.png


But for some reason now, I can set them and they work.
Thanks for your help and patience with me :-)
 
Upvote 0
Yeah, unfortunately they don't appear within the Object Browser either. But if you manually insert a ListView control on a UserForm, select the control, and then check the Properties window, you'll see that they do appear there. Oh well. :-)
 
Upvote 0

Forum statistics

Threads
1,223,884
Messages
6,175,177
Members
452,615
Latest member
bogeys2birdies

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top