Selecting WinCC HMI Text and Graphic List Values via VBScript

David Krause18 min read
SiemensTutorial / How-toWinCC
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Overview

This reference describes how to read the selected entry of a text list or graphic list in a Siemens WinCC HMI runtime using VBScript, how to compare that selection against another bit or value (PLC tag or internal HMI tag), and how to apply multiplexing so the same script can address any one of N indexed list entries without leaving the HMI. The patterns apply to WinCC Comfort/Advanced and WinCC Professional runtime targets configured in TIA Portal V16 through V19, including Comfort Panels, PC Runtime Advanced, and PC Runtime Professional. (Unified Comfort Panels use a JavaScript API and are not covered here.)

Three recurring questions are answered end-to-end:

  1. How do you read which entry of a text or graphic list is currently selected, and how do you recover the displayed text or graphic index from VBScript?
  2. How do you compare that selection to another bit or value in the PLC (or an internal HMI tag) and write a result back from the script?
  3. How do you use multiplexing (an index-driven pointer into a group of tags) to address one of many list sources from a single script?

All code blocks use the SmartTags and HMIRuntime object models documented in the WinCC TIA Portal scripting help. The multiplexing pattern is the canonical workaround for the absence of first-class indirect addressing in WinCC VBScript.

Prerequisites

Item Version / Detail
TIA Portal V16, V17, V18, or V19 (scripting API is stable across these releases)
HMI Runtime WinCC Runtime Advanced, WinCC Runtime Professional, or a Comfort Panel
Panel firmware Must match the TIA Portal project version. Mismatched firmware is a leading cause of script errors at runtime
Scripting language VBScript (Project → Properties → Runtime settings → Scripts → Active script language = VBScript)
Tags At least one HMI tag bound to a text or graphic list; at least one external or internal tag to compare against
Authoring access Local help files installed with TIA Portal for the VBScript reference and the text/graphic list configuration help
Note: On WinCC Professional both VBScript and C scripts are supported. C scripts are compiled to native code at build time; VBScript is interpreted. VBScript is the lowest-friction path for the patterns shown here, and is the only scripting language supported on Comfort Panels and WinCC Runtime Advanced.

Text Lists and Graphic Lists in TIA Portal

A text list is a configuration object that maps an integer value to a display string. A graphic list maps an integer to a graphics file (.png, .bmp; .svg is supported on Unified only). The integer lives in the HMI tag; the displayed value is the list entry at that index.

Property Text list Graphic list
Tag type Int (Word) or DInt Int or DInt
Configuration path HMI tags → Text and graphic lists → Text list HMI tags → Text and graphic lists → Graphic list
Range entries Default value + range (e.g. 0 = "Stop", 1 = "Run", 2 = "Fault") Default graphic + range (e.g. 0 = lamp_off.png, 1 = lamp_on.png)
Bound to Symbolic I/O field, button label, status display Graphic I/O field, graphic view
Selection feedback at runtime Tag value = index, displayed text = entry at index Tag value = index, displayed graphic = entry at index
Localized Yes — multiple language rows per index No (graphics are language-neutral)

Because the list is bound to a tag, the integer in the tag is the selection. There is no separate "selected text" register to read — the text is purely a presentation of the integer. To compare a selection in VBScript, compare the integer. To display the corresponding text, let the HMI render the list. This is a frequent point of confusion for engineers familiar with desktop list controls, where a list box holds both a value and a displayed string as separate fields.

WinCC VBScript Object Model: The Parts You Need

Three objects cover virtually every HMI scripting task:

  • SmartTags — a project-global collection of all HMI tags. SmartTags("TagName") reads the tag; SmartTags("TagName") = value writes it. For array tags, SmartTags("ArrayName")(i) reads/writes element i. SmartTags is the only object you need for tag-only logic.
  • HMIRuntime — the runtime root. Exposes Tags, Screens, Trace, and the alarm/Logging subsystems.
  • HMIRuntime.Screens("ScreenName").ScreenItems("ItemName") — a specific screen item. Use this to read or write control properties such as .Text, .Value, .Selection, .OutputValue, and .BackColor.
' Pattern: read a tag
Dim v
v = SmartTags("ModeIndex")

' Pattern: write a tag
SmartTags("MatchFound") = 1

' Pattern: read element i of an array tag
Dim i, elem
i   = SmartTags("MuxIndex")
elem = SmartTags("MuxArray")(i)

' Pattern: read a screen item property (WinCC Professional)
Dim oItem, sText
Set oItem = HMIRuntime.Screens("Main").ScreenItems("ModeIOField")
sText = oItem.Text
Comfort vs. Professional: On Comfort Panels and WinCC Runtime Advanced the screen-item API is much smaller. The I/O field exposes its displayed text through a property that varies by firmware (typically OutputValue on a configured symbolic I/O field); use the property picker in the TIA Portal script editor to confirm the exact name for your firmware version.

Reading the Selection in VBScript

The basic read pattern addresses the HMI tag through the SmartTags collection. The tag may be an internal HMI tag or a pointer into the PLC.

' Read the integer index of the text list selection
Dim iSelection
iSelection = SmartTags("ModeIndex")     ' tag bound to a text list

' Read the bit/word to compare against
Dim iRefValue
iRefValue  = SmartTags("RefValue")       ' PLC tag or internal tag

' Drive a result tag back to the PLC
If iSelection = iRefValue Then
    SmartTags("MatchFound") = 1
Else
    SmartTags("MatchFound") = 0
End If

This is the smallest useful pattern: read a list selection, compare it to a reference, and write a result. Both tags must exist in the HMI tag table; the script will throw a runtime error if a referenced tag is missing, or if the connection to the PLC is not established when the script first runs.

Reading the displayed text, not just the index

If you need the text that the HMI is rendering (for logging, for forwarding to a string tag, or for string comparison against a fixed label), you must read it from the screen item, because the HMI list itself is not directly addressable as a VBScript object. The general approach mirrors the technique documented for retrieving the inner text of a list or dropdown element (see Microsoft DevBlogs: How Can I Get the Actual Text of a List Box or Dropdown List Option?) — the value is one thing, the displayed text is another, and the script must read the visible property rather than the value.

On WinCC Comfort/Advanced (symbolic I/O field bound to a text list):

' Get the displayed text of the symbolic I/O field "ModeField"
Dim sText
sText = SmartTags("ModeField")     ' the .Text / .OutputValue property of the I/O field

On WinCC Professional, screen items are addressable as HMIRuntime.Screens("ScreenName").ScreenItems("ItemName"):

Dim oItem, sText
Set oItem = HMIRuntime.Screens("Main").ScreenItems("ModeIOField")
sText = oItem.Text      ' or .OutputValue, depending on the control
Caution: The exact property name depends on the runtime (Comfort, Advanced, Professional) and on the specific control. Open the HMI screen, select the I/O field, and inspect the property list in the object model. Test in TIA simulation first; production runtime is far less forgiving of a misspelled property name than the editor is.

Multiplexing: One Script, Many List Sources

Multiplexing is the technique of using an index tag to select which of N underlying values the script should act on. In Siemens HMI scripting it is the standard workaround for the absence of full indirect addressing — VBScript cannot dereference a pointer in the way that, for example, a C script with an HMI_TAG_POINTER can.

Pattern A — array tag with index

Configure a tag as a one-dimensional array (DInt array of N elements) and read element iIndex:

Dim iIndex, iValue
iIndex = SmartTags("MuxIndex")              ' 0..N-1
iValue = SmartTags("MuxArray")(iIndex)      ' element access

Array tags must be declared as a one-dimensional array in the HMI tag table. The size of the array is fixed at project compile time. If iIndex is out of range, VBScript raises a runtime error — guard the read.

Pattern B — string-built tag name

When the data is stored as separate scalar tags (no array), build the tag name as a string and use the indirect read:

Dim iIndex, sTagName, vValue
iIndex   = SmartTags("MuxIndex")
sTagName = "MuxValue_" & CStr(iIndex)
vValue   = SmartTags(sTagName)

This requires that tags MuxValue_0, MuxValue_1, …, MuxValue_N-1 exist in the HMI tag table. The script will fail if the constructed name does not match a real tag, so the multiplexer index must be bounded by the project's tag count. Use this pattern when you must multiplex across structurally different data sources that cannot be arrayed (for example, a mix of Bool, Int, and String tags).

Pattern C — array of pointer names plus indirect read

For more complex cases where the multiplexer picks a tag by name, store both the source tag name and the value in coordinated arrays:

Dim iIndex, sName, vValue
iIndex = SmartTags("MuxIndex")
sName  = SmartTags("MuxNames")(iIndex)      ' array of strings (tag names)
vValue = SmartTags(sName)                   ' then indirect read

Pattern C is the most flexible — it lets the multiplexer point at any tag in the project — but the most error-prone. It is the right pattern when the multiplexer must be reconfigured at runtime by the operator (e.g. selecting which recipe source drives a comparison), and the wrong pattern when a fixed set of pointers will do.

Sizing the multiplexer

Choose N (the number of multiplexer positions) based on the use case:

Use case Recommended N Notes
Mode selection (Auto/Manual/Service) 3–8 Pattern A with DInt[8] is typical
Recipe source (one of 16 recipe slots) 16–32 Pattern A or B; array of DInt[16] is typical
Alarm routing (one of many source tags) Variable Pattern C with string-name array
Page selector (jump to one of many screens) 8–32 Pattern B with "Screen_" & iIndex naming

The array-tag approach (Pattern A) is the fastest at runtime because the HMI runtime holds the array in memory. The string-built approach (Pattern B) is slower because the runtime must resolve the tag name on every read, but it allows tag types to differ per index.

Comparing a Selection to a Bit or Value

The comparison is the same regardless of whether the second operand is a Bool, an integer, a real, or a string tag. VBScript coerces types implicitly; declare the comparison variables explicitly to avoid type-mismatch errors at runtime.

' --- Bit comparison ---
If SmartTags("ModeIndex") = 1 And SmartTags("EnableBit") = True Then
    SmartTags("RunEnable") = 1
End If

' --- Value comparison with tolerance (real) ---
Dim rPV, rSP, rTol
rPV  = SmartTags("ProcessValue")
rSP  = SmartTags("Setpoint")
rTol = 0.5
If Abs(rPV - rSP) <= rTol Then
    SmartTags("InBand") = 1
Else
    SmartTags("InBand") = 0
End If

' --- String comparison (only valid for tags typed as WString) ---
If SmartTags("RecipeName") = "RUN_42" Then
    SmartTags("RecipeOK") = 1
End If
Note on Booleans: WinCC Bool tags are exposed to VBScript as 0/1 integers. Comparing with True/False works, but a literal = 1 / = 0 is the convention used in production WinCC code. Mixing the two is a common source of subtle bugs in code review.

Step-by-Step Implementation

The following procedure produces a working selection-comparison script bound to a button event, including multiplexing.

  1. Declare tags in the HMI tag table.
    • ModeIndex — Int, bound to a text list (e.g. 0 = "Auto", 1 = "Manual", 2 = "Service")
    • RefValue — Int, external PLC tag
    • MatchFound — Bool, internal HMI tag, written back to the PLC
    • MuxIndex — Int, internal, 0..7, controlled by the operator or by the PLC
    • MuxArray — DInt[8] array, internal or external
    • MuxError — Bool, internal, set to 1 on out-of-range index
  2. Add a text list in HMI tags → Text and graphic lists. Map 0 → "Auto", 1 → "Manual", 2 → "Service".
  3. Place a symbolic I/O field on the screen and bind its Value property to ModeIndex. Bind its Display to the text list from step 2.
  4. Place an I/O field for the multiplexer bound to MuxIndex. Set a configured range of 0 to 7 and a step of 1.
  5. Add a button "Evaluate". In the Events tab, configure the Click event to run a VBScript.
  6. Paste the script from the snippet below into the Click event of the button.
  7. Compile the project (Ctrl+F7 in TIA Portal) and download to the HMI. Update the panel firmware first if the runtime version requires it.
  8. Test by changing ModeIndex and MuxIndex from the screen, then pressing Evaluate and observing MatchFound in the HMI tag monitor and on the PLC (TIA Watch table or the PLC online view).
' ----- Evaluate button Click event -----
Dim iMode, iRef, iMux, vMuxValue, iResult

' Read the current text-list selection
iMode = SmartTags("ModeIndex")
iRef  = SmartTags("RefValue")

' Read the multiplexed value at MuxIndex
iMux = SmartTags("MuxIndex")
If iMux < 0 Or iMux > 7 Then
    SmartTags("MuxError") = 1
    Exit Sub
Else
    SmartTags("MuxError") = 0
End If
vMuxValue = SmartTags("MuxArray")(iMux)

' Combine the conditions: list selection AND value match
If iMode = iRef And vMuxValue > 0 Then
    iResult = 1
Else
    iResult = 0
End If

' Write the result back to the PLC-visible tag
SmartTags("MatchFound") = iResult

Using the Script in a Scheduled Task

If the comparison must run continuously rather than on a button press, attach the same script body to a scheduled task on the HMI (Schedules → Add → Trigger = "Cyclic", Update = 500 ms). Scheduled VBScript runs in the global script context, so SmartTags continues to work and no screen reference is required.

Performance: On Comfort Panels the VBScript engine is single-threaded and slower than PC Runtime. Avoid putting the script on a 100 ms cycle if the body references more than a handful of tags. 250–500 ms is the practical floor on a TP700 / TP1500. On a Unified Panel use the JavaScript equivalent with a 100–250 ms cycle, or use a tag-side calculation if WinCC Unified supports it.

Cross-Screen and Cross-Panel Patterns

When the selection lives on Screen A and the comparison runs on Screen B, you can keep the script identical by attaching it to a button on either screen, because SmartTags is global to the HMI project. The screen-item text access path is the only piece that is screen-local; replace the screen name accordingly.

' Cross-screen text access (WinCC Professional)
Dim sText
sText = HMIRuntime.Screens("Overview").ScreenItems("ModeIOField").Text

For an aggregation screen that displays a multiplexer-driven value, use the same array-index read as in Pattern A. The same multiplexer index tag can be read from any screen; only the bound display control changes.

Logging the Result

A common follow-up requirement is to log the match to the alarm or audit trail. Write a short message to an HMI tag that the alarm log has been configured to capture, or use HMIRuntime.Trace for a development trace:

HMIRuntime.Trace "Mode match: iMode=" & iMode & " vMux=" & vMuxValue & " result=" & iResult & vbCrLf
SmartTags("LastTraceMessage") = "Mode=" & iMode & "; Mux=" & vMuxValue & "; Result=" & iResult
Do not use MsgBox in production runtime. It blocks the HMI thread and forces operator intervention. Reserve it for the TIA simulation during commissioning. Use a status tag or alarm log entry in production.

Edge Cases and Performance Notes

  • Type coercion at the boundary. If a Bool PLC tag is wired to an HMI Int tag, both reads return 0/1 but the type info is lost. Use the HMI tag type that matches the PLC variable type to keep the boundary clean.
  • Power Tags (WinCC Professional / Unified). Marking a tag as a Power Tag changes update behavior; multiplexer arrays benefit noticeably from Power Tag status, but each Power Tag consumes a license.
  • String tag length. WString tags are typically limited to 255 characters; longer strings require a custom PLC data type and a different HMI tag type. Comparison against a literal in VBScript is then case-sensitive by default.
  • Cyclic vs on-demand scripts. A button-click event is the simplest hook. Use a cyclic scheduled task only if the comparison must be continuous — the script will otherwise idle for hours between operator actions, consuming scheduler slots.
  • Localization. Text lists can be localized. The integer index is stable across languages, but the displayed text is not. Always compare on the integer; do not hardcode language-specific text in a script that will be deployed to a multi-language HMI.
  • Tag name length. Siemens HMI tag names are limited to 128 characters. The string-concatenation pattern ("MuxValue_" & CStr(iMux)) must not exceed that limit; use numeric indices wherever possible.
  • Set MuxError before Exit Sub. A failed array access will throw, but the operator should see the diagnostic state. Set the error tag first, then exit.

Troubleshooting Matrix

Symptom Likely cause Fix
"Tag not found" or similar at script start Tag missing in HMI tag table, or the project has not been compiled/recompiled Add the tag, full compile (Ctrl+F7), redownload to the HMI
"Subscript out of range" on MuxArray MuxIndex outside the array bounds Add the guard If iMux < 0 Or iMux > UBound(arr) Then SmartTags("MuxError") = 1 : Exit Sub
Tag value reads, but the comparison never matches Type mismatch (Int vs DInt, signed vs unsigned, BCD on PLC side) Match the tag data type in TIA Portal to the PLC; check the PLC data block type
Script runs in TIA simulation but not on the panel Panel firmware older than project, or scripting disabled in runtime settings Update firmware, enable VBScript in project properties
"Object variable not set" on ScreenItems(...) Wrong screen name, wrong item name, or item not configured with the expected property Use the object picker in the TIA Portal script editor to confirm names
Tag value toggles rapidly between two list entries HMI tag connected to a noisy PLC bit; no debounce in script Add a hysteresis timer or a debounce counter before writing the result
Multiplexer index never updates on the screen Tag is write-protected or not connected to a configurable control Check the I/O field's "Operability" property and the tag's acquisition mode
Script runs but MatchFound stays at its previous value The result tag is read-only or not declared as a writable PLC point Confirm the tag has a direction of "read/write" in the HMI tag table and is mapped to a writable PLC address
Array element always reads 0 The multiplexer index is being reset by another script or by the PLC faster than the script reads it Snapshot the index into a local variable at the start of the script, then read the array element from that snapshot

Verification

After download, perform the following checks before signing off the change:

  1. Open the HMI tag simulation in TIA Portal (Online → HMI Tag Simulation) and force ModeIndex to each configured value. Confirm the text list displays the right string on the screen.
  2. Force RefValue to match ModeIndex; press the Evaluate button; verify MatchFound becomes 1 in the HMI tag monitor and in the PLC (using TIA Watch table or the PLC online view).
  3. Force RefValue to a different value; verify MatchFound returns to 0.
  4. Set MuxIndex to 0..7 in turn, with a non-zero MuxArray element at each index, and confirm the result is correct. Then set MuxIndex to 8 — confirm the script raises MuxError and does not write garbage to MatchFound.
  5. Disconnect the PLC and confirm the script handles a connection loss gracefully: the comparison will run against the last-cached value; MatchFound should reflect that cache, not freeze or throw.
  6. If the script runs on a scheduled cycle, log the cycle time from the trace and confirm it stays below the configured update interval. A script that runs longer than its cycle interval will backlog on a Comfort Panel.

FAQ

How do I read the currently selected entry of a text list in VBScript?

Read the HMI tag that the list is bound to with SmartTags("ModeIndex"). The integer value of the tag is the selection index; the displayed text is the list entry at that index and is rendered automatically by the HMI. To recover the actual text, read the .Text property of the screen item (WinCC Professional) or the I/O field's OutputValue (WinCC Comfort/Advanced).

Can I compare the text string directly, not the integer index?

Not reliably. The list maps an integer to a text; the text is presentation. Always compare on the integer — string comparison breaks under localization, where the same integer can display different texts per language, and is fragile across firmware updates where label text may be reworded.

What is multiplexing in a Siemens HMI script?

Multiplexing uses an index tag to choose which of N values the script acts on. In VBScript the two practical implementations are (a) an array tag plus an index read (SmartTags("MuxArray")(iIndex)) and (b) a string-built tag name (SmartTags("MuxValue_" & iIndex)) for an indexed set of scalar tags. Pattern A is faster; Pattern B supports mixed tag types.

Why does my script throw "Subscript out of range" on the array read?

Because the index tag moved outside the array bounds. Guard the read with a range check and write a diagnostic to an error tag before exiting. Example: If iMux < 0 Or iMux > UBound(arr) Then SmartTags("MuxError") = 1 : Exit Sub. A mismatched multiplexer index is the most common cause in production code.

Does this work on a Unified Comfort Panel?

No — Unified Panels use JavaScript for screen-side scripting, not VBScript. The multiplexing and comparison logic transfers directly, but the tag access syntax changes (use the Unified JS API or the item property model). This article covers WinCC Comfort/Advanced and WinCC Professional, which use VBScript.

How do I avoid MsgBox blocking the HMI at runtime?

Replace MsgBox with writes to an HMI tag that is bound to a status display, or with HMIRuntime.Trace for development. MsgBox in a runtime script pauses the entire HMI and forces operator interaction — it is acceptable only in the simulation for debugging and must be removed before deployment.

Back to blog