Avatar billede hjald8 Nybegynder
16. oktober 2009 - 10:34 Der er 8 kommentarer og
1 løsning

ListBox afhængighed i en userform

Hej

Jeg har en userform, hvor jeg har fået lavet en fin(via hjælp fra spørgsmål/svar i Eksperten) listbox (Listbox1) der viser de første 5 kolonner i en lille database (excelark).

Nu vil jeg gerne have denne Listbox1 styret af mulige kriterier/valg fra 2 af kolonnerne. Altså 2 listboxe (fx Listbox2 - kolonne 1 og Listbox3 - kolonne 5) som brugeren valgfrit kan afgrænse mulighederne (listens længde) i Listbox1 via afgrænsning i i de nævnte (Listbox2/Listbox3).

Kan det lade sig gøre?

Denne kode viser en meget fin listbox i min userform - og det er resultatet af denne som jeg gerne vil afgrænse:

Private Sub Userform_Activate()
    Dim rListRange As Range
    Set rListRange = Worksheets("SamletListe").Range("A4:E175")
    With ListBox1
        .ColumnWidths = "23;30;85;35;100"
        .Clear
        .BoundColumn = rListRange.Columns.Count
        .ColumnCount = rListRange.Columns.Count
        .ColumnHeads = True
        .RowSource = Worksheets("SamletListe").Name & "!" & rListRange.Address
        .ListIndex = 0
    End With
End sub

På forhånd tak.
Avatar billede tjacob Juniormester
16. oktober 2009 - 12:30 #1
Afgrænse hvordan?
Hvad skal ListBox 2 og 3 indeholde, og hvordan skal brugerens valg her afgrænse i ListBox1?
Avatar billede hjald8 Nybegynder
16. oktober 2009 - 13:44 #2
Hej.
Listbox2 skal indeholde indholdet (ej dubletter) af kolonne A fra A4 til sidste række med indhold. Dette er firmakoder (altså talkombinationer).

Listbox3 skal indeholde indholdet (ej dubletter) af kolonne E fra E4 til sidste række med indhold. Dette er initialer for personer.

Hvis man i Listbox2 har valgt firmakode 999, samt man i Listbox3 har valgt initialerne NNN, så skulle der kun blive vist rækker i Listbox1 som opfylder disse kriterier (999 i kolonne A og NNN i kolonne E).

Hvis man i Listbox2 ikke har valgt noget, men i Listbox3 har valgt NNN, så skal der i Listbox1 blive vist alle firmakoder men afgrænset til dem som har NNN i kolonne E.

Ved ikke om det gør det klarere?
Avatar billede tjacob Juniormester
16. oktober 2009 - 18:35 #3
Det gør det helt klart.

Det bliver noget langt hvis der er MultiSelect i de to andre listboxe. Uden MultiSelect kan koden kortes noget ned. Men her er et bud:

Læg to listboxe i formen: De skal hedde ListBox2 og ListBox3. Jeg har som sagt lavet koden efter MultiSelect, så hvis du vil kan du sætte de to listboxes MultiSelect-property til 1 - fmMultiSelectMulti, men det er ikke tvunget..;)

Jeg har lavet en ny version af Userform_Activate, så du skal slette den gamle. Jeg har opdateret med de to nye listboxe, og desuden sat den til selv at finde enden på data (i stedet for række 175).

Den fungerer ved at når du klikker på et item i listbox 2 eller 3, så vil listbox1 blive opdateret.

Kopier hele dynen ind i formens kodemodul:

Private Sub ListBox2_Change()
    Call OpdaterListBox1
End Sub

Private Sub ListBox3_Change()
    Call OpdaterListBox1
End Sub

Private Sub UserForm_Activate()

    Application.ScreenUpdating = False
    Dim i As Long, j As Long, k As Long, l As Long
    Dim rListRange As Range
    Dim pValues() As Variant
    j = Worksheets("SamletListe").Range("A4").End(xlDown).Row
    Set rListRange = Worksheets("SamletListe").Range(Cells(4, 1).Address & ":" & Cells(j, 5).Address)
    With ListBox1
        .ColumnWidths = "23;30;85;35;100"
        .Clear
        .BoundColumn = rListRange.Columns.Count
        .ColumnCount = rListRange.Columns.Count
        .ColumnHeads = True
        .RowSource = Worksheets("SamletListe").Name & "!" & rListRange.Address
        .ListIndex = 0
    End With
    With ListBox2
        .ColumnWidths = "100"
        .Clear
        .BoundColumn = 1
        .ColumnCount = 1
        .ColumnHeads = True
    End With
    With ListBox3
        .ColumnWidths = "100"
        .Clear
        .BoundColumn = 1
        .ColumnCount = 1
        .ColumnHeads = True
    End With
    ReDim pValues(0)
    For i = 4 To j
        For l = 0 To UBound(pValues)
            If pValues(l) = Worksheets("SamletListe").Cells(i, 1) Then Exit For
        Next l
        If l = UBound(pValues) + 1 Then
            k = k + 1
            ReDim Preserve pValues(k)
            pValues(k) = Worksheets("SamletListe").Cells(i, 1)
        End If
    Next i
    For i = 1 To UBound(pValues)
        ListBox2.AddItem pValues(i)
    Next i
    ReDim pValues(0)
    k = 0
    For i = 4 To j
        For l = 0 To UBound(pValues)
            If pValues(l) = Worksheets("SamletListe").Cells(i, 5) Then Exit For
        Next l
        If l = UBound(pValues) + 1 Then
            k = k + 1
            ReDim Preserve pValues(k)
            pValues(k) = Worksheets("SamletListe").Cells(i, 5)
        End If
    Next i
    For i = 1 To UBound(pValues)
        ListBox3.AddItem pValues(i)
    Next i
    ListBox1.Selected(0) = True
    Application.ScreenUpdating = True

End Sub

Private Sub OpdaterListBox1()

    Application.ScreenUpdating = False
    Dim pVal1() As Variant
    Dim pVal5() As Variant
    ReDim pVal1(0)
    ReDim pVal5(0)
    Dim lRækker() As Long
    Dim i As Long, j As Long
    For i = 0 To ListBox2.ListCount - 1
        If ListBox2.Selected(i) = True Then
            j = j + 1
            ReDim Preserve pVal1(j)
            pVal1(j) = ListBox2.List(i)
        End If
    Next i
    j = 0
    For i = 0 To ListBox3.ListCount - 1
        If ListBox3.Selected(i) = True Then
            j = j + 1
            ReDim Preserve pVal5(j)
            pVal5(j) = ListBox3.List(i)
        End If
    Next i
    lRækker = FindRækker(pVal1, pVal5)
    ListBox1.RowSource = ""
    ListBox1.Clear
    If UBound(lRækker) = 0 Then
        MsgBox "Der er ingen poster, der opfylder begge kriterier.", vbInformation
        Exit Sub
    End If
    For i = 1 To UBound(lRækker)
        ListBox1.AddItem Worksheets("SamletListe").Cells(lRækker(i), 1).Formula
        For j = 1 To 4
            ListBox1.List(i - 1, j) = Worksheets("SamletListe").Cells(lRækker(i), j + 1).Formula
        Next j
    Next i
    ListBox1.Selected(0) = True
    Application.ScreenUpdating = True

End Sub

Private Function FindRækker(ByRef pV1() As Variant, ByRef pV5 As Variant) As Long()

    Dim i As Long, j As Long, k As Long, l As Long, Lastrow As Long
    Dim lRows() As Long, bAddRow As Boolean
    ReDim lRows(0)
    Lastrow = Worksheets("SamletListe").Range("A4").End(xlDown).Row
    For i = 4 To Lastrow
        bAddRow = False
        If UBound(pV1) = 0 And UBound(pV5) = 0 Then
            bAddRow = True
        Else
            If UBound(pV1) = 0 Then
                For j = 1 To UBound(pV5)
                    If pV5(j) = Worksheets("SamletListe").Cells(i, 5).Formula Then
                        bAddRow = True
                        Exit For
                    End If
                Next j
            End If
            If UBound(pV5) = 0 Then
                For j = 1 To UBound(pV1)
                    If pV1(j) = Worksheets("SamletListe").Cells(i, 1).Formula Then
                        bAddRow = True
                        Exit For
                    End If
                Next j
            End If
            If UBound(pV1) <> 0 And UBound(pV5) <> 0 Then
                For j = 1 To UBound(pV1)
                    If pV1(j) = Worksheets("SamletListe").Cells(i, 1).Formula Then
                        For k = 1 To UBound(pV5)
                            If pV5(k) = Worksheets("SamletListe").Cells(i, 5).Formula Then
                                bAddRow = True
                                Exit For
                            End If
                        Next k
                    End If
                Next j
            End If
        End If
        If bAddRow = True Then
            ReDim Preserve lRows(l + 1)
            lRows(l + 1) = i
            l = l + 1
        End If
    Next i
    FindRækker = lRows

End Function


Håber du kan bruge det, men uanset var det en interessant opgave.
Avatar billede hjald8 Nybegynder
17. oktober 2009 - 06:58 #4
Det må jeg nok sige.Det er virkeligt godt. Det ser ud til at virke helt fantastisk. Det er godt regnet ud ....

Jeg stødte ind i følgende problemer:

Punkt 1
Mit Excel fil ikke accepterer kombinationen af Worksheet-betegnelse og andre betegnelser i samme 'sætning - fx:
Worksheets("SamletListe").Cells(i, 5).Formula Then
Dette er løst ved at lave en Public ShData as Worksheet, samt at lave en Set ShData = Sheets("Samletliste") i Private Sub UserForm_Activate

Punkt 2
Der kommer ikke overskrifter i mine listboxe mere. Det gjorde der før. Overskriftsrækken er i alle Listboxene - men teksten kommer ikke. Overskriften er i række 3

Punkt 3
Hvis man 'leget' med valg i Listbox1 og Listbox2 kan man så lave en reset - eller skal man gøre det ved en commandbutton ved siden af som en opdatering af formen?

Punkt 4
Denne er mere pinlig. Jeg mente at jeg havde kolonnen med Personer/initialer i kolonne 5 - det var desværre kolonne 6. Jeg kan ikke helt gennemskue hvor mange steder som skal rettes.

Punkt 5
Det kan være, at det ikke har noget med denne makro at gøre - men jeg har ikke set det før ved denne fil. Der kommer nu en sikkerhedsadvarsel: Active-objekter er deaktiveret.

Men det er supert - og det er virkelig noget som kan bruges. Supert
Avatar billede hjald8 Nybegynder
18. oktober 2009 - 09:13 #5
Puslet lidt med det:

Punkt 1. Løst jf ovenfor

Punkt 2. Det kan jeg ikke finde ud af

Punkt 3. Forsøgt løst på denne måde:
Indsat en Commandbutton 'Reset'. Denne laver en:
  Unload Me
  FindRaekker.Hide
  FindRaekker.Show
Det virker - men det er måske en langsom måde.

Punkt 4. Denne er næsten løst.
ListBox3 er nu kolonne 6. Den søger også og kombinere med kolonne 6. Men Listbox1 viser fortsat ikke den 6. kolonne. Selvom jeg synes at have ændret alle parametre fra 5 til 6?

Punkt 5. Denne er løst - jeg er dog ikke sikker på hvordan. Men det har formentlig ikke været noget med denne userform i filen at gøre.
Avatar billede tjacob Juniormester
19. oktober 2009 - 11:18 #6
Undskyld ventetiden; Jeg har været på lang weekend....

Pkt 2)
Ja, jeg havde selv det samme problem.....
Efter at have googlet noget rundt: Det ser ud til at når listboxen fyldes via VBA så kan Column Headers ikke bruges. Så du har 2 muligheder: Brug ikke column headers og slet alt i koden med relation hertil. Eller: læg nogle labels i formen der ligger lige over listboxen og "ser ud som om".

Pkt 3)
Her er det nemmeste simpelt hen at gendanne formen fra start, så i commandbutton indsætter du blot: Call UserForm_Activate
Der resettes jo også ved fravælge alle punkter i box 2 og 3.

Pkt 4)
Problemet med ListBox1 skyldes sikkert at du kun har 5 kolonner;
Øverst i koden skal disse linier ændres:

Set rListRange = Worksheets("SamletListe").Range(Cells(4, 1).Address & ":" & Cells(j, 5).Address)
    With ListBox1
        .ColumnWidths = "23;30;85;35;100"
        .Clear

Til:

Set rListRange = Worksheets("SamletListe").Range(Cells(4, 1).Address & ":" & Cells(j, 6).Address)
    With ListBox1
        .ColumnWidths = "23;30;85;35;100;100"
        .Clear
Avatar billede tjacob Juniormester
19. oktober 2009 - 11:28 #7
mere til pkt 4:

Koden skal også ændres i bunden af OpdaterListBox1:

For j = 1 To 4
      ListBox1.List(i - 1, j) = Worksheets("SamletListe").Cells(lRækker(i), j + 1).Formula
Next j

ændres til :

For j = 1 To 5
      ListBox1.List(i - 1, j) = Worksheets("SamletListe").Cells(lRækker(i), j + 1).Formula
Next j
Avatar billede hjald8 Nybegynder
19. oktober 2009 - 12:45 #8
Vi skal også holde weekend - det siges at være rigtig sundt.

Tusind tak for en meget fin support og hjælp - samt en meget, meget fin løsning.

Enig i dit svar på punkt 2. Punkt 3 er smartere end min løsning. Punkt 4: Jeg havde gjort som i #6 - men havde overset de nævnte punkter i #7.

Læg et svar. Og Tak ;-)
Avatar billede tjacob Juniormester
19. oktober 2009 - 13:16 #9
-kommer her.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Excel kurser for alle niveauer og behov – find det kursus, der passer til dig

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester