Grafikus template könyvtár

Sulyok Péter

programtervező matematikus

nappali tagozat

témavezető: Porkoláb Zoltán

EÖTVÖS LORÁND TUDOMÁNYEGYETEM
INFORMATIKAI KAR

SZAKDOLGOZAT-TÉMA BEJELENTŐ

Név:	Sulyok Péter
Tagozat:	nappali	Szak:	programozó matematikus
Témavezető neve:	Porkoláb Zoltán
munkahelyének neve és címe:	ELTE IK Programozási Nyelvek és Fordítóprogramok Tanszék
beosztása és iskolai végzettsége:	adjunktus, Ph.D.
A dolgozat címe:	Grafikus template könyvtár
A dolgozat témája: A generatív programozás új, elterjedőben lévő programozási paradigma, melynek egyik leggyakrabban használt példája a szabványos C++ STL könyvtár. Elve szerint az adatszerkezetek és a rajta alkalmazott algoritmusok nem osztályok­ban kapcsolódnak össze, hanem ortogonálisak: (majdnem) tetszőleges algoritmus végrehajtható az összes adatszerkezeten. A módszer alkalmazhatóságát egyelőre kevés alkalmazás bizonyítja. Koráb­ban kísérleti jelleggel létrejött egy generikus elvű könyvtár (GTL), mely alakzatok és a rajtuk végzett általános algoritmusok gyűjteménye. E szakdolgozat célja a GTL új­ragondolása, kiterjesztése, és a könyvtár alkalmazhatóságát bizonyító grafikus alkal­mazás kifejlesztése.
A témavezetést vállalom:
	.................................................... (a témavezető aláírása)

Kérem a szakdolgozat témájának jóváhagyását.

Budapest, 2004. október 15.

	.................................................... (a hallgató aláírása)

A szakdolgozat-témát az Informatikai Kar jóváhagyta.

Budapest, 2004. ……………			
	......................................................
	Dr. Kozma László
	dékán

Felhasználói dokumentáció

Bevezetés

A feladat egy olyan rajzoló alkalmazás elkészítése, ami messzemenőkig kihasz­nálja a generikus grafikai programkönyvtár nyújtotta lehetőségeket.

Az alkalmazás a grafikus munkaasztalon fut, és tartalmazza a korszerű grafikus felületi elemeket: menü, eszköztár, vászon, állapotsor. A vezérlés nagy mértékben tá­maszkodik az egér és egyéb mutató eszközök használatára.

A feladat tulajdonképpen egy vektorgrafikus rajzoló elkészítése, ami tárgyakat – vonalakat, köröket, stb. – kezel; illetve ezeken a tárgyakon végez el műveleteket mint mozgatás, elforgatás, átméretezés, nyújtás, stb.

A rajzalkalmazások két nagy osztályba sorolhatók:

képmanipuláló programok: egy képpontból és rétegből álló objektumot kezel­nek, ahol a képpontok tulajdonsága a színe és átlátszósága. Jellemző műveletek a képpontok színének, átlátszóságának megváltoztatása.

vektorgrafikus alkalmazások: koordinátáikkal megadott kettő vagy három dimenziós ob­jektumokat kezelnek, jelenítenek meg. Jellemző műveleteik a jelenetek beállítására va­lók: elforgatás, eltolás, leképezés síkra.

A felhasználói felület

1. ábra: A Qdraw alkalmazás fő ablaka Ahogy a mellékelt ábra is mutatja a program felülete – felülről lefelé haladva – fej­lécből, menüből, eszköztárból, rajzvászonból (ennek része a vízszintes és a függőleges gör­dítősáv) és állapotsorból áll.

A rajz (dokumentum) fájlból történő be­töltésére illetve fájlba történő kimentésére külön ikonok vannak a menü alatt található eszköztár­ban. A többi művelet: a kilépés, új ablak nyitása a Fájl menüben; alakzatok rajzolása az Alakzatok menüben; alakzatok megváltoztatása a Művelet menüben található menüpontok kivá­lasztásával lehetséges.

Ezek részletes tárgyalása a következő fejezetekben történik.

A rajzvászon rögzített méretű, és az ab­lak átméretezésével sem növekszik. Ha az al­kalmazás ablaka kisebb, mint a vászon mérete, akkor a gördítősáv segítségével jeleníthe­tik meg a rajz különböző részeit.

Az állapotsorban, mindig az aktuális, vagy az utoljára végrehajtott műveletről szó­ló tájékoztató szöveg jelenik meg. Ezáltal tudhatja a felhasználó, hogy például az egér jobb gombjának a megnyomásának éppen milyen következménye van.

2. ábra: A Fájl menü Fájlműveletek

Új ablak nyitása

Lehetőség van egyszerre több kép szer­kesztésére is. Ehhez válassza ki a Fájl menü Új menüpontját, vagy használja a Ctrl+N billentyű­kombinációt!

Több nyitott ablak közül egy bezárása a Fájl menü Bezárás menüpontjának kiválasztá­sával, vagy a Ctrl+W billentyűkombináció lenyo­másával történik. Amennyiben az ablakkezelő témája tartalmazza az ablak bezáró gombját – az ábrán egy X a jobb felső sarokban –, akkor annak a gombnak a megnyomásával is bezárható az ablak.

Az alkalmazás összes ablakának bezá­rása, egyben az alkalmazásból való kilépés a Fájl menü Kilépés menüpontjával vagy a Ctrl+Q billentyűkombinációval lehetséges.

Dokumentum betöltése

Egy korábban fájlba mentett dokumentum betöltése a Fájl menü Megnyitás me­nüpontjának kiválasztásával történik.

3. ábra: A Megnyitás dialógus A betöltendő fájlt a felbukkanó fájl megnyitása című párbeszéd dobozban levő listában történő tallózással, fájlnév címkéjű beviteli sor kitöltésével, majd az Megnyitás gomb vagy az Enter megnyomásával választhatjuk ki. Ha a felhasználó meggondolja ma­gát, akkor az Esc billentyű vagy a Mégsem gomb megnyomásával visszatérhet az aktuális rajz szerkesztéséhez.

Az alkalmazás csak a saját XML formátumú dokumentumait képes betölteni. A be­töltéskor az ablakban esetlegesen meglévő objektumok törlésre kerülnek, majd létrejön­nek a betöltött adatok alapján az új objektumok.

Dokumentum mentése

Az aktuális rajz egy új fájlba történő mentése a Fájl menü Mentés másként me­nüpontjának kiválasztásával történik. Ha még egyetlen egy mentés sem történt, és nem egy korábban kimentett rajz betöltése után választja ki a felhasználó a Mentés menüpon­tot, vagy az eszköztár mentés ikonját, akkor is a következő párbeszéd doboz jelenik meg:

Itt a betöltéshez hasonlóan adhatja meg a fájl nevét a Fájl neve címkéjű beviteli sorban, vagy a listából egy elemet kiválasztva.

4. ábra: A Mentés másként dialógus A kiválasztás vagy fájlnév megadása után a Mentés gomb vagy az Enter billentyű megnyomásával fejezheti be a műveletet, illetve félbehagyhatja ha az Esc billentyűt vagy a Mégsem gombot nyomja meg.

Alakzatok

Vonal

5. ábra: Alakzatok menü Törött egyenes vonal rajzolásához válassza ki az Alakzatok menüből a Vonal menüpontot! A bal egérgombbal a vászonra kattintva adhatja meg a vonal pontjait, majd a jobb egérgomb lenyomására a program rögzíti a vonal adatait, és befejezi a rajzolás műveletét.

A vonal a töréspontokat jelölő kicsi négyzetekből, és a töréspontokat összekötő egyenesekből áll. Műveletek elvégzésekor vonalat kiválasztani a vonal egyik töréspontjára – a bal egérgombbal – történő kattintással lehet.

Kör

Körlap rajzolásához válassza ki az Alakzatok menüből a Kör menüpontot! A kör egy átmérőjét kell megadni a bal egérgombbal kettőször a vászonra kattintva. Ezután a program magától befejezi a rajzolás műveletét, és rögzíti a megadott adatokat.

A kör az egyik átmérőjét jelölő kettő kicsi négyzetből, és kör területét kitöltő mintá­zatból áll. Műveletek elvégzésekor kört kiválasztani az egyik négyzetre – a bal egérgomb­bal – történő kattintással lehet.

Műveletek

Eltolás

Egy tárgy eltolásához válassza ki a Műveletek menüből az Eltolás menüpontot! Vigye az egérkurzort az eltolandó tárgy egyik pontját reprezentáló négyzetecskére! Nyomja le a bal egérgombot! Ekkor a tárgy az egérkurzorral együtt mozog, amíg az egérgomb lenyomott állapotban marad. Miután felengedi, a tárgy új koordinátái rögzülnek, és befejeződik a művelet.

Elforgatás

Egy tárgy elforgatásához válassza ki a Műveletek menüből az Elforgatás menü­pontot! Vigye az egérkurzort az elforgatandó tárgy egyik pontját reprezentáló négyzetecs­kére! Nyomja le a bal egérgombot! Ekkor a tárgy az egérkurzorral együtt mozog, amíg az egérgomb lenyomott állapotban marad. Miután felengedi, a tárgy új koordinátái rögzülnek, és befejeződik a művelet.

Átméretezés

Egy tárgy átméretezéséhez válassza ki a Műveletek menüből az Átméretezés menüpontot! Vigye az egérkurzort az átméretezendő tárgy egyik pontját reprezentáló négyzetecskére! Nyomja le a bal egérgombot! Ekkor a tárgy az egérkurzor mozgásával együtt változik, amíg az egérgomb lenyomott állapotban marad. Miután felengedi, a tárgy új koordinátái rögzülnek, és befejeződik a művelet.

Nyújtás

Egy tárgy nyújtásához válassza ki a Műveletek menüből a Nyújtás menüpontot! Vigye az egérkurzort az nyújtandó tárgy egyik pontját reprezentáló négyzetecskére! Nyomja le a bal egérgombot! Ekkor a tárgy az egérkurzor mozgásával együtt változik, amíg az egérgomb lenyomott állapotban marad. Miután felengedi, a tárgy új koordinátái rögzülnek, és befejeződik a művelet.

6. ábra: A Súgó menü Súgó

A felhasználói dokumentációt tartalmazó súgó nincs megvalósítva az alkalmazásban. Azonban van egy az egyes felületi elemekről rövid leírásokat adó funkció, ami a Súgó menü Mi ez menüpontjának kivá­lasztásával, illetve a Shift+F1 billentyűkombináció lenyomásával, vagy az eszköztárban a nyilat és kérdőjelt ábrázoló nyomógombra kattintva aktíválható.

Ekkor az egérkurzor mellett megjelenik egy kérdőjel jelezvén, hogy a „Mi ez” funkció aktív. Ezután kell az egérrel a kívánt felületi elemet kiválasztani, amire egy tipp ablakocskában megjelenik a leírás.

Az alkalmazás tartalmaz névjegyet is, amely szokás szerint a Súgó menüből a Névjegy menüpont kiválasztásával, vagy az F1 billentyű lenyomásával érhető el.

8. ábra: A Qt névjegye 7. ábra: A Qdraw névjegye Az alkalmazás szintén tartalmazza a QT eszközkészlet névjegyét is, amelyet a Qt névjegye menüpont kiválasztásával tekinthetnek meg.

Fejlesztői dokumentáció

A feladat

A probléma lényege hogy grafikus alakzatok (egyenes, kör, stb.) adatait kell tárol­ni, és azokon különféle műveleteket (eltolás, elforgatás, stb.) kell végrehajtani. A megol­dás során törekedni kell arra, hogy a rendszert a lehetőleg meglévő alakzatok illetve mű­veletek implementációjának változtatása nélkül lehessen bővíteni újabb alakzatokkal és műveletekkel.

Kitekintés

Az előzőekben megfogalmazott feladat megoldására alapvetően kétféle megoldás terjedt el különféle programkönyvtárak formájában:

„canvas” objektumok: általában grafikus felhasználói felületek készítésére kifejlesztett eszközkészletek része, amihez néhány egyszerű osztály tartozik (pl. egyenes, ellipszis), néhány az adott osztályra jellemző művelettel.

OpenGL-szerű API-k: koordinátákkal megadott objektumokat jelenítenek meg hardve­res támogatással, azaz egy grafikus processzor végzi el a három dimenziós jelenet le­képezését a képernyőre.

Módszerek

Az alkalmazás „lelkét” a Standard Template Library mintájára készült Graphical Template Library [GTL] újragondolásával készített saját adatszerkezetek és algoritmusok valósítják meg.

Objektum-orientált vagy generikus megközelítés?

A napjainkban leggyakrabban használt objekum-elvű megközelítésben a feladat megfogalmazásában szereplő mondatok elemzésével meghatározott objektumokat a tu­lajdonságaikkal és műveleteikkel osztályokba sorolják. Ez az osztályok zárt egységek, egyfajta „fekete dobozok”, amelyek tulajdonságait csak a kiviteli felületükön deklarált mű­veletekkel lehet megváltoztatni, illetve elérni.

Egy másik megoldás az, hogy az adatszerkezetek és a hozzájuk tartozó műveletek nem képeznek zárt egységet, hanem bizonyos mértékig bele lehet látni, és csak az adatszerkezet integritása miatt korlátozzák az attribútumokhoz való hozzáférést. Ez esetben az adatszerkezeteken általános (generikus) algoritmusokkal hajtanak végre műveleteket, amelyek jóval rugalmasabbak az újrafelhasználás tekintetében.

Generikus előnyök

A generikus megoldás előnye az objektum-elvűvel szemben a forráskód méretében illetve bonyolultságában nyilvánul meg. Tegyük fel, hogy van darab adatszerkezet és minden egyes adatszerkezethez van darab művelet. Ez az első esetben – az implementált műveletek számát tekintve – bonyolultságú programkönyvtárt eredményez, mivel minden egyes műveletet a saját osztályában kell megvalósítani. Ugyanez a második megoldásban csak bonyolultságú, mivel ugyanazokat a műveleteket lehet használni minden egyes adatszerkezetre.

További előny a könnyebb kezelhetőség. Az egymással laza kapcsolatban levő algoritmusok és adatszerkezetek egymástól független építőelemek, amelyek többféle kombinációban fordulhatnak elő, mint a hagyományos összetevők.

A fordítási idejű mechanizmusokat kihasználva megvalósíthatók általános algoritmusok a hatékonyság csökkenése nélkül is. Ez lényegesen különbözik a C++-ban szokásos kevésbé hatékony programkönyvtáraktól, amelyek rendszerint bonyolult származási hierarchiákat, illetve számos virtuális műveletet, futási idejű típusazonosítást, dinamikus osztályzást alkalmaznak.

Példák

A generikus programozás terén számos megoldás született a legkülönbözőbb problémákra. Ilyenek például:

C++ Standard Template Library: klasszikus adatszerkezetek, algoritmusok gyűjteménye, és néhány C++-specifikus dolog (memóriakezelés) [STL], [TC++PL]

Loki: Generikus „tervminták”, azaz generikus komponensek halmaza gyakran visszatérő tervezési feladatokra. [Loki], [MC++D]

The ADAPTIVE Communication Environment (ACE): szoftveres kommunikáció gyakori eseteinek a megvalósítása. Címszavakban: eseménykezelés, szignálok kezelése, folyamatok közötti kommunikáció, osztott memóriakezelés, üzenet-útválasztás, konkurens végrehajtás és szinkronizáció, stb. [ACE]

Boost: felsorolhatatlanul sok generikus programkönyvtár gyűjteménye a legkülönfélébb problémákra. Célja: „létező gyakorlat” és referencia-alkalmazások megteremtése, a szabványosítás érdekében. [Boost]

Az első Graphical Template Library (GTL)

Grafikus objektumokat (kör, poligon, stb.) manipulál generikus algoritmusok (mozgatás, forgatás, tükrözés, nagyítás, stb.) felhasználásával az C++STL mintájára. A GTL megvalósításának céljai a következők voltak:

egy könnyen érthető, de nem triviális programkönyvtár definiálása, amelyen világosan látszanak a generikus megoldás előnyei,

a feladat korlátozása az implementáció-specifikus elemek minimalizálása érdekében,

egy valós feladat megoldása: ez lehet egy rajzoló eszköz (mint pl. az xfig) motorja.

Ezt a változatot Kisteleki Róbert készítette 1999-ben.[GTL] A jelen szakdolgozat célja egyrészt a programkönyvtár újragondolása és továbbfejlesztése; valamint egy alkalmazás készítése, ami bizonyítja a módszer működőképességét, és lehetővé teszi e témában a további vizsgálódást.

Bonyolultság

Az objektum-orientált programozásról szóló tankönyvek példáiban a grafikus objektumokat egyetlen egy közös szülő osztályból származtatják. Ebben az osztályban leginkább csak tiszta virtuális műveletek vannak. E minta szerint a műveleteket a leszármaztatott osztályokban valósítják meg.

GTL-ben nincs közös szülő osztály. Minden grafikus osztály definiál egy iterátor osztályt, ami biztosítja a hozzáférést az adatokhoz az algoritmusok számára. Ez redukálja a bonyolultságot -re. Ennek kapcsán felmerül egy probléma is: hogyan lehet dinamikusan kezelni olyan objektumokat, amiknek az osztályát futási időben ismerjük fel, anélkül, hogy futási időben osztályoznánk (casting) őket?

Az objektum-orientált megoldást a generikus minta szerint átalakítva – nem virtuális műveletekkel és virtuális iterátor-műveletekkel a szülő osztályban – elérhető a generikus megoldás bonyolultsága. Azonban új művelet implementálásakor a szülő osztályt kell módosítani, amire a GTL-ben nincs szükség, csak a művelet megvalósítására. Ezáltal a karbantartás illetve a továbbfejlesztés kevésbé bonyolult a generikus megoldás esetében.

Közös alaposztály

A GTL első változatában nem volt megvalósítva a „composite” osztály. Azonban a leírásában kifejtésre került egy megoldás:

A composite osztály grafikus objektumokat gyűjt össze. A composite osztály iterátorát úgy implementálják, hogy minden iteráció az egyik tartalmazott objektum iterátorát adja vissza. Itt egy algoritmus (például egy mozgatás művelet) egy composite objektumra meghívva bejárja a tartalmazott objektumokat és minden egyes tagobjektumra meghívja önmagát. A rekurzió akkor áll le amikor egy „levélen” hajtanák végre a műveletet. Ez persze nem igazi rekurzió, hanem a template-függvény paraméterének rekurzív feloldása, ami fordítási időben történik, ezért nincs futási idejű költsége.

A composite objektumon belül szükséges a tartalmazott objektumok iterátorait tárolni, amit a típusbiztos módon közös ősiterátor-osztály megvalósításával lehet megvalósítani. Ez visszavezet az objektum-orientált megoldás közös alaposztályának fogalmához.

Mindemellett ezzel a módszerrel minden műveletnek meg kell valósítani a composite objektumot bejáró változatát is. Ekkor a műveletek száma megduplázódik. A composite és nem-composite algoritmusokat, persze össze is lehet vonni egy függvénybe, de ez a kód hosszát nem csökkenti. Sőt még egy futás közbeni típusellenőrzést illetve egy elágazást is igényel. Ha mindez túl körülményesnek tűnik, az némiképp magyarázatot ad arra, hogy miért nem implementálták a composite osztályt.

Iterátorok

Az STL tartalmaz input vagy output, egyirányú, több irányú, direkt elérésű iterátorokat. Ezek mindegyike rendelkezik az őt megelőzők funkcionalitásával. Például egy több irányú iterátor egyben egyirányú iterátor is. Az STL mindezt absztrakt osztályokból illetve felületekből való származtatási hierarchiába rendezés nélkül teszi, mivel az iterátorai egymás funkcionalitásának tartalmazásából következően megvalósítanak egy közös felületet származtatás nélkül is.

A GTL állítólag az előbbiektől különböző iterátorokkal rendelkezik: vannak benne egyirányú, több irányú, ciklikus, direkt elérésű iterátorok. A ciklikus iterátorokra a magyarázat az, hogy zárt objektumoknál a kezdőpont és végpont megegyezik. (Persze megkérdőjelezhető, hogy célszerű-e megkülönböztetni ilyen fajta objektumokat.) A szabályos poligonok pontjai pedig egyfajta direkt iterátorral érhetők el, mert ezek két pontjából meghatározható az összes többi. Azaz csak kettő pont koordinátáit érik el (tárolják), a többit kiszámolják. Az persze kétséges, hogy egy ilyen ábrázolás miatt érdemes-e új iterátort bevezetni, vagy az objektum adatainak másik típusra való átalakításakor célszerű a „hiányzó” pontok kiszámítása.

További speciális – például párhuzamos feldolgozást támogató – iterátorok megvalósítását is érdemes megfontolni.

Eredmények és további tervek

A GTL egy működő programkönyvtár. Tanulságos a generikus programozás és az objektum-orientált tervezés kapcsolatát tekintve, illetve nagyon hasznos oktatási célból is. Jó példa arra, hogy a generikus programozás módszerei nem csak egy programkönyvtár létrehozásához (STL) használható, hanem általánosabban többféle feladatra is alkalmazható.

A további vizsgálódások négy fő iránya:

GTL kiterjesztése, újragondolása, composite típus megvalósítása, GUI és rajzoló alkalmazás megvalósítása (ez a jelen szakdolgozat témája),

új feladatok megfogalmazása, kifejezetten generikus megoldás céljából,

az objektum-orientált tervezés és a generikus programozás közötti kapcsolat vizsgálata, ez tartalmazza a GTL implementálását a Bonyolultság szakaszban leírtak szerint. E kettő megoldás összehasonlítása bonyolultság, módosíthatóság és hatékonyság szerint.

a generikus megoldások párhuzamosításának vizsgálata, például párhuzamos for_each() művelet megvalósításával.

Az új GTL

A Graphical Template Library (GTL) új változata, amit ebben az alkalmazásban használtam fel több ponton lényegesen eltér az előzőtől. A változtatások céljai:

az STL adatszerkezeteinek és iterátorainak lehető legnagyobb mértékű kihasználása, hogy ne találjam fel újra a kereket,

composite típus megvalósítása az egyszerűségre törekedve

az adatszerkezetek kialakítása úgy hogy futási időben dinamikusan és hatékonyan kezelhetők legyenek.

A legnagyobb különbség a korábbi változathoz képest, hogy nincsenek benne iterátorok megvalósítva – legalábbis az alapvető grafikus objektumok osztályaiban. Nincsenek külön input és output iterátorok sem. Ennek a megoldásnak a kulcsa, hogy az objektumok kizárólag egyetlen egy STL-tartályt (leginkább a vector típust) használnak az adataik tárolására – mivel kizárólag néhány pont koordinátáit tárolják, amelyekkel leírható az adott objektum –, amihez van az STL-ben definiált iterátor. Az objektumok egyszerűen csak visszaadják bennük levő STL-tartály iterátorát. Az osztályok saját névtereiben levő tagiterátorok pedig csak álnevek az STL-iterátoraira.

Ebből következik, hogy az új változat forráskódjának hossza csak – az adatszerkezeteket tekintve – töredéke az előzőének.

Az algoritmusokat tekintve az új GTL szintén jobban támaszkodik az STL-re mint az elődje: korábban a GTL-ben volt megvalósítva például a for_each() és find() algoritmus, most már viszont a STL algoritmusait használják a GTL műveletei is. Már egyetlen egy algoritmus sincs duplikálva.

Composite

A composite objektum megvalósítása eltér a korábban felvázolt tervtől. Nem az algoritmusok működnek rajta a többi objektumtól eltérő módon, hanem egy speciális iterátora van, ami a composite objektum által tartalmazott objektumok iterátorait adja vissza szimulálva az egyszerű objektumok viselkedését. Ezért az egyszerű objektumokra használt műveletek változtatás nélkül használhatók a composite objektumokra is.

Ennek kapcsán felmerül egy – a jelenlegi GTL-ben megoldatlan – probléma, a műveletek értelmezése különféle objektumokra, illetve az emiatt fellépő inkompatibilitás az objektumok között.

Például a nyújtás művelet egy adott objektum koordinátáinak egy az argumentumként megadott vektorra merőleges egyenestől mért távolságát változtatja a vektor hosszának megfelelő tényezővel, azaz az illető egyenesre merőleges irányban mozgatja el az adott pontokat. Ez a művelet jól működik pontokra, egyenesekre, általános poligonokra. Nem értelmes azonban szabályos poligonokra és körre:

Ha a szabályos poligonokat vagy köröket 2 pontjukkal ábrázoljuk, akkor a nyújtás művelet rajtuk elvégezve valójában egy átméretezés lesz. Ez a megoldás van jelen most a GTL-ben.

Ha redundáns módon a szabályos poligonokat általános poligonokként az összes csúcsukkal ábrázoljuk, akkor a nyújtás művelet elvégzésével általános poligonokká válnak.

Ha a köröket általános poligonokkal közelítjük nyújthatóvá válnak, persze nyújtás művelet után azok már nem körök lesznek. Másrészről a megkívánt pontosság eléréséhez a közelítő megoldás memóriaigénye nagyságrendekkel több lehet annál, ha köröket és egyéb speciális görbéket néhány koordinátával megadott polinomokkal írunk le.

Generikus dekompozíció

Az előző szakaszban felvetett problémára egy lehetséges megoldás az ún. policy alapú osztályok kialakítása. [MC++D]

A policy-k az STL traits osztályaihoz hasonlóan felületeket valósítanak meg, amiket ún. gazdaosztályokhoz (host) adnak hozzá. A különbség közöttük az, hogy míg a traits osztályokban a típusra helyezik a hangsúlyt, a policy-k esetében viselkedési minták megvalósításáról van szó.

Ha az algoritmusokat, tehát a grafikus objektumokon értelmezett műveleteket policy-kben implementálnák, míg a lineáris algebrát traits-ekben, akkor minden objektumon csak a rá értelmezhető műveleteket lehetne végrehajtani.

A szokásos megoldás az, hogy a traits-eket és a policy-ket paraméterként átadják gazdaosztályoknak, miközben azokat a gazdaosztályokat a saját paramétereikből származtatják.

E trükknek van még egy további előnye is. A GTL eddigi változatai egy kettő dimenziós ortogonális rendszert adnak. (Az osztályok és a műveletek ortogonálisak ha függetlenek egymástól.) Ez azt jelenti, hogy a tetszőleges művelet tetszőleges objektumon végrehajtható, ellentétben az objektum-orientált tanpéldával, ahol minden osztálynak saját műveletei vannak. Az osztályok viselkedésének és tulajdonságainak vizsgálatával ha sikerül többféle szempont alapján egymástól függetlenül külön-külön komponensekre bontani az egyes traits-eket illetve policy-ket, akkor kettőnél több dimenziójú ortogonális rendszert lehet létrehozni. Így a programkönyvtár bonyolultsága nem egyszerűen -ről -re csökkenne, hanem dimenzió esetén -ről -re.

E bevezető magyarázat nem konkrétan a jelen alkalmazás leírása, hanem a kevésbé megszokott megoldás megértésének megkönnyítését szolgálja. Az igazi leírás a következő fejezetekben található.

A GTL programkönyvtár

9. Ábra: A GTL osztálydiagramja Statikus nézet

A grafikus felület mögött dolgozó „motor” a GTL programkönyvtár. Jelenleg három fő komponensből áll, amelyek egymástól függetlenek. Tehát bármelyik a másik kettő változtatása nélkül megváltoztatható, bővíthető, vagy helyettesíthető egy kompatibilis felületű osztályokból álló komponenssel.

Ezek a komponensek a következők:

vertex osztály (lineáris algebra), vertex_array osztály és leszármazottai a grafikus objektumok reprezentációi

algorithm modul: ez tartalmazza az objektumok műveleteit, az algoritmusokat

composite és composite_iterator osztály: az összetett objektumok megvalósítása

Az előző oldalon egy UML osztálydiagrammal kíséreltem meg szemléltetni a GTL statikus szerkezetét. A diagram nem felel meg teljesen az UML szabványnak, például az algorithm nem osztály, hanem egyszerűen csak paraméteres függvények halmaza…

Úgy tűnik az ábrán az összefüggések hiányoznak, például nem derül ki, hogy mi a kapcsolat az algorithm „osztály” és a másik két componens között. A kapcsolatot az algorithm modulban levő függvények paramétere jelenti, ami C++-ban implicit, tehát nem jelenik meg függvényhíváskor, hanem a fordító e paraméter alapján specializálja a függvényt. Így minden egyes hivatkozott függvény-osztály párra létrejön az adott osztályhoz tartozó művelet.

Az algoritmusok (műveletek) szempontjából teljesen mindegy, hogy egy egyszerű objektumra hívják meg, vagy egy composite típusúra. A műveletek működéséhez kettő szükséges feltétel van:

az objektumoknak kell legyen egy iterátora a szokásos begin() és end() műveletekkel, amik az adatszerkezet bejárásához szükségesek,

az objektumok adataira – amik az iterátorokkal elérhetők – a lineáris algebrai műveletek értelmezett kell legyenek.

Az egyszerű objektumokat megvalósító komponens már összetettebb, több paraméteres osztályt tartalmaz, amelyek között UML-ben is ábrázolható összefüggések vannak.

A vertex osztály valósítja meg a lineáris algebrából ismert vektor típust és műveleteit. Az osztály paramétere egy számtípus kell legyen, aminek a megválasztásával a memóriaigényt illetve a számítások pontosságát lehet befolyásolni. A vertex osztály maximális mértékben kihasználja a C++ nyelv kínálta lehetőségeket, például az „operator overloding”-ot. Így mind a skalárral való szorzás, mind a skaláris szorzat megvalósítása a „*” művelettel történt. A programban a „3*v” és az „v*3” skalárral való szorzást jelent, míg a „v*v” skaláris szorzatot, ahol a v vertex típusú.

A grafikus objektumok osztályainak a megvalósítása két szinten történik.

Az elsőn a vertex_array osztály definiálja az adatszerkezetet egy iterátorral. Ez az adatszerkezet az STL vector osztálya, az iterátor pedig a hozzá tartozó iterátor. A vertex_array lényegében egy burkoló a vector körül, ami korlátozza az adatszerkezet láthatóságát, illetve akadályozza azon a nem kívánatos műveletek végzését.

A második szinten a vertex_array – az egyes grafikus objektumok speciális tulajdonságainak megfelelő konstruktorokkal ellátott – leszármazottai vannak. Ezek a leszármazottak biztosítják, hogy a grafikus objektumoknak megfelelő reprezentációk jöjjenek létre, amik a műveletek során megtartják lényeges tulajdonságaikat. Ilyen tulajdonságok például: a kör esetében az, hogy két pontja reprezentálja, és a pontok száma nem változik; illetve a törött vonal esetében, hogy a kezdő-, vég-, töréspontja reprezentálja és a pontok száma változhat.

A harmadik komponens a composite osztály és a composite_iterator osztály. Az előbbi hasonlít a vertex_array-hez, mivel beburkol egy STL tartályt (nevezetesen egy list osztályt), illetve definiál rá egy iterátort. Azonban ez a tartály maga nem egy grafikus objektum adatszerkezete, hanem ilyen adatszerkezetek gyűjtője. Az iterátora pedig nem e tartalmazott adatszerkezetek elérését szolgálja, hanem – egyetlen adatszerkezetet szimulálva – az azokban tárolt adatokét.

Fejlesztői nézet

fájlnév	tartalom
algorithm.H	a grafikus objektumok műveletei
vertex.H	lineáris algebra implementációja
vertex_array.H	a vertex_array osztály
line.H	a line osztály
circle.H	a circle osztály
composite.H	a composite és a composite_iterator osztályok

Környezeti nézet

A GTL új változata a GNU C++ fordítóprogram 3.4-es változatának felhasználásával készült. Ez a template-ek használatában jelentősen eltér az elődeitől. Az ISO C++ szabvány számos új elemét implementálták, míg több korábbi nem szabványos megoldást elhagytak. Régebbi fordítóval felmerülhetnek problémák, ezért ajánlott a GNU C++ 3.4-es vagy újabb változat a program fordításához.

Egy példa a változásokból: egy származtatott template osztály nem hivatkozhat direkt módon a szülő osztályban deklarált változókra, függvényekre. Ezért van a line és a circle osztályokban a „this->vertices” hivatkozás, ahol a „vertices” a szülő, vertex_array osztály változója.

Az alkalmazás szerkezete

Statikus nézet

10. ábra: Az alkalmazás osztálydiagramja Az alkalmazás felületének megvalósítása a KDevelop nevű intergrált fejlesztőkör­nyezet által új projekt teremtésekor felkínált „QMake project” alapján készült. Ez a sablon tartalmazza az alkalmazás osztályát – ami itt a Qdraw –, egy dokumentum-osztályt – amit töröltem –, és egy View osztályt – ami eredetileg egy egyszerű szövegszerkesztő ablak volt, de lecseréltem egy a QCanvasView-ból származtatott osztályra.

A Qdraw osztály a konstruktorában hozza létre az alkalmazás fő ablakát a menü­vel, az eszköztárral, az állapotsorral és a grafikus objektumokat megjelenítő MyCanvasVi­ew osztályú canvas objektummal. Ez az alkalmazás indításakor, illetve a Fájl menü Új menüpontjának kiválasztásakor történik.

A fájlműveleteket – Mentés, Mentés másként…, Megnyitás… – a külön doku­mentum osztály helyett több szinten a Qdraw, a MyCanvasView illetve a Grobj osztályok között szétosztva implementáltam. A fájlba mentést a Qdraw save() illetve saveAs() slotjai végzik el, a kimentendő XML szöveget a másik kettő osztály text() metódusaiból nyerik. A saját XML formátumú fájl betöltését a Qdraw load() slotja a MyCanvasView read(file­Name) műveletének meghívásával végzi.

A betöltött fájl feldolgozását a mycanvasview.cpp fájlban található StructureParser osztály végzi el, ami menet közben a Grobj osztály create_va(), add(double x, double y) és finish() műveletei felhasználásával létrehozza a háttérben levő grafikus objektumokat, és az őket reprezentáló objektum-listákat. Ez az osztály a QXmlSimpleReader típusú (sablon művelet tervminta) reader objektum kezelője, amit a reader parse() függvénye használ az XML szöveg feldolgozására.

Dinamikus nézet

11. ábra: Egy aktivációs példa A fenti ábra a futás közben létrejövő objektumok közötti kommunikációjának egy lehetséges esetét mutatja be. Ez semmiképpen sem egy általános mindenre kiterjedő leírás, csupán a megértést szolgáló szemléletes példa.

Az ábra azt az esetet szemlélteti, amikor a felhasználó elindítja az alkalmazást, és létrehoz benne egy objektumot, majd azon műveletet hajt végre. Jellemzően ilyen forgatókönyv szerint történhet a felhasználás: Egy Qdraw típusú objektum, az alkalmazás főablaka, induláskor létrehozza a saját rajzvásznát (MyCanvasView). A főablak Alakzatok illetve Művelet menüiben levő menüpontok jelzései a rajzvászon foglalataira vannak rákötve. Ez az üzenetküldés könyvtárszinten történik, ezért nem szerepel az ábrán. Egy alakzat készítésekor a rajzvászon létrehoz egy Grobj objektumot, ami egyrészt burkolja a GTL-objektumot, másrészt gondoskodik a GTL-objektum más adattípusokra (Qt rajzobjektum vagy XML dokumentum) való átalakításáról. A rajzvászon a az objektumokat érintő eseményeket (move) az illetékes Grobj típusú objektumnak továbbítja, ami szükség szerint továbbítja azt a benne levő GTL-objektumnak, és frissíti (recreate) a Qt-rajzobjektumokat.

Fejlesztői nézet

fájlnév	tartalom
qdraw.*	a kdevelop projektfájljai
teszt.qdraw*	tesztdokumentumok
src/src.pro	a qmake projektfájlja
*.ts, *.qm	lokalizációs fájlok
main.cpp	a főprogram
qdraw.h, qdraw.cpp	Qdraw osztály
mycanvasview*	MyCanvasView osztály
grobj*	Grobj osztály

Környezeti nézet

A fejlesztés és tesztelés a QT 3.3.4-es változatának alkalmazásával történt Fedora Core 3 rendszerben. 3.3-asnál korábbi rendszerekben a sikeres fordítás egyáltalán nem garantált.

A fejlesztés a Kdevelop nevű integrált fejlesztői környezet 3.1.1-es változatával történt. Újra fordítással ezért ajánlatos a 3.1-es sorozatból való változatot használni.

A fordítóprogram a GCC 3.4.3-as változata. A rendszerben levő szoftverek a 3.4-es sorozat a korábbi változatokhoz képest sokkal szigorúbb C++ szabványkövetéséhez igazodnak, ezért kisebb-nagyobb inkompatibilitás áll fent a korábbi GCC-változatokkal. Tehát az ajánlott fordító a GCC 3.4-es vagy 4.0-ás sorozata.

I18N, L10N

Az I18N az angol „internationalization” szó rövidítése, ami a programok nemzetkö­zi használatra való felkészítését jelenti. Ennek a legelterjettebb módja, hogy a programo­kat angol nyelvű szövegekkel írják meg, de az adott string-literálokat – amik végül megje­lennek a képernyőn – egy fordító függvény paramétereként adják meg a program külön­böző pontjain.

Az L10N az angol „localization” szó rövidítése, ami a nemzetközi használatra fel­készített programok helyi viszonyokhoz való igazítását jelenti. Ez lényegében a fent emlí­tett string-literálok lefordítását jelenti.

Az egész folyamat a következő lépésekben foglalható össze:

a programozó a programban a megjelenítendő szövegeket a használt I18N/L10N prog­ramkönyvtár megfelelő függvényhívás vagy makró paramétereként adja meg,

a fordítók egy segédprogrammal elkészítik vagy időszerűsítik a saját nyelvüknek meg­felelő szövegeket tartalmazó dokumentumokat, amik a program forrásnyelvű fájljaiban meglévő szövegek kivonatai, (ekkor történik a fordítás)

egy másik segédprogrammal a fordítást tartalmazó fájlokat átalakítják egy optimalizált formátumra. Majd elhelyezik azokat a megfelelő rendszermappába.

A program az induláskor a környezeti változóknak megfelelő nyelvű fájlt betölti, és az abban levő szövegeket jeleníti meg az eredetiek helyett.

Ez az alkalmazás a QT QTranslator nevű osztályával megvalósított megoldást használja. A fordítást tartalmazó fájlok neve „qdraw_*.ts” alakú, ahol a „*” helyére az or­szág/nyelv kódját kell írni. A magyar szövegek például a „qdraw_hu.ts” nevű fájlban van­nak. Fordítást a „linguist” nevű alkalmazás könnyíti meg, de mivel a fájlok XML formátu­múak, bármely szövegszerkesztővel is lehetséges az.[QT Ref.Man.]

Ebben a témában a legelterjedtebb megoldás a GNU Gettext programkönyvtára, ami számtalan programnyelvet támogat. Emellett még a szavak egyes, kettes, többes stb. számú alakjait is kezeli. Régebbi a QT megoldásánál, több szolgáltatást kínál és ismertebb is.[Gettext]

Fájlműveletek

Dokumentum betöltése

Az alkalmazás a saját XML formátumában kimentett fájlokat a QT XML-modulját használva tölti be, értelmezi és jeleníti meg.[QT Ref.Man.]

Dokumentum kimentése

Az adatok fájlba mentése a QT egy QFile osztályú objektumát felhasználva törté­nik. Az XML-dokumentum előállítása egyszerűen Qstring-objektumok összefűzésével va­lósul meg a MyCanvasView illetve a Grobj osztályok text() metódusában. [QT Ref.Man.]

Tesztek

Környezet

Az alkalmazás fejlesztése és tesztelése is egy Fedora Core 3 nevű linux-disztribúció felhasználásával történt. Az e rendszerben rendelkezésre álló, az alkalmazás szempontjából leglényegesebb programkönyvtárak a QT (3.3.4-es változat) és az STL (amit a GCC 3.4.3-as változata tartalmaz).

Mivel a programcsomagok nevei eltérnek a különböző rendszerekben az alábbiakban csak az alkalmazás futtatásához szükséges dinamikusan szerkeszthető programkönyvtárak (shared object, azaz a „.so” fájlok) neveit sorolom fel. Ezt a listát felhasználva más rendszerekben is fel lehet állítani a fordításhoz illetve teszteléshez szükséges környezetet. Másrészről ez alapján le lehet ellenőrizni, hogy a tesztelésre kiszemelt rendszer valóban alkalmas-e az alkalmazás lefordítására és futtatására.

libqt-mt.so.3 => /usr/lib/qt-3.3/lib/libqt-mt.so.3 (0x0453e000)

libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x0036c000)

libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x07701000)

libpthread.so.0 => /lib/tls/libpthread.so.0 (0x00851000)

libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x0098e000)

libm.so.6 => /lib/tls/libm.so.6 (0x0073b000)

libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00984000)

libc.so.6 => /lib/tls/libc.so.6 (0x0060f000)

libmng.so.1 => /usr/lib/libmng.so.1 (0x00d27000)

libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x00a5c000)

libpng12.so.0 => /usr/lib/libpng12.so.0 (0x00b75000)

libz.so.1 => /usr/lib/libz.so.1 (0x00766000)

libXrender.so.1 => /usr/X11R6/lib/libXrender.so.1 (0x00964000)

libXrandr.so.2 => /usr/X11R6/lib/libXrandr.so.2 (0x0095c000)

libXcursor.so.1 => /usr/X11R6/lib/libXcursor.so.1 (0x00845000)

libXinerama.so.1 => /usr/X11R6/lib/libXinerama.so.1 (0x00950000)

libXft.so.2 => /usr/X11R6/lib/libXft.so.2 (0x00282000)

libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x07832000)

libfontconfig.so.1 => /usr/lib/libfontconfig.so.1 (0x0025a000)

libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0x0087f000)

libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0x00865000)

libdl.so.2 => /lib/libdl.so.2 (0x00760000)

/lib/ld-linux.so.2 (0x005f5000)

libexpat.so.0 => /usr/lib/libexpat.so.0 (0x00239000)

A programkönyvtárak különböző mértékű inkompatibilitásának köszönhetően ettől a listától eltérő konfigurációban is futhat az alkalmazás. Például a Fedora Core 3-ban található „libstdc++.so.6” fájl átvitelével sikerült az alkalmazást futtatni egy UHU-linux 2-es rendszerben. Azonban az ilyen hackelés nem ajánlatos, mert bizonyos programkönytárak egyszerre csak egy példányban lehetnek betöltve a memóriába, különben néhány a rendszerben futó folyamat között zajló kommunikáció lehetetlenné válik rendellenes működést eredményezve. Ilyen például a „libqt-mt.so.3” a Qt osztott programkönyvtára.

Az alkalmazás tesztelése az Intel 32-bites architektúrájával kompatibilis AMD Duron processzoros rendszerben, illetve egy Intel Pentium4-es rendszerben történt. Mindemellett a fent említett programkönyvtárakat, fordítót és a szükséges header fájlokat tartalmazó bármilyen rendszerben lefordítható és futtatható az alkalmazás.

A tesztelés során a lokalizáció beállítására használatos környezeti változók közül csak a LANG volt beállítva. A többi – az LC kezdetűek – nem szerepeltek a set parancs kimenetében. Fontos a teszteléskor, hogy a LANG változó értéke egy „hu”-val kezdődő szöveg legyen – például „hu_HU.UTF-8” –, mert az alkalmazás ez alapján választja ki a kívánt nyelvű szövegeket tartalmazó erőforrást, amiből a menük, menüpontok neveit és egyéb a különféle ablakokban, állapotsorban megjelenő szövegeket veszi.

Amennyiben a megjelenő szövegekben az ékezetes betűk az „árvíztűrő tükörfúrógép”  „Ã¡rvÃ-ztÅ±rÅ‘ tÃ¼kÃ¶rfÃºrÃ³gÃ©p” mintájára romlanak el, az nem az alkalmazás hibája. Ezt okozhatják nem megfelelő környezeti beállítások, illetve az unicode-támogatás hiánya a szoftverrendszerben (akár a betűkészletekben is).

A fejlesztői illetve tesztelői környezetben az alkalmazást a qdraw mappából kell indítani ./bin/qdraw paranccsal, vagy a Kdevelopból a Futtatás menüpont/nyomógomb kiválasztásával/megnyomásával. Ez szükséges a helyes lokalizációhoz, mivel a főprogramban relatív elérési utak vannak a nyelvi erőforrásokhoz.

Egy rendszer-specifikus programcsomag elkészítésekor a disztribútor dolga az abszolút elérési utak beállítása, és az erőforrások elhelyezése a megfelelő rendszermappába. Ilyen például a /usr/share/locale/hu/LC_MESSAGES/, ahol a magyar nyelvű szöveges erőforrások helye van. A fájlrendszer kialakításakor ajánlatos követni a Filesystem Hierarchy Standard-et. [FHS] Azonban ettől gyakran eltérnek: például a QT esetében ld. „/usr/lib/qt-3.3/”. Itt a /usr/lib/qt-3.3/translations/ mappába helyezték a qt-*.qm fájlokat, amiknek a szabvány szerint a /usr/share/locale/*/LC_MESSAGES/ mappákban lenne a helyük.

A főablak tesztesetei

Ez a szakasz csak a program fő funkcióit: belépés, kilépés tartalmazza. Az ablakkezelés alapjai – mozgatás, átméretezés, minimalizálás, stb. – itt nem szerepelnek, mert azokat a műveleteket nem az alkalmazás végzi.

lépés	akció	eredmény
1	Indítsa el az alkalmazást az előző szakaszban leírtak szerint!	Megjelenik az alkalmazás főablaka: 1. ábra: A Qdraw alkalmazás fő ablaka
2.a Kattintson az ablakot bezáró gombra, ha van ilyen! 2.b Válassza ki a Bezárás menüpontot a Fájl menüből! 2.c Nyomja le a Ctrl+W billentyűkombinációt! 2.d Válassza ki a Kilépés menüpontot a Fájl menüből! 2.e Nyomja le a Ctrl+Q billentyűkombinációt!	Az alkalmazás kilép, a terminálban megjelenik a prompt. Ha a Kdevelopból futtatta, akkor az üzenetek között egy „Az alkalmazás sikeresen kilépett.” vagy hasonló üzenet jelenik meg.

A fájlműveletek tesztesetei

A fájlműveletek során a Megnyitás és a Mentés másként című dialógusok használata nem szerepel, mert ez a QT saját kütyüje, és nem az alkalmazás része. Azonban érdemes odafigyelni rájuk, mert az ezekben megjelenő magyar szövegeket jelenleg a qdraw/src/qt-hu.qm illetve a qdraw/src/qt-hu.ts fájl tartalmazza, mivel a QT-nak hivatalos magyarítása még nincs.

lépés	akció	eredmény
1.a Válassza ki az Új menüpontot a Fájl menüből! 1.b Nyomja le a Ctrl+W billentyűkombinációt!	Egy új, üres főablak jelenik meg, amely a már meglévőtől függetlenül bezárható kilépés nélkül.
2.a Nyomja meg a megnyitás gombját az eszköztárban! 2.b Válassza ki az Megnyitás menüpontot a Fájl menüből! 2.c Nyomja le a Ctrl+O billentyűkombinációt!	Felbukkan a Megnyitás dialógus, amiben kiválasztva a „teszt.qdraw” nevű fájlt, az aktív főablakban egy törött vonal és egy kör jelenik meg. A főablak fejlécében megjelenik a fájl teljes elérési útja és a neve.
3.a Nyomja meg a mentés gombját az eszköztárban! 3.b Válassza ki az Mentés menüpontot a Fájl menüből! 3.c Nyomja le a Ctrl+S billentyűkombinációt!	Az előző lépésben betöltött „teszt.qdraw” nevű fájl utolsó módosításának az ideje megváltozik. A fájl tartalmának meg kell egyeznie a „teszt.qdraw.bak” nevű fájléval; feltéve, hogy nem módosította a dokumentumot a betöltés után.
4	Válassza ki az Mentés másként... menüpontot a Fájl menüből, és adjon meg egy új nevet!	Egy új fájl jelenik meg a megadott új névvel, a kiválasztott mappában. Az alkalmazás főablakának a fejlécében megjelenik a fájl neve a tejles elérési útjával.

Az alakzatok tesztesetei

lépés	akció	eredmény
1	Válassza ki a Vonal menüpontot az Alakzatok menüből!	Az állapotsorban megjelenik a „Vonal rajzolása” tájékoztató szöveg.
2	Kattintson 3-5 alkalommal a rajzvászonra az egér 1. gombjával!	Minden egyes gombnyomásra megjelenik egy négyzet, és ezt egy egyenes fekete vonal köti össze az utolsó előtti négyzettel.
3	Nyomja le az egér 1. gombját a rajzvászonon és mozgassa, majd engedje fel!	Az egérgombot megnyomva az egérkurzort utolsó megadott ponttal egy piros egyenes vonal köti össze. Az egérgombot felengedve megjelenik a kis fekete négyzet és az összekötő fekete vonal.
4	Nyomja le az egér 2. gombját a rajzvászonon!	Az állapotsorban megjelenik a „Kész” felirat.
5	Válassza ki a Kör menüpontot az Alakzatok menüből!	Az állapotsorban megjelenik a „Kör rajzolása” tájékoztató szöveg.
6	Kattintson egyszer a rajzvászonra az egér 1. gombjával!	A rajzvászonon megjelenik egy négyzet.
7.a	Kattintson egyszer a rajzvászonra az egér 1. gombjával!	A rajzvászonon megjelenik egy négyzet, és egy kör, amely egyik átmérőjét a két négyzet határozza meg. Az állapotsorban megjelenik a „Kész” felirat.
7.b	Nyomja le az egér 1. gombját a rajzvászonon és mozgassa, majd engedje fel!	A rajzvászonon megjelenik egy kör, amely egyik átmérőjét az előbbi négyzet és az egérmutató határozza meg. A gomb felengedése után megjelenik egy négyzet. Az állapotsorban megjelenik a „Kész” felirat.

A műveletek tesztesetei

A műveletek végzésének teszteseteiben feltételezzük, hogy van a rajzvászonon megfelelő kész alakzat.

lépés	akció	eredmény
1	Válassza ki a Mozgatás menüpontot az Művelet menüből!	Az állapotsorban megjelenik a „Mozgatás” felirat.
2	Nyomja le az egér 1. gombját az egyik alakzat egyik négyzetén és mozgassa, majd engedje fel!	Az egész alakzat követi az egérmutató mozgását, majd az egérgomb felengedése után rögzül az utolsó helyen. Az állapotsorban megjelenik a „Kész” felirat.
3	Válassza ki a Forgatás menüpontot az Művelet menüből!	Az állapotsorban megjelenik a „Forgatás” felirat.
4	Nyomja le az egér 1. gombját az egyik alakzat egyik négyzetén és mozgassa, majd engedje fel!	Az egész alakzat egérmutató mozgásának megfelelően forog, majd az egérgomb felengedése után rögzül az utolsó állapotban. Az állapotsorban megjelenik a „Kész” felirat.
5	Válassza ki a Méretezés menüpontot az Művelet menüből!	Az állapotsorban megjelenik a „Méretezés” felirat.
6	Nyomja le az egér 1. gombját az egyik alakzat egyik négyzetén és mozgassa, majd engedje fel!	Az egész alakzat mérete egérmutató mozgásának megfelelően nő illetve csökken, majd az egérgomb felengedése után rögzül az utolsó állapotban. Az állapotsorban megjelenik a „Kész” felirat.
7	Válassza ki a Nyújtás menüpontot az Művelet menüből!	Az állapotsorban megjelenik a „Nyújtás” felirat.
8.a	Nyomja le az egér 1. gombját egy vonal egyik négyzetén és mozgassa, majd engedje fel!	Az egész alakzat mérete egérmutató mozgásának megfelelően nő illetve csökken, majd az egérgomb felengedése után rögzül az utolsó állapotban. Az állapotsorban megjelenik a „Kész” felirat.
8.b	Nyomja le az egér 1. gombját egy kör egyik négyzetén és mozgassa, majd engedje fel!	Semmi sem történik.

A súgó tesztesetei

lépés	akció	eredmény
1.a Válassza ki a Névjegy menüpontot az Súgó menüből! 1.b Nyomja le az F1 billentyűt!	Megjelenik az alkalmazás névjegye: 7. ábra: A Qdraw névjegye
2	Válassza ki a Qt névjegye menüpontot az Súgó menüből!	Megjelenik a Qt névjegye: 8. ábra: A Qt névjegye
3.a Válassza ki a Mi ez? menüpontot az Súgó menüből! 3.b Nyomja le az Shift+F1 billentyűkombinációt! 3.c Nyomja meg a Mi ez? funkció gombját az eszköztárban!	A Mi ez? funkció nyomógombja benyomott állapotba kerül. Az egérmutató mellett megjelenik egy kérdőjel, amennyiben az ablakkezelő rendszer témája ilyen egérmutató képet tartalmaz.
4	Kattintson az eszköztár egyik gombjára.	Egy felbukkanó ablakban megjelenik a súgó szöveg.

Tartalomjegyzék

SZAKDOLGOZAT-TÉMA BEJELENTŐ	2

I.Felhasználói dokumentáció	4

1.Bevezetés	5

2.A felhasználói felület	6

3.Fájlműveletek	7

Új ablak nyitása	7

Dokumentum betöltése	7

Dokumentum mentése	8

4.Alakzatok	9

Vonal	9

Kör	9

5.Műveletek	10

Eltolás	10

Elforgatás	10

Átméretezés	10

Nyújtás	10

6.Súgó	11

II.Fejlesztői dokumentáció	12

1.A feladat	13

2.Kitekintés	14

3.Módszerek	15

Objektum-orientált vagy generikus megközelítés?	15

Generikus előnyök	15

Példák	15

Az első Graphical Template Library (GTL)	16

Bonyolultság	16

Közös alaposztály	17

Iterátorok	17

Eredmények és további tervek	18

Az új GTL	18

Composite	19

Generikus dekompozíció	19

4.A GTL programkönyvtár	21

Statikus nézet	21

Fejlesztői nézet	23

Környezeti nézet	23

5.Az alkalmazás szerkezete	24

Statikus nézet	24

Dinamikus nézet	25

6.I18N, L10N	26

7.Fájlműveletek	27

Dokumentum betöltése	27

Dokumentum kimentése	27

8.Tesztek	28

III.Tartalomjegyzék	29

IV.Ábrajegyzék	31

V.Irodalomjegyzék	32

Ábrajegyzék

1. ábra: A Qdraw alkalmazás fő ablaka	6

2. ábra: A Fájl menü	7

3. ábra: A Megnyitás dialógus	7

4. ábra: A Mentés másként dialógus	8

5. ábra: Alakzatok menü	9

6. ábra: A Súgó menü	11

7. ábra: A Qdraw névjegye	11

8. ábra: A Qt névjegye	11

9. Ábra: A GTL osztálydiagramja	21

10. ábra: Az alkalmazás osztálydiagramja	24

11. ábra: Egy aktivációs példa	25

Irodalomjegyzék

GTL: Zoltán Porkoláb, Róbert Kisteleki, Alternative Generic Libraries, 1999

STL: , Standard Template Library Programmer's Guide, , http://www.sgi.com/tech/stl/

TC++PL: Bjarne Stroustrup, The C++ Programming Language Third Edition, 1997

Loki: , Loki, , http://sourceforge.net/projects/loki-lib/

MC++D: Andrei Alexandrescu, Modern C++ Design: Generic Programming and Design Patterns Applied, 2001

ACE: , The ADAPTIVE Communication Environment, , http://www.cs.wustl.edu/~schmidt/ACE-overview.html

Boost: , Boost Libraries and Documentation, , http://www.boost.org/libs/libraries.htm

QT Ref.Man.: Trolltech, Qt Reference Documentation (Open Source Edition), , http://doc.trolltech.com/3.3/index.html

Gettext: Free Software Foundation, GNU gettext Utilities - Table of Contents, , http://www.gnu.org/software/gettext/manual/gettext.html

FHS: , Filesystem Hierarchy Standard, , http://www.pathname.com/fhs/

Irodalomjegyzék	38

Szakdolgozat

Grafikus template könyvtár

2005-03-08T10:54:38