17. september 2002 - 12:57Der er
36 kommentarer og 1 løsning
OnIdle i en dialogbaseret MFC app.
Er der nogen der ligger inde med et eksempel på hvordan man benytter sig af OnIdle i en dialogbaseret MFC applikation !? Har fundet flere eksempler, men det er vist lidt noget specielt noget nu når det er en dialogbaseret applikation jeg har valgt at lave det i.
På http://www.codeproject.ch/dialog/idledialog.asp kan man hente et umiddelbart udemærket eksempel, men ClassWizard'en kommer med forskellige fejl når man skal til at arbejde videre med eksemplet!
Hvorfor er det specielt ved en dialogbaseret app..? WM_IDLE sendes til din CWinApp-nedarvede klasse, som eksisterer både i en SDI/MDI/dialogbaseret app.
Hvad kan du ikke finde ud af, hvordan du "fanger" den message eller hvad du skal bruge den til eller?
if (lCount == 0) { TRACE("App idle for short period of time\n"); bMore = TRUE; } else if (lCount == 10) { TRACE("App idle for longer amount of time\n"); bMore = TRUE; } else if (lCount == 100) { TRACE("App idle for even longer amount of time\n"); bMore = TRUE; } else if (lCount == 1000) { TRACE("App idle for quite a long period of time\n"); // bMore is not set to TRUE, no longer need idle // IMPORTANT: bMore is not set to FALSE since CWinApp::OnIdle may // have more idle tasks to complete. }
return bMore; // return TRUE as long as there is any more idle tasks }
Det burde virke fint, du skal bare huske på, at hvis du bruger en modal dialog, blokeres der for messages..! (Men det gælder jo ikke kun idle messages)
Kan jeg lokke dig til at lave et lille eksempel (er nybegynder i Visual C++) !? Der kommer faktisk ikke andre forme frem end main formen der er i programmet, så der er vel "frit løb" for WM_ beskederne !?
Så gider du lave et lille eksempel der bare (!?) i en label eller tekstfelt skriver hvor lang tid programmet har været Idle !?
Hvis du bruger Wizarden til at lave en std dlg baseret app, er den jo netop modal. Prøv at checke din kode (i den CWinApp-nedarvede klasse) og se om du ikke kan finde linien der indeholder koden: dlg.DoModal()
DoModal blokerer i dens natur for udførelse af programmet på det sted, indtil funktionen returnerer (dialogen lukkes).
Det betyder at applikationen modtager events (incl. idle-eventen), men ikke får mulighed for at processere dem sålænge dialogen vises.
Det lyder helt vanvittigt - så burde screensavers jo ikke virke på modale vinduer ?!?. Kunne man ikke i stedet forestille sig at dialogen også har en default idle funktion, som du skal "overloade" for at fange idle i dialogen ?
Så har jeg i hvert fald aldrig hørt om den! Men man kan jo altid selv: 1) Processere alle messages og så lave idle work eller 2) checke om køen er tom og så lave idle work
soepro >> jeg mener applikations-objektet (instans af den CWinApp-nedarvede klasse) i ovenstående indlæg hvor jeg skriver applikationen, måske det kan forklare...
Nu siger jeg så lige det magiske ord igen: Eksempel :) Er jo som sagt nybegynder i Visual C++, så hvis du lige gider lave et lille hurtigt eksempel som du gjorde med OnKickIdle !? :)
Rolig nu, man kunne vel se bort fra visse messages. Hvis du du laver en timer til at opdatere din counter med og så ser bort fra WM_TIMER messages i dialogens overridede WindowProc, det kunne måske virke...
Jeg kan godt prøve at lave et eksempel til dig, hvis du ikke er helt med...
Tja, måske du bruge dette til noget. Det virker med en variabel der IKKE vises på skærmen, men det må naturligvis kunne løses på en fornuftig måde, kigger på det imorgen...
LRESULT COnIdleDialogDlg::OnKickIdle(WPARAM, LPARAM lCount) { // Do idle processing here, just like CWinApp::OnIdle if(!m_bIsIdle) { m_BeginIdleTime = CTime::GetCurrentTime(); SetTimer(0, 1000, NULL); m_bIsIdle = true; }
Jeg sender hele projektet til dig, men for en god ordens skyld, poster jeg også lige løsningen her... Den interessante del er en delmængde af dialogklassen, alt andet er blot standard kode hvilket jeg IKKE poster! Hvis andre vil have hele projektet, kan de bare lave et indlæg der inkluderer deres mail-adresse.
class COnIdleDialogDlg : public CDialog { // Construction public: CTime m_BeginIdleTime; COnIdleDialogDlg(CWnd* pParent = NULL); // standard constructor
LRESULT COnIdleDialogDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // Når du får en ny besked, kan du "fange" den her i WindowProc // For at opdatere variablen der indeholder tiden siden applikationen blev idle, // har jeg lavet en timer, der affyres for hver 100ms. Den timer genererer dog // også en message (WM_TIMER), som egentlig får programmet til at "gå ud af" idle tilstanden. // Her fanger vi så WM_TIMER, opdaterer tiden og returnerer 0 (så behandles message'en // ikke videre og programmet går ikke ud af idle tilstand if(message == WM_TIMER) { CTime CurTime = CTime::GetCurrentTime(); CTimeSpan Span(CurTime-m_BeginIdleTime); m_TimeDisplay = Span.Format("%D:%H:%M:%S"); UpdateData(false); return 0; }
// Linien UpdateData(false); herover, gør at der sendes en WM_CTLCOLORSTATIC message // (Fordi tiden bliver vist i en CStatic kontrol) Den fanger vi, tjekker om den // tilhører vores timervindue (der kunne jo være andre CStatic kontroller på dialogen) // og returnerer, så CDialog::WindowProc ikke får mulighed for at processere den. if(message == WM_CTLCOLORSTATIC && (HWND)lParam == m_TimeStatic.m_hWnd) return 0;
// Hvis det ikke er en WM_KICKIDLE message, er vi ikke længere idle if(message != WM_KICKIDLE) m_bIsIdle = false;
// Lad default implementationen håndtere de messages der slap igennem return CDialog::WindowProc(message, wParam, lParam); }
Dine kommentare er gode, så jeg er ret godt med på hvad der foregår :)
Har en sidste lille bøn for at gøre det helt perfekt. Kan du sortere bevægelser fra musen fra også !? Altså så tælleren ikke nulstilles når man bevæger musen hen over formen. Du skal kun lave det hvis det er en forholdvis lille ændring at lave !?
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.