programing

VBA를 사용하여 Excel 사용자 양식의 다중 열 목록 상자에 헤더를 추가하는 방법

subpage 2023. 6. 23. 22:08
반응형

VBA를 사용하여 Excel 사용자 양식의 다중 열 목록 상자에 헤더를 추가하는 방법

워크시트 범위를 원본으로 사용하지 않고 다중 열 목록 상자에서 헤더를 설정할 수 있습니까?

다음은 목록 상자의 목록 속성에 할당된 변형 배열을 사용하는 방법입니다. 머리글은 비어 있습니다.

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

문제를 해결하기 위한 저의 접근 방식은 다음과 같습니다.

이 솔루션을 사용하려면 두 번째 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

아니오. 목록 상자 위에 레이블을 만들어 머리글로 사용합니다.당신은 목록 상자가 바뀔 때마다 라벨을 바꾸는 것이 왕실의 고통이라고 생각할 수 있습니다.당신이 옳을 것입니다 - 그것은 고통입니다.처음 설정하는 것은 고통이지만, 변경은 말할 것도 없습니다.하지만 저는 더 좋은 방법을 찾지 못했습니다.

저는 방금 이 문제를 보고 이 해결책을 찾았습니다.RowSource가 셀 범위를 가리킬 경우 다중 열 목록 상자의 열 머리글은 RowSource 바로 위의 셀에서 가져옵니다.

여기 그림의 예를 사용하여 목록 상자 안에 기호이름이 제목 제목으로 나타납니다.AB1 셀에서 이름이라는 단어를 변경한 다음 VBE에서 양식을 다시 열었을 때 열 제목이 변경되었습니다.

Screenshot displaying a named range and the column headings outside the range.

예제는 S의 VBA 모델러용 워크북에서 제공됩니다.크리스찬 올브라이트, 그리고 나는 그가 어떻게 그의 목록 상자에 열 제목을 넣었는지 알아내려고 노력하고 있었습니다 :)

간단한 대답: 아니오.

제가 예전에 했던 일은 표제를 0행에 로드한 다음 양식을 표시할 때 ListIndex를 0으로 설정하는 것이었습니다.그런 다음 머리글이 파란색으로 강조 표시되어 머리글처럼 보입니다.ListIndex가 0으로 유지되면 양식 작업 단추가 무시되므로 이러한 값을 선택할 수 없습니다.

물론 다른 목록 항목을 선택하는 즉시 제목의 포커스가 사라지지만, 이때쯤이면 해당 항목의 작업이 완료됩니다.

이러한 방식으로 작업을 수행하면 목록 상자 위에 떠 있는 별도의 레이블로 수행하기 어렵거나 불가능한 가로 스크롤 제목을 사용할 수도 있습니다.반대로 목록 상자를 세로로 스크롤해야 하는 경우 제목이 표시되지 않습니다.

기본적으로 제가 처한 상황에서 효과가 있는 절충안입니다.

여러 열 목록 상자의 맨 위에 머리글을 표시하는 매우 쉬운 솔루션이 있습니다.기본적으로 false인 "열 제목"에 대한 속성 값을 "true"로 변경하면 됩니다.

그런 다음 데이터 범위에서 헤더를 제외한 "행 소스" 속성의 데이터 범위를 언급하고 헤더가 데이터 범위의 첫 번째 맨 위 행에 있어야 합니다. 그러면 헤더가 자동으로 선택되고 헤더가 동결됩니다.

데이터 범위가 "A1:" 데이터가 있다고 가정합니다.H100" 및 "A1:H1"의 헤더는 첫 번째 행이고 데이터 범위는 "A2:속성 "rowsource" 및 "columnheads" 속성 값에서 언급해야 하는 H100"은 참이어야 합니다.

잘 부탁드립니다.

두 개의 목록 상자(하나는 머리글용, 다른 하나는 데이터용)만 사용

  1. 헤더의 경우 - RowSource 속성을 맨 위 행으로 설정합니다.사건들!Q4:S4

  2. 데이터의 경우 - 행 소스 속성을 인시던트로 설정합니다!Q5:S10

"3-frm 특수 효과 식각"에 대한 특수 효과

CboBx가 워크시트에서 로드되지 않는 ComboBox의 헤더에 대해 다음과 같은 접근 방식을 사용하고 싶습니다(예: sql의 데이터).워크시트에서 지정하지 않는 이유는 RowSource를 작동시키는 유일한 방법은 워크시트에서 로드하는 것이라고 생각하기 때문입니다.

이것은 나에게 도움이 됩니다.

  1. ComboBox를 만들고 동일한 레이아웃에 하나의 행만 있는 ListBox를 만듭니다.
  2. 콤보 상자 바로 위에 목록 상자를 놓습니다.
  3. VBA에서 ListBox 행 1을 원하는 헤더로 로드합니다.
  4. ListBoxName_Click 작업의 VBA에 다음 코드를 입력합니다.

    yourComboBoxName.Activate`
    yourComboBoxName.DropDown`
    
  5. 목록 상자를 클릭하면 목록 상자의 제목이 목록 위에 있는 동안 콤보 상자가 드롭다운되고 정상적으로 작동합니다.

저는 별도의 시트를 사용하지 않고 헤더를 추가하고 모든 것을 사용자 양식에 복사할 수 있는 솔루션을 한참 찾고 있었습니다.

제 해결책은 첫 번째 행을 헤더로 사용하여 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는 listbox이고 lborow count는 다음 listbox 항목을 추가할 행입니다.5열 목록 상자입니다.이상적이지는 않지만 작동하며 수평으로 스크롤해야 할 경우 "헤더"가 행 위에 유지됩니다.

제 해결책은 이렇습니다.

VBE의 속성 창을 통해 목록 상자의 행 소스를 지정하면 헤더가 팝업되지 않습니다.VBA 코드를 통해 행 소스를 정의하려고 할 때에만 헤더가 손실됩니다.

먼저 속성 창을 통해 목록 상자 행 소스를 VBE의 명명된 범위로 정의한 다음 VBA 코드에서 행 소스를 재설정할 수 있습니다.헤더는 여전히 매번 표시됩니다.

이것을 목록 개체의 고급 필터 매크로와 함께 사용하여 행 소스의 기반이 되는 다른 (필터링된) 목록 개체를 만듭니다.

이것은 나에게 효과가 있었습니다.

루나틱의 또 다른 변형은 로컬 부울 및 변경 이벤트를 사용하여 초기화 시 행을 강조 표시할 수 있지만 사용자가 선택을 변경한 후 선택을 취소하고 차단하는 것입니다.

Private Sub lbx_Change()

    If Not bHighlight Then

        If Me.lbx.Selected(0) Then Me.lbx.Selected(0) = False

    End If

    bHighlight = False

End Sub

목록 상자가 초기화되면 bHighlight 및 lbx를 설정합니다.Selected(0) = True. 헤더 행이 선택을 초기화할 수 있도록 합니다. 그 후 첫 번째 변경을 수행하면 선택이 취소되고 행이 다시 선택되지 않습니다.

목록 상자의 각 열 위(워크시트)에 레이블을 자동으로 생성하는 방법은 다음과 같습니다.

목록 상자에 가로 스크롤 막대가 없으면 작동합니다(예쁘지는 않습니다!

Sub Tester()
Dim i As Long

With Me.lbTest
    .Clear
    .ColumnCount = 5
    'must do this next step!
    .ColumnWidths = "70;60;100;60;60"
    .ListStyle = fmListStylePlain
    Debug.Print .ColumnWidths
    For i = 0 To 10
        .AddItem
        .List(i, 0) = "blah" & i
        .List(i, 1) = "blah"
        .List(i, 2) = "blah"
        .List(i, 3) = "blah"
        .List(i, 4) = "blah"
    Next i

End With

LabelHeaders Me.lbTest, Array("Header1", "Header2", _
                     "Header3", "Header4", "Header5")

End Sub

Sub LabelHeaders(lb, arrHeaders)

    Const LBL_HT As Long = 15
    Dim T, L, shp As Shape, cw As String, arr
    Dim i As Long, w

    'delete any previous headers for this listbox
    For i = lb.Parent.Shapes.Count To 1 Step -1
        If lb.Parent.Shapes(i).Name Like lb.Name & "_*" Then
            lb.Parent.Shapes(i).Delete
        End If
    Next i

    'get an array of column widths
    cw = lb.ColumnWidths
    If Len(cw) = 0 Then Exit Sub
    cw = Replace(cw, " pt", "")
    arr = Split(cw, ";")

    'start points for labels
    T = lb.Top - LBL_HT
    L = lb.Left

    For i = LBound(arr) To UBound(arr)
        w = CLng(arr(i))
        If i = UBound(arr) And (L + w) < lb.Width Then w = lb.Width - L
        Set shp = ActiveSheet.Shapes.AddShape(msoShapeRectangle, _
                                         L, T, w, LBL_HT)
        With shp
            .Name = lb.Name & "_" & i
            'do some formatting
            .Line.ForeColor.RGB = vbBlack
            .Line.Weight = 1
            .Fill.ForeColor.RGB = RGB(220, 220, 220)
            .TextFrame2.TextRange.Characters.Text = arrHeaders(i)
            .TextFrame2.TextRange.Font.Size = 9
            .TextFrame2.TextRange.Font.Fill.ForeColor.RGB = vbBlack
        End With
        L = L + w
    Next i
End Sub

한 번 해보세요.저는 이 포럼에 처음 참가하는 사람이지만 과거에 이 사이트에서 많은 도움을 받았기 때문에 저에게 도움이 되는 무언가를 제안하고 싶었습니다.이것은 본질적으로 위의 변형이지만, 저는 그것이 더 간단하다는 것을 알았습니다.

사용자 양식에 붙여넣기만 하면 됩니다.사용자 양식 코드의 섹션을 초기화합니다.사용자 양식에 목록 상자가 이미 있거나 이 코드 위에 동적으로 작성되어 있어야 합니다.또한 배열은 제목 목록입니다(아래 "Header1", "Header2" 등).사용자의 제목으로 대체합니다.그러면 이 코드는 목록 상자의 열 너비를 기준으로 상단에 제목 표시줄을 설정합니다.죄송합니다. 스크롤이 안 됩니다. 고정 라벨입니다.

더 많은 고위 코더 - 이 문제에 대해 자유롭게 의견을 제시하거나 개선하십시오.

    Dim Mywidths As String
    Dim Arrwidths, Arrheaders As Variant
    Dim ColCounter, Labelleft As Long
    Dim theLabel As Object                

    [Other code here that you would already have in the Userform_Initialize section]

    Set theLabel = Me.Controls.Add("Forms.Label.1", "Test" & ColCounter, True)
            With theLabel
                    .Left = ListBox1.Left
                    .Top = ListBox1.Top - 10
                    .Width = ListBox1.Width - 1
                    .Height = 10
                    .BackColor = RGB(200, 200, 200)
            End With
            Arrheaders = Array("Header1", "Header2", "Header3", "Header4")

            Mywidths = Me.ListBox1.ColumnWidths
            Mywidths = Replace(Mywidths, " pt", "")
            Arrwidths = Split(Mywidths, ";")
            Labelleft = ListBox1.Left + 18
            For ColCounter = LBound(Arrwidths) To UBound(Arrwidths)
                        If Arrwidths(ColCounter) > 0 Then
                                Header = Header + 1
                                Set theLabel = Me.Controls.Add("Forms.Label.1", "Test" & ColCounter, True)

                                With theLabel
                                    .Caption = Arrheaders(Header - 1)
                                    .Left = Labelleft
                                    .Width = Arrwidths(ColCounter)
                                    .Height = 10
                                    .Top = ListBox1.Top - 10
                                    .BackColor = RGB(200, 200, 200)
                                    .Font.Bold = True
                                End With
                                 Labelleft = Labelleft + Arrwidths(ColCounter)

                        End If
             Next

아쉽습니다.엑셀이 헤더를 잡을 수 있도록 중간 시트를 사용하여 데이터를 넣어야 합니다.하지만 저는 워크북이 숨겨져 있기를 원했습니다. 그래서 제가 행 소스를 어떻게 해야 했는지를 보여드리겠습니다.이 코드의 대부분은 단지 상황을 설정하는 것일 뿐입니다.

Sub listHeaderTest()
Dim ws As Worksheet
Dim testarr() As String
Dim numberOfRows As Long
Dim x As Long, n As Long

'example sheet
Set ws = ThisWorkbook.Sheets(1)
'example headers
For x = 1 To UserForm1.ListBox1.ColumnCount
    ws.Cells(1, x) = "header" & x
Next x
'example array dimensions
numberOfRows = 15
ReDim testarr(numberOfRows, UserForm1.ListBox1.ColumnCount - 1)
'example values for the array/listbox
For n = 0 To UBound(testarr)
    For x = 0 To UBound(testarr, 2)
        testarr(n, x) = "test" & n & x
    Next x
Next n

'put array data into the worksheet
ws.Range("A2").Resize(UBound(testarr), UBound(testarr, 2) + 1) = testarr

'provide rowsource
UserForm1.ListBox1.RowSource = "'[" & ws.Parent.Name & "]" & ws.Name & "'!" _
& ws.Range("A2").Resize(ws.UsedRange.Rows.Count - 1, ws.UsedRange.Columns.Count).Address

UserForm1.Show

End Sub

스크롤의 경우 전체 목록 상자를 왼쪽과 오른쪽으로 이동하는 시뮬레이션 스크롤 막대를 만드는 것이 좋습니다.

  1. 가로 스크롤 막대가 나타나지 않도록 목록 상자를 전체 너비로 설정합니다(사용 가능한 공간보다 작거나 스크롤할 필요가 없음).
  2. 사용 가능한 수평 공간과 일치하도록 .left 및 .width를 사용하여 하단에 스크롤 막대 컨트롤 추가(너무 넓지 않은 목록 상자)
  3. 확장 목록 상자의 너비와 사용 가능한 수평 공간의 너비 간의 차이로 스크롤해야 하는 거리 계산
  4. .Min을 0으로 설정하고 .스크롤해야 하는 최대 양
  5. set.Large 슬라이더 막대를 더 넓게 변경합니다(총 스팬의 절반만 사용할 수 있었습니다).

이렇게 하려면 목록 상자가 해당 보기 공간 아래를 통과하고 양식의 수평 프레임을 유지할 수 있도록 보기 공간의 왼쪽과 오른쪽을 프레임으로 가릴 수 있어야 합니다.목록 상자를 덮을 프레임을 얻는 것은 쉽게 작동하지 않는 것처럼 보이기 때문에 이것은 어려운 것으로 밝혀졌습니다.저는 그 시점에서 포기했지만 이 단계들을 후손들을 위해 공유하고 있습니다.

작동하는 것처럼 보이는 방법을 찾았지만 검색이나 범위를 변경할 때마다 동적으로 범위를 삭제하면 코드가 복잡해질수록 더 복잡해질 수 있습니다.

스프레드시트:

A    B       C  

1   LName    Fname 

2   Smith    Bob  

set rng_Name = ws_Name.range("A1", ws_Name.range("C2").value 
    
lstbx.Main.rowsource = rng_Name.Address

그러면 머리글이 목록 상자에 로드되고 스크롤할 수 있습니다.

가장 중요한 것은 데이터를 반복하고 있는데 범위가 비어 있는 경우 목록 상자에서 헤더를 올바르게 로드하지 않으므로 "일치"를 고려하지 않아도 된다는 것입니다.

목록 상자의 맨 위에 레이블을 추가하고 변경이 필요한 경우 프로그래밍 방식으로 변경해야 하는 것은 레이블뿐입니다.

언급URL : https://stackoverflow.com/questions/657498/how-to-add-headers-to-a-multicolumn-listbox-in-an-excel-userform-using-vba

반응형