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.
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
- 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.
- Tilføj to uafhængige CheckBoxes (chkWelcomeEmail, chkNewsletter) og bekræft under test, at afkrydsning af den ene aldrig påvirker den anden.
- 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).
- 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".
1. Erstatning af cboStatus med en Ramme af OptionButtons
- Slet først
cboStatusog 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
.Valueindividuelt medIf...ElseIf— der findes ingen enkelt egenskab, der fortæller dig "hvilken i gruppen er markeret". - Da
cboStatus.Valueikke længere eksisterer, skalcmdSave_Clickhave enstatus-variabel, der bygges ud fra OptionButtons i stedet, og skrives ind inewRowi 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
cboCityblev udfyldt — gentagne.AddItem-kald iUserForm_Initialize. ListIndex = -1betyder 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å.
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å
chkWelcomeEmailogchkNewsletteruafhæ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.Valuestadig bruges til den faktiske gemning (newRow.Range(1, 5)), menslstCitieskun eksisterer som en separat, uafhængigt valideret kontrol ifølge opgaven — de to er ikke forbundet, medmindre du selv vælger at udvide det.
Tak for dine kommentarer!
Spørg AI
Spørg AI
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.
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
- 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.
- Tilføj to uafhængige CheckBoxes (chkWelcomeEmail, chkNewsletter) og bekræft under test, at afkrydsning af den ene aldrig påvirker den anden.
- 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).
- 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".
1. Erstatning af cboStatus med en Ramme af OptionButtons
- Slet først
cboStatusog 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
.Valueindividuelt medIf...ElseIf— der findes ingen enkelt egenskab, der fortæller dig "hvilken i gruppen er markeret". - Da
cboStatus.Valueikke længere eksisterer, skalcmdSave_Clickhave enstatus-variabel, der bygges ud fra OptionButtons i stedet, og skrives ind inewRowi 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
cboCityblev udfyldt — gentagne.AddItem-kald iUserForm_Initialize. ListIndex = -1betyder 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å.
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å
chkWelcomeEmailogchkNewsletteruafhæ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.Valuestadig bruges til den faktiske gemning (newRow.Range(1, 5)), menslstCitieskun eksisterer som en separat, uafhængigt valideret kontrol ifølge opgaven — de to er ikke forbundet, medmindre du selv vælger at udvide det.
Tak for dine kommentarer!