如何使用VBA在Excel用户窗体中为多列列表框添加标题

19

是否可以在多列列表框中设置标题,而不使用工作表范围作为数据源?

以下使用一个变量数组赋值给列表框的列表属性,但标题显示为空白。

Sub testMultiColumnLb()
    ReDim arr(1 To 3, 1 To 2)

    arr(1, 1) = "1"
    arr(1, 2) = "One"
    arr(2, 1) = "2"
    arr(2, 2) = "Two"
    arr(3, 1) = "3"
    arr(3, 2) = "Three"


    With ufTestUserForm.lbTest
        .Clear
        .ColumnCount = 2
        .List = arr
    End With

    ufTestUserForm.Show 1
End Sub
17个回答

20

这是我的解决方案:

该解决方案要求您添加第二个ListBox元素并将其放置在第一个元素之上。

像这样:

Add an additional ListBox

然后调用函数CreateListBoxHeader使对齐正确并添加标题项。

结果:

Call the function CreateListBoxHeader

代码:

  Public Sub CreateListBoxHeader(body As MSForms.ListBox, header As MSForms.ListBox, arrHeaders)
            ' make column count match
            header.ColumnCount = body.ColumnCount
            header.ColumnWidths = body.ColumnWidths

        ' add header elements
        header.Clear
        header.AddItem
        Dim i As Integer
        For i = 0 To UBound(arrHeaders)
            header.List(0, i) = arrHeaders(i)
        Next i

        ' make it pretty
        body.ZOrder (1)
        header.ZOrder (0)
        header.SpecialEffect = fmSpecialEffectFlat
        header.BackColor = RGB(200, 200, 200)
        header.Height = 10

        ' align header to body (should be done last!)
        header.Width = body.Width
        header.Left = body.Left
        header.Top = body.Top - (header.Height - 1)
End Sub

使用方法:

Private Sub UserForm_Activate()
    Call CreateListBoxHeader(Me.listBox_Body, Me.listBox_Header, Array("Header 1", "Header 2"))
End Sub

2
谢谢。我喜欢这个方法。我有一个列表框,它比表单的宽度要宽。因此,用户必须水平滚动才能查看其他列。标题列表框不会随着数据列表框一起滚动。您有任何解决这种情况的方案吗? - GisMofx
我知道这很老,但我必须稍微调整一下代码,以便从Excel范围创建一个标题数组。对于i = LBound(arrHeaders)到UBound(arrHeaders)'更改为使用LBound header.List(0,i-1)= arrHeaders(i)'更改为i-1 - j2associates
2
我不知道为什么后面的答案被接受了。这个更简洁、更易懂,适用于任意数量的列。我只会添加header.Locked = True,以避免用户搞乱它。 - Marcelo Scofano Diniz
我们有关于标题列表框能否在数据列表框移动时也一同移动的更新吗? - WIL

19

不需要。我在列表框上方创建标签作为标题。你可能认为每次列表框更改时更改标签很麻烦。你是对的 - 它确实很麻烦。第一次设置就很麻烦,更改就更麻烦了。但我没有找到更好的方法。


是的,如果你的列表框只有很少的列,比如说5列或更少,那么Dick的答案就是正确的选择。 - Lunatik
如果您的列表框可以滚动,使用标签的解决方案就毫无用处。即使在2020年,11年过去了,微软仍然无法更新Excel以便更有用。每个版本的VBA都比上一年更糟糕。 - Neil

9
我刚才看到这个问题,并找到了这个解决方案。如果你的 RowSource 指向一系列单元格,多列列表框中的列标题将从紧挨着 RowSource 上面的单元格中取得。
以此处的示例为例,在列表框内,“Symbol”和“Name”这两个词会显示为标题。当我更改单元格 AB1 中的“Name”一词后,再次在 VBE 中打开表单,列标题随之改变。
这个示例来自 S. Christian Albright 的《VBA for Modelers》工作簿,我正在尝试弄清楚他是如何在列表框中获得列标题的:)

4
没错,你不想要一个工作表范围作为源。希望人们觉得这很有趣。我惊讶地发现自己竟然花了一年时间才注意到这一点。 - Rick Henderson
非常有用。感谢您的分享。使用您的建议可以更轻松地创建多列列表框。 - Karolis

5
简单的回答是:不行。
过去我做过的方法是将标题加载到第一行,然后在显示表单时将ListIndex设置为0。这样会将“标题”突出显示为蓝色,看起来像一个标题。如果ListIndex保持为零,则表单动作按钮将被忽略,因此永远无法选择这些值。
当然,一旦选择了另一个列表项,标题就会失去焦点,但此时它们的工作已经完成。
这样做还允许您拥有水平滚动的标题,这对于浮动在列表框上方的单独标签来说很难/不可能实现。反过来,如果列表框需要垂直滚动,则标题不会保持可见。
基本上,这是一种妥协方案,在我遇到的情况下有效。

2
创建另一个ListBox,紧挨着“真正的”ListBox。这个ListBox只有1行来包含标题,然后同时滚动它们。我没有尝试过,但认为可以做到,不是吗? - David Zemens
不幸的是,ListBox 没有 "Scrolled" 事件。 但是可以创建足够宽的 ListBox,并在其上方放置标签作为列标题。然后把它们都放在一个框架中,在水平方向上滚动框架以及标签和 ListBox。 - alexkovelsky

4

只需使用两个列表框,一个用于标题,另一个用于数据

  1. 对于标题 - 将 RowSource 属性设置为顶部行,例如 Incidents!Q4:S4

  2. 对于数据 - 将 RowSource 属性设置为 Incidents!Q5:S10

将 SpecialEffects 设置为“3-frmSpecialEffectsEtched” enter image description here


这比目前提到的任何其他方法都要好得多。谢谢! - Jim Bray

4
非常简单的解决方法,可以在多列列表框的顶部显示标题。只需将属性“columnheads”值更改为“true”,默认情况下为false。
之后,仅在“rowsource”属性中提及数据范围,数据范围应排除标题,并且标题应位于数据范围的第一行顶部,然后它会自动选择标题并将其冻结。
例如,如果您的数据范围是“A1:H100”,标题在“A1:H1”中,即第一行,则您的数据范围应为“A2:H100”,需要在“rowsource”属性中提及,并且“columnheads”属性值应为true。
谢谢, Asif Hameed

7
你漏掉了原帖作者想要在不使用工作表范围作为数据源的情况下完成它这一部分。 - Darren Bartrup-Cook

2

我喜欢在ComboBox的标题上采用以下方法,其中CboBx不是从工作表(例如来自SQL的数据)加载的。 我指定不是来自工作表的原因是我认为RowSource能够正常工作的唯一方法是从工作表加载。

这对我有效:

  1. Create your ComboBox and create a ListBox with an identical layout but just one row.
  2. Place the ListBox directly on top of the ComboBox.
  3. In your VBA, load ListBox row1 with the desired headers.
  4. In your VBA for the action yourListBoxName_Click, enter the following code:

    yourComboBoxName.Activate`
    yourComboBoxName.DropDown`
    
  5. When you click on the listbox, the combobox will drop down and function normally while the headings (in the listbox) remain above the list.


非常有趣。 - Rick Henderson

1

我曾经搜索了很长时间,想要找到一种方法在不使用单独的样式表并复制所有内容到用户窗体中的情况下添加标题。

我的解决方案是使用第一行作为标题,并通过 if 条件运行它,并在下面添加其他项目。

就像这样:

If lborowcount = 0 Then
 With lboorder
 .ColumnCount = 5
 .AddItem
 .Column(0, lborowcount) = "Item"
 .Column(1, lborowcount) = "Description"
 .Column(2, lborowcount) = "Ordered"
 .Column(3, lborowcount) = "Rate"
 .Column(4, lborowcount) = "Amount"
 End With
 lborowcount = lborowcount + 1
End If
        
        
With lboorder
 .ColumnCount = 5
 .AddItem
 .Column(0, lborowcount) = itemselected
 .Column(1, lborowcount) = descriptionselected
 .Column(2, lborowcount) = orderedselected
 .Column(3, lborowcount) = rateselected
 .Column(4, lborowcount) = amountselected
 
 
 End With

lborowcount = lborowcount + 1

在这个例子中,lboorder是列表框,lborowcount计算下一个列表框项要添加到哪一行。它是一个5列的列表框。虽然不是理想的,但它能够工作,并且当你需要水平滚动时,“标题”会保持在行上方。

1
这是我的解决方案。
我注意到,当我通过VBE中的属性窗口指定列表框的行来源时,标题会很容易地弹出。只有当我们尝试通过VBA代码定义行来源时,标题才会丢失。
因此,我首先在VBE中将列表框行来源定义为命名区域,然后我可以在VBA代码中重置行来源。标题每次都会显示出来。
我将其与列表对象的高级筛选宏结合使用,然后创建另一个(过滤后的)列表对象,该对象基于行来源。
这对我起作用了。

0
可以按照以下方式进行...
Sub testMultiColumnLb()
   ReDim arr(0 To 3, 0 To 2)

   'Header Row
   arr(0, 1) = "Number"
   arr(0, 2) = "Number in Text"

   'Content Rows
   arr(1, 1) = "1"
   arr(1, 2) = "One"
   arr(2, 1) = "2"
   arr(2, 2) = "Two"
   arr(3, 1) = "3"
   arr(3, 2) = "Three"


   With ufTestUserForm.lbTest
     .Clear
     .ColumnCount = 2
     .List = arr
   End With

   ufTestUserForm.Show 1
End Sub

请记住,Stack Overflow 不仅仅是为了解决当前的问题,还要帮助未来的读者找到类似问题的解决方案,这需要理解底层代码。对于我们社区中的初学者来说,这尤为重要,他们可能不熟悉语法。鉴于此,请问您能否编辑您的回答,包括对您所做的操作的解释以及为什么您认为这是最佳方法? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接