VEDOUCÍ: | Lubomír Krejčí |
NÁZEV: | Realizace primitiv skriptového jazyka z projektu Petra Kuby |
ŘEŠENÍ: | Realizaci projektu jsem pojal jako vytvoření
jednoduchého grafického prostředí, které uživateli umožní jednoduchým způsobem
vytvářet grafické rozhraní ke svému programu. Dále umožní číst stav klávesnice
a myši jednotným, jednoduchým způsobem.
Prostředí je navrženo jako objektové a událostmi řízené. V prostředí jsou implementovány některé základní objekty - obrázek, čára, výpis textu, vstupní textový řádek. Uživatel může změnit chování objektů tím, že vytvoří potomka, ve kterém si potřebné metody předefinuje.
Komunikace objektů mezi sebou je řešena formou zasílání událostí. Události jsou shromažďovány ve frontě a odtud později vybírány a obsluhovány. Také klávesnice, myš a časovač jsou zdroji událostí. Událost může být různého druhu – stisk klávesy, aktivita myši, příkaz,… Objekt může v sobě obsahovat i jiné objekty - stává se skupinou. Prostředí dále poskytuje uživateli snadnou správu paměti pomocí vlastních knihovních funkcí a objektů. |
IMPLEMENTACE: | Prostředí je celé napsáno v Borland C++
a některé pasáže v Assembleru (kvůli rychlosti). Jádrem celého systému
je objekt desktop typu “t_desktop”.
Do tohoto objektu uživatel vkládá / odebírá objekty, které chce zobrazit.
Tedy, jeho funkcí je správné zobrazení všech do něj vložených objektů a
výběr událostí z fronty a posílání jich jednotlivým objektům.
Nyní se blíže podíváme na jeho implementaci. Desktop obsahuje dynamicky alokované pole vrstev. Vrstvy mají umožnit umístit objekty nejen v rovině ale i v prostoru, tím je umožněno, aby objekt zakrýval jiný apod. Vrstva je reprezentována řetězeným seznamem objektů, přičemž z důvodu urychlení při vykreslování může být tento seznam setřízen, například dle souřadnice x. Vykreslování objektů je realizováno do 64KB bufferu. Buffer reprezentuje výřez obrazovky, který je po vykreslení všech objektů do něj zasahujících zobrazen na správné místo na obrazovce. Objekty se malují v pořadí od nejvzdálenějších k nejbližším (od nejvzdálenější vrstvy k nejbližší). Důvodem k použití této metody mne vedlo zamezení efektu blikání při překreslování. V seznamech objektů v desktopu může být jeden objekt význačný – aktivní. To znamená, že jako první dostává možnost obsloužit vzniklou událost. Tím dostáváme i aktivní vrstvu – obsahuje aktivní objekt. Dalším význačným objektem je objekt předvolený – tento objekt dostává možnost zpracovat událost hned po aktivním (vhodné například při dialogu se vstupním polem a potvrzovacím tlačítkem – po stisku ENTER je dialog potvrzen). Událost je deklarována jako struktura: union { // jedna z nasl. moznosti tkey key; // klavesnice tcommand command; // prikaz tfunc func; // zavolej funkci např.: evLBMDown = 0x0002 // leve tlac. Mysi stisknuto evLBMUp = 0x0004 // leve tlac. Mysi uvolneno evKeyDown = 0x0400 // klavesa stisknuta Struktura tmouse: struct tmouse { // mysStruktura tkey:int buttons; // stav tlacitek}; struct tkey { // klavesniceStruktura tcommand:unsigned flags; // viz vyse}; union { // co je zrovna potreba void (*infoFunc)(); long infoLong; int infoInt; unsigned infoUnsigned; char infoChar; Obsluhu událostí vybraných z fronty objekt desktop řeší metodou handle_ev (obsluž událost). Událost zaslaná určitému objektu je zpracována vlastní metodou handle_ev. Desktop zasílá události objektům dle následujícího pořadí:
Tento způsob zpracování událostí je nazýván jako z-pořadí. Knihovna “xms” zpřístupňuje uživateli XMS paměť voláním například těchto funkcí:
Podobné funkce má i knihovna “ems” pro práci s EMS pamětí. Na knihovně “xms” je postaven objekt bmpmanager. Tento objekt umožňuje načítání obrázků ze souboru a jejich uložení v paměti a samozřejmě i zpřístupnění těchto dat. Na data se odkazuje způsobem stejným jako v XMS, tedy pomocí handlu. Voláním funkce ins vložíme obrázek ze souboru, bmpmanager vrací handle na data nebo chybový kód. Pomocí del obrázek uvolníme. Funkce copy_to_buffer zpřístupňuje data. Bmpmanager se chová inteligentně,
vkládáme-li stejný obrázek vícekrát, pak nealokuje paměť pro každý zvlášť,
ale u prvního obrázku zvýší počet odkazů na něj. Při uvolňování sníží počet
odkazů a při nule paměť uvolní. Chová se tedy podobně jako i-uzly v UNIXu.
Knihovna “mouse” usnadňuje práci s myší. Funkce:
Funkce mouseChangeCursor z knihovny “mouse” je používána každým objektem, protože každý objekt umožňuje změnit tvar myšky, když se nad ním pohybuje. Nastavení grafického režimu, inicializaci správy událostí a inicializaci bmpmanageru provádí metoda init objektu desktop. Po ukončení programu metoda done vrací vše do původního stavu. Vlastní běh programu je metoda run, ta v cyklu vybírá události z fronty a posílá je na zpracování. Na závěr bych uvedl možná rozšíření a příklad programu. Projekt lze rozšířit na větší počet rozlišení (zatím pouze v 320x200 256 barev). Jak jsem již zmínil podpora více grafických formátů, podpora odkládání na disk. A doplnit další užitečné objekty, jako je např. okno, tlačítko, nabídka, … |
#include <conio.h>
#include <stdio.h>
#include <dos.h>
t_image *image; // typ obrázek
volatile int s=0;
void my_func() { // funkce,
která bude volána časovačem
s = (s + 10) % 330; //
pohyb obrázku po obrazovce
image -> move(s, 70);
}
void main() {
int id_timer, id_image,
id_font;
tevent ev;
t_inputline *input;
char data[11] = "Ahoj";
ev.what = evCommand; //
nastav událost na volání funkce my_func
ev.command.command =
cmCallFunc;
ev.command.infoFunc =
&my_func;
desktop
= new t_desktop(1); // vytvoř desktop s modrým pozadím (1)
desktop -> init(meAll);
// inicializuj ho
id_image
= BMPManager -> ins("j:\\vlasta\\obr.bmm", 2);
// nacti obrazek ze souboru (.bmm – vlastní formát obsahující více
// obrázků) a pořadí v souboru je 2 (počítáno od 0)
if (id_image < 0)
{ // chyba obrázek se nenatáhl
desktop ->
done(); // vrať vše do původního stavu
delete desktop;
printf("CHYBA:
BMPManager -> ins() (bmp): %d\n", id_image);
getchar();
return; //
a skonči
}
image = new t_image(200,
100, id_image);
// objekt obrázek na pozici 200,100 s daty obrázku v handlu id_image
desktop -> add_view((t_object
*)image, 2);
// vlož ho do 2. Vrstvy (opět od nuly)
id_font
= BMPManager -> ins("j:\\vlasta\\obr.bmm", 1);
// načti font, pozice dat fontu je v souboru na druhém místě
if (id_font < 0) {
// chyba font se nenatahl
desktop ->
done();
delete desktop;
printf("CHYBA:
BMPManager -> ins() (fnt): %d\n", id_font);
getchar();
return;
}
input = new t_inputline(100,
100, id_font, data, 10);
// vstupní řádek na pozici 100,100 s fontem id_font, textem data
// a max. délkou 10 znaků
desktop -> add_view((t_object
*)input, 1); // vlož do vrstvy 1.
desktop -> focus(input);
// udělej ho aktivním
desktop
-> draw(); // vykresli všechny vložené objekty
id_timer = TimerInsert(3,
ev); // do časovače vlož požadavek
desktop -> run(); // spusť program, ukončí se stiskem AltX
TimerDelete(id_timer);
// odeber požadavek z časovače
BMPManager -> del(id_image);
// uvolni obrázek a font z paměti
BMPManager -> del(id_font);
desktop
-> done(); // vrať vše do původního stavu
delete desktop;
}
VÝSTUP: Výřezy obrazovkového výstupu. (pohybující se obrázek esa a změněný vstupní řádek).