# Twincat Dialoge öffnen und schließen in Abhängigkeit



## Minehunter (20 Juli 2017)

Hallo,

ich habe ein kleines Problem und hoffe hier Hilfe finden zu können.
In meinem SPS Programm habe ich eine Benzueroberflöche in Twincat 3.1, PLC-HMI angelegt und möchte nun über verscheidene Dialoge (Login, Auftrag, usw.) den Benutzer zur eingabe bringen.
Das erstellen dieser Dialoge ist ja recht einfach. Auch das aufrufen über einen Button in der Visualisierung (Über Dialog öffnen).

Nun möchte ich aber folgendes Problem gelöst haben.
Achtung, mein Problem soll bitte nicht durch eigenständige Visualisierungseiten gelöst werden, sonder über Dialoge.

1. Die Anlage startet und wird in den Hauptbildschrim (Start-Visu) gebracht. Nach einiger Zeit, wenn alles gladen ist, stellt die Anlage fest, es ist noch kein Benutzer ausgewählt. (Variable = FALSE)

Durch diese Variable wird nun automatisch der Login-Dialog geöffnet.
Hat sich der Benutzer richtig angemeldet, Datenbankabfrage extern, dann wird diese Variable wieder TRUE, und der Dialog wird vom System geschlossen.

2. Warum kein Visualisierungswechsel: 
Durch ein Timeout, wird der Benutzer wutomatisch wieder abgemeldet, Bei einem Visu_Wechsel sehe ich nicht mehr den Zustand der Anlage.
Des weiteren sollen auch andere Aktionen ausgelöst werden, wenn bestimmt Ereignisse eintreffen. Auftrag abgearbeitet => Neuen Auftrag beginnen, Fehlermeldungen, Warnungen, Errors, usw.

Ziel:
Aus dem Programm heraus sollen Dialoge geöffnet und geschlossen werden können.

Ich Danke im voraus für eure hilfe.


----------



## _Eddi_ (26 Juli 2017)

Ich habe mit Dialogen noch nicht gearbeitet, aber "im Prinzip" sollte das ganz einfach dadurch gehen, daß du eine Visualisierungsseite wie normal anlegst, dann im Projekt mit rechter Maustaste anklickst, auf "Properties" gehst, und dort "Use visualization as" auf "Dialog" umstellst. Dann kannst du die über die "Input Configuration" von Buttons o.ä. öffnen und schließen.


----------



## Minehunter (1 August 2017)

Hallo,

anbei die Lösung für mein Problem, vllt hilft es ja auch anderen Nutzern

Ausgangslage:

Euer Programm ist gestartet, die Visualisierung auch hochgefahren (Wichtig !!!, da Dialoge nur bei gestarteter Visu aufgerufen werden können, sonst stürtzt das System ggf. ab)

in euere GVL deklariert ihr bitte folgendes

```
//------------------------------------------
    // GLOBAL
    stMyRect         :     VisuElems.VisuStructSimpleRectangle;
    pTempClientData :     POINTER TO VisuElems.VisuStructClientData;
    pLastClientData :     POINTER TO VisuElems.VisuStructClientData;
    pClientData     :     POINTER TO VisuElems.VisuStructClientData;
    nIteratorSave     :     INT;    
    iDialogManager2 :     VisuElems.IDialogManager2 := 0;
```

im nächsten Schritt habe ich einen FB erstellt, welches 2 Actionen beinhaltet.
Action 1: "OpenDialog"
Action 2: "OpenDialog"


Code: "OpenDialog"

```
SIKA_GVL_VISU.nIteratorSave := VisuElems.VisuElemBase.Visu_Globals.g_ClientManager.SaveIteration(); 
VisuElems.VisuElemBase.Visu_Globals.g_ClientManager.BeginIteration();

iDialogManager := VisuElems.VisuElemBase.g_VisuManager.GetDialogManager();

// Assign the argument in all currently active clients
SIKA_GVL_VISU.pTempClientData := VisuElems.VisuElemBase.Visu_Globals.g_ClientManager.GetNextClient();

WHILE SIKA_GVL_VISU.pTempClientData <> 0 DO
    iMessageDialog := iDialogManager.GetDialog(sVisuName); // dialog to be handled is specified
    SIKA_GVL_VISU.pLastClientData := SIKA_GVL_VISU.pTempClientData;
    SIKA_GVL_VISU.pTempClientData := VisuElems.VisuElemBase.g_ClientManager.GetNextClient();
END_WHILE

// Open Dialog on all Clients
iMessageDialog := iDialogManager.GetDialog(sVisuName); // dialog to be handled is specified
IF iMessageDialog <> 0 THEN
    //stMyRect.ptTopLeft.iX := P_DB_LogIn.nXPos;
    //stMyRect.ptTopLeft.iY := P_DB_LogIn.nYPos;
    //stMyRect.ptBottomRight.iX := 100;
    //stMyRect.ptBottomRight.iY := 100;
    //iDialogManager.OpenDialog(iMessageDialog, pLastClientData, TRUE, ADR(stMyRect));
    iDialogManager.OpenDialog3(iMessageDialog, SIKA_GVL_VISU.pLastClientData, TRUE, ADR(SIKA_GVL_VISU.stMyRect), 0, VisuElems.Visu_InputFlags.GlobalOpenCloseDialog);
END_IF

VisuElems.VisuElemBase.Visu_Globals.g_ClientManager.RestoreIteration(SIKA_GVL_VISU.nIteratorSave);
```



Code "CloseDialog"

```
SIKA_GVL_VISU.nIteratorSave := VisuElems.VisuElemBase.Visu_Globals.g_ClientManager.SaveIteration(); 
VisuElems.VisuElemBase.Visu_Globals.g_ClientManager.BeginIteration();

iDialogManager := VisuElems.VisuElemBase.g_VisuManager.GetDialogManager();

SIKA_GVL_VISU.pClientData := VisuElems.VisuElemBase.Visu_Globals.g_ClientManager.GetNextClient();

// Cloase Dialog on all Clients
IF SIKA_GVL_VISU.pClientData <> 0 THEN
    iMessageDialog := iDialogManager.GetDialog(sVisuName); // dialog to be handled is specified
    IF iMessageDialog <> 0 THEN
        IF (SIKA_GVL_VISU.iDialogManager2 = 0) THEN
            __QUERYINTERFACE(VisuElems.g_VisuManager.GetDialogManager(), SIKA_GVL_VISU.iDialogManager2);
        END_IF
        IF (SIKA_GVL_VISU.iDialogManager2 <> 0) THEN
            SIKA_GVL_VISU.iDialogManager2.CloseDialog2(iMessageDialog, SIKA_GVL_VISU.pClientData, VisuElems.Visu_InputFlags.GlobalOpenCloseDialog);
        ELSE
            iDialogManager.CloseDialog(iMessageDialog, SIKA_GVL_VISU.pClientData);    // Closes The Dialog on all "pClientData"    
        END_IF
    END_IF
END_IF

VisuElems.VisuElemBase.Visu_Globals.g_ClientManager.RestoreIteration(SIKA_GVL_VISU.nIteratorSave);
```



Im Funktionsbaustein deklariert Ihr euch dann entsprechend zwei Trigger.
Wichtig ist, das der dialog nur einmal aufgerufen werden sollte

```
// Deklaration
sVisuName               :     STRING    := 'VISU_LOGIN';
TrigOpenDialog        :    R_TRIG;
TrigCloseDialog        :    R_TRIG;
bOpenDialog            :    BOOL;
bCloseDialog            :    BOOL;
```

nun kann im FB entsprechend der Trigger die Visu geöffnet oder geschlossen werden.

!!!! Anpassungen im Code sind erforderlich, dies ist nur ein auszug aus dem Komplettcode !!!!


```
// öffne Dialog
TrigOpenDialog(CLK:= bOpenDialog);
IF TrigOpenDialog.Q THEN
    OpenDialog();
    bOpenDialog    :=     FALSE;
END_IF


// Schließe Dialog
TrigCloseDialog(CLK:= bCloseDialog);
IF TrigCloseDialog.Q THEN
    CloseDialog();
    bCloseDialog    :=     FALSE;
END_IF
```

Viel Spaß beim Programmieren.


----------



## wollvieh (1 August 2017)

Wie,das System  stürzt eventuell ab? Hast Realtime oder was? Eventuell? Gott würfelt nicht. Zitat Albert Einstein


----------



## Minehunter (1 August 2017)

Hallo wollvieh,

Ja das System stürtzt ab.

folgende Situation:
CP6606:
- start der SPS: 
   - PLC Task 10ms, Prio 20, 
   - Visu-Task 200ms, Prio 30
- in dem Programm öffnest du sofort einen Dialog.

Ergebnis: 
- Fehlermeldungen bzgl des VISU-TASK.
- Im besten Fall arbeitet der PLC Task weiter, nur der VISU Task hängt sich auf.
- im schlimmsten Fall Geht die SPS in den Status "undefiniert"


Fall 2:
SPS Simulation auf entwicklungsrechner
- 1 Core Isolated, PLC Task 10ms, Prio 20, Visu-Task 200ms, Prio 30
- Sofortiges öffnen eines Dialoges.

Ergebnis
- Besten Fall geht die PLC in den Status "undefiniert"
- Im schlimmstenfall "BlueScreen" Grund: Twincat.exe


Dieses Problem ist seitens Beckhoff nachstellbar. auch auf denen PCs und SPSen.
Workaround:
1. Visu immer aus dem SPS-Code heraus starten, nicht über den Autostartmanager
2. Warten bis die Visu gestartet ist, dann die Dialoge öffnen

In meinem Programm ist in meiner Initialisierungphase nun auch die Startbedinung der Visu integriert.

Hoffe ich konnte dies etwas besser erklären


----------



## _Eddi_ (4 August 2017)

Mal zwei Zwischenfragen dazu:
Wo hast du denn Dokumentation zu diesen VisuElemBase-Interfaces gefunden?
Und wie startest du die Visu von der SPS aus, und überprüfst, ob sie läuft?


----------



## Minehunter (7 August 2017)

Hallo,

die Doku zu den VisuElemBase - Elementen ist seitens Beckhoff noch nicht fertiggestellt. Hier wurden zahlreiche Gespräche geführt. Eine Doku soll noch kommen. 

Das starten einer VISU ist ganz leicht, da es sich hier um eine externes Programm handelt.


Hier ein Beispielprogramm welches ich aktuell immer nutze
Deklaration

```
PROGRAM P_VISU_CE7_AUTOSTART
VAR_OUTPUT
    bHmiReady    :    BOOL;
END_VAR
VAR
    ntStartHmi    :     NT_StartProcess;
    nHmiStart    :    USINT;
END_VAR
```

Programmcode

```
//--------------------------------------
// Start SPS und VISU
//--------------------------------------
ntStartHmi(
    NETID:='' , 
    PATHSTR:='\Hard Disk\TwinCAT\3.1\Components\Plc\Tc3PlcHmi\Tc3PlcHmiCE7ARMV7.exe' , 
    DIRNAME:='\Hard Disk\TwinCAT\3.1\Components\Plc\Tc3PlcHmi\' , 
    TMOUT:=T#5S );
CASE nHmiStart OF
    0:    ntStartHmi(START:=TRUE);
        bHmiReady := FALSE;
        IF NOT ntStartHmi.BUSY THEN
            nHmiStart := 1;
        END_IF
    1:    IF VisuElems.CurrentClientType <> 0 THEN
            nHmiStart := 2;
        END_IF
    2:
        bHmiReady := TRUE;    
END_CASE
```



Wenn ihr das ganze auf dem Entwicklungsrechner oder ggf. PC systemen starten wollt, müsst ihr den Pfad ändern.

```
ntStartHmi(
    NETID:='' , 
    PATHSTR:='C:\TwinCAT\3.1\Components\Plc\Tc3PlcHmi\Tc3PlcHmi.exe' , 
    DIRNAME:='C:\TwinCAT\3.1\Components\Plc\Tc3PlcHmi\' , 
    TMOUT:=T#5S );
```

Bei mir funktioniert es alles sehr gut, da ich nun solange in meiner Systeminitialisierung warte, bis die Visu gestartet ist. 
(natürlich werden hier noch andere Sachen getan, wie Lesen von INI Dateien, Datenbankabfragen usw.)


----------



## _Eddi_ (7 August 2017)

Danke, das habe ich mal folgendermaßen vereinfacht (mich intererssiert gerade nicht wirklich, ob die visu tatsächlich läuft)

```
IF (NOT initialized) OR startVisu.BUSY THEN
    startVisu(
        NetID := '',
        PathStr := '\Hard Disk\TwinCAT\3.1\Components\Plc\Tc3PlcHmi\Tc3PlcHmiCE7ARMV7.exe',
        Dirname := '\Hard Disk\TwinCAT\3.1\Components\Plc\Tc3PlcHmi\',
        start := NOT initialized
    );
END_IF
IF NOT initialized THEN
    (*andere Initialisierungen*)
    initialized := TRUE;
END_IF
```


----------

