Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Arbeide med skjemakontroller | Brukerinteraksjon
Excel VBA for Forretningsautomatisering

Arbeide med skjemakontroller

Sveip for å vise menyen

TextBoxes og ComboBoxes dekker de fleste dataregistreringer, men noen andre kontroller uttrykker visse valg på en mer naturlig måte — og det å lese verdiene deres korrekt har noen reelle fallgruver det er verdt å kjenne til før du stoler på dem.

Figur 5.5

CheckBoxes

En CheckBox sin Value-egenskap er en enkel boolsk verdi — True når den er avkrysset, False når den ikke er det:

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

Hver CheckBox på et skjema er helt uavhengig av de andre — å krysse av chkWelcomeEmail har ingen effekt på chkNewsletter, noe som er akkurat den oppførselen du ønsker når valgene ikke utelukker hverandre.

OptionButtons

OptionButtons oppfører seg motsatt: innenfor samme gruppe vil det å velge én automatisk fjerne valget fra alle de andre — akkurat det Status-valgene på skjermbildet trenger, siden en kunde ikke kan være både Aktiv og Inaktiv samtidig. For å lese av hvilken som er valgt, må du sjekke verdien til hver enkelt:

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

Gjensidig utelukkelse håndteres automatisk av VBA — du trenger aldri å skrive kode som fjerner avkrysningen på de andre når én velges. Gruppinndeling er viktig: OptionButtons utelukker bare hverandre innenfor samme beholder (selve skjemaet, eller en Frame-kontroll plassert på det), så to separate grupper med OptionButtons på samme skjema — for eksempel Status og Prioritet — må ligge i to ulike Frames, ellers vil VBA behandle alle som én enkelt gjensidig utelukkende gruppe.

ListBoxes

En ListBox viser flere valg samtidig uten at du må klikke den opp, slik som City-listen i Figur 5.5. Fyll den på samme måte som en ComboBox, med .AddItem, og les utvalget tilbake 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 posisjonen til det valgte elementet, talt fra 0 for det første elementet — og viktigst, den er -1 når ingenting er valgt ennå, noe som er sjekken cmdAssign_Click bruker for å fange en bruker som klikker knappen uten å velge en by først. .Value gir deg den valgte teksten direkte, noe som vanligvis er mer nyttig enn den numeriske posisjonen .ListIndex gir.

Multi-Page Forms

En MultiPage-kontroll (fanene Details / Preferences øverst i Figur 5.5) grupperer relaterte kontroller på separate sider i samme fysiske skjema — nyttig når et skjema har for mange felt til å få plass på én skjerm. Hver side adresseres etter posisjon, og bare kontrollene på den synlige siden er relevante for brukeren, selv om alle fortsatt eksisterer og kan leses fra kode uansett hvilken side som vises:

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

MultiPage1.Value følger samme 0-baserte telling som ListIndex — første side er 0, andre (Preferences, i Figur 5.5) er 1 — og Change-hendelsen utløses automatisk hver gang brukeren klikker på en annen fane.

Oppgave

  1. Legg til en ramme (Frame) som inneholder tre alternativknapper (optActive, optInactive, optProspect) i frmAddCustomer, og erstatt den tidligere cboStatus ComboBox. Skriv If...ElseIf-blokken vist ovenfor for å lese valget.
  2. Legg til to uavhengige avkrysningsbokser (chkWelcomeEmail, chkNewsletter) og bekreft under testing at det å merke én aldri påvirker den andre.
  3. Legg til en listeboks (lstCities) som fylles i UserForm_Initialize, og skriv en sjekk som viser en feilmelding hvis brukeren prøver å fortsette uten å ha valgt noe (ListIndex = -1).
  4. Utfordring: plasser feltene Company Name, Contact og Email på én MultiPage-side kalt "Details", og avkrysningsboksene og alternativknappene på en annen side kalt "Preferences".
Tips
expand arrow

1. Erstatte cboStatus med en ramme med alternativknapper

  • Slett først cboStatus og dens etikett fra skjemaet — du erstatter den, ikke legger til i tillegg.
  • Dra en Frame-kontroll inn på skjemaet, og dra deretter alle tre alternativknappene inn i rammens område — denne innkapslingen gjør dem gjensidig utelukkende som én gruppe.
  • Gi hver alternativknapp nytt navn individuelt i egenskapsvinduet; selve rammen kan ha en enkel bildetekst som "Status", men trenger ikke et kodenavn med mindre du skal referere til den direkte.
  • For å lese valget må du sjekke hver alternativknapps .Value individuelt med If...ElseIf — det finnes ingen enkelt egenskap som forteller deg "hvilken i gruppen som er valgt".
  • Siden cboStatus.Value ikke lenger finnes, må cmdSave_Click ha en status-variabel bygget fra alternativknappene i stedet, som skrives inn i newRow på samme sted.

2. Legge til to uavhengige avkrysningsbokser

  • Disse plasseres direkte på skjemaet (ikke inne i rammen) — avkrysningsbokser utenfor en delt beholder påvirker aldri hverandre uansett gruppering.
  • For å "bekrefte under testing", merk bare av i én, deretter den andre, og se at ingen av dem fjerner merkingen fra den første.

3. Legge til og validere en listeboks

  • Fyll den på samme måte som cboCity ble fylt — gjentatte .AddItem-kall i UserForm_Initialize.
  • ListIndex = -1 betyr spesifikt at ingenting er valgt ennå — det er akkurat denne tilstanden du skal sjekke før lagring kan fortsette.
  • Denne sjekken hører hjemme i samme valideringsblokk som de andre obligatoriske feltene, og legges til i samme errors-streng.

4. MultiPage-utfordring

  • Dra en MultiPage-kontroll inn på skjemaet — den har to sider som standard, akkurat så mange du trenger.
  • Gi hver side nytt navn via høyreklikk → Page Order, eller ved å velge sidens fane og bruke egenskapsvinduets Caption-felt (Caption styrer fanens synlige tekst; det finnes også et eget (Name)-felt hvis du vil referere til en side i kode).
  • For å flytte eksisterende kontroller til en side, dra dem fysisk inn på den sidens synlige område i designvisning — kodereferanser til dem endres ikke, siden kontrollens navn ikke avhenger av hvilken side den ligger 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

Testnotater:

  • Punkt 2 (avkrysningsbokser) har ingen egen validering — bare klikk på chkWelcomeEmail og chkNewsletter uavhengig og bekreft at hver kan slås av og på uten å påvirke den andre.
  • Punkt 4 (MultiPage) er kun en layoutendring — ingen kodeendringer er nødvendig utover det som allerede finnes her, siden hver kontroll beholder sitt eget navn uansett hvilken side den ligger på.
  • Merk at cboCity.Value fortsatt brukes for selve lagringen (newRow.Range(1, 5)), mens lstCities kun eksisterer som en separat, uavhengig validert kontroll i henhold til oppgaven — de to er ikke koblet sammen med mindre du selv velger å utvide det slik.
Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 5. Kapittel 4

Spør AI

expand

Spør AI

ChatGPT

Spør om hva du vil, eller prøv ett av de foreslåtte spørsmålene for å starte chatten vår

Arbeide med skjemakontroller

TextBoxes og ComboBoxes dekker de fleste dataregistreringer, men noen andre kontroller uttrykker visse valg på en mer naturlig måte — og det å lese verdiene deres korrekt har noen reelle fallgruver det er verdt å kjenne til før du stoler på dem.

Figur 5.5

CheckBoxes

En CheckBox sin Value-egenskap er en enkel boolsk verdi — True når den er avkrysset, False når den ikke er det:

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

Hver CheckBox på et skjema er helt uavhengig av de andre — å krysse av chkWelcomeEmail har ingen effekt på chkNewsletter, noe som er akkurat den oppførselen du ønsker når valgene ikke utelukker hverandre.

OptionButtons

OptionButtons oppfører seg motsatt: innenfor samme gruppe vil det å velge én automatisk fjerne valget fra alle de andre — akkurat det Status-valgene på skjermbildet trenger, siden en kunde ikke kan være både Aktiv og Inaktiv samtidig. For å lese av hvilken som er valgt, må du sjekke verdien til hver enkelt:

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

Gjensidig utelukkelse håndteres automatisk av VBA — du trenger aldri å skrive kode som fjerner avkrysningen på de andre når én velges. Gruppinndeling er viktig: OptionButtons utelukker bare hverandre innenfor samme beholder (selve skjemaet, eller en Frame-kontroll plassert på det), så to separate grupper med OptionButtons på samme skjema — for eksempel Status og Prioritet — må ligge i to ulike Frames, ellers vil VBA behandle alle som én enkelt gjensidig utelukkende gruppe.

ListBoxes

En ListBox viser flere valg samtidig uten at du må klikke den opp, slik som City-listen i Figur 5.5. Fyll den på samme måte som en ComboBox, med .AddItem, og les utvalget tilbake 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 posisjonen til det valgte elementet, talt fra 0 for det første elementet — og viktigst, den er -1 når ingenting er valgt ennå, noe som er sjekken cmdAssign_Click bruker for å fange en bruker som klikker knappen uten å velge en by først. .Value gir deg den valgte teksten direkte, noe som vanligvis er mer nyttig enn den numeriske posisjonen .ListIndex gir.

Multi-Page Forms

En MultiPage-kontroll (fanene Details / Preferences øverst i Figur 5.5) grupperer relaterte kontroller på separate sider i samme fysiske skjema — nyttig når et skjema har for mange felt til å få plass på én skjerm. Hver side adresseres etter posisjon, og bare kontrollene på den synlige siden er relevante for brukeren, selv om alle fortsatt eksisterer og kan leses fra kode uansett hvilken side som vises:

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

MultiPage1.Value følger samme 0-baserte telling som ListIndex — første side er 0, andre (Preferences, i Figur 5.5) er 1 — og Change-hendelsen utløses automatisk hver gang brukeren klikker på en annen fane.

Oppgave

  1. Legg til en ramme (Frame) som inneholder tre alternativknapper (optActive, optInactive, optProspect) i frmAddCustomer, og erstatt den tidligere cboStatus ComboBox. Skriv If...ElseIf-blokken vist ovenfor for å lese valget.
  2. Legg til to uavhengige avkrysningsbokser (chkWelcomeEmail, chkNewsletter) og bekreft under testing at det å merke én aldri påvirker den andre.
  3. Legg til en listeboks (lstCities) som fylles i UserForm_Initialize, og skriv en sjekk som viser en feilmelding hvis brukeren prøver å fortsette uten å ha valgt noe (ListIndex = -1).
  4. Utfordring: plasser feltene Company Name, Contact og Email på én MultiPage-side kalt "Details", og avkrysningsboksene og alternativknappene på en annen side kalt "Preferences".
Tips
expand arrow

1. Erstatte cboStatus med en ramme med alternativknapper

  • Slett først cboStatus og dens etikett fra skjemaet — du erstatter den, ikke legger til i tillegg.
  • Dra en Frame-kontroll inn på skjemaet, og dra deretter alle tre alternativknappene inn i rammens område — denne innkapslingen gjør dem gjensidig utelukkende som én gruppe.
  • Gi hver alternativknapp nytt navn individuelt i egenskapsvinduet; selve rammen kan ha en enkel bildetekst som "Status", men trenger ikke et kodenavn med mindre du skal referere til den direkte.
  • For å lese valget må du sjekke hver alternativknapps .Value individuelt med If...ElseIf — det finnes ingen enkelt egenskap som forteller deg "hvilken i gruppen som er valgt".
  • Siden cboStatus.Value ikke lenger finnes, må cmdSave_Click ha en status-variabel bygget fra alternativknappene i stedet, som skrives inn i newRow på samme sted.

2. Legge til to uavhengige avkrysningsbokser

  • Disse plasseres direkte på skjemaet (ikke inne i rammen) — avkrysningsbokser utenfor en delt beholder påvirker aldri hverandre uansett gruppering.
  • For å "bekrefte under testing", merk bare av i én, deretter den andre, og se at ingen av dem fjerner merkingen fra den første.

3. Legge til og validere en listeboks

  • Fyll den på samme måte som cboCity ble fylt — gjentatte .AddItem-kall i UserForm_Initialize.
  • ListIndex = -1 betyr spesifikt at ingenting er valgt ennå — det er akkurat denne tilstanden du skal sjekke før lagring kan fortsette.
  • Denne sjekken hører hjemme i samme valideringsblokk som de andre obligatoriske feltene, og legges til i samme errors-streng.

4. MultiPage-utfordring

  • Dra en MultiPage-kontroll inn på skjemaet — den har to sider som standard, akkurat så mange du trenger.
  • Gi hver side nytt navn via høyreklikk → Page Order, eller ved å velge sidens fane og bruke egenskapsvinduets Caption-felt (Caption styrer fanens synlige tekst; det finnes også et eget (Name)-felt hvis du vil referere til en side i kode).
  • For å flytte eksisterende kontroller til en side, dra dem fysisk inn på den sidens synlige område i designvisning — kodereferanser til dem endres ikke, siden kontrollens navn ikke avhenger av hvilken side den ligger 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

Testnotater:

  • Punkt 2 (avkrysningsbokser) har ingen egen validering — bare klikk på chkWelcomeEmail og chkNewsletter uavhengig og bekreft at hver kan slås av og på uten å påvirke den andre.
  • Punkt 4 (MultiPage) er kun en layoutendring — ingen kodeendringer er nødvendig utover det som allerede finnes her, siden hver kontroll beholder sitt eget navn uansett hvilken side den ligger på.
  • Merk at cboCity.Value fortsatt brukes for selve lagringen (newRow.Range(1, 5)), mens lstCities kun eksisterer som en separat, uavhengig validert kontroll i henhold til oppgaven — de to er ikke koblet sammen med mindre du selv velger å utvide det slik.
Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 5. Kapittel 4
some-alt