Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Arbejde med Formularstyringselementer | Brugerinteraktion
Excel VBA til Forretningsautomatisering

Arbejde med Formularstyringselementer

Stryg for at vise menuen

TextBoxes og ComboBoxes dækker de fleste dataindtastninger, men nogle få andre kontroller udtrykker visse typer valg mere naturligt — og det at læse deres værdier korrekt har et par reelle faldgruber, som er værd at kende, før du stoler på dem.

Figur 5.5

CheckBoxes

En CheckBox's Value-egenskab er en simpel boolesk værdi — True når den er markeret, False når den ikke er:

If chkWelcomeEmail.Value = True Then
    MsgBox "A welcome email would be sent here."
End If

Hver CheckBox på en formular er fuldstændig uafhængig af de andre — at markere chkWelcomeEmail har ingen effekt på chkNewsletter, hvilket er præcis den adfærd, du ønsker, når valgene ikke udelukker hinanden.

OptionButtons

OptionButtons opfører sig modsat: inden for samme gruppe vil valg af én automatisk fravælge alle de andre — præcis det, som skærmbilledets Status-valg kræver, da en kunde ikke kan være både Active og Inactive på samme tid. For at aflæse hvilken der er valgt, skal du kontrollere hver enkelt Value individuelt:

Dim status As String
If optActive.Value = True Then
    status = "Active"
ElseIf optInactive.Value = True Then
    status = "Inactive"
ElseIf optProspect.Value = True Then
    status = "Prospect"
End If

Den gensidige udelukkelse sker automatisk og håndteres fuldstændigt af VBA — du behøver aldrig skrive kode, der fravælger de andre to, når én vælges. Gruppéringen er dog vigtig: OptionButtons udelukker kun hinanden inden for samme container (selve formularen eller en Frame-kontrol placeret på den), så to separate grupper af OptionButtons på samme formular — f.eks. Status og Priority — skal placeres i to forskellige Frames, ellers vil VBA behandle dem alle som én enkelt gensidigt udelukkende gruppe.

ListBoxes

En ListBox viser flere valg på én gang uden at skulle klikkes op, som City-listen i Figur 5.5. Udfyld den på samme måde som en ComboBox, med .AddItem, og læs valget tilbage enten via .Value eller .ListIndex:

Private Sub UserForm_Initialize()
    lstCities.AddItem "Chicago"
    lstCities.AddItem "Boston"
    lstCities.AddItem "Austin"
End Sub
 
Private Sub cmdAssign_Click()
    If lstCities.ListIndex = -1 Then
        MsgBox "Please select a city first."
        Exit Sub
    End If
    MsgBox "Assigning to: " & lstCities.Value
End Sub

ListIndex er positionen for det valgte element, talt fra 0 for det første element — og vigtigt, den er -1, når intet er valgt endnu, hvilket er det, cmdAssign_Click bruger til at fange en bruger, der klikker på knappen uden først at vælge en by. .Value giver dig den valgte tekst direkte, hvilket som regel er mere nyttigt end den numeriske position, .ListIndex giver.

Multi-Page Forms

En MultiPage-kontrol (fanerne Details / Preferences øverst i Figur 5.5) grupperer relaterede kontroller på separate sider af den samme fysiske formular — nyttigt, når en formular har for mange felter til at kunne være på én skærm. Hver side adresseres efter position, og kun kontrollerne på den aktuelt synlige side er meningsfulde for brugeren, selvom de alle stadig eksisterer og kan læses fra kode uanset, hvilken side der vises:

Private Sub MultiPage1_Change()
    If MultiPage1.Value = 1 Then
        MsgBox "Now viewing Preferences"
    End If
End Sub

MultiPage1.Value følger samme 0-baserede optælling som ListIndex — den første side er 0, den anden (Preferences, i Figur 5.5) er 1 — og Change-begivenheden udløses automatisk, hver gang brugeren klikker på en anden fane.

Opgave

  1. Tilføj en Ramme med tre OptionButtons (optActive, optInactive, optProspect) til frmAddCustomer, som erstatter den tidligere cboStatus ComboBox, og skriv If...ElseIf-blokken vist ovenfor for at læse valget.
  2. Tilføj to uafhængige CheckBoxes (chkWelcomeEmail, chkNewsletter) og bekræft under test, at afkrydsning af den ene aldrig påvirker den anden.
  3. Tilføj en ListBox (lstCities), der udfyldes i UserForm_Initialize, og skriv en kontrol, der viser en fejl, hvis brugeren forsøger at fortsætte uden at have valgt noget (ListIndex = -1).
  4. Udfordring: placer felterne Company Name, Contact og Email på én MultiPage-side med navnet "Details", og CheckBoxes og OptionButtons på en anden side med navnet "Preferences".
Tip
expand arrow

1. Erstatning af cboStatus med en Ramme af OptionButtons

  • Slet først cboStatus og dens Label fra formularen — du erstatter den, ikke tilføjer ved siden af.
  • Træk en Ramme-kontrol ind på formularen, og træk derefter alle tre OptionButtons indenfor rammens grænse — denne indkapsling gør dem gensidigt udelukkende som én gruppe.
  • Omdøb hver OptionButton individuelt i Egenskabsvinduet; selve rammen kan beholde en simpel Caption som "Status", men behøver ikke et kodevenligt navn, medmindre du planlægger at referere direkte til den.
  • For at læse valget skal du kontrollere hver OptionButtons .Value individuelt med If...ElseIf — der findes ingen enkelt egenskab, der fortæller dig "hvilken i gruppen er markeret".
  • Da cboStatus.Value ikke længere eksisterer, skal cmdSave_Click have en status-variabel, der bygges ud fra OptionButtons i stedet, og skrives ind i newRow i stedet for.

2. Tilføjelse af to uafhængige CheckBoxes

  • Disse placeres direkte på formularen (ikke inde i rammen) — CheckBoxes uden for en delt container påvirker aldrig hinanden, uanset gruppering.
  • For at "bekræfte under test" skal du blot markere den ene, derefter den anden, og se at ingen afmarkerer den første.

3. Tilføjelse og validering af en ListBox

  • Udfyld den på samme måde som cboCity blev udfyldt — gentagne .AddItem-kald i UserForm_Initialize.
  • ListIndex = -1 betyder specifikt intet er blevet klikket endnu — det er den præcise betingelse, der skal kontrolleres, før gemning tillades.
  • Denne kontrol hører til i samme valideringsblok som de andre påkrævede felter, og tilføjes til den samme errors-streng.

4. MultiPage-udfordring

  • Træk en MultiPage-kontrol ind på formularen — den har to sider som standard, hvilket er præcis det antal, du har brug for.
  • Omdøb hver side via dens egen højreklik → Page Order, eller ved at vælge sidens fane og bruge Egenskabsvinduets Caption-felt (Caption styrer fanens synlige tekst; der er også et separat (Name)-felt, hvis du vil referere til en side ved navn i kode).
  • At flytte eksisterende kontroller til en side betyder at trække dem fysisk ind på den pågældende sides synlige område i Design-visning — kodehenvisninger til dem ændres ikke, da en kontrols navn ikke afhænger af, hvilken side den er placeret på.
Løsning
expand arrow
Private Sub UserForm_Initialize()
    cboCity.AddItem "Chicago"
    cboCity.AddItem "Boston"
    cboCity.AddItem "Austin"
    cboCity.AddItem "Seattle"
    cboCity.AddItem "Denver"

    lstCities.AddItem "Chicago"
    lstCities.AddItem "Boston"
    lstCities.AddItem "Austin"
    lstCities.AddItem "Seattle"
    lstCities.AddItem "Denver"
End Sub

Private Sub cmdCancel_Click()
    Unload Me
End Sub

Private Sub cmdSave_Click()
    Dim tbl As ListObject
    Dim newRow As ListRow
    Dim errors As String
    Dim status As String

    ' --- Reset field colors ---
    txtCompanyName.BackColor = vbWhite
    txtContact.BackColor = vbWhite
    txtEmail.BackColor = vbWhite

    ' --- Required field checks ---
    If Trim(txtCompanyName.Value) = "" Then
        errors = errors & "- Company Name is required" & vbNewLine
        txtCompanyName.BackColor = RGB(255, 199, 206)
    End If

    If Trim(txtContact.Value) = "" Then
        errors = errors & "- Contact is required" & vbNewLine
        txtContact.BackColor = RGB(255, 199, 206)
    End If

    If Trim(txtEmail.Value) = "" Then
        errors = errors & "- Email is required" & vbNewLine
        txtEmail.BackColor = RGB(255, 199, 206)
    End If

    ' --- Status via OptionButtons ---
    If optActive.Value = True Then
        status = "Active"
    ElseIf optInactive.Value = True Then
        status = "Inactive"
    ElseIf optProspect.Value = True Then
        status = "Prospect"
    Else
        errors = errors & "- Please select a Status" & vbNewLine
    End If

    ' --- ListBox check ---
    If lstCities.ListIndex = -1 Then
        errors = errors & "- Please select a city from the list" & vbNewLine
    End If

    If errors <> "" Then
        MsgBox "Please fix the following:" & vbNewLine & errors, vbExclamation
        Exit Sub
    End If

    ' --- All checks passed — safe to save now ---
    Set tbl = ThisWorkbook.Worksheets("Customers").ListObjects("tblCustomers")
    Set newRow = tbl.ListRows.Add

    newRow.Range(1, 1).Value = "C0" & (tbl.ListRows.Count + 100)
    newRow.Range(1, 2).Value = txtCompanyName.Value
    newRow.Range(1, 3).Value = txtContact.Value
    newRow.Range(1, 4).Value = txtEmail.Value
    newRow.Range(1, 5).Value = cboCity.Value
    newRow.Range(1, 6).Value = status

    If chkWelcomeEmail.Value = True Then
        MsgBox "A welcome email would be sent to " & txtEmail.Value & "."
    End If

    MsgBox txtCompanyName.Value & " was added successfully."
    Unload Me
End Sub

Testnoter:

  • Punkt 2 (CheckBoxes) har ingen dedikeret validering — klik blot på chkWelcomeEmail og chkNewsletter uafhængigt og bekræft, at hver kan slås til/fra uden at påvirke den anden.
  • Punkt 4 (MultiPage) er kun en layoutændring — der er ikke behov for kodeændringer ud over det, der allerede er her, da hver kontrol beholder sit eget navn uanset, hvilken side den trækkes til.
  • Bemærk, at cboCity.Value stadig bruges til den faktiske gemning (newRow.Range(1, 5)), mens lstCities kun eksisterer som en separat, uafhængigt valideret kontrol ifølge opgaven — de to er ikke forbundet, medmindre du selv vælger at udvide det.
Var alt klart?

Hvordan kan vi forbedre det?

Tak for dine kommentarer!

Sektion 5. Kapitel 4

Spørg AI

expand

Spørg AI

ChatGPT

Spørg om hvad som helst eller prøv et af de foreslåede spørgsmål for at starte vores chat

Arbejde med Formularstyringselementer

TextBoxes og ComboBoxes dækker de fleste dataindtastninger, men nogle få andre kontroller udtrykker visse typer valg mere naturligt — og det at læse deres værdier korrekt har et par reelle faldgruber, som er værd at kende, før du stoler på dem.

Figur 5.5

CheckBoxes

En CheckBox's Value-egenskab er en simpel boolesk værdi — True når den er markeret, False når den ikke er:

If chkWelcomeEmail.Value = True Then
    MsgBox "A welcome email would be sent here."
End If

Hver CheckBox på en formular er fuldstændig uafhængig af de andre — at markere chkWelcomeEmail har ingen effekt på chkNewsletter, hvilket er præcis den adfærd, du ønsker, når valgene ikke udelukker hinanden.

OptionButtons

OptionButtons opfører sig modsat: inden for samme gruppe vil valg af én automatisk fravælge alle de andre — præcis det, som skærmbilledets Status-valg kræver, da en kunde ikke kan være både Active og Inactive på samme tid. For at aflæse hvilken der er valgt, skal du kontrollere hver enkelt Value individuelt:

Dim status As String
If optActive.Value = True Then
    status = "Active"
ElseIf optInactive.Value = True Then
    status = "Inactive"
ElseIf optProspect.Value = True Then
    status = "Prospect"
End If

Den gensidige udelukkelse sker automatisk og håndteres fuldstændigt af VBA — du behøver aldrig skrive kode, der fravælger de andre to, når én vælges. Gruppéringen er dog vigtig: OptionButtons udelukker kun hinanden inden for samme container (selve formularen eller en Frame-kontrol placeret på den), så to separate grupper af OptionButtons på samme formular — f.eks. Status og Priority — skal placeres i to forskellige Frames, ellers vil VBA behandle dem alle som én enkelt gensidigt udelukkende gruppe.

ListBoxes

En ListBox viser flere valg på én gang uden at skulle klikkes op, som City-listen i Figur 5.5. Udfyld den på samme måde som en ComboBox, med .AddItem, og læs valget tilbage enten via .Value eller .ListIndex:

Private Sub UserForm_Initialize()
    lstCities.AddItem "Chicago"
    lstCities.AddItem "Boston"
    lstCities.AddItem "Austin"
End Sub
 
Private Sub cmdAssign_Click()
    If lstCities.ListIndex = -1 Then
        MsgBox "Please select a city first."
        Exit Sub
    End If
    MsgBox "Assigning to: " & lstCities.Value
End Sub

ListIndex er positionen for det valgte element, talt fra 0 for det første element — og vigtigt, den er -1, når intet er valgt endnu, hvilket er det, cmdAssign_Click bruger til at fange en bruger, der klikker på knappen uden først at vælge en by. .Value giver dig den valgte tekst direkte, hvilket som regel er mere nyttigt end den numeriske position, .ListIndex giver.

Multi-Page Forms

En MultiPage-kontrol (fanerne Details / Preferences øverst i Figur 5.5) grupperer relaterede kontroller på separate sider af den samme fysiske formular — nyttigt, når en formular har for mange felter til at kunne være på én skærm. Hver side adresseres efter position, og kun kontrollerne på den aktuelt synlige side er meningsfulde for brugeren, selvom de alle stadig eksisterer og kan læses fra kode uanset, hvilken side der vises:

Private Sub MultiPage1_Change()
    If MultiPage1.Value = 1 Then
        MsgBox "Now viewing Preferences"
    End If
End Sub

MultiPage1.Value følger samme 0-baserede optælling som ListIndex — den første side er 0, den anden (Preferences, i Figur 5.5) er 1 — og Change-begivenheden udløses automatisk, hver gang brugeren klikker på en anden fane.

Opgave

  1. Tilføj en Ramme med tre OptionButtons (optActive, optInactive, optProspect) til frmAddCustomer, som erstatter den tidligere cboStatus ComboBox, og skriv If...ElseIf-blokken vist ovenfor for at læse valget.
  2. Tilføj to uafhængige CheckBoxes (chkWelcomeEmail, chkNewsletter) og bekræft under test, at afkrydsning af den ene aldrig påvirker den anden.
  3. Tilføj en ListBox (lstCities), der udfyldes i UserForm_Initialize, og skriv en kontrol, der viser en fejl, hvis brugeren forsøger at fortsætte uden at have valgt noget (ListIndex = -1).
  4. Udfordring: placer felterne Company Name, Contact og Email på én MultiPage-side med navnet "Details", og CheckBoxes og OptionButtons på en anden side med navnet "Preferences".
Tip
expand arrow

1. Erstatning af cboStatus med en Ramme af OptionButtons

  • Slet først cboStatus og dens Label fra formularen — du erstatter den, ikke tilføjer ved siden af.
  • Træk en Ramme-kontrol ind på formularen, og træk derefter alle tre OptionButtons indenfor rammens grænse — denne indkapsling gør dem gensidigt udelukkende som én gruppe.
  • Omdøb hver OptionButton individuelt i Egenskabsvinduet; selve rammen kan beholde en simpel Caption som "Status", men behøver ikke et kodevenligt navn, medmindre du planlægger at referere direkte til den.
  • For at læse valget skal du kontrollere hver OptionButtons .Value individuelt med If...ElseIf — der findes ingen enkelt egenskab, der fortæller dig "hvilken i gruppen er markeret".
  • Da cboStatus.Value ikke længere eksisterer, skal cmdSave_Click have en status-variabel, der bygges ud fra OptionButtons i stedet, og skrives ind i newRow i stedet for.

2. Tilføjelse af to uafhængige CheckBoxes

  • Disse placeres direkte på formularen (ikke inde i rammen) — CheckBoxes uden for en delt container påvirker aldrig hinanden, uanset gruppering.
  • For at "bekræfte under test" skal du blot markere den ene, derefter den anden, og se at ingen afmarkerer den første.

3. Tilføjelse og validering af en ListBox

  • Udfyld den på samme måde som cboCity blev udfyldt — gentagne .AddItem-kald i UserForm_Initialize.
  • ListIndex = -1 betyder specifikt intet er blevet klikket endnu — det er den præcise betingelse, der skal kontrolleres, før gemning tillades.
  • Denne kontrol hører til i samme valideringsblok som de andre påkrævede felter, og tilføjes til den samme errors-streng.

4. MultiPage-udfordring

  • Træk en MultiPage-kontrol ind på formularen — den har to sider som standard, hvilket er præcis det antal, du har brug for.
  • Omdøb hver side via dens egen højreklik → Page Order, eller ved at vælge sidens fane og bruge Egenskabsvinduets Caption-felt (Caption styrer fanens synlige tekst; der er også et separat (Name)-felt, hvis du vil referere til en side ved navn i kode).
  • At flytte eksisterende kontroller til en side betyder at trække dem fysisk ind på den pågældende sides synlige område i Design-visning — kodehenvisninger til dem ændres ikke, da en kontrols navn ikke afhænger af, hvilken side den er placeret på.
Løsning
expand arrow
Private Sub UserForm_Initialize()
    cboCity.AddItem "Chicago"
    cboCity.AddItem "Boston"
    cboCity.AddItem "Austin"
    cboCity.AddItem "Seattle"
    cboCity.AddItem "Denver"

    lstCities.AddItem "Chicago"
    lstCities.AddItem "Boston"
    lstCities.AddItem "Austin"
    lstCities.AddItem "Seattle"
    lstCities.AddItem "Denver"
End Sub

Private Sub cmdCancel_Click()
    Unload Me
End Sub

Private Sub cmdSave_Click()
    Dim tbl As ListObject
    Dim newRow As ListRow
    Dim errors As String
    Dim status As String

    ' --- Reset field colors ---
    txtCompanyName.BackColor = vbWhite
    txtContact.BackColor = vbWhite
    txtEmail.BackColor = vbWhite

    ' --- Required field checks ---
    If Trim(txtCompanyName.Value) = "" Then
        errors = errors & "- Company Name is required" & vbNewLine
        txtCompanyName.BackColor = RGB(255, 199, 206)
    End If

    If Trim(txtContact.Value) = "" Then
        errors = errors & "- Contact is required" & vbNewLine
        txtContact.BackColor = RGB(255, 199, 206)
    End If

    If Trim(txtEmail.Value) = "" Then
        errors = errors & "- Email is required" & vbNewLine
        txtEmail.BackColor = RGB(255, 199, 206)
    End If

    ' --- Status via OptionButtons ---
    If optActive.Value = True Then
        status = "Active"
    ElseIf optInactive.Value = True Then
        status = "Inactive"
    ElseIf optProspect.Value = True Then
        status = "Prospect"
    Else
        errors = errors & "- Please select a Status" & vbNewLine
    End If

    ' --- ListBox check ---
    If lstCities.ListIndex = -1 Then
        errors = errors & "- Please select a city from the list" & vbNewLine
    End If

    If errors <> "" Then
        MsgBox "Please fix the following:" & vbNewLine & errors, vbExclamation
        Exit Sub
    End If

    ' --- All checks passed — safe to save now ---
    Set tbl = ThisWorkbook.Worksheets("Customers").ListObjects("tblCustomers")
    Set newRow = tbl.ListRows.Add

    newRow.Range(1, 1).Value = "C0" & (tbl.ListRows.Count + 100)
    newRow.Range(1, 2).Value = txtCompanyName.Value
    newRow.Range(1, 3).Value = txtContact.Value
    newRow.Range(1, 4).Value = txtEmail.Value
    newRow.Range(1, 5).Value = cboCity.Value
    newRow.Range(1, 6).Value = status

    If chkWelcomeEmail.Value = True Then
        MsgBox "A welcome email would be sent to " & txtEmail.Value & "."
    End If

    MsgBox txtCompanyName.Value & " was added successfully."
    Unload Me
End Sub

Testnoter:

  • Punkt 2 (CheckBoxes) har ingen dedikeret validering — klik blot på chkWelcomeEmail og chkNewsletter uafhængigt og bekræft, at hver kan slås til/fra uden at påvirke den anden.
  • Punkt 4 (MultiPage) er kun en layoutændring — der er ikke behov for kodeændringer ud over det, der allerede er her, da hver kontrol beholder sit eget navn uanset, hvilken side den trækkes til.
  • Bemærk, at cboCity.Value stadig bruges til den faktiske gemning (newRow.Range(1, 5)), mens lstCities kun eksisterer som en separat, uafhængigt valideret kontrol ifølge opgaven — de to er ikke forbundet, medmindre du selv vælger at udvide det.
Var alt klart?

Hvordan kan vi forbedre det?

Tak for dine kommentarer!

Sektion 5. Kapitel 4
some-alt