Már régóta beszélünk róla, hogy kellene készíteni egy olyan felhasználói-felületet szöveges módban, mely garfikus kinézetű. Ezt már sok cég programja meg is valósította. (DOS / MSAV - Defrag, NU, SR) Próbáljunk az eddigi sok program hibáiból okulni, és praktikumait felhasználni.

Az elsô dolog, hogy felmérjük a feladatunkat. Meg kell határozni mibôl, mit akarunk csinálni.

  • Elôször is, azt tudjuk, hogy a Turbo Vision felületet akarjuk átalakítani egy szebb, színesebb felületre
  • Ehhez karakterátírást fogunk alkalmazi, sôt a háttérszíneket is át kell állítani, hogy lehessen magas intenzitású szín.
  • Új, a régiekbôl származtatott objektumokat kell létrehozni, melyek már használják az átírt (grafikus kinézetű) karaktereket, létrehozva így egy szebb felületet.
  • S végül, az egerentyű formáját valami szebbé tenni

Lássuk a fô három pont megvalosítási lépéseit:

Elôször, a TV átalakítása, szinesebbét tétele:

  • Vettük, hogy a fô objektum mely az egész felhasználói-felületet összefogja a TProgram, ill. a használt TApplication. Ezekbôl kell származtatni olyan új Applikáció objektumot melynek segítségével a TApplication által létrehozott desktop - background - stb. már megfelel egy szebb program részeként.
    Másik egyáltalán nem elhanyagolható lépés az applikáció szineinek átírása. A Turbo Vision szinpalettáiról már beszéltünk, és egy konkrét példát is csináltunk. Oly rég volt, hogy gondoltam felteszem a PC-XUSER\OOP\OOP03.HLP\ könyvtárba, hogy ne kelljen a !OLDUSER-ben kersgetni. (Szóval a 4. számban vettük a paletta-átdefiniálását, ill. felépítését.)
    Lássuk ennek megvalosítását nagy vonalakban:
    type   PPCXDeskTop = ^TPCXDeskTop;   TPCXDeskTop = Object(TDeskTop)     procedure InitBackGround; virtual;   end;   PPCXApplication = ^TPCXApplication;   TPCXApplication = Object(TApplication)   public     constructor Init;     destructor  Done; virtual;     procedure InitDeskTop; virtual;     function  GetPalette: PPalette; virtual;   end;

Látjuk, hogy új desktop-ot definiáltunk, annak érdekében, hogy a #176-os (kockás) karaktert, egy üresre a space (helyköz - #32)-re cseréljük.

Mivel az applikációnak a GetPalette metódusával már át is definiáltuk (lást OOP03.doc) a palettáját, és a TBackground palettájának egyetlen eleme a tulajdonosának - az-az az applikáció - palettájának elsô elemére mutat, így elég volt csak az applikáció palettájának elsô elemét megváltoztani a más háttérszín elérése végett. (Persze azért megjegyzem, hogy az applikáció palettájának elsô eleme csak a háttér színének tárolására van fenntarva.)

Nos ahogy új desktop-ot adunk az új (PCX) applikációhoz, úgy annak a színe, s a feltöltési karaktere is megváltozik.

Továbbá (sôt továbbá javasolnám Karthago elfoglalását ... huhhh de régen voltam én történelem órán ...), szóval továbbá érdemes lenne az applikációnak elmenteni a képernyôn lévô szöveget, hogy a programból való kilépés után ugyanazt lássuk, mint elôtte. Ezt simán $B800:0 címtôl 4096 byte elmentése a prg. indítása elôtt (constructor Init; elôtt), majd kilépéskor, az-az a destructor Done;-ban. (Lásd a forráskódot.)

Ha már ennyire belelendültünk akkor, alakítsuk még "pofásabbra" az applikációt. Vegyük a drága - jó Windows-t. Nos ott van minden programnak egy fejléce, amire a program neve van írva. Huhh, ok csináljuk ezt meg mi is.

Ezt legegyszerűbben egy TStaticText-tel oldhatjuk meg. Persze valami izléses színben. Legyen mondjuk sötétkék (01 szín) háttér, és fehér szinű betűk (15). Ehhez, mint már lassan megszoktuk új objektumot kell örökítenünk a TStaticText-bôl, amit nevezzünk a könnyebb elérhetôség végett TPCXTitleBar-nak. Lássuk az új objektum felépítését:

    type   PPCXTitleBar = ^TPCXTitleBar;   TPCXTitleBar = Object(TStaticText)     constructor Init(AText: String);     function GetPalette: PPalette; virtual;     procedure SetTitleText(AText: String);   end;

Nos azt láthatjuk, hogy eltér az eredeti TStaticText-tôl már az init is. Hogy miért, a válasz egyszerű: hol akarná az ember a program fejlécét máshol, mint a 0,0 (bal-felsô sarokban). Így nem kell a koordinátákat megadni.

A GetPalette metódus egyértelmű, hisz ezzel adjuk meg a színt. A kérdés, hogy hogyan ? Mibôl, ... mi fog mire mutatni ? Az applikáció palettájához hozzá kell adni egy új színt a program-cím szinét. Legyen ez esetünkben az utolsó. (175. fô paletta index.) Erre az indexre fog mutatni a TPCXTitleBar palettájának egyetlen eleme.

A SetTitleText meg arra szolgál, hogyha egy program esetleg idô közben morfoizálódna avagy a programozó hirtelen felindulásból topic-ot (címet) kívánna váltani az az OOP elvei szerint könnyen megoldható legyen.

Megvalósítás a forráskódban (PCX_APP.pas).

Fontos megemlíteni hogy a Borland, a Turbo Vision alkotói azt a szokást alakították ki, hogy bizonyos az applikációhoz tartozó elemeket nem az objektumban (tehát nem a TApplication-ban) deklaráltak, hanem az ôket tartalmazó unit-ban az APP.pas-ban. Nyilván ezt azért tették, hogy az összes objektum elérhesse, igaz ezzel megsértették az adatrejtés elvét. De hát mi is így teszünk, s a TPCXTitleBar-t a PCX_APP.pas Interface részében deklaráljuk.

    const   PCXTitlebar: PPCXTitleBar = nil;

Ehhez az inicializált változóhoz (konstanshoz) a TPCXApplication Init-je hozza létre a view-ot.

Eredeti célkitűzésünk a Turbo Vision színesebbé tétele, ehhez szükséges az az információ ami segít minket abban, hogy ne csak az alacsony intenzitású szineket (0-7) lehessen háttérszínként használni, hanem a világosabbakat (0-15) is. Ez persze azzal jár, hogy nem lesznek villogó szineink de ki bánja !? Fent ezt már a háttérszín kialakításánál fel is használtuk.

A háttér-intenzitás és a karakterátírás megvalósítása

A háttér-intenzitás gyakorlati megvalósítása:

    procedure SetBackGroundIntensity(On: Boolean); Assembler; asm   mov bl, On   or  bl, bl   jne @To0   mov bl, 01h   jmp @Folyt @To0:   xor bl, bl @Folyt:   mov ax, 1003h   int 10h end;

Láthatjuk, hogy videó (INT 10h) megszakítás valósítja ezt meg. Ha fenti procedure True értéket kap akkor felkapcsolja, ha False akkor lekapcsolja a háttérintenzitást. A háttérintemzitást le is lehet kérdezni a memória $40:$65 byte-ján, s ezen byte 5. bit-én. Ha ez a bit lekapcsolt akkor van háttérintenzitás, ellenkezô esetben nem.

A karakterátírás gyakorlati megvalosítását a Tippek - Trükkök rovat 3. számában közöltem. Mivel nem kívánom újra leírni így teljes mélységeiben mindent megtalálhattok a PC-XUSER\OOP\T&T03.HLP\ könyvtárban t&t03.arj file-ban. Ez a T&T 3. száma tömörítve.

A lényeg a amire hangsúlyt kell helyeznünk - hisz már mindenki tud karaktert átírni - hogy milyen képű karaktereket kell létrehoznunk. A rég említett CHAREDIT vizuális programmal fogjuk megtervezni a karakterek képét. Vegyük sorra gondolatainkat:

  • Mivel szép ablakokat - ill. menüt kívánunk létrehozni, így szépen a karakter szélén illeszkedô keretet kell létrehozni.
  • A keretet a keretrajzoló karakterekkel, a #192-#223 közötti karakterekkel kell megrajzolni.
    Mint a T&T03 cikkben elmondtam ezek a karakterek abban különböznek a többitôl, hogy:
    A karakter képe 8x16-os mátrix két karakter között egy nem programozható 9. oszlop tesz egy pont széles helyet, ettôl lesz két nagy M betű között egy pontnyi hely. Viszont ha szöveges módban keretet, vagy illezkedô karakter sorozatot kívánunk definiálni, akkor a 9. oszlop nem lehet üres, mert akkor nem illezkedne. Így van az, hogy a 192 és 223 közötti karaktereknek a 9. oszlopa nem más lesz, mint a 8. oszlopban található pontok megiszmétlése. Így lesz folytonos a keret.
  • Nos a keret létehozásához kell a négy sarok, méghozzá a bal felsô és alsó:

  • Melyekrôl látjuk, hogy a karakter szélein elhelyezkedô két pont vastag vonal alkotja a keretet.
  • A keretnek a bal oldalát ugyanígy kell egy vonalat készíteni mi bal alsó és felsô csücsköt köti össze. Ez a karakter szélén elhelyezkedô két pont vastag vonal.
  • Ugyanígy kell még két másik karakter mely a keret tetejét adja (a bal és jobb csöcsköt köti össze), ez a karakter tetején a fentiekhez hasonlóan két pont vastag 8 pont hosszú vonal.
  • Ugyanígy a keret alját is hasonló vonal alkotja, mely a balalsó és jobbalsó csöcsköt köti össze.
  • Nyilván azért van szükség ennyi keret-karakterre, mert nem a 8 pont közepén helyezkednek el a keretet alkotó pontok, hanem a széleken. Ettôl esz szép a keret.
  • Lássuk a jobb oldali keret karakterek képét, a jobb felsô - ill. alsô csücsköt:

  • Az álmos Olvasó esetleg megretten ha ezt a két keretet meglátja, de hamarosan rájön miért van ez így:
    (a fentiek szerint:) Nos mivel ez keretrajzoló karakter, elég a 8. oszlopba egy pont széles vonalat húzni, így az úgy is megismétli a 8. oszlopot teljesen a 9.-dikben, és ettôl ugyanolyan 2 pont széles vonalat kapunk.
  • A jobb felsô ill. alsó sarkot nyilván-valóan hasonló egy pont vastag a karakter jobb szélére illesztett vonal köti össze.

Lássuk, hogyan is szerkesztjük meg ezeket a karaktereket László József CHAREDIT programjával:

Láthatóak az egyes karakterek, az F1-vel lehívjuk ôket, a kék mezôben szerkesztjük ôket a space billentyűvel kapcsoljuk ki ill. be a pontokat. Az F2 gombbal pedig mentjük el a kész karakter bit-térképét.

(Itt láthatók a keret sarkait összekötô karakterek !!!)

Nos térjünk vissza lassan a GUI-k (Graphical User Interface, pl. OS/2, Windows) ablakcímeihez. Nyilván észrevettük, hogy a bal felsô sarokban található egy kis gomb aminek a segítségével egy menüt hívhatunk le. Ez a menü tartalmazza az ablakkal (- vagy az applikáció ablakával) végezhetô műveleteket: kicsinyítés, nagyítás, bezárás. Ezt control-box-nak nevezzük. Rajzoljuk mi is egyet. Ezt csak két karakterbôl tudjuk létrehozni így:

A középen látható vastag vonal a két karakter határa. Fontos: hogy takarékoskodjunk a keret rajzoló karakterekkel, így elég, ha csak a bal oldali karakter a keret-karakter - hogy összeérjen a control-box, és jobb oldalinak nem kell annak lennie.

Az átírt, új karaktereket használó származtatott objektumok írása I.

A Turbo Vision-nek is van valami hasonló gombja, igaz nincs parosítva hozzá menü. Ez a gomb három karakterbôl van, s valahogy így néz ki: [ð ] Nos hát a milyen ennél szebb. Ezt a három karaktert kell kicserélnünk a sajátunkra. Ez a forráskód átirásával lehetséges. Lássuk ezt nagy vonalakban:

Gondoljuk végig, milyen objektumokra lesz szükség, és ezeket a program mely részein kívánjuk használni:

  • Egy biztos, hogy az applikációnak, a Cím-szövegnél, a bal-felsô sarokban kell lennie egy control-box-nak
  • Arról is beszéltünk, hogy szükségesnek tartjuk, hogy szebb gomb, s ha már gomb van akkor menüt is társítsunk az ablakok és dialógusok bal-felsô csücskében található pucukához. (gombhoz)

Ezek megvalósítása nagy lépésekben:

Mivel több helyen kívánjuk alkalmazni a controll-box-ot (applikáció - window - dialog) ezért hozzunk létre egy közös ôst mely elvégzi a legalapvetôbb műveleteket. Legyen ô a TPCXControllbox. Metódusai:

      PPCXControlBox = ^TPCXControlBox;   TPCXControlBox = Object(TStaticText)     constructor Init(P: TPCXPoint);     procedure HandleEvent(var Event: TEvent); virtual;     procedure ExecControlMenuBox; virtual;   private     ControlMenuBox: PPCXMenuBox;   end;

Láthatjuk, hogy ez is, mint a titleline is a TStaticText-bôl származik hisz nem más, mint két - vagy három kiirandó karakter, amihez menüt társítunk. A továbbiakban esetleges menüt a ControlMenuBox változóban tároljuk.

  • Lássuk az objektum init-jét:
    constructor TPCXControlBox.Init(P: TPCXPoint); var   R    : TRect;   TempS: String; begin   ControlMenuBox:=nil;   R.A.X:=P.X; R.A.Y:=P.Y;               R.B.Y:=R.A.Y+1;   if IsPCXGraphCharsOn   then begin          R.B.X:=2;          TempS:=ControlBox;         end   else begin          R.B.X:=3;          TempS:='[X]';        end;   Inherited Init(R, TempS); end;

Láthatjuk, hogy inicializáljuk a ControlMenuBox vátozót. Elôkészítjük az R: TRect változót a TStatusLine örökölt inicializálásához. Az R.A = P. Az-az a koordináták az R. A mezôjében megegyeznek, 1 sor lesz a szélesség.

Ha grafikus kinézetű az applikációnk (az-az használunk karakterátírást) akkor kettô széles a kiirandó szöveg, és a szöveg - pontosabban a kiirandó két karakter - a fent lerajzolt ábra szerint, ill. ha csak sima textmódban vagyunk akkor ugye 3 karakteres, még pedig ez: [X] .

Majd meghívjuk az örökölt TStatusLine init-et.

  • A HandleEvent() metódus:

Ezen view handleevent-je akkor hívódik meg ha rá klikkelünk, vagy forrókulccsal elôhívjük az-az ha fókuszba kerül. Ekkor meg kell jelenni egy menünek amibôl ki lehet választani, hogy milyen műveletet akarok elvégezni.

  • ExecControlMenuBox; metódus:

Ez a virtuális (!) metódus valósítja meg, a menü lefuttatását. Fontos, hogy virtuális legyen, mert akkor az utódok más és más menüket jeleníthetnek meg annélkül, hogy a HandleEvent()-et újra kellene írni.

Ennek a fô objektumnak nem kell ehhez a metódushoz kódot társítania így simán ennyi lesz:

    procedure TPCXControlBox.ExecControlMenuBox; begin   Abstract; end;

Ahol az absztrakt jelzi, hogy még nem használt metódus, majd az utódok használják. Ha mégis meghívnánk szépen leáll runtime error-ral a programunk, figyelmeztetve, hogy ez csak egy absztrakt metódus.

Lássuk a belôle származtatott utódokat, és egynek részletes felépítését. (a többi hasonló analógia alapján felépíthetô). Három utód lesz, a három különbözô használati helyen:

  • TPCXControlBoxApp - az applikáció részére, ezt részletezzük
  • TPCXControlBoxDlg - a dialógusok részére
  • TPCXControlBoxWin - s az ablakok részére

Két metódust kell átírnia az utódnak. Nyilván az új palettát kell a view-hoz rendelni, ill. a MenuBox-ot lefuttatni:

  • Paletta:
    function  TPCXControlBoxApp.GetPalette: PPalette; const P: String[Length(CPCXControlBoxApp)] = CPCXControlBoxApp; begin   GetPalette:=@P; end;

Nyilván virtuális metódus ez is, s a palettául szolgáló konstans az Interface részben van deklarálva. Ennek egy eleme van, mivel ez az applikáció controlbox-a, és ez a címsorban helyezkedik ez azonos színű lesz vele. Ez az egy elem, mint a címsor szine (CPCXTitleBar) a 175. indexre mutat a tulajdonosa, most az applikáció palettájában. Tehát: CPCXControlBoxApp = #175;

A többi ôs is hasonlóan rendeli a controlbox-hoz a palettát, de ott mivel a dialógus ill. az ablak a paletta-tulajdonosa ezért a #34-dik indexre mutat.

  • A MenuBox lefuttatása:
    procedure TPCXControlBoxApp.ExecControlMenuBox; var   R    : TRect;   O    : TPCXPoint;   C    : Word;   Event: TEvent; begin   O.Assign(0,0);   MakeGlobal(O, O);   R.Assign(O.X,O.Y+1,O.X+18,O.Y+7);   New(ControlMenuBox, Init(R, NewMenu(     NewItem('~M~ove', 'Crt-F5', kbCtrlF5, cmMove, hcNoContext,     NewItem('~Q~uit', 'Alt- X', kbAltQ, cmQuit, hcNoContext,     NewLine(     NewItem('~R~efresh', '', kbNoKey, cmRefresh, hcNoContext, nil))))),     nil));   C:=Application^.ExecView(ControlMenuBox);   if C<>cmCancel then   begin     case C of cmMove:               begin                 KeyStrokeToKeyboardBuffer(0, $62);                 Message(Application, evCommand, cmMouseChanged, @Self);               end;               cmRefresh: Application^.ReDraw;               cmQuit   : Message(Application, evCommand, cmQuit, @Self);     end;   end; end;

Láthatjuk ez már egy fokkal szebb.

  • Mivel ez applikáció controllbox-a, így ez a 0, 0 helyen fog elhelyezkedni. Ez a 0, 0 pont lehet logikai ill. általában inkább fizikai is. Megkeressük a 0, 0 logikai (a view-hoz viszonyított) koordinátához tartozó képernyô fizikait, s az O: TPCXPoint-ba tesszük.
    A controlbox-ot inicializáljuk, s elôtte kiszámoljuk a méreteit (R). A rég megszokott módon létrehozzuk a menüt. (menü-elemek beszúrása, stb.)
  • Majd lefuttatjuk a menüt, mint egy sima view-ot. Valahogy kilépünk belôle, vagy úgy, hogy egy menü-elemre enter-elünk, vagy ESC-vel.
  • Ettôl függôen a menüben megadott parancsokat le is kezeljük.
    Általában az applikáció nem move-olható (mozgatható), de azért lehet próbálkozni ...
    Az applikáció újra rajzoltatása, ha esetleg egy view nem tenné meg magától.
    És a kilépés, mely hasznos lehet ... (Az applikációnak küldünk egy üzenetet, hogy ugyan már' öreg lép le ill. ki.)

A többi (a dialógus - ill. az ablak) controlbox menüje annyiban különbözik, hogy az az 1, 0 koordinátán található, ill. azokat lehet is mozgatni. Méghozzá most el is mondom mi van ott feljebb a cmMove:-nál:

KeyStrokeToKeyboardBuffer(0, $62);

  • Ez a sor azt jelenti, hogy a billentyű buffer-be ALT+F5 scan kódját helyezzük ami annyit tesz, mintha lenyomtuk volna az ALT+F5-öt. Egyszerűbb így megoldani, mint eseménnyel.

Nos ezzel persze még nincs vége. Ahhoz, hogy lássunk is valamit a mi sok fáradtsággal elkészített controlbox-unkból, ahhoz létre is kell hozni ôket. Persze mindegyiküket a rá jellemzô helyen. Vegyük egy példát az applikációt:

Az applikáció init-jében (TPCXApplication.Init) simán létrehozzuk, és láthatóvá teszük:

    {...}   New(PCXTitlebar, Init(#3+ApplicationName)); {látható a cím-sor létrehozása}   Insert(PCXTitlebar); {láthatóvá tétele}   P.Assign(0,0); {a controlbox helyének kijelölése}   New(ControlBoxApp, Init(P)); {létrehozása}   Insert(ControlBoxApp); {megjelenítése} {...}

Nos ez mind szép és jó, van már működô controlbox-unk, de mi van a kerettel, ettôl még nem lesz szép menünk, ill. ablakunk.

A menü új keret-karakterekkel történô kirajzolása

Mai témánk utolsó részéhez érkeztünk. Ez lesz tán' a legnehezebb, részint azért mert már a végére elfáradtunk, részint azért mert nagyon régen magyaráztam azokat a rutinokat melyeket az alábbi kódrészlet tartalmaz. (!OLDUSER\all.exe, OOP02.doc).

Nos mivel a menüt akarjuk kirajzoltatni, elôször nézzük meg a Pascal RTL (forráskód) \TV könyvtárában a MENUS.PAS unit-ot mely tartalmazza a TMenuBox objektumot mely, mint vettük egy menüt (egy menü téglalapot) rajzol ki. Tehát nézzük, meg hogy is oldották meg eredetileg, s ezt a forráskódot magunkhoz átmásolva módosítgassuk úgy, hogy szép legyen.

Szerencsénk van minimális átírással elérhetjük azt, hogy szép legyen a menü. Vegyük végig a menü kirajzolásának elvét:

  • Mint ahogy ezt megszoktuk, úgy lesz egy buffer amibe dolgozunk, a kiirandó karaktereket és színüket írjuk, majd ezt a szín-karakter-es buffert iratjuk ki.
  • A TMenuBox.Draw; procedure elején beállítjuk a menü szineit, stb.
  • majd a menü elsô sorát kirajzoltatjuk.
  • ha van menü, tehát PMenu <> nil akkor kirajzoljuk a menü belsejét,
  • majd a menü utolsó sorát.

A menü keretét akarjuk csak modosítani, így csak azt kell átírni a procedure-ában.

Szerencsénkre el van különítve egy rutin mely a buffer-be írja a keretet (ez a Draw procedure-án belűl egy lokális rutin a FrameLine() mely egy sort ír ki a keretbôl, a buffer-be), a képernyôre a DrawLine úgyszint lokális procedure írja ki.

Tehát nekünk a FrameLine rutint kell tanulmányoznunk, lássuk az eredeti lokális rutint:

    procedure FrameLine(N: Integer); const   FrameChars: Array[0..19] of Char = ' é`ùë_û½½ý-í'; begin   MoveBuf(B[0], FrameChars[N], Byte(CNormal), 2);   MoveChar(B[2], FrameChars[N + 2], Byte(Color), Size.X - 4);   MoveBuf(B[Size.X - 2], FrameChars[N + 3], Byte(CNormal), 2); end;

Hogyan működik ?

  • Az elsô sor a MoveBuf a FrameChar tömbbôl, mely a keret karaktereket tartalmazza, a bufferbe másolja az elsô kettôt a helyközt és a keret bal felsô sarkát.
  • A második sor a MoveChar egy karaktert a bal felsô ill. a jobb felsô keretet összekötô kis vonalat: - másolja a tömbbe Size.X-4 db-szor. Azért csak ennyiszer mert a bal felsô keret elôtt egy space van, tehát 4 karakterrel kevesebb összekötô vonal kell.
  • Majd a harmadik sor a jobb felsô keret-karakter írja a bufferbe, nyílván a Size.X-2 -dik pozícióra (mert 0 .. Size.X-1 -ig van) a jobb felsô karaktert, ill, a Size.X-1-re megy egy space-t.
  • És ezzel egy vonal kész. Ha N-re 0 jön akkor a legfelsô menüsor íródik ki.
  • Ha N = 5 akkor a legalsó
  • ha N = 10 akkor egy olyan sor amibe rendes menüszöveg kerül,
  • ha N = 15 akkor NewLine(), tehát elválasztó vonal íródik ki.

Lássuk, hogyan kell módosítani a kiírást:

  • Létre kell hozni egy tömböt ami ugyanígy van felépítve, csak az átírt karakterek ASCII kódját tartalmazza.
  • Ha karakterátírást alkalmazunk használjuk az új tömböt a PCXFrameChars-t, ha nem akkor marad minden a régi.

Lássuk az ezt megvalosító új forráskódot:

    procedure FrameLine(N: Integer); const      FrameChars: Array[0..19] of Char =  = ' é`ùë_û½½ý-í';   PCXFrameChars: Array[0..19] of Char =     GFrameCornerLU+GFrameSummitU+GFrameSummitU+GFrameSummitU+GFrameCornerRU+     GFrameCornerLD+GFrameSummitD+GFrameSummitD+GFrameSummitD+GFrameCornerRD+     GFrameEdgeL+#32#32#32+GFrameEdgeR+     GFrameEdgeL+#32#196#32+GFrameEdgeR; begin   if IsPCXGraphCharsOn   then begin          MoveBuf(B[0], PCXFrameChars[N], Byte(CNormal), 2);          MoveChar(B[2], PCXFrameChars[N + 2], Byte(Color), Size.X - 4);          MoveBuf(B[Size.X - 2], PCXFrameChars[N + 3], Byte(CNormal), 2);        end   else begin          MoveBuf(B[0], FrameChars[N], Byte(CNormal), 2);          MoveChar(B[2], FrameChars[N + 2], Byte(Color), Size.X - 4);          MoveBuf(B[Size.X - 2], FrameChars[N + 3], Byte(CNormal), 2);        end; end;

Hogy is van ez ?

  • Ha nem használunk grafikus (átírt) karaktereket akkor minden marad a régi, ha igen:
  • Nem space-t kell a menü szélére rajzolni hanem rögtön a sarkot, mert így lesz szép. Lássuk:

  • Tehát úgy kell majd megoldani, hogy amikor a régi rutin a tömbbôl space-t akar venni, az már a sarok legyen, s amikor a sarkot akarná akkor már az a felsô összekötô vonalacska legyen: GFrameCornerLU+GFrameSummitU
  • A rendes helyen lehet az összekötô felsô vonalacska amit Size.X-4 -szer másolunk a buffer-be, ez a: GFrameSummitU
  • És végül a jobb felsô sarok: GFrameCornerRU. Ezzel kész is az elsô menüsor kiírása.
  • Az utolsó menüsor kiírása hasonlóan folytatódhat: bal alsó sarok GFrameCornerLD, összekötô vonalacska : GFrameSummitD
  • Majd Size.X-4 szer a GFrameSummitD.
  • Újra egy GFrameSummitD. és a GFrameSummitRD.
  • A rendes szöveg kiírása is hasonlóan történik, a bal felsô csücsköt az alsóval összekötô vonalacska (a GFrameEdgeL) majd a space (#32),
  • ill. ezután SizeX-4 hosszon space kerül másolásra a buffer-be, és végül
  • még egy space a Size.X-2 indexre a bufferbe, és a Size.X-1-re a jobb felsô csücsköt az alsóval összekötô vonalacska, a GFrameEdgeR.
  • Ha NewLine() - elválasztó vonal van akkor a fent elmondottak szerint történik.

Lássuk PCXFrameChars tömb felépítését. Konkretizálom a konstansok nevének logikáját:

  • GFramexxxxxx jelenti, hogy grafikus keret-karakterrôl van szó. Különben ezeket a karaktereket a PCX_DLG.pas Interface-ében deklaráltuk.
  • A GFrameCorner a keret valamely sarkát jelöli. A Corner után az L ill R betűk a Left (bal) ill. Right (jobb) oldali keret-karakterre utalnak.
  • A GFrameSummitU, a felsô sarkokat összekötô vonal ASCII kódja, míg a GFrameSummitD az alsókat köti össze.
  • A menüpont szövegének szélein a keretet GFrameEdgeL ill. GFrameEdgeR karakterek képezik az alsó ill. felsô sarkok között.
  • Az elválasztó vonal olyan, mintha a szöveg mezôben minusz jel, inkább #196 lenne.

Nos most már remélhetôleg minden világos. Ha nem az egyántalát nem baj, mert szerintem a cikk, és az összes forráskód (PCX_APP, PCX_DLG, PCX_UTIL, TVDEMO) együttes figyelésével lehet megérteni. A menü kirajzolásánál ajánlom a debugging-ot (F8 bill.). Következô számunkban remélhetôleg az ablakok - dialógusok szebb kivitelezésérôl beszélgetünk.

Hát ennyi mára, hisz ez már a 9.5-dik oldal. Ha valaki a forráskód részletes átrágása után se értené a dolgok mikéntjét, az eMail-ezzen.

Ízelítôül egy szebb kinézetű program: