26. Mai 2008

Open-Form benötigt eine Exit-Form-Strategie

Dieser Artikel soll all jenen weiterhelfen, die mit OPEN_FORM statt CALL_FORM arbeiten.

OPEN_FORM hat Vorteile aber auch ein paar Probleme. Der Anwender kann zwischen allen offenen Masken hin und herspringen, beendet er jedoch eine Maske, wird immer nur die aktuelle Maske geschlossen.

Lösung: Gehen wir einmal von einer normalen Applikation aus, in der es eine Startmaske gibt, von der aus alle anderen Masken per OPEN_FORM geöffnet werden. Wenn die Startmaske den Fokus hat und man klickt auf Beenden, dann möchte man die gesamte Applikation beenden und nicht nur die Maske in der man sich befindet. Wir brauchen an der Stelle eine Funktionalität, die zuerst einmal in einer Schleife durch alle geöffneten Masken läuft, die schliesst und am Ende die Startmaske beendet.

Alle geöffneten Masken zu finden ist nicht einfach. Am besten speichert man diese Daten in einer globalen Liste namens GLOBAL.OPEN_FORMS. Die Werte werden durch Semikolon getrennt gespeichert, z.B. ;STARTFORM;EMP;DEPT;

Wir brauchen nun einen PRE-FORM und einen POST-FORM-Trigger für alle Masken, außer der Startmaske. Der Pre-Form hängt einen neuen Eintrag ans Ende der Liste und der Post-Form löscht entsprechende Einträge wieder raus.

PRE-FORM :

DEFAULT_VALUE (';', 'GLOBAL.OPEN_FORMS');
:GLOBAL.OPEN_FORMS := :GLOBAL.OPEN_FORMS ||
:SYSTEM.CURRENT_FORM || ';';

POST-FORM :

:GLOBAL.OPEN_FORMS := REPLACE (:GLOBAL.OPEN_FORMS,
';' || :SYSTEM.CURRENT_FORM || ';',
';');

Nun haben wir die Namen aller geöffneten Masken in der globalen Liste gespeichert.

Der KEY-EXIT Trigger in der Startmaske arbeitet in einer Schleife nun alle Listeneinträge ab und schliesst diese Masken.


KEY-EXIT
der Startmaske :

DECLARE
V_Form VARCHAR2 (30);
BEGIN
One_Time_Timer.Initialize ('EXIT_STARTFORM');
DEFAULT_VALUE (';', 'GLOBAL.OPEN_FORMS');
WHILE :GLOBAL.OPEN_FORMS != ';'
LOOP
V_Form := Substr (:GLOBAL.OPEN_FORMS,
2,
InStr (:GLOBAL.OPEN_FORMS, ';', 1, 2) - 2);
COPY ('J', 'GLOBAL.EXIT_IMMEDIATE');
GO_FORM (V_Form);
END LOOP;
END;

Die Startmaske wird durch einen WHEN-TIMER-EXPIRED beendet:

IF One_Time_Timer.Get_Value = 'EXIT_STARTFORM' THEN
EXIT_FORM (no_validate);
END IF;

Alle anderen Masken benötigen noch einen WHEN-FORM-NAVIGATE Trigger:

DEFAULT_VALUE ('N', 'GLOBAL.EXIT_IMMEDIATE');
IF :GLOBAL.EXIT_IMMEDIATE = 'J' THEN
EXIT_FORM (no_validate);
END IF;


Nun haben wir eine gut funktionierende AutoClose-Methode für alle unsere Applikationen.

Viel Spass damit
Gerd


Hier ist der One-Time-Timer Artikel. Der Einfachheit halber hier direkt der Code für die Startmaske:

PACKAGE Const IS
gbl_One_Time_Timer CONSTANT VARCHAR2 (61) :=
upper ('global.One_Time_Timer');
END;

PACKAGE One_Time_Timer IS
FUNCTION Get_Value RETURN VARCHAR2;
PROCEDURE Initialize (P_Event IN VARCHAR2);
END;

PACKAGE BODY One_Time_Timer IS
FUNCTION Get_Value RETURN VARCHAR2 IS
BEGIN
Default_Value (NULL, Const.gbl_One_Time_Timer);
RETURN (NAME_IN (Const.gbl_One_Time_Timer));
END;

PROCEDURE Initialize (P_Event IN VARCHAR2) IS
tm_id timer;
tm_name VARCHAR2 (30) := 'ONE_TIME_TIMER';
BEGIN
tm_id := Find_Timer (tm_name);
IF ID_Null (tm_id) THEN
tm_id := Create_Timer (tm_name, 10, NO_REPEAT);
COPY (p_Event, Const.gbl_One_Time_Timer);
END IF;
END;
END One_Time_Timer;