Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lära Arbeta med formulärkontroller | Användarinteraktion
Excel VBA för affärsautomatisering

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.

Figur 5.5

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

  1. 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.
  2. Lägg till två oberoende Kryssrutor (chkWelcomeEmail, chkNewsletter) och bekräfta vid testning att markering av den ena aldrig påverkar den andra.
  3. 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).
  4. 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".
Tips
expand arrow

1. Ersätta cboStatus med en Ram av Alternativknappar

  • Ta först bort cboStatus och 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 .Value individuellt med If...ElseIf — det finns ingen enskild egenskap som talar om "vilken i gruppen som är markerad".
  • Eftersom cboStatus.Value inte längre finns, behöver cmdSave_Click en status-variabel som byggs utifrån Alternativknapparna och skrivs in i newRow istä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 cboCity fylldes — upprepade .AddItem-anrop i UserForm_Initialize.
  • ListIndex = -1 betyder 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å.
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

Testanteckningar:

  • Punkt 2 (Kryssrutor) har ingen särskild validering — klicka bara på chkWelcomeEmail och chkNewsletter oberoende 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.Value fortfarande används för själva sparandet (newRow.Range(1, 5)), medan lstCities existerar 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å.
Var allt tydligt?

Hur kan vi förbättra det?

Tack för dina kommentarer!

Avsnitt 5. Kapitel 4

Fråga AI

expand

Fråga AI

ChatGPT

Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal

Avsnitt 5. Kapitel 4
some-alt