Šta je novo?

MFC pitanje

Mrav

Čuven
Učlanjen(a)
28.04.2002
Poruke
87
Poena
609
preopteretio sam funkciju CWinApp::OnIdle()

virtual BOOL OnIdle(LONG lCount);

napisao definiciju:

BOOL OnIdle(LONG lCount)
{
CWinApp::OnIdle(); //preporucuju da se ovo prvo pozove
nekaFunkcijaZaIzvrsavanjeUPozadini();
return TRUE;
}

ali se funkcija OnIdle u radu programa nikada ne poziva, jel zna neko moguce razloge?
 
Sustinski, napravio si dve odnosno tri greske.

Prvo par napomena u vezi OnIdle. Valjda znas za sta sluzi ICount parametar; kada program nema nijedan message u svom scheduleru da obradi, pocne da otkucava ICount. Svaki tick radi inkrement ICount varijable za 1. Cim aplikacija procesira samo jednu jedinu poruku (tipa WM_VSCROLL, recimo), ICount se resetuje na 0.
Ovo je vezano za tvoju prvu gresku; naime, kada si napravio svoju preopterecenu funkciju, naravno da treba da pozoves prvo njen nasledjeni kod, pa onda da dodas neko svoje izvrsavanje. Medjutim, ti joj nisi ovde prosledio ICount parametar.

Druga napomena je vezana za drugu gresku; funkcija OnIdle vraca true ili false u odnosu na to da li treba jos vremena da zavrsi svoj background posao (true) ili je zavrsila sa tim pozadinskim poslom (false). Kada si pozvao prvo nasledjenu funkciju, ti uopste nisi proveravao da li je ona gotova ili ne. Ako vrati true, onda nema vremena za izvrsavanje tvoje dodatne pozadinske funkcije (sve se to nize i dodaje).

Tu je i treca greska, koja ne upada toliko u oci -> ti uvek vracas true. Tehnicki, ako tvoja pozadinska funkcija zavrsava posao, slobodno vratis false i ona nece biti ponovo povucena na sledeci OnIdle event.

Dakle, malo izmenjeno, to bi trebalo izgledati otprilike ovako:

[code:1]
BOOL OnIdle(LONG lCount)
{
// prosledi prvo ICount da se izvrse nasledjene obaveze
// te ako one nisu gotove, izadji iz event-handlera
// uz obavezu da se tu vrati tok programa na sledeci OnIdle
if( CWinApp::OnIdle(ICount) )
return TRUE;

// ako je nasledjeno procesiranje gotovo, zovi svoju funkciju
if (nekaFunkcijaZaIzvrsavanjeUPozadini())
return TRUE;
else
return FALSE;
}
[/code:1]

P.S.
Naravno, prepravis svoju funkciju da vraca bool vrednost u zavisnosti da li je gotova ili ne. Vodi racuna da ona ne sme imati neko opseznije izvrsavanje, jer jednostavno za tako nesto nema vremena - kratko i jednostavno, kao i kod interrupt-handlera.
 
Hajde da rezimiram ovde mi nesto ne stima

BOOL glpaint(int color)
{
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (static_cast<float>(color),1.0,1.0);
glBegin(GL_POLYGON);
glVertex3f (0.25, 0.25, 0.0);
glVertex3f (0.75, 0.25, 0.0);
glVertex3f (0.75, 0.75, 0.0);
glVertex3f (0.25, 0.75, 0.0);
glEnd();
glFlush();
if(SwapBuffers(wglGetCurrentDC()))
return TRUE;
else return FALSE; //ovo je poslednja f-ja u nizu i ako ona vraca true trebalo bi da se cela f-ja izvrsila.
}

BOOL idlefunc(int)
{
if(glpaint(0))
return FALSE;
else
return TRUE; //ova f-ja proverava da li je f-ja izvrsena do kraja i na osnovu toga vraca rezultat
}

BOOL CMyApp::OnIdle(LONG lCount)
{

if(CWinApp::OnIdle(lCount))
return TRUE; //ovo bi trebalo da je kako treba, uzgred i prvi put sam predao lCount parametar samo sam u postu propustio da napisem
if(idlefunc(0))
return TRUE; //znaci i ovo bi trebalo da valja?
else
return TRUE; //f-ja bi trebalo da se izvrsava koliko je moguce puta dok je program u idle statusu.
}


Ne obracaj paznju na parametre nekih f-ja koje sam napisao to su parametri za koje sam siguran da pravilno rade i tu su radi testiranja.

Heeeeeeeeeeeelp!
 
Hm, nisam znao da ti hoces da crtas nesto u OnIdle eventu. Malo neuobicajeno. Obicno se OnIdle koristi da bi se nesto proverilo ili sinhronizovalo (recimo rad razlicitih threadova).

Ovo zbog toga sto crtanje (u ovom slucaju OGL) *traje*, a OnIdle treba da bude sto je moguce kraci. Plus, sto ne znas kako je koja funkcija u biblioteci odradjena; sta ako se inicira WM_PAINT za refresh kontroler i resetuje ICount ? Tada u preopterecenoj funkciji CWinApp::OnIdle poziv nasledjene funkcije OnIdle uhvati taj WM_PAINT i nikada ne dozvoli tvojoj funkciji idlefunc() da se izvrsi.

Licno, za bilo kakvo crtanje ne bih koristio OnIdle. Radije bih kreirao poseban thread (poigras se sa njihovim prioritetima), pa kada se okine tvoj custom definisani event, (recimo GLrepaint.setevent) onda se iscrtava. Ukoliko bih bas morao da vezem to nekako za OnIdle, onda postoje dva nacina; ako je kreiran thread kao suspended, da ga OnIdle 'probudi', ili ako je kreiran kao aktivan, onda da OnIdle samo postavi thread-safe flag, tako da u WaiFor (event) petlji samo proverim taj flag, pa ako je setovan, vozi taj repaint u krug sve dok se flag ne resetuje.

Ovo nije bas najelegantiniji nacin da pustis da ti se neki task vrti, pogotovo OGL iscrtavanje. Tehnici, deluje OK, samo sto si dole u OnIdle napravio lapus - u oba slucaja vraca TRUE. Smanji glPaint funkciju da radi manje posla cisto da vidis da li se okida uopste. Jesi li probao da pogledas debuggerom da li uopste ulazi u nju ?
 
Nasao sam! uz pomoc spy++ primetio sam da program iz nekog razloga konstantno salje ON_WM_PAINT, razlog za to je bio sto sam OpenGL inicijalizovao uz pomoc CClientDC, kada sam to izmenio i prepravio ga da u OnPaint inicijalizuje GL sa CPaintDC stvar je proradila, sada samo da izdvojim kod za inicijalizaciju izvan OnPaint (slozices se to nije dobro projektovanje i na konju sam!
 
Nazad
Vrh Dno