26. Juni 2008

Schneller Kompilieren im Forms Builder

Die Geschwindigkeit des "Compile All" im Forms Builder kann dramatisch erhöht werden, wenn man vor dem Kompilieren alle Knoten schliesst und nur den obersten Knoten im Object-Navigator offen lässt und von dort aus den Kompiliervorgang startet:


Kompilierzeit einer normalen PL/SQL-Library mit 70 Program Units

geschlossene Knoten : 2 sec
geöffnete Knoten : 18 sec

Kompilierzeit einer grossen PL/SQL-Library mit 130 Program Units

geschlossene Knoten : 2 sec
geöffnete Knoten : 34 sec

Kompilierzeit einer normalen Maske mit 14 Blöcken

geschlossene Knoten : 3 sec
geöffnete Knoten : 12 sec

Kompilierzeit einer grossen Maske mit 24 Blöcken und sehr viel Sourcecode

geschlossene Knoten : 6 sec
geöffnete Knoten : 37 sec



Mit diesem kleinen Trick kann man unglaublich viel Zeit sparen!
Viel Spass damit
Gerd

19. Juni 2008

Compile oder Compile All ?

Wie sollte man eine Maske am besten kompilieren? Bevor ich die Problematik dieses Themas erläutere, hier erst ein paar Erklärungen:

Compile Incremental : Ctrl + K
Compile All : Shift + Ctrl + K
Compile Module (Generate): Ctrl + T
Run : Ctrl + R

In den älteren Versionen von Forms war Compile Module als Generate bekannt. Das bevorzuge ich auch heute noch, da die Tastenkombination Ctrl+T das FMX generiert.

Bei der täglichen Arbeit werde ich ab und zu mit einem nicht reproduzierbaren Problem konfrontiert. Nachdem Änderungen in einer Maske gemacht wurden startet man den Generate. Nun wird automatisch intern ein Compile Incremental durchgeführt und danach das FMX erzeugt.

Und das ist das Problem. In 9 von 10 Fällen läuft das FMX ohne Probleme, aber ab und zu arbeitet das Compile Incremental nicht zuverlässig. Dies erkennt man aber erst zur Laufzeit durch merkwürdige nicht reproduzierbare Fehlermeldungen.

Meine Lösung für dieses Problem ist:

Nach dem Öffnen einer Maske wird sofort ein Compile All gestartet. Jeder Incremental Compile und jeder Generate, der von nun an gestartet wird läuft ohne Probleme. D.h. wenn die Maske einmal gründlich kompiliert wurde kann man ab diesem Zeitpunkt ohne Bedenken Generates starten.

Try it
Gerd

5. Juni 2008

Forms Shut-Down

Letztes Jahr schrieb ich einen Artikel Forms Start-Up in dem ich demonstrierte, wie man ein Browser-Fenster beim Applikationsstart verstecken kann. Eine ähnliche Fragestellung kommt beim Schliessen auf uns zu: Wie schliesse ich das Browser-Fenster, wenn ich die Applikation beende? Dies ist meine aktuelle Lieblingsmethode:

1) Erzeuge eine HTML-Datei z.B. close.html im html-Verzeichnis. Dieser Befehl schliesst das Browser-Fenster.

< BODY onLoad="window.close();" >

2) Setze den formsweb.cfg Parameter HTMLbeforeForm im server-Verzeichnis. Damit wird die Sicherheits-Abfrage "Möchten Sie das Fenster schliessen" unterdrückt.

HTMLbeforeForm=< SCRIPT LANGUAGE="JavaScript" >window.opener = top;< /SCRIPT >

3) Die Maske, die die Gesamt-Applikation beendet, benötigt einen POST-FORM-Trigger. /forms/html ist ein virtuelles Verzeichnis, welches auf die close.html zeigt.

web.show_document ('/forms/html/close.html', '_self');

Verzeichnisse:

< DevSuite-Home > : Developer-Suite Home Verzeichnis
html-Verzeichnis : < DevSuite-Home >\tools\web\html
server-Verzeichnis : < DevSuite-Home >\forms\server
virtual-html-Verzeichnis : /forms/html definiert in forms.conf

Vielen Dank an Duncan Mills, Frank Nimphius und Richard Squires, die diese Ideen vor einigen Jahren im OTN veröffentlichten.

Pro) Diese Technik arbeitet auf IE 6 und IE 7, getestet mit dem JInitiator und dem Sun-Plugin.
Kontra) Keine Firefox-Unterstützung. Seit Firefox 2.0 ist es nicht mehr erlaubt, ein Fenster per JavaSript zu schliessen.

Wichtig: Die Restriktionen dieses Blogs zwangen mich, nach jedem "<" und vor jedem ">" ein Leerzeichen zu schreiben. Bitte entfernen vor dem Einsatz.

viel Spass
Gerd

3. Juni 2008

Sourcecode-Formatierung im OTN-Forum

Fast jeden Tag sehe ich im OTN-Forum unformatierte Sourcecodes. Warum?

Das Problem ist, dass viele User gar nicht wissen, wie man Sourcecode formatieren kann. Beispiel:

/*
|| Summierung aller Sub-Aufträge
*/
if :control.sub_order_id is not null then
select sum (value)
into :control.sum
from sum_orders
where order_id in (select order_id
from sub_orders
where sub_order_id = :control.sub_order_id
and sub_order_type = 'ONLINE');
else
:control.sum := 0;
end if;
/*
|| Diese Summe benötigen wir nun für ...
*/

Wer kann das lesen? Ich löse zwar gerne Rätsel, aber nicht, wenn es sich um Sourcecodes handelt. Wie können wir das Problem lösen?

Benutze [pre] vor dem Sourcecode und [/pre] am Ende. Dann ist es lesbar wie im Original:

[pre]
...
if :control.sub_order_id is not null then
select sum (value)
into :control.sum
...
[/pre]

und so sieht der vorformatierte Text dann aus, nachdem die preformat-tags genutzt wurden:

/*
|| Summierung aller Sub-Aufträge
*/
if :control.sub_order_id is not null then
select sum (value)
into :control.sum
from sum_orders
where order_id in (select order_id
from sub_orders
where sub_order_id = :control.sub_order_id
and sub_order_type = 'ONLINE');
else
:control.sum := 0;
end if;
/*
|| Diese Summe benötigen wir nun für ...
*/

Besser kann der Sourcecode kaum aussehen!

Viel Spass damit
Gerd

2. Juni 2008

Open-Form und die Exit-Form-Strategie (2)

Manchmal benutzt man Sourcecodes schon seit vielen Jahren und denkt, dass es keinen einfacheren und besseren Weg gibt um ein bestimmtes Problem zu lösen als durch den Einsatz genau dieses Stück Codes.

So auch hier. Nachdem ich den letzten Artikel geschrieben hatte lief alles so wie immer und war bestens!

Nachdem ich heute den Code ein wenig refaktorieren wollte, entwarf ich eine viel einfachere und wirkungsvollere Methode (was normalerweise nicht das Ziel eines Refactorings sein sollte!):

Alles was man nun noch benötigt ist ein

KEY-EXIT in der Startmaske:

COPY ('TRUE', 'GLOBAL.EXIT_IMMEDIATE');
EXIT_FORM (no_validate);

und ein WHEN-FORM-NAVIGATE in allen anderen Masken

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


Diese Technik arbeitet mit einer Kettenreaktion. Jede geschlossene Maske lässt den Fokus auf eine noch geöffnete Maske überspringen, in der dann der WHEN-FORM-VNAVIGATE ausgeführt wird. Diese Maske wird dann auch wieder geschlossen usw... Dies geschieht, da die globale Variable AUTOCLOSE auf TRUE gesetzt wurde.

Nach der letzten Maske ist somit die gesamte Applikation beendet und wir haben das Ziel erreicht, dass wir zu Beginn beabsichtigten.

Wenn einige dieser Masken weitere Masken per Call_Form starten, dann benötigt man hier dem WHEN-WINDOW-ACTIVATED als Event, da der WHEN-FORM-NAVIGATE nicht zündet, wenn der Fokus an die Maske zurückübermittelt wird.

Das ist nun mit Abstand die einfachste Lösung dieses Problems, die ich kenne?
Viel Spass damit
Gerd