Arbeta med formulärkontroller
Svep för att visa menyn
TextBoxes och ComboBoxes täcker de flesta datainmatningar, men några andra kontroller uttrycker vissa typer av val mer naturligt — och att läsa deras värden korrekt har några verkliga fallgropar som är värda att känna till innan du förlitar dig på dem.
CheckBoxes
En CheckBoxs Value-egenskap är en enkel Boolean — True när den är markerad, False när den inte är det:
If chkWelcomeEmail.Value = True Then
MsgBox "A welcome email would be sent here."
End If
Varje CheckBox på ett formulär är helt oberoende av de andra — att markera chkWelcomeEmail påverkar inte chkNewsletter, vilket är precis det beteende du vill ha när valen inte är ömsesidigt uteslutande.
OptionButtons
OptionButtons fungerar tvärtom: inom samma grupp avmarkerar valet av en automatiskt alla de andra — exakt vad skärmdumpens Status-val behöver, eftersom en kund inte kan vara både Active och Inactive samtidigt. För att läsa av vilken som är vald måste du kontrollera värdet på var och en individuellt:
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 ömsesidiga uteslutningen är automatisk och hanteras helt av VBA — du behöver aldrig skriva kod som avmarkerar de andra två när en väljs. Gruppindelning är dock viktig: OptionButtons utesluter bara varandra inom samma behållare (själva formuläret eller en Frame-kontroll placerad på det), så två separata grupper av OptionButtons på samma formulär — till exempel Status och Priority — måste ligga i två olika Frames, annars behandlar VBA dem som en enda ömsesidigt uteslutande grupp.
ListBoxes
En ListBox visar flera val samtidigt utan att behöva klickas upp, som City-listan i Figur 5.5. Fyll den på samma sätt som en ComboBox, med .AddItem, och läs tillbaka valet via antingen .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 är positionen för det valda objektet, räknat från 0 för det första objektet — och viktigt nog, det är -1 när inget alls har valts ännu, vilket är kontrollen cmdAssign_Click använder för att fånga en användare som klickar på knappen utan att först välja en stad. .Value ger dig den valda texten direkt, vilket oftast är mer användbart än den numeriska positionen som .ListIndex ger.
Multi-Page Forms
En MultiPage-kontroll (flikarna Details / Preferences överst i Figur 5.5) grupperar relaterade kontroller på separata sidor av samma fysiska formulär — användbart när ett formulär har för många fält för att rymmas bekvämt på en skärm. Varje sida adresseras efter position, och endast kontrollerna på den aktuellt synliga sidan är meningsfulla för användaren, även om alla fortfarande existerar och kan läsas från kod oavsett vilken sida som visas:
Private Sub MultiPage1_Change()
If MultiPage1.Value = 1 Then
MsgBox "Now viewing Preferences"
End If
End Sub
MultiPage1.Value följer samma 0-baserade räkning som ListIndex — första sidan är 0, den andra (Preferences, i Figur 5.5) är 1 — och Change-händelsen utlöses automatiskt varje gång användaren klickar på en annan flik.
Uppgift
- Lägg till en Ram som innehåller tre Alternativknappar (optActive, optInactive, optProspect) till frmAddCustomer, och ersätt den tidigare cboStatus Kombinationsrutan. Skriv If...ElseIf-blocket som visas ovan för att läsa av valet.
- Lägg till två oberoende Kryssrutor (chkWelcomeEmail, chkNewsletter) och bekräfta vid testning att markering av den ena aldrig påverkar den andra.
- Lägg till en ListBox (lstCities) som fylls i UserForm_Initialize, och skriv en kontroll som visar ett felmeddelande om användaren försöker fortsätta utan att ha gjort ett val (ListIndex = -1).
- Utmaning: placera fälten Företagsnamn, Kontakt och E-post på en sida i en MultiPage med namnet "Details", och Kryssrutorna samt Alternativknapparna på en andra sida med namnet "Preferences".
1. Ersätta cboStatus med en Ram av Alternativknappar
- Ta först bort
cboStatusoch dess etikett från formuläret — du ersätter den, inte lägger till den bredvid. - Dra en Ram-kontroll till formuläret och dra sedan alla tre Alternativknappar inuti Ramens gräns — denna inneslutning gör dem ömsesidigt uteslutande som en grupp.
- Byt namn på varje Alternativknapp individuellt i egenskapsfönstret; själva ramen kan ha en enkel rubrik som "Status" men behöver inget kodvänligt namn om du inte planerar att referera till den direkt.
- Att läsa av valet innebär att kontrollera varje Alternativknapps
.Valueindividuellt medIf...ElseIf— det finns ingen enskild egenskap som talar om "vilken i gruppen som är markerad". - Eftersom
cboStatus.Valueinte längre finns, behövercmdSave_Clickenstatus-variabel som byggs utifrån Alternativknapparna och skrivs in inewRowistället.
2. Lägga till två oberoende Kryssrutor
- Dessa placeras direkt på formuläret (inte i ramen) — Kryssrutor utanför en gemensam behållare påverkar aldrig varandra oavsett gruppering.
- För att "bekräfta vid testning" markerar du bara en, sedan den andra, och ser att ingen avmarkerar den första.
3. Lägga till och validera en ListBox
- Fyll den på samma sätt som
cboCityfylldes — upprepade.AddItem-anrop iUserForm_Initialize. ListIndex = -1betyder specifikt inget har klickats än — det är exakt det tillståndet som ska kontrolleras innan sparandet får fortsätta.- Denna kontroll hör hemma i samma valideringsblock som de andra obligatoriska fälten, och läggs till i samma
errors-sträng.
4. MultiPage-utmaning
- Dra en MultiPage-kontroll till formuläret — den har två sidor som standard, vilket är precis vad du behöver.
- Byt namn på varje sida via högerklick → Sidordning, eller genom att välja sidfliken och använda egenskapsfönstrets rubrikfält (Caption styr flikens synliga text; det finns ett separat (Name)-fält om du vill referera till en sida i kod).
- Att flytta befintliga kontroller till en sida innebär att dra dem fysiskt till den sidans synliga yta i designvyn — kodreferenser till dem ändras inte alls, eftersom en kontrolls namn inte beror på vilken sida den ligger 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
Testanteckningar:
- Punkt 2 (Kryssrutor) har ingen särskild validering — klicka bara på
chkWelcomeEmailochchkNewsletteroberoende och bekräfta att varje växlar utan att påverka den andra. - Punkt 4 (MultiPage) är endast en layoutändring — inga kodändringar behövs utöver det som redan finns här, eftersom varje kontroll behåller sitt eget namn oavsett vilken sida den dras till.
- Observera att
cboCity.Valuefortfarande används för själva sparandet (newRow.Range(1, 5)), medanlstCitiesexisterar enbart som en separat, självständigt validerad kontroll enligt uppgiften — de två är inte kopplade om du inte själv väljer att utöka det så.
Tack för dina kommentarer!
Fråga AI
Fråga AI
Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal