Avatar billede snowball Novice
17. september 2002 - 12:57 Der 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.

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!

Snowball
Avatar billede jpk Nybegynder
17. september 2002 - 13:08 #1
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?
Avatar billede snowball Novice
17. september 2002 - 13:24 #2
Helt basal set, så kunne jeg godt tænke mig at få nedenstående eksempel til at virke i en dialogbasret MFC applikation!

BOOL CMyApp::OnIdle(LONG lCount)
{
    BOOL bMore = CWinApp::OnIdle(lCount);

    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 er taget fra http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_mfc_cwinapp.3a3a.onidle.asp

Snowball
Avatar billede snowball Novice
17. september 2002 - 13:26 #3
Eller måske endnu bedre at bruge http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_mfc_cwinthread.3a3a.isidlemessage.asp da den anden bruger en del CPU kraft i den sidste ende !

Snowball
Avatar billede jpk Nybegynder
17. september 2002 - 13:29 #4
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)
Avatar billede snowball Novice
17. september 2002 - 13:35 #5
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 !?

Snowball
Avatar billede jpk Nybegynder
17. september 2002 - 13:41 #6
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.
Avatar billede snowball Novice
17. september 2002 - 13:47 #7
OK. Det er det eksemplet på http://www.codeproject.ch/dialog/idledialog.asp skulle råde bod på, men eksemplet bruger bare meget CPU kraft synes jeg !?

Snowball
Avatar billede soepro Nybegynder
17. september 2002 - 13:49 #8
jpk >> Er det virkeligt rigtigt ?

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 ?
Avatar billede jpk Nybegynder
17. september 2002 - 13:55 #9
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
Avatar billede jpk Nybegynder
17. september 2002 - 14:07 #10
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...
Avatar billede jpk Nybegynder
17. september 2002 - 15:16 #11
Prøv at include afxpriv.h i din dialog-klasses headerfil

#include <afxpriv.h>              // For WM_KICKIDLE

Tilføj også understående til din klasse:
afx_msg LRESULT OnKickIdle(WPARAM, LPARAM);


I .cpp-filen (dialogens) tilføjer du så:

ON_MESSAGE(WM_KICKIDLE, OnKickIdle)

til messagemappen (mellem linierne med BEGIN_MESSAGE_MAP og END_MESSAGE_MAP)

og understående nederst i filen:

//////////////////
// Handle MFC private message WM_KICKIDLE. LPARAM is the idle count.
// Return TRUE/FALSE continue/discontinue idle processing.
//
LRESULT CMyDlg::OnKickIdle(WPARAM, LPARAM lCount)
{
      // Do idle processing here, just like CWinApp::OnIdle
      //
      TRACE("CMyDlg::OnKickIdle, do priority %d stuff\n", lCount);
      return (lCount <= 2);
}
Avatar billede snowball Novice
17. september 2002 - 15:32 #12
jpk: Tak for eksemplet. Det bruger stort set ingen CPU kraft i forholdt til det andet jeg fandt :)

Kan man så på en relativ let måde for den til at tælle hvor mange sekunder programmer har været idle !?

Snowball
Avatar billede jpk Nybegynder
17. september 2002 - 15:35 #13
I alt eller siden "sidst"?
Avatar billede snowball Novice
17. september 2002 - 15:41 #14
Siden sidst, altså så når man bruger programmet igen (trykker på en knap, skriver noget i en edit box osv.), så nulstilles tælleren !

Snowball
Avatar billede jpk Nybegynder
17. september 2002 - 15:47 #15
Du kan jo tage klokkeslættet når du går idle og så igen når du modtager en message (du kan fx override MessageProc).
Avatar billede snowball Novice
17. september 2002 - 15:54 #16
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 !? :)

Snowball
Avatar billede jpk Nybegynder
17. september 2002 - 15:57 #17
Skal der være en counter på dialogen, så man løbende kan se hvor længe, programmet har været idle?
Avatar billede snowball Novice
17. september 2002 - 16:00 #18
Ja bare som jeg skrev tidligere med at man i en label eller tekstfelt kan se hvor lang tid programmet har været Idle.

Snowball
Avatar billede jpk Nybegynder
17. september 2002 - 16:05 #19
Har du overvejet at opdateringen af denne label medfører at der sendes nogle events, som så gør at programmet ikke længere er idle..?
Avatar billede snowball Novice
17. september 2002 - 16:08 #20
DOH! Det er lige det der med at tænke lidt længere frem ;)

Hvad så bare med en intern variabel i programmet som ikke bliver udskrevet nogen steder !?

Snowball
Avatar billede jpk Nybegynder
17. september 2002 - 16:12 #21
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...
Avatar billede snowball Novice
17. september 2002 - 16:15 #22
Du må meget gerne lave et eksempel til mig :)

Snowball
Avatar billede jpk Nybegynder
17. september 2002 - 17:01 #23
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;
    }

    TRACE("COnIdleDialogDlg::OnKickIdle, do priority %d stuff\n", lCount);
    //return (lCount <= 2);
    //return TRUE;
    return FALSE;
}

LRESULT COnIdleDialogDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    if(message == WM_TIMER)
    {
        CTime CurTime = CTime::GetCurrentTime();
        CTimeSpan Span(CurTime-m_BeginIdleTime);
        m_Time = Span.Format("%D:%H:%M:%S");
        TRACE(m_Time + "\n");
        //UpdateData(false); // Hvis denne linie udføres, kommer der en masse messages => ikke længere idle...
        return 0;
    }

    if(message != WM_KICKIDLE)
        m_bIsIdle = false;

    TRACE("Message: %d\n", message);
    return CDialog::WindowProc(message, wParam, lParam);
}
Avatar billede snowball Novice
17. september 2002 - 17:39 #24
Kan du ikke sende det komplette eksempel til mig (mail@geertsen.dk) så jeg kan få de rigtige datatyper på variablerne og sådan !? :)

Snowball
Avatar billede jpk Nybegynder
18. september 2002 - 09:37 #25
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.


// OnIdleDialogDlg.h : header file
//
#include <afxpriv.h>              // For WM_KICKIDLE

/////////////////////////////////////////////////////////////////////////////
// COnIdleDialogDlg dialog

class COnIdleDialogDlg : public CDialog
{
// Construction
public:
    CTime m_BeginIdleTime;
    COnIdleDialogDlg(CWnd* pParent = NULL);    // standard constructor

// Dialog Data
    //{{AFX_DATA(COnIdleDialogDlg)
    enum { IDD = IDD_ONIDLEDIALOG_DIALOG };
    CStatic    m_TimeStatic;
    CString    m_TimeDisplay;
    //}}AFX_DATA

    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(COnIdleDialogDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
    //}}AFX_VIRTUAL

// Implementation
protected:
    bool m_bIsIdle;
    HICON m_hIcon;

    // Generated message map functions
    //{{AFX_MSG(COnIdleDialogDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg LRESULT OnKickIdle(WPARAM, LPARAM);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};



// OnIdleDialogDlg.cpp : implementation file
//

#include "stdafx.h"
#include "OnIdleDialog.h"
#include "OnIdleDialogDlg.h"

/////////////////////////////////////////////////////////////////////////////
// COnIdleDialogDlg dialog

COnIdleDialogDlg::COnIdleDialogDlg(CWnd* pParent /*=NULL*/)
    : CDialog(COnIdleDialogDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(COnIdleDialogDlg)
    m_TimeDisplay = _T("");
    //}}AFX_DATA_INIT
    // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void COnIdleDialogDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(COnIdleDialogDlg)
    DDX_Control(pDX, IDC_TIME_DISPLAY, m_TimeStatic);
    DDX_Text(pDX, IDC_TIME_DISPLAY, m_TimeDisplay);
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(COnIdleDialogDlg, CDialog)
    //{{AFX_MSG_MAP(COnIdleDialogDlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_MESSAGE(WM_KICKIDLE, OnKickIdle)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COnIdleDialogDlg message handlers

LRESULT COnIdleDialogDlg::OnKickIdle(WPARAM, LPARAM lCount)
{
    if(!m_bIsIdle)
    {
        m_BeginIdleTime = CTime::GetCurrentTime();
        SetTimer(0, 100, NULL);
        m_bIsIdle = true;
    }

    return FALSE;
}

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);
}
Avatar billede snowball Novice
18. september 2002 - 09:47 #26
Så var det næsten rigtigt det jeg havde gættet mig frem til ;)

Jeg får dog en fejl ved IDC_TIME_DISPLAY

--------------------Configuration: My - Win32 Debug--------------------
Compiling...
MyDlg.cpp
E:\C progs\My\MyDlg.cpp(32) : error C2065: 'IDC_TIME_DISPLAY' : undeclared identifier
Error executing cl.exe.

My.exe - 1 error(s), 0 warning(s)

Snowball
Avatar billede jpk Nybegynder
18. september 2002 - 09:49 #27
Jeg har lige sendt projektet til dig, prøv at kompilere det.
Avatar billede snowball Novice
18. september 2002 - 09:50 #28
Yeps. Fandt ud af det da jeg modtog dit projekt :)

Snowball
Avatar billede jpk Nybegynder
18. september 2002 - 09:54 #29
Prøv at læse kommentarerne jeg har lavet i projektet.
Hvis du stadig ikke er helt med på hvad der foregår, skal du bare spørge...
Avatar billede snowball Novice
18. september 2002 - 09:59 #30
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 !?

Du har dog allerede fuldt fortjent point'ene :)

Snowball
Avatar billede jpk Nybegynder
18. september 2002 - 10:11 #31
Jeg tænkte nok du ville spørge om det...

Hvis nu du gennemlæser koden et par gange tror du så ikke du kan finde ud af at lave tilføjelsen..?

Jeg vil hellere have du også lærer lidt af det...
Avatar billede snowball Novice
18. september 2002 - 10:18 #32
Kan godt regne ud af det nok har noget med WM_MOUSEMOVE at gøre, men nedenstående virker ikke.

if((message == WM_TIMER) || (message == WM_MOUSEMOVE))

Et hint !?

Snowball
Avatar billede jpk Nybegynder
18. september 2002 - 10:21 #33
Til VS hører et lille program kaldet Spy++, prøv om du kan finde det i programmenuen
Avatar billede snowball Novice
18. september 2002 - 10:26 #34
Jeg får følgende beskeder når jeg bevæger musen i mit program: WM_NCHITTEST, WM_SETCURSOR og WM_MOUSEMOVE

!?

Snowball
Avatar billede snowball Novice
18. september 2002 - 10:43 #35
Hvis jeg filtrere alt på nær Keyboard og Mouse fra, så får jeg kun WM_SETCURSOR og WM_MOUSEMOVE beskeder !

Snowball
Avatar billede jpk Nybegynder
18. september 2002 - 10:52 #36
1) Der hvor jeg tjekker på WM_TIMER opdateres tiden, det skal den ikke ved hver WM_MOUSEMOVE osv!

2) Du behøver ikke sætte så mange parenteser...

3) Prøv at erstatte "if(message != WM_KICKIDLE)" med:
if(message != WM_KICKIDLE && message != WM_NCHITTEST && message != WM_MOUSEMOVE && message != WM_NCMOUSEMOVE && message != WM_SETCURSOR)
Avatar billede snowball Novice
18. september 2002 - 10:54 #37
Perfekt !

Mange tak for hjælpen :)

Snowball
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester