Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Skill Display Construction

---
title: "Display Construction — Canvas, Dashboard, Dynamics, Symbols & CodeBehind"
tags: [display, canvas, dashboard, symbol, navigation, hmi, ui, layout, dynamics, codebehind]
description: "Build displays from scratch: Canvas and Dashboard layouts, zone-based Canvas positioning, symbol placement with SymbolLabel binding, visual dynamics (color, visibility, rotation), ActionDynamic click handling, CodeBehind for display logic, and asset-driven navigation"
version: "3.0"
author: "Tatsoft"
---

...

??????????????????????????????????????????????????????????????????
? PAGE TITLE BAR          (x:0, y:0, w:1366, h:50)     ACTION   NAV BTNBTNs  ?
??????????????????????????????????????????????????????????????????
? Zone 1 ? Zone 2 ? Zone 3 ? Zone 4 ? Zone 5 ? Zone 6 ? Zone 7 ?
?        ?        ?        ?        ?        ?        ?        ?
? h:300  ?        ?        ?        ?        ?        ?        ?
??????????????????????????????????????????????????????????????????
? BOTTOM PANEL: Trend, Alarms, KPIs, or ML Status (h:300+)     ?
??????????????????????????????????????????????????????????????????

Note: Page-to-page navigation buttons belong in the Header display (see Step 10b), not on the Canvas title bar. ACTION BTNs here are for in-page actions only (e.g., start/stop, acknowledge, reset).

Zone sizing rules:

  • Title bar: full width, 50px tall
  • Process zones: divide remaining width equally among process stages
  • Each zone minimum: 160px wide × 280px tall
  • Bottom panel: full width, remaining height
  • Margin between zones: 15–20px
  • Padding inside zones: 10–15px from zone border to content

...

Available width  = 1366 - 40 (left/right margin 20px each)  = 1326
Available height = 728 - 50 (title) - 20 (top margin)       = 658

Zone

...

width

...

=

...

(Available

...

width

...

-

...

(N-1)

...

×

...

15)

...

/

...

N

...

Zone

...

height

...

=

...

320

...

(for

...

process

...

row)

...

Zone

...

startY

...

=

...

60

...

(below

...

title)

...


Zone[i].Left

...

=

...

20

...

+

...

i

...

×

...

(zoneWidth

...

+

...

15)

...

Zone[i].Top

...

=

...

60

...

Zone[i].Width

...

=

...

zoneWidth

...

Zone[i].Height

...

=

...

320

...


Bottom

...

panel:

...

Left

...

=

...

20,

...

Top

...

=

...

400,

...

Width

...

=

...

1326,

...

Height

...

=

...

658

...

-

...

320

...

-

...

20

...

=

...

318

...



Example: 6 process stages

Zone width = (1326 - 5×15) / 6 = 208px each

Zone

...

0:

...

Left=20,

...

Top=60,

...

W=208,

...

H=320

...

Zone

...

1:

...

Left=243,

...

Top=60,

...

W=208,

...

H=320

...

Zone

...

2:

...

Left=466,

...

Top=60,

...

W=208,

...

H=320

...

Zone

...

3:

...

Left=689,

...

Top=60,

...

W=208,

...

H=320

...

Zone

...

4:

...

Left=912,

...

Top=60,

...

W=208,

...

H=320

...

Zone

...

5:

...

Left=1135,

...

Top=60,

...

W=208,

...

H=320

...


Bottom:

...

Left=20,

...

Top=400,

...

W=1326,

...

H=308

...



Step 2c: Zone Background Rectangles (REQUIRED)

...

???? Zone (background Rectangle) ?????????????
? ZONE TITLE (FontSize 15-16)           y+10 ?
?                                             ?
?    ????????????                        y+40 ?
?    ?  Symbol  ?   80×80 to 100×100          ?
?    ?  (pump,  ?   centered horizontally     ?
?    ?  motor)  ?                              ?
?    ????????????                       y+140 ?
?                                             ?
?  Label: Value Unit  (FontSize 14)     y+150 ?
?  Label: Value Unit                    y+176 ?
?  Label: Value Unit                    y+202 ?
?                                             ?
?  Status indicator (optional)          y+240 ?
???????????????????????????????????????????????

...

Option A: Trend + KPI sidebar

???????????????? Bottom Panel ???????????????????
? TrendChart (w:900, h:280)  ? KPI Column      ?
?                             ? Value1: ###     ?
?                             ? Value2: ###     ?
???????????????????????????????????????????????????

Option B: Trend + Alarm split

???????????????? Bottom Panel ???????????????????
? TrendChart (w:660, h:280)  ? AlarmViewer      ?
?                             ? (w:640, h:280)  ?
???????????????????????????????????????????????????

Option C: Full-width trend with status bar

???????????????? Bottom Panel ???????????????????
? Status: Score: 0.023  Confidence: 0.98       ?  (h:30)
? TrendChart (full width, h:250)               ?
??????????????????????????????????????????????????

...

  1. Zone background Rectangles (renders first = behind everything)
  2. Title TextBlock
  3. Navigation In-page action Button(s) (start/stop, acknowledge — NOT page navigation)
  4. Zone titles
  5. Symbols (centered in each zone)
  6. Value TextBlocks (below symbols in each zone)
  7. Flow arrows between zones
  8. Bottom panel background Rectangle(s)
  9. Bottom panel content (TrendChart, AlarmViewer, etc.)
  10. Dynamic indicators and status elements

...

get_table_schema('DisplaysLayouts')
get_objects('DisplaysLayouts', names=['Startup'], detail='full')

The Startup layout defines which display loads into the Content region (typically MainPage). Only modify if you need:

  • A different startup page
  • Custom header/footer regions
  • Navigation menus

The Startup layout defines which display loads into the Content region (typically MainPage). Only modify if you need:

  • A different startup page
  • Custom header/footer regions
  • Navigation menus

Layouts are document objects — read first, modify, write back. Dependencies: DisplaysSymbols → DisplaysList → DisplaysLayouts

...

Step 10b: Header Navigation Buttons (Multi-Page Solutions)

When a solution has multiple content pages (Dashboard, ProcessOverview, AlarmPage, TrendPage, etc.), navigation buttons belong in the Header display — not on each content page.

Why the Header: The Header region is persistent — it stays visible while the Content region changes. Placing navigation here means every page gets consistent navigation without duplicating buttons on each content page.

Workflow:

  1. Read the Startup layout to find the Header display:
    get_objects('DisplaysLayouts', names=['Startup'], detail='full')
    
  2. Read the Header display (it's a Canvas page assigned to the Header region):
    get_objects('DisplaysList', names=['Header'], detail='full')
    
  3. Add navigation buttons to the Header display — right-aligned in the header bar:
    {
      "Type": "Button",
      "Text": "Dashboard",
      "Left": 900, "Top": 5, "Width": 110, "Height": 32,
      "ActionDynamic": {
        "Type": "NavigateToDisplay",
        "DisplayName": "MainPage"
      }
    },
    {
      "Type": "Button",
      "Text": "Process",
      "Left": 1020, "Top": 5, "Width": 110, "Height": 32,
      "ActionDynamic": {
        "Type": "NavigateToDisplay",
        "DisplayName": "ProcessOverview"
      }
    },
    {
      "Type": "Button",
      "Text": "Alarms",
      "Left": 1140, "Top": 5, "Width": 110, "Height": 32,
      "ActionDynamic": {
        "Type": "NavigateToDisplay",
        "DisplayName": "AlarmPage"
      }
    }
    
  4. Write back the modified Header display (read-modify-write — it's a document object).

Button placement in the Header:

  • Header displays are typically 1366×40 to 1366×50
  • Navigation buttons go right-aligned (leave left side for title/logo)
  • Standard button size in headers: 100–120px wide × 30–35px tall
  • Gap between buttons: 10px

CRITICAL: Do NOT put page navigation buttons on content pages (Canvas or Dashboard). Content pages should only contain buttons for in-page actions (start/stop, acknowledge, open popup). Page-to-page navigation is always in the Header.

Exception: If the solution has NO layout (single standalone page), navigation buttons can go on the content page itself — but this is unusual for production solutions.Layouts are document objects — read first, modify, write back. Dependencies: DisplaysSymbols → DisplaysList → DisplaysLayouts

...

Step 11: Asset Navigation Pattern (Advanced)

...

  • [ ] Zones calculated to fill the FULL canvas width and height
  • [ ] Every zone has a background Rectangle with FillTheme: "PanelBackground"
  • [ ] Zone backgrounds are FIRST in the Elements array
  • [ ] Symbols are ≥ 80×80 pixels, centered in their zones
  • [ ] Zone titles are FontSize ≥ 15
  • [ ] Value text is FontSize ≥ 14
  • [ ] Value and Unit are in the SAME TextBlock (e.g., "Flow: {@Tag.X} GPM")
  • [ ] Flow arrows (→) placed between adjacent zones
  • [ ] Bottom panel fills remaining vertical space
  • [ ] Bottom panel sections have PanelBackground theme Rectangles
  • [ ] No element extends beyond 1366×728] No element extends beyond 1366×728
  • [ ] Page navigation buttons are in the Header display, NOT on the Canvas (see Step 10b)

...

Common Pitfalls

MistakeWhy It HappensHow to Avoid
Using DisplaysDraw as table_typeConfused with DisplaysListDisplaysDraw is the visual editor UI, not a writable table
Omitting PanelTypeDefaults silently to CanvasAlways set PanelType explicitly
Using @Label. in display elementsConfused with symbol definitions@Label. is only for DisplaysSymbols internals. Use @Tag. when placing symbols
Not discovering dynamics firstDoesn't know what's availableCall list_dynamics() with no parameter to see all dynamic types
Screenshots for self-validationHabit from other toolsTrust write_objects success. User sees live updates
Setting colors without clearing themeTheme overrides custom colorsSet value AND clear theme: {Fill: '#FF3498DB', FillTheme: ''} — or just omit to use themed defaults
Sending partial display contentForget it's a document objectAlways read-modify-write for existing displays
Canvas positioning in DashboardMixing layout paradigmsCanvas uses Left/Top + Elements; Dashboard uses Row/Col + Cells
Referencing symbols with wrong pathIncomplete library pathBrowse with list_elements('Symbol/HMI') to get exact paths
Guessing dynamic property namesDifferent dynamics have different schemasAlways call list_dynamics('DynamicTypeName') for exact schema
CodeBehind in wrong Contents formatMissing language prefixContents must start with CSharp\r\n or VBdotNet\r\n before code
All Canvas content in top-leftNo zone planningCalculate zones FIRST to fill the full canvas
Symbols at 40×40 or 50×50Copying library defaultsMinimum 80×80 on process overview displays
Value and Unit as separate TextBlocksSeems logical but misalignsSingle TextBlock: "{@Tag.X} GPM"
No background rectangles on zonesDoesn't know about visual groupingAlways add Rectangle with FillTheme: "PanelBackground"
Hardcoded fill colors on zone backgroundsBreaks in Dark themeUse FillTheme: "PanelBackground" instead
FontSize 10–11 for valuesDefault seemed fineMinimum 13, prefer 14 for operator readability
Page navigation buttons on content pagesSeems convenient per-pageNavigation goes in the Header display (Step 10b) — content pages only have in-page action buttons

Quick Reference

Display ActionTool Call
Get display schemaget_table_schema('DisplaysList')
Get Canvas structurelist_elements('Canvas')
Get Dashboard structurelist_elements('Dashboard')
Get element schemalist_elements('ElementName')
Browse all dynamicslist_dynamics()
Get specific dynamic schemalist_dynamics('FillColorDynamic')
Browse symbolslist_elements('Symbol/HMI') or list_elements('Library')
Browse Wizard symbolslist_elements('Wizard')
Browse theme colorslist_elements('ThemeColors')
Read existing displayget_objects('DisplaysList', names=['PageName'], detail='full')
Write displaywrite_objects('DisplaysList', data=[...])
Navigate Designer to displaydesigner_action('navigate', 'Display.PageName')
Browse runtime propertiesbrowse_runtime_properties('Client')
Read Header for nav buttonsget_objects('DisplaysList', names=['Header'], detail='full')
Read layout structureget_objects('DisplaysLayouts', names=['Startup'], detail='full')

What's Next

  • Server-side logic, tag calculations, CodeBehind patterns: Load the Scripts and Expressions skill — search_docs('scripts', labels='skill')
  • New solution from scratch: Load the New Solution skill — search_docs('new solution', labels='skill')
  • Specific protocol connectivity: Use list_protocols() to browse, then search_docs('modbus', labels='connector') for protocol-specific docs
  • Advanced symbol creation: search_docs('custom symbols', labels='tutorial') for building reusable parameterized symbols