[1] [2] [3] [4]

Neue Sprachelemente in Visual FoxPro 7

Tamar E. Granor

Jede neue Version von VFP enthält Änderungen an der Programmiersprache. VFP 7 bildet da keine Ausnahme. In diesem Artikel behandele ich die neuen und geänderten Befehle, Funktionen, Eigenschaften, Ereignisse und Methoden.

Die Änderungen in VFP 7 betreffen viele unterschiedliche Gebiete von der Stringmanipulation über die Erstellung von COM-Servern, das Datenhandling und die interaktive Entwicklungsumgebung bis in jede Ecke der Sprache. Viele der Änderungen erfüllen Forderungen aus der Gemeinschaft der VFP-Entwickler. Einige dieser Forderungen sind bereits mehrere Jahre alt.

Ich gehe in diesem Artikel davon aus, dass Sie mit Visual FoxPro 6.0 vertraut sind.

Was Sie hier nicht finden

Dieser Artikel ist nicht geplant, um jede einzelne Änderung zu behandeln, sondern geht nur auf die entscheidenden Neuerungen ein. Außerdem waren zu der Zeit, als dieser Artikel verfasst wurde, einige Änderungen noch in der Überlegung bzw. in der Entwicklung.

Stringbehandlung

Die Arbeit mit Zeichenketten ist dank des Word Wide Web in den letzten Jahren immer wichtiger geworden. Da es sich bei HTML und XML lediglich um Text mit Tags handelt, ist die Möglichkeit des schnellen und einfachen Manipulierens von Texten bedeutender denn je. FoxPro hatte schon immer gute Werkzeuge für die Behandlung von Zeichenfolgen, aber in VFP 7 wurden sie noch weiter verbessert.

Verbesserungen beim Textmerge

FoxPros Fähigkeit, Texte zu mischen gehört zu den Werkzeugen, die ihre große Zeit erlebt haben, dann in der Versenkung verschwanden und die jetzt wiederkommen. Erstmalig wurden sie in FoxPro 2.0 implementiert, um die Codegenerierung durch GENSCRN und GENMENU zu vereinfachen.

Textmerge kombiniert die Low-Level-Dateibehandlung mit der Prüfung von Ausdrücken während de Laufzeit und der Konvertierung von Datentypen, um einen einfachen Mechanismus für die Generierung komplexer Texte bereitzustellen. In VFP 7 wurde das Textmerge in vielfältiger Weise erweitert.

Es ist nun möglich, die Ausgabe von Textmerge nicht mehr in eine Datei, sondern in eine Variable zu leiten. SET TEXTMERGE TO hat eine neue Klausel MEMVAR, die Ihnen die Möglichkeit gibt, eine Variable als Ausgabeziel anzugeben. Das sieht folgendermaßen aus:

SET TEXTMERGE TO MEMVAR cContents

Zusätzlich wurde der Befehl TEXT … ENDTEXT erweitert, um dessen Fähigkeiten zum Mischen von Texten zu erweitern. Der Befehl TEXT verfügt jetzt über mehrere Optionen, wo in früheren Versionen lediglich TEXT stand. Hier die neue Syntax:

TEXT [ TO VarName [ ADDITIVE ] ;
       [ TEXTMERGE ] [ NOSHOW ] ]
   Text lines
ENDTEXT

Die neue Syntax ermöglicht es Ihnen, ein Textmerge in eine Variable einfach durch die Sequenz TEXT … ENDTEXT auszuführen, ohne vorher SET TEXTMERGE einzusetzen. Als Beispiel sendet der folgende Codeblock einen String und zusätzlich das aktuelle Datum in die Variable cDate, ohne dass auf dem Bildschirm etwas angezeigt wird:

TEXT TO cDate TEXTMERGE NOSHOW
Today is <<DATE()>>
ENDTEXT

Die größte Änderung im Hinblick auf Textmerge ist die neue Funktion Textmerge(), die einen zu prüfenden Ausdruck erwartet, ein Flag, das anzeigt, ob die Prüfung rekursiv ist sowie Trennzeichen und das Ergebnis der Prüfung zurückgibt. Die folgende Zeile entspricht dem obigen Beispiel:

cDate = Textmerge( ;
          "Today is <<Date()>>")

Das Formular TextMerge.SCX auf der Begleitdiskette demonstriert alle drei Möglichkeiten des Textmerge.

Analysieren von Zeichenketten

Die neue Funktion StrExtract() wurde neu eingeführt, um das Aufteilen von Strings in ihre Komponenten zu vereinfachen. Obwohl diese Funktion wohl für die Behandlung von XML gedacht war, kann sie auch an anderen Stellen sinnvoll eingesetzt werden.

Die Syntax von StrExtract() ist:

cResult = StrExtract( cSource, ;
       cBeginningDelimiter ;
    [, cEndingDelimiter ;                     [, nOccurrence [, nFlags ]]] )

Ein wichtiger Aspekt dieser Funktion ist, dass die Trennzeichen am Anfang und am Ende aus mehreren Zeichen bestehen können. Sie können die Funktion mit einem XML-String anwenden und ihr die Anfangs- und Endtags übergeben. Das Beispiel. 

cXML = "<customer><custid>37" + ;
       "</custid>"+"<name>Fred's " + ;
       "Auto Parts</name></customer>"
 
ergibt die Ausgabe:
 
Fred's Auto Parts

Sie können durch Angeben des optionalen Parameters nOccurrence jedes Auftreten zwischen den angegebenen Trennzeichen extrahieren. Der Parameter nFlags ist die Summe mehrerer Werte. Addieren Sie 1, wird zwischen Groß- und Kleinschreibung unterschieden. Addieren Sie 2, wird das Trennzeichen am Ende optional – in diesem Fall gibt die Funktion alles hinter dem Trennzeichen am Anfang bis zum Ende des Strings aus. Dies geschieht auch, wenn kein abschließendes Trennzeichen gefunden wird.

Nehmen wir als Beispiel den String cXML, den wir weiter oben definiert haben:

?StrExtract( cXML, "<NAME>", </NAME>")

Wir erhalten einen leeren String zurück, während

?StrExtract( cXML, "<NAME>", ;
              </NAME>",1,1)

folgendes zurückgibt:

Fred's Auto Parts

Verschiedene andere Änderungen zur Stringverarbeitung

Zusätzlich zu den Verbesserungen der Textmerge-Fähigkeiten hat das VFP-Team einige der Stringfunktionen aus den FoxTools aufgenommen und andere erweitert. Im Ergebnis ist die Arbeit mit Text in VFP 7 erheblich einfacher geworden als es in VFP 6.0 war.

Die aus den FoxTools übernommenen Funktionen sind GetWordCount() und GetWordNum(), auch wenn sie dort andere Namen hatten. Sie tun das, was die neuen Namen aussagen: Rückgabe der Anzahl der Worte und des im ersten Parameter angegebenen Wortes. Jede Funktion akzeptiert einen optionalen Parameter, um anzuzeigen, wo ein Wort endet und ein anderes beginnt – wird der Parameter nicht gesetzt, trennt ein Leerzeichen, ein Tab oder ein Return die Worte. Eine Möglichkeit für die gemeinsame Verwendung dieser zwei Funktionen ist die Ausgabe der Worte in einem String mit jeweils einem Wort je Zeile. Nehmen wir an, cInputString enthält den String in der Frage. Dann sieht der Code folgendermaßen aus:

LOCAL nWordCount, nWordNum
nWordCount = ;
          GetWordCount(cInputString)
FOR nWordNum = 1 TO nWordCount
   ? GetWordNum( cInputString, ;
                 nWordNum)
ENDFOR

Ich habe diesen Code mit einem entsprechenden Code unter Verwendung von STRTAN() und ALINES() verglichen, um die Worte herauszuziehen, sowie mit traditionellem Xbase-Code unter Verwendung von AT() und SUBSTR(). Das Ergebnis dieses Vergleichs war, dass die neuen Funktionen mit kleinen Strings sehr schnell umgehen können. Sobald cInputString aber groß wird, ist die Kombination STRTAN() / ALINES() die bessere Wahl. Hier der alternative schnellere Code:

LOCAL nWordCount, cModString
LOCAL ARRAY aWords[1]
cModString = STRTRAN(STRTRAN( ;
          cInputString," ",CHR(13)), ;
          CHR(9),CHR(13))
nWordCount = ALINES(aWords,cModString)
FOR nWordNum = 1 TO nWordCount
   ?aWords[nWordNum]
ENDFOR

Tatsächlich ist der schnellste Weg, mit VFP 7 diese Analyse auszuführen, der Einsatz von ALINES(), da diese Funktion einen neuen Parameter hat, um zusätzliche Zeichen anzugeben, die das Ende der Zeile anzugeben (zusätzlich zu CHR(13) und CHT(10)). Hier die erweiterte Syntax für ALINES():

nNumberOfLines = ALINES( ;
       aArrayOfLines, cExpression ;
       [, lTrim ] [, cParseChar1, … ,;
       cParseCharn ] )

Dementsprechend kann der Code, der jedes Wort in einer eigenen Zeile ausgibt, noch einmal geschrieben werden:

LOCAL nWordCount
LOCAL ARRAY aWords[1]
nWordCount = ALINES(aWords, ;
       cInputString, " ", CHR(9))
FOR nWordNum = 1 TO nWordCount
   ?aWords[nWordNum]
ENDFOR

Das Formular WordsOut.SCX auf der Begleitdiskette führt die Tests auf alle vier Arten durch.

Auch die Funktion STRTRAN() wurde in dieser Version geändert. Sie hat einen neuen Parameter, der anzeigt, ob die Suche und das dadurch ausgelöste Austauschen von Zeichen zwischen Groß- und Kleinschreibung unterscheiden soll oder nicht. Wird der Parameter nicht übergeben, wird genau wie in älteren Versionen von FoxPro die Unterscheidung gemacht. Wird der Parameter gesetzt, kann er drei Werte annehmen:

0 – Unterscheidung zwischen Groß- und Kleinschreibung.

1 - Unterscheidung zwischen Groß- und Kleinschreibung ohne dass dies beim Austauschen geändert wird.

3 - Unterscheidung zwischen Groß- und Kleinschreibung mit Änderungen beim Austauschen.

Die 2 wird als Wert für diesen Parameter akzeptiert, liefert aber das gleiche Ergebnis wie 0.

Als Beispiel dieser Aufruf ohne den neuen Parameter:

? STRTRAN("Now is the time", ;
          "now", "then")

gibt die Originalzeichenfolge “Now is the time” zurück. Mit dem neuen Parameter können wir die Funktion folgendermaßen aufrufen:

? STRTRAN("Now is the time", ;
          "now", "then", -1, -1, 1)

und die Rückgabe lautet:

"then is the time"

Um die Groß- und Kleinschreibung wie im Original zu erhalten, starten Sie folgenden Aufruf:

? STRTRAN("Now is the time", ;

          "now", "then", -1, -1, 3)

und Sie sehen:

"Then is the time"

Beachten Sie, dass Sie die case-sensitive Suche nicht mit Änderung der Groß- und Kleinschreibung im Austausch kombinieren können.

Änderungen, die die Daten betreffen

Zusätzlich zu den neuen Datenbankereignissen wurden auch einige Befehle und Funktionen in VFP 7 geändert, die die Daten betreffen. Die meisten dieser Änderungen waren Reaktionen auf Anfragen aus den Reihen der Entwickler. Alle diese Änderungen machen es einfacher, einen soliden Code zu entwickeln.

Zunächst wurde die Klausel IN einer Anzahl von Xbase-Befehlen hinzugefügt, die über diese Klausel noch nicht verfügten. Dazu gehören BLANK, SET FILTER, PACK, RECALL und CALCULATE. Die Benutzung der IN-Klausel mit diesen und anderen Xbase-Befehlen hat den Vorteil, dass Sie sich nicht darum kümmern müssen, den richtigen Arbeitsbereich zu wählen, bevor Sie den Befehl absetzen. Die IN-Klausel gibt den Arbeitsbereich für den entsprechenden Befehl an und beeinflusst keine anderen Befehle.

Zwei Änderungen betreffen den Befehl SQL SELECT. Zunächst gibt es das neue Schlüsselwort READWRITE in der Klausel INTO CURSOR. Mit diesem Schlüsselwort können Sie einen Cursor erstellen, der geändert werden kann. Damit wird der vielleicht am häufigsten geäußerte Wunsch der FoxPro-Entwickler erfüllt, seit in FoxPro 2.0 der Befehl SELECT hinzugefügt wurde.

Wenn Sie ein SELECT ... INTO CURSOR absetzen, ist der neu erstellte Cursor schreibgeschützt. Es gibt einige Tricks, mit denen man diese Beschränkung aufheben kann. Die neue Klausel READWRITE macht diese Tricks überflüssig. Die mit SELECT ... INTO CURSOR name READWRITE erstellten Cursor können geändert werden. Natürlich werden die Originaldaten, auf denen der Cursor basiert, von diesen Änderungen nicht berührt.

Hier ist ein Beispiel. Diese Abfrage (die Daten aus der Beispieldatenbank TasTrade benutzt) erstellt einen schreibgeschützten Cursor:

SELECT First_Name, Last_Name ;
    FROM (_SAMPLES + ;
"TasTrade\Data\Employee") ;
       INTO CURSOR EmployeeNames

Fügen Sie das Schlüsselwort READWRITE hinzu und der Cursor kann geändert werden:

SELECT First_Name, Last_Name ;
        FROM (_SAMPLES + ;
       "TasTrade\Data\Employee") ;
   INTO CURSOR EmployeeNames READWRITE

Es sollte auch erwähnt werden, dass in manchen Situationen die erste Version einer Abfrage in einem Filter der Originaltabelle endet, wenn Sie das Schlüsselwort NOFILTER nicht benutzen. Wenn Sie das Schlüsselwort READWRITE einsetzen, können Sie auf NOFILTER verzichten, da ein nicht schreibgeschützter Cursor keine gefilterte Version der Originaltabelle sein kann.

Die Funktion SYS(3054), mit der Sie die Optimierung von Abfragen prüfen können, hat in VFP 7 einige neue Parameter erhalten. Übergeben Sie als zweiten Parameter eine 2 oder eine 12, damit die Abfrage selbst auch in der Ausgabe aufgeführt wird. Dies ist vor allem sinnvoll, wenn Sie mehrere Abfragen testen. SYS(3054, 2) zeigt die Optimierungsinformation zusammen mit der Abfrage an. Anders gesagt, Sie erhalten das gleiche Ergebnis wie mit SYS(3054, 1) mit der zusätzlichen Anzeige der Abfrage. SYS(3054, 12) entspricht SYS(3054, 1) plus der Anzeige der Abfrage – es zeigt die Optimierung von Filter und Join.

Diese Funktion hat noch einen neuen Parameter. Sie können ihr den Namen einer Variablen übergeben und die Optimierungsinformation wird nicht angezeigt, sondern in eine Variable geschrieben. Ein Beispiel:

SYS(3054, 2, "cOptim")
SELECT Last_Name, First_Name ;
       FROM _SAMPLES + ;
       "TasTrade\Data\Employee" ;
   WHERE Country = "UK" ;
   INTO CURSOR Junk

Die Variable enthält anschließend folgende Inhalte:

SELECT Last_Name, First_Name ;
       FROM _SAMPLES + ;
       "TasTrade\Data\Employee" ;
       WHERE Country = "UK" ;
       INTO CURSOR Junk
 
Rushmore optimization level for table employee: none

Sehen Sie sich das Formular SYS3054.SCX auf der Begleitdiskette an, um weitere Beispiele zu erhalten.

Zwei Änderungen helfen Ihnen, einen besseren Überblick zu erhalten, was mit Ihren Daten vorgeht. Als erstes wurde die Funktion IsReadOnly() erweitert, um sowohl auf Datenbanken als auch auf Tabellen arbeiten zu können. Sie können nur die aktuelle Datenbank testen. Dafür übergeben Sie der Funktion die 0:

?IsReadOnly(0)

Wenn keine Datenbank geöffnet ist, erhalten Sie einen Fehler.

Nach der neuen Funktion ATagInfo() haben FoxPro-Entwickler schon lange gefragt. Sie stellt die Informationen über die Indizes einer Tabelle in ein Array mit einer Zeile je Index. Das Array enthält Spalten für den Namen des Index, den Typ (primary, candidate, regular oder unique), den Schlüssel, den Filter und die Sortierung.

Wie die anderen Funktionen, die Daten in Arrays schreiben, erstellt auch ATagInfo() das ihm übergebene Array oder verändert die Größe. In das daraus resultierende Array schreibt sie die entsprechenden Zeilen. Dieses Beispiel führt die Funktion auf der Tabelle Employee der Datenbank TasTrade aus und zeigt einige der Resultate.

? ATAGINFO(aEmplTags)
LIST MEMORY like aEmplTags
 
AEMPLTAGS           Pub            A    
(    1,    1)    C  "GROUP_ID"
(    1,    2)    C  "REGULAR"
(    1,    3)    C  "GROUP_ID"
(    1,    4)    C  ""
(    1,    5)    C  "ASCENDING"
(    1,    6)    C  "MACHINE"
(    2,    1)    C  "LAST_NAME"
(    2,    2)    C  "REGULAR"
(    2,    3)    C  "UPPER(LAST_NAME)"
(    2,    4)    C  ""
(    2,    5)    C  "ASCENDING"
(    2,    6)    C  "MACHINE"
(    3,    1)    C  "EMPLOYEE_I"
(    3,    2)    C  "PRIMARY"
(    3,    3)    C  "EMPLOYEE_ID"
(    3,    4)    C  ""
(    3,    5)    C  "ASCENDING"
(    3,    6)    C  "MACHINE"

Im Formular ShowATags.SCX auf der Begleitdiskette können Sie einen Index wählen und ATagInfo() darauf ausführen.

Eine Änderung der Funktion GetNextModified() vereinfacht die Entwicklung Ihres Codes zur Lösung von Konflikten. Aus irgendeinem Grunde löst GetNextModified() die Prüfung der Eindeutigkeit eines Index aus, obgleich keine Daten geschrieben wurden. Ein neuer optionaler Parameter gibt Ihnen die Möglichkeit, dieses Verhalten zu unterbinden, so dass Sie einfach alle geänderten Datensätze finden und mit ihnen arbeiten können. Dabei müssen Sie natürlich die Konflikte in den Primär- und Candidateindizes behandeln. Die richtige Zeit dafür ist aber, wenn Sie die einzelnen Datensätze auf Probleme prüfen, nicht wenn Sie die Datensätze identifizieren. Hier die geänderte Syntax für GetNextModified():

nRecordNumber = GetNextModified( ;
       nStartRecord [, cAlias | ;
       nWorkarea [, lIgnoreRules ] ]

Hier noch eine weitere Erweiterung in VFP 7, die als Antwort auf die Anfragen der Entwickler vorgenommen wurde. Der Befehl VALIDATE DATABASE RECOVER ist jetzt auch im Code erlaubt, nicht nur im Befehlsfenster. Sie müssen sich im Klaren sein, dass VALIDATE DATABASE RECOVER nicht so intelligent ist, Ihre Datenbank zu reparieren – in der Regel ist er nur in der Lage, den Datensatz zu entfernen, der die Probleme hervorruft, und die Spuren zu beseitigen. Eine langfristig bessere Lösung für gesunde Datenbanken ist der Einsatz eines Third-Party-Werkzeugs wie des Stonefield Database Toolkit.

Verwaltung der Ressourcen

Einige neue oder geänderte Befehle und Funktionen machen es einfacher festzustellen, was in Ihrer Anwendung vorgeht. Einige der Änderungen verbessern bestehende Elemente der Sprache oder machen sie besser einsetzbar, während andere neue Funktionalität hinzufügen.

Eine Änderung, die viele Menschen glücklich machen sollte ist, dass die Funktion DISKSPACE() jetzt auch auf Laufwerken korrekt arbeitet, die größer als 2 GB sind. Außerdem wurde die Funktion verbessert – sie akzeptiert einen optionalen Parameter, mit dem Sie die gesamte Speicherkapazität des Laufwerks herausfinden können. Ein Beispiel:

? DISKSPACE( "C" )    && 2053126144
? DISKSPACE( "C", 1)  && 3249307648
? DISKSPACE( "C", 2)  && 2053126144

Seien Sie sich darüber im Klaren, dass DISKSPACE() bei einem entsprechend großen Laufwerk den Wert in wissenschaftlicher Notation zurückgibt.

Die Funktion OS(), die Ihnen mitteilt welches Betriebssystem ausgeführt wird, bietet jetzt eine Menge anderer Informationen. Tabelle 1 zeigt die Parameter, die Sie OS() übergeben können und die zurückgegebenen Informationen.

Tabelle 1 Parameter für OS() Diese Funktion wurde in VFP 7 entscheidend erweitert. Alle Rückgabewerte werden als Character geliefert, auch wenn sie numerische Werte repräsentieren.

Parameter Rückgabewert

Nicht gesetzt oder 1

Die Version des Betriebssystems, also die Windows-Version

2

Werden Zeichen mit zwei Byte unterstützt? Wenn ja wird „DBCS“ zurückgegeben, sonst ein leerer String

3

Major-Versionsnummer des Systems

4

Minor-Versionsnummer des Systems

5

Build des Betriebssystems

6

Plattform des Betriebssystems (unterscheidet Win95/98 von Win NT/2000)

7

Servicepack des Betriebssystems

8

Nummer des Servicepacks des Betriebssystems

9

Minor-Nummer des Servicepacks des Betriebssystems

10

Bitflags, mit denen Produkte identifiziert werden, die auf dem Betriebssystem verfügbar sind, z. B. Small Business Server, Windows 2000 Advanced Server usw.

11

Zusätzliche Informationen über das Betriebssystem. Aktuell enthält dieser Wert nur für Windows 2000 verwertbare Informationen, wo er die installierte Version anzeigt.

Ein Beispiel. Auf einer Maschine, auf der NT 4 Service Pack 5 in US Englisch ausgeführt wird, gibt OS() die folgenden Werte zurück:

? OS()   && Windows NT 4.00
? OS(1)  && Windows NT 4.00
? OS(2)  &&
? OS(3)  && 4
? OS(4)  && 0
? OS(5)  && 1381
? OS(6)  && 2
? OS(7)  && Service Pack 5
? OS(8)  && 5
? OS(9)  && 0
? OS(10) && 0
? OS(11) && 1

Zwei Änderungen machen es einfacher, mit DLLs zu arbeiten. In früheren Versionen entfernte der Befehl CLEAR DLLS alle DLLs aus dem Speicher – oder gar keine. Während Sie mit DECLARE die DLLs einzeln in den Speicher laden konnten, mussten Sie sie anschließend alle zur gleichen Zeit wieder entfernen. In VFP 7 haben Sie die Möglichkeit, einzelne DLLs durch die Angabe des Namens, den Sie ihr bei der Deklaration gegeben haben, freizugeben. Hier ein Beispiel:

DECLARE INTEGER GetSystemDirectory ;
        IN Win32api AS GetSysDir;
        STRING @cWinDir, ;
        INTEGER nWinDirLength
DECLARE DOUBLE GetSysColor ;
        IN Win32API;
        INTEGER nIndex
* Now do something with these
* Now clean these up without
* releasing other DLL functions
CLEAR DLLS GetSysDir, GetSysColor

Die neue Funktion ADLLS() ermöglicht Ihnen die Prüfung, welche DLLs deklariert sind. In VFP 6.0 und in älteren Versionen bestand die einzige Möglichkeit darin, die Ausgabe von LIST STATUS zu analysieren.

Wie die anderen „A“-Funktionen speichert auch ADLLS() sein Ergebnis in einem Array. Dieses Array hat drei Spalten. Die erste Spalte enthält den Namen der Funktion, die zweite deren Alias und die dritte den Namen der Bibliothek, in der die Funktion enthalten ist. Beachten Sie, dass auch, wenn die Funktion mit der Syntax IN WIN32API deklariert wurde, ADLLS() die aktuelle Bibliothek auflistet, in der die Funktion sich befindet. Hier ein Beispiel, das davon ausgeht, dass wir die gleichen Deklarationen vorgenommen haben wie im letzten Beispiel:

ADLLS( aDeclaredDLLS )
LIST MEMORY LIKE aDeclaredDLLS
 
ADECLAREDDLLS           Pub            A    
(    1,    1)    C  "GetSysColor"
(    1,    2)    C  "GetSysColor"
(    1,    3)    C
       "C:\WINNT\system32\USER32.DLL"  
(    2,    1)    C
       "GetSystemDirectory"
(    2,    2)    C  "GetSysDir"
(    2,    3)    C
       "C:\WINNT\system32\KERNEL32.DLL" 

ShowDLLs.SCX auf der Begleitdiskette demonstriert Ihnen beide neuen Möglichkeiten.

Eine andere neue „A“-Funktion in VFP ist ASessions(), die ein Array mit einer Liste der bestehenden Datensitzungen füllt. Jedes Element des Arrays enthält die Nummer der Datensitzung. ASessions() auszuführen ist einfach. Hier ein Beispiel 

nActiveSessions = ASessions( ;
                  aActiveSessions )

Auf den ersten Blick scheint es, dass diese Funktion Ihnen ein Array liefert, dessen Element 1 eine 1 enthält, Element 2 eine 2 usw. Das ist aber nicht der Fall. Da die Nummern der Datensitzungen zu dem Zeitpunkt zugewiesen werden, an dem die Formulare und Berichte instanziiert werden und sich nicht ändern, so lange ein Formular oder Bericht existiert, ist es möglich, Löcher in dieser Sequenz zu haben. Auch wenn Datensitzungen erneut verwendet werden (nachdem das Formular oder der Bericht geschlossen wurde), ist es möglich, dass die Liste nicht geordnet ist. Führen Sie das Formular ShowSessions.SCX auf der Begleitdiskette aus, um eine Demonstration dieses Verhaltens zu sehen.

Eine interessantere Frage ist, wie Sie das von ASessions() erstellte Array eigentlich nutzen. Die Funktion vereinfacht es, einen Shutdown-Code zu entwickeln, der nicht gespeicherte Änderungen behandelt. Code, der sich an diesen Zeilen orientiert, kann den Shutdown besser durchführen und Situationen, in denen Sie Datensitzungen verlassen haben sowie hängende Pointer besser behandeln.

* Table handling portion of generic
* shutdown code. This version reverts * all changes.
#DEFINE DB_BUFOFF               1
 
LOCAL nCurrentSession
LOCAL nActiveSessions, nSession
LOCAL nCursors, nCursor
nCurrentSession = SET("DATASESSION")
 
nActiveSessions = ASESSIONS( ;
              aActiveSessions )
FOR nSession = 1 TO nActiveSessions
   * Switch to this session
   SET DATASESSION TO ;
          aActiveSessions[ nSession ]
   nCursors = AUSED(aCursors)
   FOR nCursor = 1 TO nCursors
      * Process each open cursor
      SELECT (aCursors[ nCursor, 1])
      IF CURSORGETPROP("Buffering") ;
                 <> DB_BUFOFF
          * If it's buffered, revert
          * all changes
         TABLEREVERT(.T.)
      ENDIF
   ENDFOR
ENDFOR
 
SET DATASESSION TO nCurrentSession

Manchmal gibt es Situationen, in denen man einem Anwender einen Dateinamen mit dem dazugehörenden Pfad zeigen will, aber der Pfad ist zu lang, um ihn in dem verfügbaren Platz zeigen zu können. Die neue Funktion DisplayPath() löst dieses Problem. Übergeben Sie ihr einen Dateinamen und eine Länge und sie gibt eine abgekürzte Version des Dateinamens zurück, die nicht länger ist als die angegebene Länge. Ganze Verzeichnisse werden aus dem Pfad gelöscht und durch drei Punkte ersetzt. Unser Beispiel ist ein guter Fall für diese Funktion. Der Pfad für den zu kürzenden Dateinamen ist so lang, dass er nicht in eine Zeile passt.

? DisplayPath( "C:\WINNT\PROFILES\
 TAMAR\APPLICATION DATA\MICROSOFT\
TEMPLATES\NORMAL.DOT", 40)
 
c:\...\microsoft\templates\normal.dot

Beachten Sie, dass das Ergebnis kürzer sein kann als die angegebene Länge, da jeweils ein ganzes Verzeichnis herausgeschnitten wird. In unserem Beispiel ist der Ergebnisstring 37 Zeichen lang.

Die Funktion ADIR(), die ein Array mit einer Liste von Dateien und/oder Verzeichnissen füllt, gibt es in FoxPro bereits seit langem, aber seit es 32-Bit-Betriebssysteme gibt, hat sie einige Schwächen. Zusätzlich zu einem neuen Parameter behandelt VFP 7 diese Schwächen. Im optionalen vierten Parameter, nFlags, können Sie angeben, ob die Datei- oder die Verzeichnisnamen in Großbuchstaben angezeigt werden sollen (das Vorgabeverhalten, das auch frühere Versionen kannten) oder ob die tatsächlich angewandte Schreibweise verwendet werden soll. Sie können auch die alten DOS-Namen im Format 8.3 für Dateien oder Verzeichnisse verwenden. Sie können diese Verhaltensweisen auch kombinieren, da dieser Parameter wie andere Flags additiv wirkt. Geben Sie 1 für die Originalschreibweise und 2 für Dateinamen im Format 8.3 an.

Eines der trickreicheren Dinge, mit denen sich Entwickler herumschlagen müssen, ist das Herausfinden der aktuellen Größe des nutzbaren Raums auf dem Bildschirm. Der nutzbare Raum umfasst den gesamten Bildschirm, der von Visual FoxPro genutzt wird abzüglich des Platzes für Menüs, Statusleiste und angedockte Toolbars. VFP 7 macht es einfacher. Die Eigenschaften Height und Width von _SCREEN geben jetzt den Innenraum wieder, während die Eigenschaften von _VFP weiterhin den gesamten Raum angeben, der von VFP belegt wird.

Auf einem meiner Systeme, auf dem die Standard-Toolbar unterhalb des Menüs angedockt und die Statusleiste auf ON gestellt ist, werden die folgenden Werte zurückgegeben:

?_VFP.Height     && 733
?_VFP.Width      && 893
?_SCREEN.Height  && 624
?_SCREEN.Width   && 885

Wenn ich die Toolbar wegnehme, ändern sich die Werte für _VFP nicht, aber _SCREEN.Height gibt jetzt 653 zurück. Nach dem Andocken der Toolbar an der Seite ändert sich _SCREEN.Width auf 850, während die anderen Werte gleich bleiben.

Die Behandlung von Arrays

Zusätzlich zu den neuen Funktionen, die Arrays zurückgeben (ATagInfo(), ASessions() und ADLLS()) enthält Visual FoxPro 7 auch zahlreiche Änderungen in den Funktionen, die mit den Arrays umgehen, sowie eine zusätzliche große Änderung im Bezug auf die Arrays, die Funktionen im Allgemeinen betrifft.

Als Erstes die große Änderung. Es ist jetzt möglich, eine Funktion ein Array zurückgeben zu lassen. In älteren Versionen von VFP war dies nicht möglich. In VFP 7 kann eine Funktion ein Array zurückliefern, vorausgesetzt das Array befindet sich immer noch im Bereich der Anwendung, wenn die Funktion beendet wurde. In der Praxis bedeutet dies, dass die Möglichkeit auf Methoden eingeschränkt ist, die Arrays zurückgeben, die Eigenschaften sind. In diesem Beispiel (das Sie in Colors.PRG auf der Begleitdiskette finden) verfügt die Klasse über eine Array-Eigenschaft, die aRGB genannt wird. Die Methode RGBComp akzeptiert eine Farbe als Parameter und gibt ein Array zurück, das die Komponenten rot, grün und blau der Farbe enthält. Damit imitiert sie das Verhalten der Funktion RGBComp der FoxTools, mit Ausnahme der Art der Rückgabe der Werte.

DEFINE CLASS Colors AS Custom
* Color handling code
DIMENSION aRGB[3]
 
FUNCTION RGBComp(nColor) AS Array
* RGBComp returns the Red, Green and
* Blue Components of a color in an
* array
 
This.aRGB[1] = -1
This.aRGB[2] = -1
This.aRGB[3] = -1
 
IF VARTYPE(nColor)="N"
   This.aRGB[3] = INT(nColor/(256^2))
   nColor = MOD(nColor,(256^2))
   This.aRGB[2] = INT(nColor/256)
   This.aRGB[1] = MOD(nColor,256)
ENDIF
 
RETURN @This.aRGB
 
ENDDEFINE

Beachten Sie, dass Sie dem zurückzugebenden Array ein „@“ voranstellen müssen. Dies entspricht der Art, wie Sie einen Parameter als Referenz übergeben.

Um die Methode nutzen zu können, müssen wir natürlich zunächst die Klasse instanziieren:

oColors = NewObject("Colors", ;
          "Colors.PRG")

Anschließend rufen wir die Methode auf und speichern den Rückgabewert in einem Array. Wenn das Array nicht existiert, wird es (innerhalb einer privaten Datensitzung) erstellt. Sollte es mit den falschen Dimensionen existieren, werden diese angepasst:

aResult = oColors.rgbcomp(255)

Zwei der Funktionen zur Behandlung von Arrays wurden geändert, um sie besser einsetzbar zu machen. Sowohl ASCAN() als auch ASORT() besitzen jetzt die Möglichkeit, Groß- und Kleinschreibung zu ignorieren. ASCAN() hat noch zusätzlich weitere neue Fähigkeiten: Sie können jetzt wählen, ob Sie eine exakte Suche (im Sinne von SET EXACT) durchführen wollen, Sie können die Suche auf eine bestimmte Spalte beschränken und Sie können ASCAN() anweisen, die Zeilennummer statt der Elementnummer in einem zweidimensionalen Array zurückzugeben. Diese Änderungen wurden seit Jahren von der Gemeinschaft der VFP-Entwickler gefordert.

Lassen Sie uns einen Blick auf die Syntax und einige Beispiele werfen. Als Erstes nehmen wir ASORT(), da es am wenigsten geändert wurde. Die Funktion hat einen neuen (fünften) Parameter, nFlags, der angibt, ob die Suche nach Groß- und Kleinschreibung unterscheiden soll. Wird dieser Parameter nicht angegeben oder ist er 0, werden Groß- und Kleinschreibung beachtet, so wie wir es aus früheren Versionen von FoxPro kennen. Enthält der Parameter den Wert 1, werden Groß- und Kleinschreibung ignoriert (da der Parameter nFlags genannt wird, ist es möglich, dass in der Zukunft noch weitere Schalter hinzugefügt werden. Vergleichen Sie die Behandlung des Befehls ASCAN() weiter unten, um zu sehen, wie die Werte eines Flags addiert werden, damit mehrere Auswahlmöglichkeiten kombiniert werden können).

Diese Abfrage erstellt ein Array, mit dem wir arbeiten können. Es zieht drei Mal den Vornamen der Tabelle Employee aus TasTrade, jeweils eines in der vorgegebenen Form, in Kleinschreibung und in Großschreibung.

SELECT First_Name FROM _SAMPLES+"TasTrade\Data\Employee";
UNION ;
SELECT LOWER(First_Name) FROM _SAMPLES+"TasTrade\Data\Employee" ;
UNION ;
SELECT UPPER(First_name) FROM _SAMPLES+"TasTrade\Data\Employee" ;
INTO ARRAY aNames
 
Hier ein Teil der Ergebnisse aus dem Aufruf von ASORT() ohne das neue Flag:
 
ANAMES                  Pub            A    
   (    1,    1)                       C     "ALBERT    "
   (    2,    1)                       C     "ANDREW    "
   (    3,    1)                       C     "ANNE      "
   (    4,    1)                       C     "Albert    "
   (    5,    1)                       C     "Andrew    "
   (    6,    1)                       C     "Anne      "
   (    7,    1)                       C     "CAROLINE  "
   (    8,    1)                       C     "Caroline  "
   (    9,    1)                       C     "JANET     "
   (   10,    1)                       C     "JUSTIN    "
   (   11,    1)                       C     "Janet     "
   (   12,    1)                       C     "Justin    "
   (   13,    1)                       C     "LAURA     "
   (   14,    1)                       C     "LAURENT   "
   (   15,    1)                       C     "Laura     "
   (   16,    1)                       C     "Laurent   "

Beachten Sie, dass hier keiner der Namen in Kleinschreibung angezeigt wird. Diese befinden sich alle am Ende des Listing.

Um das neue Flag zu nutzen, ohne eine Anfangsposition oder die Anzahl der Elemente anzugeben, übergeben Sie als zweiten und dritten Parameter jeweils –1. Hier der Aufruf, mit dem aNames korrekt sortiert ausgegeben wird: 

ASORT(aNames, -1, -1, 0, 1)

Hier ein Teil des Ergebnisses. Beachten Sie, dass in jeder Gruppe keine Vorhersage möglich ist, welche Version des Namens als Erste angezeigt wird. Die Funktion sieht „ANDREW“, „Andrew“ und „andrew“ als identisch an.

ANAMES                  Pub            A    
   (    1,    1)                       C     "ALBERT    "
   (    2,    1)                       C     "albert    "
   (    3,    1)                       C     "Albert    "
   (    4,    1)                       C     "ANDREW    "
   (    5,    1)                       C     "Andrew    "
   (    6,    1)                       C     "andrew    "
   (    7,    1)                       C     "anne      "
   (    8,    1)                       C     "ANNE      "
   (    9,    1)                       C     "Anne      "
   (   10,    1)                       C     "CAROLINE  "
   (   11,    1)                       C     "caroline  "
   (   12,    1)                       C     "Caroline  "
   (   13,    1)                       C     "Janet     "
   (   14,    1)                       C     "janet     "
   (   15,    1)                       C     "JANET     "
   (   16,    1)                       C     "Justin    "
   (   17,    1)                       C     "JUSTIN    "
   (   18,    1)                       C     "justin    "
   (   19,    1)                       C     "laura     "
   (   20,    1)                       C     "Laura     "
   (   21,    1)                       C     "LAURA     "
   (   22,    1)                       C     "Laurent   "
   (   23,    1)                       C     "LAURENT   "
   (   24,    1)                       C     "laurent   "

ShowASort.SCX auf der Begleitdiskette gibt Ihnen die Möglichkeit, mit ASORT() zu experimentieren.

ASCAN() verfügt über zwei neue Parameter. Der hinzugefügte fünfte Parameter ist nSearchColumn – damit wird angezeigt, in welcher Spalte gesucht werden soll. Sie können ihn mit den Parametern für die Startposition und der Anzahl der Elemente für eine nur teilweise Suche innerhalb der Spalte kombinieren. Alternativ können Sie sowohl für die Startposition als auch für die Anzahl der Elemente –1 angeben, wenn die gesamte Spalte durchsucht werden soll.

Um unser Beispiel vorzubereiten, erstellt diese Zeile ein Array, das die Informationen über die persistenten Relationen in der Datenbank TasTrade enthält:

ADBOBJECTS(aRelns,"RELATION")0

Das Array enthält fünf Spalten: die erste ist der Name der untergeordneten Tabelle in der Relation, die zweite der Name der übergeordneten Tabelle. Die dritte und vierte Spalte enthält die Namen der Tags, die für die Verwaltung dieser Relation benötigt werden. In der letzten Spalte finden Sie einen Wert, der den Typ der relationalen Integrität für diese Relation anzeigt.

Wenn wir die erste Relation finden wollen, die eine bestimmte Tabelle als untergeordnet nutzt, müssen wir sicherstellen, dass wir nur in der ersten Spalte suchen. Als Beispiel findet dieser Aufruf die erste Relation, in der die Tabelle Products als untergeordnete Tabelle vorkommt.

? ASCAN( aRelns, "PRODUCTS", -1, -1, 1) && displays 16

Der neue sechste Parameter, nFlags, gibt uns die Möglichkeit, die Suche auf unterschiedliche Arten zu verbessern. In Visual FoxPro 7 kann nFlags vier additive Bitwerte annehmen, die Sie in Tabelle 2 sehen.

Tabelle 2. Die Flags von ASCAN() – Addieren Sie die Werte, um den Parameter nFlags zu erstellen.
Bit Wert Bedeutung

0

0

Die Suche unterscheidet zwischen Groß- und Kleinschreibung. Vorgabewert.

0

1

Suche unterscheidet nicht zwischen Groß- und Kleinschreibung.

1

0

EXACT ist ausgeschaltet. Arbeitet nur, wenn Bit 2 gesetzt ist (4).

1

2

EXACT ist eingeschaltet. Arbeitet nur, wenn Bit 2 gesetzt ist (4).

2

0

Die aktuellen Einstellungen von SET EXACT gelten.

2

4

Benutzen der Einstellung von Bit 1.

3

0

Gibt die Elementnummer der passenden Zeile zurück.

3

8

Gibt die Zeilennummer der passenden Zeile zurück, wenn es sich um ein zweidimensionales Array handelt.

Wenn wir noch einmal zum letzten Beispiel zurückgehen, können wir verschiedene Änderungen antesten. Die sinnvollste ist das Erhalten der Zeilennummer statt der Elementnummer:

? ASCAN( aRelns, "PRODUCTS", -1, -1, 1, 8) && displays 4

Vielleicht wollen wir auch Missverständnisse durch die Groß- und Kleinschreibung der Daten im Array ausschließen. Wir können also dem Flag den Wert für die Unterscheidung der Groß- und Kleinschreibung hinzufügen:

? ASCAN( aRelns, "PRODUCTS", -1, -1, 1, 9) && displays 4

Die Flags für die Behandlung der EXACT-Einstellungen sind ein wenig verwirrend. Es ist kein Unterschied, welchen Wert Sie Bit 1 übergeben, wenn Sie Bit zwei nicht den Wert 4 zuweisen. Damit erhalten Sie die Möglichkeit, entweder die aktuelle Einstellung von SET EXACT zu nutzen oder sie für die Suche zu überschreiben. Die Addition von 4 zu nFlags stellt sicher, dass Sie mit der Einstellung EXACT OFF suchen, die Addition von 6 bewirkt, dass ASCAN() mit EXACT ON sucht. Unabhängig davon, welchen Wert Sie übergeben, hat dies keine Auswirkungen außerhalb des einzelnen Aufrufs von ASCAN().

Die Behandlung des Datums

Einige Änderungen bringen Verbesserungen im Umgang mit dem Datum. Die neue Funktion QUARTER() nimmt ein Datum und teilt Ihnen mit, in welches Quartal des Jahres es fällt. Sie können einen Startmonat für das Jahr angeben, so dass Sie neben dem Kalenderjahr auch das Fiskaljahr behandeln können. Ein Beispiel:

? QUARTER( {^ 2000-9-23} )

gibt 3 zurück, da der 23. September im dritten Quartal des Jahres liegt. Aber wenn Sie ein Jahr angeben, das am 1. Juli beginnt, also folgendermaßen:

? QUARTER( {^ 2000-9-23}, 7 )

gibt die Funktion statt dessen 1 zurück.

SET(“CENTURY“) hat eine neue Option erhalten. Wenn Sie als zweiten Parameter eine 3 übergeben, gibt die Funktion das höchste Rollover-Datum zurück, so wie es in der Systemsteuerung eingestellt ist. Diese Möglichkeit gilt nur für Windows 98 und 2000. In allen anderen Versionen gibt SET(“CENTURY“, 3) –1 zurück.

Erweiterte Werkzeuge der Benutzeroberfläche

Eine Anzahl der Änderungen betreffen das Erstellen der Benutzeroberfläche. Sie können in zwei Kategorien eingeteilt werden: in solche, die Kontrollelemente und solche, die sich auf andere Eingabemechanismen beziehen.

Erweiterungen der Kontrollelemente

Viele der Änderungen an den Kontrollelementen unterstützen das neue flache Aussehen. Viele Kontrollelemente haben die neue Einstellung „Hot Tracking“, die sie flach aussehen lassen, außer die Maus wird über sie gezogen. In diesem Moment erscheinen sie entweder erhöht oder gedrückt. Die Einstellung von Hot Tracking arbeitet nur, wenn Style auf Graphical gesetzt ist.

Alle Kontrollelemente haben die neuen Ereignisse MouseEnter und MouseLeave, die Ihnen die Möglichkeit eröffnen, eine Aktion auszuführen, wenn die Maus über das Kontrollelement geführt wird. Diese Ereignisse erhalten die gleichen Parameter wie MouseMove: die Maustasten sind gerade gedrückt sowie die aktuelle Position der Maus.

Die Schaltflächen haben die neue Eigenschaft VisualEffect, die nur zur Laufzeit verfügbar ist und die die Schaltfläche erhöht oder gedrückt erscheinen lässt. Durch die Manipulation dieser Eigenschaft in den Methoden MouseEnter und MouseLeave können Sie Ihre eigenen Hot Tracking-Effekte erstellen.

Das Formular in Abbildung 1 zeigt Ihnen die neue Einstellung SpecialEffect, die Ereignisse MouseEnter und MouseLeave, die Eigenschaft VisualEffect sowie eine Reihe anderer Änderungen der Benutzeroberfläche, die im nächsten Abschnitt beschrieben werden. Das Formular finden Sie als UIChanges.SCX auf der Begleit-CD.

Abbildung 1. Was ist neu bei den Formularen? - Dieses Formular demonstriert einige der Änderungen der Kontrollelemente und anderer Eingabetechniken, einschließlich der neuen Ereignisse MouseEnter und MouseLeave, die Eigenschaft VisualEffect für Schaltflächen und die neue Einstellung Hot Tracking für die Eigenschaft SpecialEffect.

Einige Änderungen bei den Grids behandeln seit Langem nachgefragte Erweiterungen. Die Eigenschaft WordWrap wurde dem Header-Objekt hinzugefügt, so dass die Header nicht mehr auf eine Zeile beschränkt sind. Im Formular in Abbildung 2, das Sie auf der Begleitdiskette als GridSample.SCX finden, ist WordWrap für die erste Spalte auf .T., für die anderen Spalten auf .F.  gesetzt.

Abbildung 2. Neue Features des Grid - Spaltenüberschrifen können bei Bedarf gewrappt werden. Zusätzlich können Sie herausfinden, ob es eine Änderung an der Spalte oder an der Zeile war, die BeforeRowColChange oder AfterRowColChange ausgelöst hat.

Bereits seit Visual FoxPro haben sich die Entwickler gefragt, weshalb die Ereignisse BeforeRowColChange und AfterRowColChange nicht in die getrennten Ereignisse BeforeRowChange, BeforeColChange, AfterRowChange und AfterColChange aufgeteilt waren. Obwohl VFP 7 nicht so weit geht, macht es die neue Eigenschaft RowColChange einfach, festzustellen warum die beiden Ereignisse ausgelöst werden. Sie enthält einen Wert, der anzeigt, was geändert wurde: die Zeile (1), die Spalte (2), beides (3) oder nichts (4). Im Formular in Abbildung 2 wird eine Messagebox angezeigt, die mitteilt, was ausgelöst wird. Hier der Code:

LPARAMETERS nColIndex
 
#DEFINE MB_ICONINFORMATION      64      && Information message
 
LOCAL cWhatChanged
 
DO CASE
CASE This.RowColChange = 0
   cWhatChanged = "nothing has"
CASE This.RowColChange = 1
   cWhatChanged = "row only has"
CASE This.RowColChange = 2
   cWhatChanged = "column only has"
CASE This.RowColChange = 3
   cWhatChanged = "row/column have"
ENDCASE
MESSAGEBOX("In AfterRowColChange - " + cWhatChanged + " changed", ;
"Grid Information",;
MB_ICON INFORMATION)
 
RETURN

Eine andere neue Eigenschaft, die den Code betrifft, den Sie schreiben müssen, ist hWnd, die den Formularen und Toolbars hinzugefügt wurde. Diese Eigenschaft enthält immer den Handle des Formulars oder der Toolbar. Sie kann in den Funktionen des Windows API genutzt werden. In älteren Versionen müssen Sie mehrere Funktionsaufrufe starten, um diese Information zu erhalten. Abbildung 3 zeigt ein Formular, das seine hWnd an eine API-Funktion übergibt und sich selbst in einen Kreis verwandelt. Den Code des Formulars wie er aus dem Klassenkatalog exportiert wurde, sehen Sie weiter unten (ich danke dabei David Frankenbach, der mir diese Technik gezeigt hat). Auf der Begleitdiskette finden Sie das Formular unter MkCircle.SCX.

Abbildung 3. Erhalten eines Handle auf ein Formular - Dieses Formular übergibt sein Handle von Windows der API-Funktion SetWindowRgn, um seine Form in einen Kreis zu ändern.

PUBLIC ofrmcircle
 
SET CLASSLIB TO d:\fox\ ;
       testcode\vfp6test\ ;
       controls\forms.vcx ADDITIVE
 
ofrmcircle=NEWOBJECT("frmcircle")
ofrmcircle.Show
RETURN
 
DEFINE CLASS frmcircle AS frmform
 
   Height = 400
   Width = 400
   DoCreate = .T.
   AutoCenter = .T.
   BorderStyle = 0
   Movable = .F.
   TitleBar = 0
   BackColor = RGB(0,0,255)
   Name = "frmCircle"
 
 
PROCEDURE Init
LOCAL nhWnd, nWidth, nHeight, nRegion
 
DECLARE INTEGER CreateEllipticRgn ;
       IN gdi32 INTEGER X1, INTEGER ;
       Y1 , INTEGER X2 , INTEGER Y2
DECLARE INTEGER SetWindowRgn IN ;
       user32 INTEGER HWND, ;
       INTEGER hRgn , INTEGER bRedraw
 
nhWnd = This.HWnd
nWidth = This.WIDTH / 1 ;
          && change ratio
nHeight = This.HEIGHT / 1 ;
          && change ratio
nRegion = CreateEllipticRgn(0, 0, ;
          nWidth, nHeight)
SetWindowRgn(nhWnd, nRegion, 1)
ENDPROC
 
PROCEDURE DblClick
       ThisForm.Release()
ENDPROC
 
ENDDEFINE

Beachten Sie im Zusammenhang mit den anderen Änderungen an _SCREEN, dass sowohl _VFP als auch _SCREEN über die Eigenschaft hWnd verfügen, dass diese aber unterschiedliche Werte enthalten.

Andere Erweiterungen der Benutzeroberfläche

Nicht jede Interaktion geschieht über Formulare und Kontrollelemente. Es gibt eine Vielzahl anderer Möglichkeiten, mit dem Anwender zu kommunizieren, und einige der Änderungen von VFP behandeln diese Lösungen.

Die Menüs von Visual FoxPro wurden erweitert, um die neuesten Techniken der Interaktion zu unterstützen. Der Befehl DEFINE BAR enthält einige neue Klauseln. PICTURE  und PICTRES geben Ihnen die Möglichkeit, den Menüpunkten Bilder hinzuzufügen. Mit PICTURE geben Sie eine Datei einschließlich Pfad an. Mit PICTRES legen Sie die Nummer eines Menüs im Systemmenü von FoxPro fest und die dazugehörende Grafik wird mit diesem Menü benutzt. Um Grafiken nutzen zu können, muss das Popup, das das Menü enthält, mit der Klausel MARGIN definiert werden.

INVERT ermöglicht Ihnen, ein Menü mit einem helleren Hintergrund und als ob es angeklickt wäre darzustellen. Auf diese Art werden in Office-Anwendungen die seltener genutzten Menüpunkte dargestellt, wenn sie alle erscheinen.

Die letzte neue Klausel ist die komplexeste, da Sie zunächst Code entwickeln müssen, damit sie sinnvoll arbeitet. MRU steht für „most recently used“. Wenn Sie diese Klausel einem Menüpunkt hinzufügen, erscheint er als hervorgehobenes Zeichen, das nach unten zeigt und dadurch mitteilt, dass das Menü erweitert werden kann. Wenn der Anwender die Maus über diesen Punkt zieht oder darauf klickt können Sie darauf mit dem Hinzufügen weiterer Menüpunkte (oder mit jedem anderen Code, den Sie ausführen lassen wollen) antworten. Vermutlich werden die hinzugefügten Menüpunkte farblich umgekehrt dargestellt.

Das folgende Programm erstellt innerhalb des Systemmenüs ein neues Menü mit drei Einträgen. Den ersten beiden sind Bilder zugeordnet. Der dritte Eintrag ist ein MRU. Wenn der Anwender das MRU auswählt wird ein separates Programm aufgerufen, in dem das Popup geändert wird. Zunächt das Programm, das das Menü und das Popup erstellt.

* MRUMenu.PRG
* Create a menu with an MRU item.
 
DEFINE PAD MRUSample of _MSYSMENU prompt "MRU Demo"
 
DEFINE POPUP MRUpop MARGIN RELATIVE
 
ON PAD MRUSample of _MSYSMENU activate POPUP MRUPop
 
DEFINE BAR 1 of MRUPop Prompt "End MRU Demo" picture HOME() + "Fox.BMP"
DEFINE BAR 2 of MRUPop prompt "Second" pictres "_mfi_save"
DEFINE BAR 3 of MRUPop mru
 
ON SELECTION BAR 1 OF MRUPop DO ReleaseMRU
ON SELECTION BAR 2 OF MRUPop WAIT WINDOW "Not really saving anything"
ON SELECTION BAR 3 of MRUPop do ChgMRUPop

Hier nun ChgMRUPop, das aufgerufen wird, wenn der Anwender das MRU auswählt. Es Ändert das Popup, reaktiviert es ,und nachdem der Anwender seine Wahl getroffen hat, setzt er das Menü wieder in seinen Originalstatus:

* ChgMRUPop.Prg
* Change the contents of MRUPop menu
* popup in response to the MRU choice
 
* Remove the MRU bar
RELEASE BAR 3 of MRUPop
 
* Add the new bars
DEFINE BAR 3 of MRUPop prompt ;
       "New Third Bar" INVERT AFTER 1
DEFINE BAR 4 of MRUPop prompt ;
       "Fourth" INVERT
 
ON SELECTION BAR 3 OF MRUPop ;
       WAIT WINDOW "Hey! This works."
ON SELECTION BAR 4 OF MRUPop ;
       WAIT WINDOW "Even the new " + ;
       "one at the bottom works"
 
* Reactivate the popup
ACTIVATE POPUP MRUPop
 
* After the user makes a choice,
* clean up, Remove the added bars
RELEASE BAR 3 of MRUPop
RELEASE BAR 4 of MRUPop
 
* Need to redefine the MRU bar
DEFINE BAR 3 of MRUPop mru
ON SELECTION BAR 3 of MRUPop ;
       do ChgMRUPop

Zum Schluss noch das Programm Release, das das Menü aufräumt, wenn der Anwender die MRU-Demo beendet.

* ReleaseMRU.PRG
* Clean up MRUMenu
 
RELEASE POPUP MRUpop
RELEASE PAD MRUSample of _MsysMenu

Abbildung 4 zeigt das Menü in der Art, in der es zunächst erscheint, während Abbildung 5 das erweiterte Menü enthält.

Abbildung 4. Menüerweiterungen - Dieses Popup zeigt sowohl Bilder für die Menüpunkte als auch ein MRU-Menü.

Abbildung 5. Expansion des Menüs - Sie können Code schreiben, der auf den MRU reagiert, um dem Menü die zusätzlichen Einträge hinzuzufügen. Die neue Klausel INVERT bietet die Möglichkeit, Menüpunkte zu entwickeln, die zurückgesetzt und abgeblendet sind.

Beide Arten der Bilder können im Menüdesigner angegeben werden. Sowohl die Optionen MRU als auch INVERT können nicht direkt im Designer abgehandelt werden. Es ist aber möglich, den Menüdesigner auszutricksen, indem Sie diese Optionen in die Klausel SKIP FOR aufnehmen.

VFP bietet durch die Funktion MessageBox() bereits seit Langem eine Möglichkeit, dem Anwender eine Nachricht im Stil von Windows anzuzeigen. In dieser Version hat die Funktion noch einen Parameter Timeout sowie die Möglichkeit, die Nachricht automatisch in eine Zeichenfolge umzuwandeln, erhalten. Das bedeutet, dass Sie der Funktion jetzt auch ein Datum oder einen numerischen Wert übergeben können, ohne ihn vorher durch TRANSFORM() oder eine andere Funktion umzuwandeln. Natürlich ist es beim Erstellen komplexer Nachrichten mit vielen unterschiedlichen Datentypen nach wie vor erforderlich, alle Daten zunächst in Zeichenfolgen umzuwandeln, bevor man sie verknüpft.

Der neue Parameter Timeout hat zur Folge, dass Sie eine Messagebox anzeigen können, bis der Anwender sie wegklickt oder bis die Zeit abgelaufen ist. Die Zeitspanne wird in Millisekunden gemessen. Wenn die Box durch Ablauf der Zeit freigegeben wird gibt die Funktion –1 zurück. Hier ein Beispiel:

nResult = MessageBox( ;
       "Don't you hate monolog boxes?";
       ,32+0,;
       "Demonstrate timeout",2000)

Diese Nachricht wird für zwei Sekunden angezeigt, wenn der Anwender vorher nicht auf OK klickt. Abbildung 6 zeigt den Dialog.

Abbildung 6. Messagebox mit Timeout. Die Funktion MessageBox() verfügt über einen neuen Parameter Timeout, der nach einer angegebenen Zeit den Dialog beendet.

Eine neue Funktion, die mit MessageBox() verwandt ist, behandelt Situationen, in denen Sie lediglich eine einzelne Eingabe vom Anwender erwarten und die Implementierung eines vollständigen Formulars übertrieben scheint. Die Funktion heißt InputBox() und bietet Ihnen Zugriff auf den gleichen Dialog, den VFP benutzt, um Ansichtenparameter zu erhalten. InputBox() akzeptiert die folgenden vier Parameter:

cInput = InputBox( cPrompt ;
          [, cCaption [, cDefault ;
          [, nTimeOut ] ] ] )

Ein Beispiel:

cUserName = InputBox( ;
       "Enter UserName",
"Tamar's Application", ;
"",10000)

Abbildung 7 zeigt den daraus resultierenden Dialog. Wie die Syntax zeigt, liefert die Funktion immer einen Zeichenwert zurück.

Abbildung 7. Einfache Eingabe - Die neue Funktion InputBox() macht es einfach, einen einzelnen Eingabewert abzufragen.

Das Formular in Abbildung 1 enthält Schaltflächen, die die Änderungen in MessageBox() und eine Schaltfläche, die InputBox() demonstriert.

Zwei Funktionen zur Anzeige von Systemdialogen wurden geändert. GetFont() besitzt jetzt die Fähigkeit, den gewählten Zeichensatz anzuzeigen. Um keinen bestehenden Code ändern zu müssen, enthält die Funktion nur dann die Zahl des Zeichensatzes, wenn ihr der optionale Parameter nCharacterSet übergeben wurde. Wurde der Parameter übergeben, wird das Feld im Fontdialog aktiviert. Abbildung 8 zeigt Ihnen den Dialog, der durch folgenden Aufruf angezeigt wird:

? GETFONT("Tahoma",24,"",1)
 

Abbildung 8. Fontauswahl - Der neue Parameter nCharacterSet von GetFont() aktiviert das Dropdown-Feld, so dass der Anwender den passenden Zeichenatz wählen kann.

Wenn der Anwender in Abbildung 8 auf OK klickt, sieht der Rückgabewert folgendermaßen aus:

"Tahoma,24,N,1"

Die Änderungen in der Funktion GETDIR() sind noch wichtiger. Zunächst benutzt die Funktion unter gewissen Umständen eine Baumansicht, um das Laufwerk und die Verzeichnishierarchie anzuzeigen statt der untereinander angezeigten Ordnersymbole in VFP 6.0 und in früheren Versionen.

Außerdem wurden noch drei neue Parameter hinzugefügt. Wird einer dieser Parameter übergeben, wird die Baumansicht im Dialog verwendet. Die neue Syntax sieht folgendermaßen aus:

cDirectory = GETDIR( [ cStartDir [, cPrompt [, cDialogCaption
                     [, nFlags [, lRootOnly ] ] ] ] ] )

Wie der Name bereits vermuten lässt, können Sie mit dem neuen Parameter cDialogCaption angeben, welcher Text in der Titelleiste des Dialogs erscheinen soll. Sie können im Parameter nFlags 0 oder mehrere additive Flags angeben. Sie arbeiten wie die Flags für ASCAN() – wählen Sie eines aus und fügen sie zusammen, um den Parameter nFlags zu erhalten. Tabelle 3 zeigt die Werte der Flags – einige davon sind nur in neueren Versionen von Windows sinnvoll einzusetzen. Der Parameter lRootOnly gibt an, ob die Baumansicht im Hauptverzeichnis des angegebenen Laufwerks (wenn er auf .T. steht) aufhören soll oder ob alle Verzeichnisse angezeigt werden (.F., dies ist der Vorgabewert).

Tabelle 3. Die Flags von GETDIR() – Die Auswahl eines Verzeichnisses ist besser konfigurierbar als je zuvor. Übergeben Sie GETDIR() diese Werte gemeinsam als vierten Parameter. Einige dieser Werte machen es möglich, mit GETDIR() einen Drucker oder einen anderen Rechner statt eines Verzeichnisses auszuwählen.

Wert des Flag Bedeutung

1

Rückgabe nur der Verzeichnisse, die Teil des Dateisystems sind. Wenn der Anwender ein Verzeichnis auswählt, das nicht Teil des Dateisystems ist, wird die Schaltfläche OK deaktiviert.

2

Enthält keine Netzwerkverzeichnisse unterhalb der Stufe der Domain in der Baumansicht.

8

Ausschließlich Rückgabe übergeordneter Verzeichnisse. Wenn der Anwender etwas anderes als ein übergeordnetes Verzeichnis auswählt wird die Schaltfläche OK deaktiviert.

16

Fügt ein Kontrollelement ein, in dem der Anwender den Namen des gesuchten Verzeichnisses angeben kann (nur in einigen Versionen von Windows verfügbar).

64

Nutzung der neuen Benutzeroberfläche (nur in Windows 2000 und höher verfügbar).

4096

Es werden nur Rechner zurückgegeben. Wenn der Anwender etwas anderes als einen Computer auswählt, wird die Schaltfläche OK deaktiviert.

8192

Es werden nur Drucker zurückgegeben. Wenn der Anwender etwas anderes als einen Drucker auswählt, wird die Schaltfläche OK deaktiviert.

16384

Zeigt sowohl Dateien als auch Verzeichnisse an (nur in einigen Versionen von Windows verfügbar).

CD ? nutzt den gleichen Dialog wie GETDIR(), bietet aber nicht alle neuen Möglichkeiten.

Nach der letzten Änderung, die der Benutzeroberfläche zuzuordnen ist, haben FoxPro-Entwickler seit vielen Versionen gefragt. Seit langem kontrolliert die Systemvariable _DBLCLICK zwei unterschiedliche Dinge. Wie der Name vermuten lässt, entscheidet sie, wie viel Zeit zwischen zwei Mausklicks vergehen darf, damit sie als ein Doppelklick gewertet werden. Außerdem entschied der Inhalt dieser Variablen darüber, wie schnell ein Anwender bei der inkrementellen Suche in Comboboxen eine Eingabe machen musste. In VFP 7 wurden diese beiden Punkte getrennt, und die inkrementelle Suche wird jetzt durch die neue Systemvariable _INCSEEK kontrolliert.

OOP-Sprache

Zusätzlich zu den verschiedenen Änderungen der Kontrollelemente, die wir bereits besprochen haben, gibt es noch verschiedene andere Änderungen an VFPs objektorientierter Sprache. Als Erstes wurde der Befehl DEFINE CLASS erweitert, um es Ihnen zu ermöglichen, die Klassenbibliothek, von der die Klasse abgeleitet wird, mit anzugeben. Die neue Syntax von DEFINE CLASS lautet:

DEFINE CLASS ClassName AS ParentClass;
[ OF ClassLibrary ]

Der Vorteil dieses Formats liegt darin, dass Sie vor der Klassendefinition kein SET CLASSLIB oder SET PROCEDURE absetzen müssen. Die Klassenbibliothek kann (und sollte in der Regel auch) den Pfad enthalten und in Anführungsstriche gesetzt werden (beispielsweise wenn der Pfad Leerzeichen enthält).

Die Funktion AMEMBERS() bietet zusätzliche Informationen sowohl für VFPs native Objekte als auch für COM-Objekte. Der neue Wert 3 für den dritten Parameter gibt an, dass die Funktion ein vierspaltiges Array zurückliefern soll – die Inhalte der Spalten sehen Sie in Tabelle 4.

Tabelle 4 Was befindet sich in einem Objekt) – Aufruf von AMEMBERS() mit 2 als dritter Parameter gibt ein vierspaltiges Array mit den folgenden Inhalten wieder.

Spalte Inhalt

1

Name der Eigenschaft, des Ereignisses oder der Methode

2

Typ des Eintrags. Für VFP-Objekte sind die möglichen Werte „Property“, „Event“ oder „Method“. Für COM-Objekte sind die möglichen Werte „PropertyPut“, „PropertyGet“ und „Method“.

3

Bei VFP-Objekte ist dieser Eintrag leer. Bei Methoden von VFP-Objekten die Parameterliste. Bei Eigenschaften und Methoden von COM-Objekten die Signatur des Mitglieds, beruhend auf der Parameterliste, zusätzlich der Rückgabewert.

4

Die Hilfe zu dem Eintrag.

AMEMBERS() hat auch den Parameter cFlags erhalten, in dem Sie für native Objekte angeben können, welche Mitglieder zurückgegeben werden sollen. Tabelle 5 listet die möglichen Werte auf. Die Flags in jeder Filtergruppe sind exklusiv. Als Vorgabeverhalten werden, wenn mehrere Werte hintereinander in cFlags eingegeben sind, diese mit OR verknüpft, so dass der Parameter mit dem Wert „HP“ alle verborgenen und geschützten Eigenschaften, Ereignisse und Methoden beinhaltet. Nach Übergabe von „GU“ sind im Ergebnis alle Untereigenschaften enthalten, die entweder global oder benutzerdefiniert sind.

Tabelle 5 Auswahl der Untereigenschaften – AMEMBERS() neuer vierter Parameter lässt Sie das Ergebnis filtern.

 
Wert Filtergruppe Bedeutung

P

Sichtbarkeit

Geschützt

H

Sichtbarkeit

Versteckt

G

Sichtbarkeit

Global

N

Ursprung

Native Eigenschaften, Ereignisse und Methoden

U

Ursprung

Benutzerdefinierte Eigenschaften, Ereignisse und Methoden

I

Vererbung

Geerbte Eigenschaften, Ereignisse und Methoden

B

Vererbung

Basis- Eigenschaften, Ereignisse und Methoden

C

Änderung

Geändert

R

Schreibgeschützt

Schreibgeschützt

Es gibt noch zwei spezielle Flags. Das Aufnehmen von „+“ irgendwo im Parameter cFlags zeigt an, dass die Filter mit AND statt mit OR verknüpft werden sollen. Er ergibt beispielsweise die Übergabe von „GU+“ ein Ergebnis, bei dem alle Mitglieder sowohl global als auch benutzerdefiniert sind.

Das zweite spezielle Flag ist „#“, mit dem das Ergebnisarray eine weitere Spalte erhält. Die neue Spalte enthält die Flags, die zu dem entsprechenden Eintrag gehören.

Hier ein Beispiel für die beiden neuen Features. Der Code erstellt eine Instanz der Klasse _MoverLists aus FoxPros Foundation Classes und listet die geschützten Teile der Klasse einschließlich ihrer Flags auf:

oObject = NewObject( "_MoverLists", ;
          HOME()+"FFC\_CONTROLS" )
AMEMBERS( aMemberList, oObject, ;
          3, "P#" )
LIST MEMORY LIKE aMemberList
AMEMBERLIST         Pub            A    
(    1,    1)    C     "ADDTOPROJECT"
(    1,    2)    C     "Method"
(    1,    3)    C     ""
(    1,    4)    C     "Dummy code for adding files to project."
(    1,    5)    C     "CPUI"
(    2,    1)    C     "NINSTANCES_ACCESS"
(    2,    2)    C     "Method"
(    2,    3)    C     ""
(    2,    4)    C     "Access method for nInstances property."
   (    2,    5)    C     "CPUI"
   (    3,    1)    C     "NINSTANCES_ASSIGN"
   (    3,    2)    C     "Method"
   (    3,    3)    C     "vNewVal"
   (    3,    4)    C     "Assign method for nInstances property."
   (    3,    5)    C     "CPUI"
   (    4,    1)    C     "NOBJECTREFCOUNT_ACCESS"
   (    4,    2)    C     "Method"
   (    4,    3)    C     ""
   (    4,    4)    C     "Access method for nObjectRefCount property."
   (    4,    5)    C     "CPUI"
   (    5,    1)    C     "NOBJECTREFCOUNT_ASSIGN"
   (    5,    2)    C     "Method"
   (    5,    3)    C     "m.vNewVal"
   (    5,    4)    C     "Assign method for nObjectRefCount property."
   (    5,    5)    C     "CPUI"

Dieses Beispiel enthält alle Teile der Klasse (da alle Möglichkeiten aufgelistet sind), aber auch die Flags. Sie sehen hier nur einen Teil der Ausgabe.

AMEMBERS(aMemberList, oObject, 3, "GPH#")
LIST MEMORY LIKE aMemberList
 
AMEMBERLIST         Pub            A    
   (    1,    1)    C     "ACTIVECONTROL"  
   (    1,    2)    C     "Property"
   (    1,    3)    C     ""
   (    1,    4)    C     "References the active control on an object."
   (    1,    5)    C     "GRNI"
   (    2,    1)    C     "ADDOBJECT"
   (    2,    2)    C     "Method"
   (    2,    3)    C     "cName, cClass"
   (    2,    4)    C     "Adds an object to a container object at run time."
   (    2,    5)    C     "GNI"
   (    3,    1)    C     "ADDPROPERTY"   
   (    3,    2)    C     "Method"
   (    3,    3)    C     "cPropertyName,eNewValue" 
   (    3,    4)    C     "Adds a new property to an object."
   (    3,    5)    C     "GNI"
   (    4,    1)    C     "ADDTOPROJECT"   
   (    4,    2)    C     "Method"
   (    4,    3)    C     ""
   (    4,    4)    C     "Dummy code for adding files to project."
   (    4,    5)    C     "CPUI"
   (    5,    1)    C     "AOBJECTREFS"  
   (    5,    2)    C     "Property"
   (    5,    3)    C     ""
   (    5,    4)    C     "Array of object references properties."
   (    5,    5)    C     "GUI"
   (    6,    1)    C     "BACKCOLOR"  
   (    6,    2)    C     "Property"
   (    6,    3)    C     ""
   (    6,    4)    C     "Specifies the background color used to display text and graphics in an object."
   (    6,    5)    C     "GNI"

Das Formular ShowAMembers.SCX auf der Begleitdiskette lässt Sie mit AMembers() experimentieren.

Erweiterungen der IDE

Viele der wichtigsten Änderungen in VFP 7 befinden sich in der Interaktiven Entwicklungsumgebung (IDE). Wie bereits in den früheren Versionen wurde die Programmiersprache erweitert, um die Änderungen in der IDE zu unterstützen. Zusätzlich zu den Neuerungen gibt es noch einige Sprachänderungen, die andere Bereiche der IDE betreffen.

Unterstützung für neue Features

Verschiedene neue Systemvariablen dienen der Unterstützung von Programmen und Tabellen für die neuen Features der IDE. Tabelle 6 zeigt Ihnen die neuen Systemvariablen, die die neuen Features referenzieren; Sie können diese ändern, so dass sie auf Programme oder Daten verweisen, durch die Sie die von VFP bereitgestellten ersetzen.

Tabelle 6 Finden neuer Features – Diese neuen Systemvariablen verweisen auf die neuen Applets von VFP und die dazugehörenden Daten. Diese können Sie durch Ihre eigenen ersetzen.

Variable Vorgabewert Bedeutung

_CodeSense

HOME() + "FoxCode.App"

Die Verwaltungsanwendung für IntelliSense

_FoxCode

<WinDir> + "\Profiles\" + <User> + "\<User Settings Dir>\Microsoft\Visual FoxPro\FoxCode.DBF"

Die Datentabelle für IntelliSense

_FoxTask

HOME() + "FoxTask.DBF"

Die Datentabelle der Aufgabenliste

_ObjectBrowser

HOME() + "ObjectBrowser.APP"

Die Anwendung Objekt Browser

_TaskList

HOME() + "TaskList.APP"

Die Anwendung der Aufgabenliste

Außerdem verfügt das Anwendungsobjekt _VFP über die zwei neuen Eigenschaften EditorOptions und LanguageOptions. Damit können Sie festlegen, welche der neuen Editierfeatures automatisch verfügbar sein sollen. Mit EditorOptions verwalten Sie die unterschiedlichen Features von IntelliSense, wie das Drag-and-Drop zwischen Worten und die automatische Erstellung von Hyperlinks. Auch wenn diese Features via EditorOptions abgeschaltet sind, werden sie über das Menü weiterhin angeboten. LanguageOptions lässt Sie entscheiden, ob das Strict Typing zur Laufzeit ausgeführt wird.

Die neuen Funktionen EDITSOURCE() und APROCINFO() lassen Sie von einigen anderen neuen Features profitieren. EDITSOURCE() öffnet den für eine bestimmte Datei richtigen Editor und positioniert optional an einen bestimmten Punkt innerhalb der Datei. Wenn Sie eine Datei übergeben, die zu einem der visuellen Designer gehört, müssen Sie eine Zeilennummer angeben. Ein Beispiel:

EditSource( HOME()+"FFC\_CONTROLS.VCX",3,"_MoverLists","SelectAll")

EDITSOURCE() gehört ebenso zu dem neuen Tool Aufgabenliste. Sie können einen Shortcut aus der Aufgabenliste übergeben und haben den entsprechenden Editor geöffnet und am angegebenen Shortcut positioniert.

APROCINFO() ist die programmatische Version des neuen Document View. Die Funktion füllt ein Array mit den gleichen Informationen, die auch beim interaktiven Gebrauch des Document View angezeigt werden. Die Funktion überlässt Ihnen die Wahl, wie viele Informationen Sie angezeigt bekommen wollen. Hier die Syntax:

nCount = AProcInfo( aArray, cFileName;
          [, nWhichInfo ] )

Der Parameter nWhichInfo kann die folgenden 4 Werte enthalten:

·        0 oder nicht übergeben – enthält alle Informationen

·        1 – enthält nur Klassendefinitionen

·        2 – enthält nur Methodeninformationen

·        3 – enthält nur Präprozessoranweisungen einschließlich #DEFINE

Ein Beispiel:

APROCINFO( aDefines, HOME()+"GENHTML.PRG", 3)

Dieser Code produziert das folgende Resultat (hier nur in Teilen aufgeführt):

 API               Pub            A    
   (    1,    1)  C     "VFP_DEFAULT_ID"
   (    1,    2)  N     32                      (          32.00000000)
   (    1,    3)  C     "Define"
   (    2,    1)  C     "M_CLASS_LOC"
   (    2,    2)  N     35                      (          35.00000000)
   (    2,    3)  C     "Define"
   (    3,    1)  C     "M_COULD_NOT_BE_INST_LOC"
   (    3,    2)  N     36                      (          36.00000000)
   (    3,    3)  C     "Define"
   (    4,    1)  C     "M_COULD_NOT_OPENED_EXCL_LOC"
   (    4,    2)  N     37                      (          37.00000000)
   (    4,    3)  C     "Define"
   (    5,    1)  C     "M_FILE_LOC"
   (    5,    2)  N     38                      (          38.00000000)
   (    5,    3)  C     "Define"
   (    6,    1)  C     "M_FILE_ALREADY_EXISTS_LOC"
   (    6,    2)  N     39                      (          39.00000000)
   (    6,    3)  C     "Define"
   (    7,    1)  C     "M_FILE_TYPE_LOC"
   (    7,    2)  N     40                      (          40.00000000)
   (    7,    3)  C     "Define"

In VFP 7 können viele der Systemfenster angedockt werden. Die Funktion WDOCKABLE() lässt Sie herausfinden, ob ein Systemfenster grundsätzlich angedockt werden kann und ob das auch aktuell möglich ist. Außerdem können Sie den Status der Andockbarkeit eines Fensters ändern. Übergeben Sie einfach den Namen des Fensters, um seinen Status zu prüfen. Mit .T. oder .F. als zweiten Parameter ändern Sie die Andockbarkeit des Fensters. So machen Sie das Befehlsfenster andockbar:

WDOCKABLE("Command", .T.)

Die Funktion ALANGUAGE() wurde eingeführt, um IntelliSense anzupassen. Sie füllt basierend auf dem zweiten übergebenen Parameter ein Array mit unterschiedlichen Komponenten der Sprache. Tabelle 7 zeigt die Auswahlmöglichkeiten:

Tabelle 7 Sprachkomponenten – ALANGUAGE() füllt ein in Abhängigkeit von diesen übergebenen Werten ein Array mit unterschiedlichen Teilen der Sprache von VFP.

2. Parameter Ergebnis

1

Erstellt ein eindimensionales Array mit Befehlen.

2

Erstellt ein zweidimensionales Array mit Funktionen einschließlich der Anzahl der akzeptierten Parameter. Die zweite Spalte könnte auch den Buchstaben „M“ enthalten, womit angezeigt wird, dass statt einer verkürzten Version der vollständige Funktionsname verwendet werden muss.

3

Erstellt ein eindimensionales Array der Basisklassen.

4

Erstellt ein eindimensionales Array der DBC-Ereignisse.

Hier ein Beispiel mit nur einem Teil der Ergebnisse:

ALANGUAGE( aFunctions, 2)
LIST MEMORY LIKE aFunctions
 
AFUNCTIONS              Pub            A    
   (    1,    1)                       C     "ABS"
   (    1,    2)                       C     "1"
   (    2,    1)                       C     "ACLASS"
   (    2,    2)                       C     "2"
   (    3,    1)                       C     "ACOPY"
   (    3,    2)                       C     "2-5"
   (    4,    1)                       C     "ACOS"
   (    4,    2)                       C     "1"
   (    5,    1)                       C     "ADATABASES"
   (    5,    2)                       C     "1"
   (    6,    1)                       C     "ADBOBJECTS"
   (    6,    2)                       C     "2"
   (    7,    1)                       C     "ADDBS"
   (    7,    2)                       C     "1"
   (    8,    1)                       C     "ADEL"
   (    8,    2)                       C     "2-3"
   (    9,    1)                       C     "ADIR"
   (    9,    2)                       C     "1-4"

Updates der bestehenden Sprache

Um die Entwickler von Third-Party-Tools zu unterstützen und für die Konsistenz mit anderen Befehlen unterstützen MODIFY VIEW und MODIFY PROCEDURE jetzt auch die Klausel NOWAIT. Dadurch können diese Befehle auch programmatisch genutzt werden, während das Programm weiter ausgeführt wird.

Die Methode WriteMethod hat einen neuen Parameter, der es ermöglicht, Methoden „on the fly“ zu erstellen. Wenn die Methode, die im ersten Parameter genannt wird, nicht existiert und der Parameter lCreateMethod auf .T. steht, wird die Methode erstellt. Diese Lösung funktioniert nur zur Designzeit und das Formular oder die Klasse muss nach dem Hinzufügen der Methode gespeichert werden. Diese Einschränkungen sind aber akzeptabel, da WriteMethod für den Einsatz in Buildern gedacht ist.

Als die Project Hooks in VFP 6.0 eingeführt wurden fanden die Entwickler schnell Einsatzmöglichkeiten dafür. Einige Features fehlten aber. Diese Löcher stopft VFP 7 mit drei neuen Ereignissen: QueryNewFile, Activate und Deactivate. QueryNewFile wird ausgeführt, wenn Sie mit dem Prozess des Hinzufügens einer Datei zu einem Projekt beginnen. Interaktiv geschieht dies durch Klicken auf die Schaltfläche „Neu“ im Projekt-Manager. In früheren Versionen wurde in diesem Fall kein Ereignis ausgelöst.

Die Ereignisse Activate und Deactivate des Objekts ProjectHook sind wie die anderer Klassen – sie werden ausgeführt, wenn das Objekt aktiv wird und wenn es den Fokus verliert. Im Fall von Project Hooks geschieht dies, wenn das Projekt, das dem Project Hook zugeordnet ist, aktiviert oder deaktiviert wird. Das bedeutet, dass wir jetzt die Umgebung von VFP verändern können, wenn wir zwischen Projekten hin- und herschalten. Dadurch erhalten wir die Chance, Einstellungen wie den VFP PATH und andere projektspezifische Einstellungen zu ändern.

Als in VFP 3.0 die Möglichkeit eingeführt wurde, den Feldern Überschriften zuzuordnen, wurde eine einfache Sache schwieriger. Wenn Sie auf eine Tabelle ein BROWSE absetzen, werden die Überschriften statt der Feldnamen genutzt. Für einen Entwickler, der nur mal schnell einen Blick auf eine Tabelle werfen will, ist dieses Verhalten ärgerlich. VFP bietet mit der Klausel NOCAPTIONS für den Befehl BROWSE jetzt eine einfache und schnelle Lösung dieses Problems.

Der Einsatz definierter Konstanten macht Code erheblich lesbarer. Das Zusammenfassen der Konstanten in einer Datei (auch bekannt als Header- oder .h-Datei) durch Einsatz von #INCLUDE oder den Menüpunkt Include-Datei ist eine mächtige Technik. Diese Technik war aber schwierig, da der Algorithmus der Suche nach der Include-Datei durch einen relativen Pfad angegeben wurde, was nicht immer intuitiv war. Wurde die Datei erneut kompiliert, wurden die Header-Dateien nicht immer gefunden, und Kompilierungsfehler waren die Folge.

In VFP 7 wurde die Suche nach Include-Dateien erweitert. In Klassen und Formularen ist die Suchreihenfolge für die Headerdatei:

Die letzten beiden Suchvorgänge sind neu. In Programmen ist die neue Suchreihenfolge für Include-Dateien folgende:

Der dritte Suchvorgang ist neu.

Dies und Das

Eine neue Funktion ist eine Hilfe für das Debugging. ASTACKINFO() liefert eine komplette Aufstellung des Programmstack zur der Zeit, zu der die Funktion aufgerufen wird. Die Funktion entspricht dem Aufrufstack-Fenster des Debuggers und SYS(16), bietet aber mehr Informationen als die anderen an. Das erzeugte Array verfügt über sechs Spalten, die in Tabelle 8 beschrieben sind.

Tabelle 8 Was läuft? ASTACKINFO() erstellt ein Array mit Informationen über alle zur Zeit ausgeführten Programme.

Spalte Inhalt

1

Stack, mit einer 1 für das Hauptprogramm.

2

Name der Datei, in der die ausgeführte Routine enthalten ist.

3

Name der ausgeführten Routine. Kann eine Prozedur, Funktion oder Methode sein. Bei einer Methode enthält der Eintrag auch den Objektnamen.

4

Name der Quelldatei, in der die Routine enthalten ist.

5

Zeilennummer innerhalb der Datei (nicht innerhalb der Routine)

Obwohl ASTACKINFO() scheinbar nur für das Debugging entwickelt wurde, ist es nicht auf diese Umgebung beschränkt. Die Funktion kann jederzeit eingesetzt werden, um eine Momentaufnahme der aktuellen Situation zu liefern.

Der Befehl USE hat eine neue Klausel CONNSTRING erhalten, die es Ihnen ermöglicht, einen Connectionstring für den Einsatz einer remoten Ansicht zu übergeben. Damit haben Sie die Möglichkeit, eine UserID und ein Passwort zur Laufzeit statt zur Designzeit anzugeben. Beachten Sie, dass wie in SQLStringConnect() der gesamte Connectionstring angegeben werden muss.

Zusammenfassung

Das Entwicklungsteam hat in sehr vielen Bereichen von VFP 7 Änderungen vorgenommen. Wie in früheren Versionen bieten viele dieser Änderungen die Möglichkeit, das Schreiben von Code zu verbessern. Dieses Mal gingen viele Änderungen aus den Wünschen der Entwickler hervor. Wir müssen jetzt das neue Material in unser Denken übernehmen, so dass wir bei Bedarf diese Features auch einsetzen.

Ich danke Randy Brown von Microsoft für seine Hilfe bei der Vorbereitung dieser Notizen.

[1] [2] [3] [4]