.[ ČeskéHry.cz ].
Problém s přístupem k objektu

 
odeslat nové téma   Odpovědět na téma    Obsah fóra České-Hry.cz -> C / C++
Zobrazit předchozí téma :: Zobrazit následující téma  
Autor Zpráva
uiii



Založen: 12. 08. 2007
Příspěvky: 251

PříspěvekZaslal: 16. leden 2009, 10:39:38    Předmět: Problém s přístupem k objektu Odpovědět s citátem

Čau, mám takový problém. Zkusím nějak popsat mojí situaci.

Mám tři třídy (ale mělo by to platit pro obecný počet tříd) co se týkají GUI:

kód:
class MainWindow
{
...
Objekt objekt;
...
};

class Objekt
{
...
AddWindow addWindow;
...
};

class AddWindow
{
...
Add();
...
};


Dále mám nějakou třídu API, ve které probíhá zpracování dat. Ve funkci main vytvořím její objekt. (Případně bych ještě v MainWindow měl ukazatel na to API, kterému bych předat adresu toho objektu API). Metoda addWindow.add() by měla zavolat nějakou metodu z API. Ale nevím jak to uvělat aby na ten objekt viděla. Nebo aby zavoalla třeba nějakou metodu z MainWindow, ale nějak jednoduše a bych si nemusel předávat ukazatel na MainWindow do všech ostatních objektů.

Doufám že jste můj problém pochopili. Tak prosím poraďte mi nějaké dobré řešení.

Dík Uiii
_________________
Twitter
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Quiark



Založen: 29. 07. 2007
Příspěvky: 816
Bydliště: Chlívek 401

PříspěvekZaslal: 16. leden 2009, 10:47:01    Předmět: Odpovědět s citátem

citace:
abych si nemusel předávat ukazatel


A jak jinak to má asi poznat, na který instanci toho objektu chceš tu metodu zavolat?
_________________
Mám strach
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovi WWW stránky
uiii



Založen: 12. 08. 2007
Příspěvky: 251

PříspěvekZaslal: 16. leden 2009, 10:52:14    Předmět: Odpovědět s citátem

Nebo tak jeste trochu to upresnim. Spis bych potreboval vedet jak se resi to kdyz mám proste naky to GUI. Tam vyvolam nejako hodne vnorenou tridu, ktera obsahuje button a kdyz na nej kliknu tak to proste v tom API ma vyvolat nejakou fci. To teda kdyby fce pro to ovladani API byli ve tride MainWindow, tak to si musim do vsech vnorenych predavat ten ukazatel na ni? To to nejde resit nejak jinak? Jak se tohle resi?
_________________
Twitter
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
rezna



Založen: 27. 07. 2007
Příspěvky: 2156

PříspěvekZaslal: 16. leden 2009, 11:01:54    Předmět: Odpovědět s citátem

uiii napsal:
Nebo tak jeste trochu to upresnim. Spis bych potreboval vedet jak se resi to kdyz mám proste naky to GUI. Tam vyvolam nejako hodne vnorenou tridu, ktera obsahuje button a kdyz na nej kliknu tak to proste v tom API ma vyvolat nejakou fci. To teda kdyby fce pro to ovladani API byli ve tride MainWindow, tak to si musim do vsech vnorenych predavat ten ukazatel na ni? To to nejde resit nejak jinak? Jak se tohle resi?


WinAPI si predava HWND (handle okna) - tzn. pointer na prvek ktery danou zpravu poslal.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Quiark



Založen: 29. 07. 2007
Příspěvky: 816
Bydliště: Chlívek 401

PříspěvekZaslal: 16. leden 2009, 11:02:22    Předmět: Odpovědět s citátem

Tak máš možnost použít globální proměnnou/singleton. S tím jsou ale spojeny jisté problémy, je tady k tomu přínosné vlákno.

Já osobně to ale řeším tak, že když mám v GUI tlačítko, které má spustit nějakou operaci, tak si instanci té pracující třídy vytvořím v tom GUI a pak ji spustím. Dále GUI frameworky obvykle fungují tak, že handlery událostí tlačítek a dalších prvků jsou metody v třídě okna/formuláře, takže tam není problém mít přístup k těm datem.
_________________
Mám strach
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovi WWW stránky
Ladis



Založen: 18. 09. 2007
Příspěvky: 1537
Bydliště: u Prahy

PříspěvekZaslal: 16. leden 2009, 15:00:58    Předmět: Odpovědět s citátem

Pred lety jsem neco takoveho resil, a tak nize prikladam svoje objektove reseni v C++. Jde o prirazeni nejake funkce nejakeho objektu k vybrane udalosti objektu tlacitka apod. Tj. kliknu na tlacitko a zavola se funkce uplne jineho objektu. Kod nize funguje v GCC i MSVC:

kód:
// Podotykam, ze v tomhle kodu funkce volana pro nejakou udalost musi byt v objektu tridy
// zdedene z CScreen, ktere predstavuji herni obrazovky (dole je treba CLoginScreen). U
// okennich aplikaci to budou asi okna/formulare, takze jde jen o pojmenovani, abyste
// nedumali, co to CScreen tady znamena :-)

// datove typy:

typedef bool (CScreen::*ScreenFuncPtr)(int data);   // vraci true, pokud probehlo uspesne

typedef struct {
  CScreen *obj;           // ukazatel na objekt
  ScreenFuncPtr func;     // ukazatel na funkci objektu
} ScreenFunc;

// promenne:

ScreenFunc *onClick;  // NULL nebo ukazatel na funkci v nejakem objektu

// ziskani a nastaveni funkce volane pro udalost:

const ScreenFunc *CButton::getClickEvent() const throw() { return onClick; }

void CButton::setClickEvent(const ScreenFunc *func) throw() {
    if (func) {        // nastavuje novou funkci na udalost
        if (!onClick)          // pokud ten objekt neni vytvoren
            onClick = new ScreenFunc;
        *onClick = *func;        // operator prirazeni
    } else {        // nastavuje NULL, tj. rusi funkci na udalost
        delete onClick;
        onClick = NULL;
    }
}

// zavolani prirazene funkce objektu pro udalost

void CButton::onMouseClick(const float x, const float y, const MouseBtn btn) {
    if (onClick)      // pokud je nastavena funkce na udalost
        (onClick->obj->*onClick->func)(0);  // ...tak ji zavolej
}

// pouziti v kodu, tj. jak vypada kod, kde predam ukazatel na funkci v objektu:

ScreenFunc f;

btnLogin = new CButton(this, 225.0f, 350.0f, 150.0f, 35.0f, "Login");
f.obj = this;
f.func = (ScreenFuncPtr)&CLoginScreen::btnLoginClick;
btnLogin->setClickEvent(&f);

_________________
Award-winning game developer
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
tuft



Založen: 29. 07. 2007
Příspěvky: 9

PříspěvekZaslal: 17. leden 2009, 17:42:29    Předmět: Odpovědět s citátem

Da se taky pouzit koncept signal/slot, jako pouziva treba Qt. Princip je podobnej tomu co pise Ladis, jen obecnejsi. Doporucuju tuhle knihovnu http://sigslot.sourceforge.net/ .
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
uiii



Založen: 12. 08. 2007
Příspěvky: 251

PříspěvekZaslal: 17. leden 2009, 23:44:23    Předmět: Odpovědět s citátem

no mozna jeste muzu dodat ze to delam v gtkmm (objektova verze GTK) a ta ma jako signal/sloty ale stejne nevim jak to resit. Jinak to pouziva knihovnu libsigc++, takze sem akorat koukal na ni.
_________________
Twitter
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
uiii



Založen: 12. 08. 2007
Příspěvky: 251

PříspěvekZaslal: 17. leden 2009, 23:50:00    Předmět: Odpovědět s citátem

Jako nakonec sem se rozhod ze to udelam, tak ze dycky pro tu urcitou tridu udelam nakej vlastni signal, kterej vysle o tridu vejs, ta zas pro to bude mit pripavenej signal, kterej posle zase vys, az se to dostane do ty MainWindow, ktera to pak preda tomu API. Asi to neni nejlepsi reseni, ale nevim jak to udelat lip a tehle se mi zda spon takovy prehledny a ty tridy se nesnazej poustet nic v jinech tridach takze takovy dobre "uzavreny".
_________________
Twitter
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Ladis



Založen: 18. 09. 2007
Příspěvky: 1537
Bydliště: u Prahy

PříspěvekZaslal: 18. leden 2009, 03:23:51    Předmět: Odpovědět s citátem

uiii napsal:
a ty tridy se nesnazej poustet nic v jinech tridach takze takovy dobre "uzavreny"

V mnou uvedenem reseni to neni o tom, ze by se nejake objekty snazily poustet neco v jinejch objektech, ale o tom aby namapovaly udalosti v jinych objektech na sve metody Wink.
_________________
Award-winning game developer
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
uiii



Založen: 12. 08. 2007
Příspěvky: 251

PříspěvekZaslal: 18. leden 2009, 10:25:10    Předmět: Odpovědět s citátem

Ladis napsal:
V mnou uvedenem reseni to neni o tom, ze by se nejake objekty snazily poustet neco v jinejch objektech, ale o tom aby namapovaly udalosti v jinych objektech na sve metody Wink.


No nebylo nijak mysleny proti tvemu kodu Wink.
_________________
Twitter
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
uiii



Založen: 12. 08. 2007
Příspěvky: 251

PříspěvekZaslal: 18. leden 2009, 10:29:58    Předmět: Odpovědět s citátem

Jako dik za ten kod. Ale nechci to zas moc komplikovat, ten by se spis hodil nekam kde nejsou k dyspozici zadny nastroje pracujici se signalama, ale kdyz uz to gtkmm je ma tak to radsi udelam nejak pomoci nich.
_________________
Twitter
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Laethnes



Založen: 14. 02. 2008
Příspěvky: 38

PříspěvekZaslal: 22. leden 2009, 20:52:35    Předmět: Moje řešení GUI Odpovědět s citátem

Mno, když jsem si tohle četl (problém i diskuzi), úplně mě běhal mráz po zádech: přesně (doslova a do písmene... snad :3) jsem řešil taky... přemýšlel jsem nad tím několik měsíců (moc času na programování jsem neměl, tak jsem to aspoň řešil v hlavě) a nakonec jsem vymyslel jeden model. Nevím, zda je to dobrý nápad, nevím, zda je to efektivní (proto bych kdyžtak požádal o kritiku), ale podařilo se mě tím vykrýt většinu problémů, co jsem potřeboval vyřešit:

Mám jednotný systém událostí. Existuje jedna globální instance třídy událostí (v podstatě singleton starající se o události programu) (já to označil jako g_event), který obsahuje CEventManager - třída manažer událostí. Existuje jedna ACEventFactory - abstraktní třída továrna na události, od které mohou dědit jednotlivé typy událostí (jde o to, že chci mít co nejméně kód závislý na jiném) a při jejich inicializaci se v tomto manažeru registrují a dostanou svoje základní base_event_id. (Momentálně mám události obecné (klávesy, myš, apod) a GUI (stisk tlačítka, posun pohledu v něčem, co jsem nazval Case (skříň) - jde o obalení objektu tak, aby se zobrazoval v určeném obdélníku a kolem něj byly posuvníky, apod.).
Při spuštění tedy registruji jednotlivé typy událostí (základní, GUI, ...). Při každém reloadu událostí je generován seznam událostí, který ukládá podle typů do polí (používám STL) - ukládám jej do CEventContainer (třída kontejner událostí).
Každý objekt, který má s událostmi nějak pracovat musí obsahovat následující funkci:
bool Events(CEventContainer& i_events);
Nějaká třída A tímto způsobem přijme události. Projde jejich seznam (buď celý, nebo jen ten base_type, na který reaguje) a podle toho se zachová (např. nějaký input vezme písmena a uloží je do textu, který pak zobrazí ve funkci Draw()) a většinou je taky smaže ze seznamu; např. událost MouseMove - pokud se myš nachází nad tímto objektem, smaže tuto událost, díky čemuž ji nemůže vzít objekt pode mnou (který je zakryt).
Pokud tato třída A obsahuje nějaké další objekty, pošle jim zbytek seznamu událostí. A teď přichází to hlavní: pokud funkce vrátí true, znamená to, že instance třídy změnila svůj stav takovým způsobem, kterého by si měly všimnout objekty, které ji volaly. Pokud třída A nějaké může přijmout, podívá se do seznamu událostí po událostech, které by od volané třídy měla zpracovat. Podle toho se třída může rozhodnout opět poslat true (což může taky i v případě vlastních reakcí) a "předat" (on se ten kontejner událostí zpět neposílá - kdo ho poslal ho má i po odeslání, ve změněném stavu) zbytek třídě, která ji volala.
Události, které zůstaly naprosto nezpracované (rozumněj žádný objekt je nesmaže) se pak mažou při příštím reloadu (nepotřebujeme, aby to pole neúměrně narůstalo např. na události MouseButtonUp, která se nemaže).

Praktický příklad: pracuju na jedné jednoduché adventuře. Rozhodl jsem se jednotlivé obrazovky rozdělit do samostatných tříd (obecně tomu říkám "pohledy", např. CMenuView, COptionsView, CMainGameView apod), které dědí od jedné základní (ACView - abstraktní třída pohled) a podle návrhového vzoru stav mám uložen pointer na aktivní pohled (a někde mám seznam všech). A teď: mám aktivní pohled menu. Třídě CMenuView pošlu události. Ta obsahuje třídu z GUI - menu, tak putují události do menu. Menu obsahuje seznam objektů - potenciálních cílů uživatele a všem postupně pošle události. Pokud nějaký řekne, že něco změnil, menu zkontroluje stav a případně jako aktuální nastaví jiný objekt (tohle momentálně dělám proto, že vstup myši si zpracovávají jednotlivé objekty, ale klávesy si zpracovává samotné menu); každý objekt si pamatuje svoje ID které bylo nastaveno při tvorbě menu. Když se nějakému objektu pošle (pomocí funkce) zpráva Focus (zaměření) či Choose (položka byla vybraná), položka přidá příslušnou událost do seznamu (spolu s tímto ID) a pošle true. Menu si ověří aktivitu a pošle true. CMenuView nic nedělá, tak jen pošle zpět to, co poslalo menu. A tak to doputuje až do hlavního cyklu. Zde se projde seznam GUI událostí a když se narazí na událost "VybranáPoložkaVMenu", podívá se na jeho ID - to je nastaveno stejně jako ID daného pohledu, takže jenom prohodí pointer na pohled. A tak se od příštího snímku bude zobrazovat nová stránka. (Akorát bych měl vytvořit novou událost ChangeViewEvent, protože se může měnit i jinak, než přes menu; např. v hlavní hře stiskem ESC.)

Pozn.: Ano, vím, že to menu mám momentálně komplikované. Uvědomil jsem si to až po jeho dodělání... Jde o to, že jsem vycházel z toho, že možná budu chtít vysouvací menu (vnořené) a tak je třeba, aby položka menu byla plnohodnotný objekt, kterému se posílají zprávy a které posílá zprávy. Akorát jsem si teď uvědomil, že nevím, jak udělat, aby to menu přečetlo kliknutí myši mimo objekt, aby se to vysunuté mohlo zrušit (jde o to, že tu událost může smazat už jiný objekt, kterému to bylo posláno dřív a do kterého se kliklo...).
Na druhou stranu tento systém toho hodně řeší: pokud se budou vytvářet nějaká okna, stačilo by naprogramovat nějaký jednoduchý manažer oken: bude obsahovat seznam objektů v pořadí, v jakém se zobrazují a v opačném, v jakém si berou vstup (to, co je vidět úplně na vrchu si bere vstup jako první, ale kreslí se jako poslední). Kliknu myší a události jdou do toho nejvrchnějšího. Pokud si tuto událost nevezme (není v souřadnicích okna), zůstane v seznamu událostí a ten putuje do dalších a dalších oken. Až narazí na okno, na které uživatel klikl a to tuto událost smaže a vrátí true; tím správce oken ví, že se tohle okno snaží získat vstup a tak jej nastaví jako první a ostatní poposune.
Stejně tak lze snadno implementovat chybovou zprávu, která vyžaduje, aby si ji uživatel přečetl a klikl na např. OK/STORNO apod; prostě vždy bude vracet true a vždy bude mazat všechny události, aby se nedostaly k ostatním. Na kliknutí mimo sebe může zareagovat zablikáním, příp. zvukem. Prostě to umožňuje udělat relativně jednoduché, ale komplexní GUI. Akorát tu mám strašně moc objektů, které dědí od nějaké AC (abstraktní třída) s HODNĚ virtuálními metodami (přinejmenším Get/Set X/Y, GetWidth/Height, Run, Draw, Events, Destroy, destruktor (který volá destroy :3, takže vlastně nemusí být :3)).

Doufám, že tahle slohovka někomu k něčemu bude Wink
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Zobrazit příspěvky z předchozích:   
odeslat nové téma   Odpovědět na téma    Obsah fóra České-Hry.cz -> C / C++ Časy uváděny v GMT + 1 hodina
Strana 1 z 1

 
Přejdi na:  
Nemůžete odesílat nové téma do tohoto fóra
Nemůžete odpovídat na témata v tomto fóru
Nemůžete upravovat své příspěvky v tomto fóru
Nemůžete mazat své příspěvky v tomto fóru
Nemůžete hlasovat v tomto fóru


Powered by phpBB © 2001, 2005 phpBB Group


Vzhled udelal powermac
Styl "vykraden" z phpBB stylu MonkiDream - upraveno by rezna