Elôzô számunkban már elkészítettük a grafikus kinézetű felhasználói felületünk alapjait: a színek átdefiniálását, karakterek megrajzolását (többek közt a keret-karaktereket, s egyéb apróságokat). Az új keretkarakterekkel megrajzoltunk egy új menüt. Továbbá még a controllbox-ot is elkészítettük, mind az applikáció számára (ekkor systembox), és mind az ablakok - dialógusok számára. Kanyarodjuk vissza az elôzô számunkban elkezdett keretrajzoláshoz. Ha már új menüt rajzoltunk új keretkarakterekkel tegyük ezt meg az ablakokkal is. Tehát elsô harci feladatunk az ablaktnak új keretet adni:

Lássuk az alapjait a TWindow objektumnak, mi is ez valójában:

  • A TGroup view egyik leszármazottja, mely
  • speciálisan több al-view-ot foglal magába, ezek:
  • TFrame objektum, mely általában nem létezik önmagában, csak ablakhoz (ill. dialógusohoz csatolatan),
  • a TScroller objektum mely lehetôvé teszi, hogy nagyobb virtuális ablakfelületet használjunk mint amekkora maga az ablak view. Az ablak ill. a virtuális ablak scroll-ozását - gördítését (szép magyarosan) a:
  • TScrollBar objektum végzi. Ez maga a 'gördítôsáv'. Ebbôl ha nagyobb a virtuális ablak, mint a valós akkor vagy egy, ill. vagy kettô van. Az egyik a vertikális - függôleges, míg a másik a horizontális - a vízszintes.
    (Eredetileg a TWindow-on egy, a vertikális scrollbar mindig látszik, de mi kicsit átalakítjuk, ha nincs rá szükség, ne ormotlankodjon ott.)

Nos e röpke áttekintésbôl láthatjuk, hogy a keret megváltoztatásához a TFrame view-ot kell kicsit átalakítgatni. De elôbb lássuk a keret (frame) és az ablak (window) kapcsolatát, hogy megértsük az összefüggéseket:

  • Mivel az ablaknak subview-ja (al-view-ja) a keret, ezért ô hozza létre, s ô rendelketik felette, úgymond owner-e (tulajdonosa).
  • A keret létrehozását az InitFrame() virtuális metódus végzi. Lényege, hogy a TWindow, publikus Frame változójának adja az általa létrehozott PFrame pointer értéket. Ez a Frame változó csak read/only (olvasható), mi magunk nem adhatunk neki értéket, csak egy ÚJ InitFrame() eljárás implementálásával. A "szerencse" az, hogy az InitFrame() virtuális, így annak új implementálása olyan hatással lesz az új TWindow-ra, hogy annak minden keretet használó metódusa az új keretet fogja használni. (Persze csak idézôjelben szerencse, hisz épp e célt szolgálja a virtuális metódus léte a polymorfizmus részeként. Igaz sajnos a Borland programozói nem tettek minden olyan metódust virtuálissá melyet a programfejlesztô át akarna írni.)

A sok locsogás után lássuk az új keret ablak view-hoz történô hozzárendelését:

  • Elôször is egy új ablak típust kell definiálni, hogy a régit az új metódusokkal megváltoztathassuk. Legyen a neve TPCXWindow, mint a PC-X User hivatalos, és kizárólagos fô ablaka:
    PPCXWindow = ^TPCXWindow; TPCXWindow = Object(TWindow)   constructor Init(var Bounds: TRect; ATitle: TTitleStr; ANumber: Integer);   procedure InitFrame; virtual;   procedure Draw; virtual;   function GetPalette: PPalette; virtual;   procedure HandleEvent(var Event: TEvent); virtual;   function StandardScrollBar(AOptions: Word): PPCXScrollBar; private   ControlBoxWin: PPCXControlBoxWin; end;
  • Elôször nézzük kitüntetett szeretettel az InitFrame() metódust. Az alábbi módon módosítjuk a régi keretet az újra:
    procedure TPCXWindow.InitFrame; var R: TRect; begin   GetExtent(R);   Frame := New(PPCXFrame, Init(R)); end;

Látható, milyen triviális a megoldás, lekérdezzük az ablaktól, hogy hé te épp most mekkora vagy, szebben: az exakt méretek TRect objektumba történô transzlantációjáról van szó. Az új keretet meg ezen méretekkel hozzuk létre, s a létrehozott keret objektum címét az ablak Frame mezôjébe (publikus változójába) másoljuk.

Ez mind szép és jó, de mitôl lesz szép új keretünk. Hát persze elôbb létre kellene hozni mint, hogy dolgoznánk vele:

    PPCXFrame = ^TPCXFrame; TPCXFrame = Object(TFrame)   procedure Draw; virtual;   function GetPalette: PPalette; virtual; private   FrameMode: Word; end;

Nos ezt a típust definiáltuk. Nyílván való hogyha új keretet akarunk akkor annak a keretrajzoló view-nak a Draw metódusát kell újraírni. A paltettát meg azért definiáljuk át, mert újkeret módokat vezetünk be úgy, mint a mozgatott ablak kerete, mely csak színben kölönbözik az aktívtól, nem karakterben, mint a sima TV-ben. A FrameMode mezôt a belsô rutinok használják ezért - is - van privátként deklarálva.

Lássuk a Draw metódust, (az alábbi metódus alapját a BP 7.0 RTL\TV\views.pas file azonos rutinja képezi. Copyright Borland International 1992.) a magyarázat a {} jelek között.

    procedure TPCXFrame.Draw; {var    ... sok kicsi változó deklarációja} begin                               {a színek beállítása következik:}   if State and sfDragging <> 0 then {ha az aplakot éppen mozgatnánk - méreteznénk}   begin     CFrame := $0706;                {a keret és a fejléc színének beállítása}     CTitle := $0007;     F := 0;   end else if State and sfActive = 0 then {ha az ablak inaktív}   begin     CFrame := $0101;                {a keret és a fejléc színének beállítása}     CTitle := $0002;     F := 0;   end else   begin                             {HA aktív az ablak:}     CFrame := $0503;                {a keret és a fejléc színének beállítása}     CTitle := $0004;     F := 9;   end;   CFrame := GetColor(CFrame);       {a keret és a fejléc fizikai színének vissza-}   CTitle := GetColor(CTitle);       { nyerése, a többszörösen indexelt palettából}   Width := Size.X;   L := Width - 10;   if PWindow(Owner)^.Flags and (wfClose+wfZoom) <> 0 then Dec(L,6);   MoveCStr(B, Copy(FrameEmpty, 1, Size.X), CTitle); {feltölti a címsor CTitle színű}   if (PWindow(Owner)^.Number <> wnNoNumber) and     { üres karakterrel }      (PWindow(Owner)^.Number < 10) then   begin                     {itt történik a címsorra az ablak számának kiírása}     Dec(L,4);     if PWindow(Owner)^.Flags and wfZoom <> 0 then I := 7 {persze hacsak zoomolt}     else I := 3;     WordRec(B[Width - I]).Lo := PWindow(Owner)^.Number + $30;   end;   if Owner <> nil then Title := PWindow(Owner)^.GetTitle(L) {ha van néve lássuk.}   else Title := '';   if Title <> '' then  {ha van az ablaknak neve =>}   begin     L := Length(Title);     if L > Width - 10 then L := Width - 10;     if L < 0 then L := 0;     I := (Width - L) shr 1;     MoveChar(B[I - 1], ' ', CTitle, 1); {=> akkor mozgassuk a FrameEmpty-vel feltöltött}     MoveBuf(B[I], Title[1], CTitle, L); {címsorba az CTitle színnel, és rakjunk elé    }     MoveChar(B[I + L], ' ', CTitle, 1); {s mögé egy space-t.}   end;   if State and sfActive <> 0 then  {ha aktív az ablak}   begin     if PWindow(Owner)^.Flags and wfClose <> 0 then {és tulajdonosát nem zárják be}       if FrameMode and fmCloseClicked = 0 then {akkor}         if IsPCXGraphCharsOn {írjuk ki a kontrolbox-ot, text vagy graph módon}         then MoveCStr(B[0], '~'+ControlBox+'~', CFrame) {#209#180}         else MoveCStr(B[1], '', CFrame) {~[n ]~}       else MoveCStr(B[2], '[~'#15'~]', CFrame); {ha textmódban éppen be akarnánk}                                                 {zárni akkor csillag legyen a helyén}     if PWindow(Owner)^.Flags and wfZoom <> 0 then     begin {itt a méret beállító gombok kirajzolása történik. fel-le-vissza}       if IsPCXGraphCharsOn       then MoveCStr(B[Width - 4], '~'+UpWin+'~', CFrame) {grafikus: fel: Ù }       else MoveCStr(B[Width - 4], '~['#24']~', CFrame);  {szöveges: fel: é }       Owner^.SizeLimits(Min, Max);       if FrameMode and fmZoomClicked <> 0 then         WordRec(B[Width - 4]).Lo := 15       else if Longint(Owner^.Size) = Longint(Max) then       begin {ha maximális az ablak mérete akkor vissza az elôzô állapotba}         if IsPCXGraphCharsOn         then MoveCStr(B[Width - 4], '~'+RestoreWin+'~', CFrame) {graf, visza: u }         else MoveCStr(B[Width - 4], '~['#18']~', CFrame);       {text, visza: u }       end;     end;   end;   WriteLine(0, 0, Size.X, 1, B);   for I := 1 to Size.Y - 2 do   begin                              {ez a sor rajzolja a menühöz hasonlóan}     if IsPCXGraphCharsOn             {a bal - jobb oldali keretet          }     then MoveCStr(B, GFrameEdgeL+Copy(FrameEmpty, 1, Size.X-2)+GFrameEdgeR, CFrame)          {a fenti a grafikus, a lenti a text karakterekkel rajzolódik ki}     else MoveCStr(B, #221+Copy(FrameEmpty, 1, Size.X-2)+#222, CFrame);     WriteLine(0, I, Size.X, 1, B); {kiírja a képernyôre}   end; {ez a sorok száma - 2-ször íródik ki a képernyôre}   if IsPCXGraphCharsOn {a keret legalsó sora: balalsó sarok ilyen vonal: ___, jobbsarok}   then MoveCStr(B, GFrameCornerLD+Copy(GFrameDown, 1, Size.X-2)+GFrameCornerRD, CFrame)   else MoveCStr(B, {#221+} Copy(FrameDown{FrameFull}, 1, Size.X) {+#222}, CFrame);   if State and sfActive <> 0 then {ha aktív az ablak:}     if PWindow(Owner)^.Flags and wfGrow <> 0 then       if IsPCXGraphCharsOn       then MoveCStr(B[Width - 2], WindowSizer, CFrame) {#210#211} {Az ablak méretezô}       else MoveCStr(B[Width - 2], '~ÄŮ~', CFrame);                {ikon}   WriteLine(0, Size.Y - 1, Size.X, 1, B); {kiírás}   Message(Application, evCommand, cmMouseChanged, @Self);     {esemény küldése, hogy    }   Message(Application, evCommand, cmPCXFrameChanged, @Self);  {megváltozott a keret és  }   Message(Application, evBroadcast, cmPCXFrameChanged, @Self);{a mouse alatti terület is} end;

Átírtuk, kicsit leegyszerüsítettük, így kaptuk ezt. Hát így működik az ablak szép új kerete. A TPCXWindow Init-jét azért írtuk újra, hogy a controllbox-ot hozzáadjuk. A Draw metódust pedig azért, hogy késôbb a mouse-nak jelezni tudjuk, hogy újra kellene rajzolni. A HandleEvent()-et szintén a controllbox miatt írtuk át, hogy az ALT+SPACE kombinációra reagáljon az ablak. A StandardScrollbar() rutint pegig csak a késôbbiekben írjuk át - ill. ekkor tárgyaljuk - mikor a scrollbar-ról (gördítôsáv) lesz szó.

Három színű ablak lesz: kék (általános), piros (hibát jelzô), és szüre.

Ezeknek csak a palettájukat kell átírni így:

    type PPCXBlueWindow = ^TPCXBlueWindow; TPCXBlueWindow = Object(TPCXWindow)   function  GetPalette: PPalette; virtual; end; PPCXRedWindow = ^TPCXRedWindow; TPCXRedWindow = Object(TPCXWindow)   function  GetPalette: PPalette; virtual; end; PPCXGrayWindow = ^TPCXGrayWindow; TPCXGrayWindow = Object(TPCXWindow)   function  GetPalette: PPalette; virtual; end;

A paletta átírás implementálása a PCX_DLG.pas unit-ban van. Nem írom le mert már ezerszer átrágtuk magunkat. A lényeg, hogy az applikáció palettájára hivatkozó palettát kell létrehozni.

Ha már az ablakokat kiveséztük lássuk kisöccsüket a Dialógusokat, ez a TDialog ősból ered.

Lássuk alapvetô tulajdonságaikat:

  • A TWindow-ból ered.
  • Arra szánták, hogy controll-okat tartalmazzon, s a tényleges mérete megegyezik a virtuális ablakmérettel.
    A TWindow-hoz képes az eltérések:
  • A GrowMode: Byte = 0 az-az nem méretezhetô,
  • A Flag-ok tekintetében: a wfMove és wfClose beállított az-az mozgatható és becsukható.
  • A TDialog HandleEnvent()-je a TWindow.HandleEvent()-bôl származik míg ugyanúgy lekezeli az ESC-et amire cmCancel-t és az ENTER-t amire cmDefault-at generál.
  • A Dialógusoknak nincs 'ablakszáma'.
  • A TDialog.Valid() metódusa ugyanúgy működik, mint a TGroup.Valid() és cmCancel-re mindig True-t ad vissza.

Lássuk a típus definíciót:

    PPCXDialog = ^TPCXDialog; TPCXDialog = Object(TDialog)   constructor Init(var Bounds: TRect; ATitle: TTitleStr);   procedure InitFrame; virtual;   procedure Draw; virtual;   function GetPalette: PPalette; virtual;   procedure HandleEvent(var Event: TEvent); virtual; private   ControlBoxDlg: PPCXControlBoxDlg; end; PPCXBlueDialog = ^TPCXBlueDialog; TPCXBlueDialog = Object(TPCXDialog)   function  GetPalette: PPalette; virtual; end; PPCXRedDialog = ^TPCXRedDialog; TPCXRedDialog = Object(TPCXDialog)   function  GetPalette: PPalette; virtual; end; PPCXGrayDialog = ^TPCXGrayDialog; TPCXGrayDialog = Object(TPCXDialog)   function  GetPalette: PPalette; virtual; end;

A TWindow()-hoz hasonlóan az InitFrame()-et átírjuk. A TPCXDialog Init-jét azért írtuk újra, hogy a controllbox-ot hozzáadjuk. A Draw metódust pedig azért, hogy késôbb a mouse-nak jelezni tudjuk, hogy újra kellene rajzolni. A HandleEvent()-et szintén a controllbox miatt írtuk át, hogy az ALT+SPACE kombinációra reagáljon az ablak.

Itt is létrehozunk kék - piros - szürke dialógusokat.

Következô számunkban a TPCXButton-nal kezdünk, s ígérem kicsit bôvebb leszek.