Avatar billede the_bma_man Nybegynder
15. marts 2004 - 15:18 Der er 16 kommentarer og
1 løsning

Grafik i titlebar i MDI Child vindue

Hejsa - så har jeg brug for hjælp fra de rigtig skrappe!!

Jeg har fået en lille opgave, jeg ikke selv tror på umiddelbart kan løses. Men håber da, at een her har løsningen.

Scenarie:
Vi har en tabel, tabelX, med data, nøgle, farvekode, procentsats.

Når jeg åbner mit child-vindue, skal jeg ud fra nøglen herpå lave et opslag i denne tabelX (det kan jeg sagtens finde ud af :-)).
Data skal så bruges til en slags "trafik-lys" - en slags progress-bar, hvor "baren" skal have den farve, som farvekoden i tabelX angiver, og den skal være så mange procent "udfyldt" som procentsatsen fra tabelX angiver. Altså - der er ingen beregninger, det skal bare vises.

Men nu kommer så problemet - det ønskes vist i titlebaren.

Kan det overhovedet lade sig gøre?

Og i så fald - hvordan gør jeg det?
Avatar billede the_bma_man Nybegynder
15. marts 2004 - 15:18 #1
P.S.
Jeg er væk i morgen, så jeg kan først vende tilbage og kigge på svar på onsdag.
Så tag Jer endelig god tid til at finde den geniale løsning :-)
Avatar billede jpk Nybegynder
16. marts 2004 - 08:46 #2
Det kan faktisk sagtens lade sig gøre.
I din klasse nedarvet fra CMDIChildWnd kan du override OnNcPaint og implementere den således:

void CChildFrame::OnNcPaint()
{
    CMDIChildWnd::OnNcPaint();

    CRect rcWindow, rcDraw, rcPercentage;
    GetWindowRect(&rcWindow);

    rcDraw.left = GetSystemMetrics(SM_CXSIZE) + GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME);
    rcDraw.top = GetSystemMetrics(SM_CYFRAME);
    rcDraw.right = rcWindow.Width() - (3*GetSystemMetrics(SM_CXSIZE) + GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME));
    rcDraw.bottom = GetSystemMetrics(SM_CYSIZE);

    CDC* pDC = GetWindowDC();

    // Values from DB
    int nPercentage = 33;
    COLORREF color = RGB(255, 0, 0);

    rcPercentage = rcDraw;
    rcPercentage.right = rcPercentage.left + (rcDraw.Width() * nPercentage) / 100;
    CPoint pt(5, 5);
    pDC->RoundRect(&rcDraw, pt);
    CBrush ProgressBrush(color);
    CBrush* pOldBrush = pDC->SelectObject(&ProgressBrush);
    pDC->RoundRect(&rcPercentage, pt);
    pDC->SelectObject(pOldBrush);
    ReleaseDC(pDC);
}

Jeg har bare indført et par variabler (nPercentage og color) som du skal give de rigtige værdier.
Du skal dog bemærke at det nok ikke er en god ide at hente værdierne fra en database hver gang, da det vil sløve funktionen en del og den bliver kaldt mange gange!

Du skal desuden, i PreCreateWindow, fjerne titlen, så den ikke tegnes i vinduet:

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    cs.style &= ~FWS_ADDTOTITLE;
    if( !CMDIChildWnd::PreCreateWindow(cs) )
        return FALSE;

    return TRUE;
}
Avatar billede the_bma_man Nybegynder
16. marts 2004 - 16:48 #3
Hep.
Du skriver, jeg skal fjerne titlen.
Men jeg skal jo gerne stadig have det med i title-baren, som der er i dag. Vinduet har faktisk en sigende caption.
Jeg forestiller mig, at denne "farvelade" skal ligge ovre til højre, lige ved siden af knapperne til minimer, windowiser og luk??
Men ellers tester jeg lige dit eksempel i morgen, når jeg er tilbage på jobbet - og vender så frygteligt tilbage :-)
Avatar billede the_bma_man Nybegynder
16. marts 2004 - 16:50 #4
Angående det at hente data fra DB. Det forestiller jeg mig heller ikke, at vi gør hele tiden. Vi læser i forvejen en masse data, der skal præcenteres i vinduet, og det vil blive i denne sammenhæng, at "farvelade"-data læses også - og gemmes i member-vaiable.
Avatar billede jpk Nybegynder
16. marts 2004 - 20:37 #5
Okay, jeg troede du ville bruge hele title bar'en til progress...

Du kan dog ret let ændre koden til at have en højrestillet progress bar på fx 60 pixels i bredden:

void CChildFrame::OnNcPaint()
{
    CMDIChildWnd::OnNcPaint();

    int nProgressWidth = 60; // Progress bar width in pixels
    CRect rcWindow, rcDraw, rcPercentage;
    GetWindowRect(&rcWindow);

    rcDraw.top = GetSystemMetrics(SM_CYFRAME);
    rcDraw.bottom = rcDraw.top + GetSystemMetrics(SM_CYSIZE);
    rcDraw.right = rcWindow.Width() - (3 * GetSystemMetrics(SM_CXSIZE) + GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME));
    rcDraw.left = rcDraw.right - nProgressWidth; // Subtract width of progress bar

    CDC* pDC = GetWindowDC();

    // Calculate space used by icons and text
    CString strTitle;
    GetWindowText(strTitle);
    int nOccupiedSpace = GetSystemMetrics(SM_CXSIZE) + GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME) + pDC->GetTextExtent(strTitle).cx + (rcWindow.Width() - rcDraw.right);
    if(nOccupiedSpace + nProgressWidth < rcWindow.Width()) // Only draw if space enough
    {
        // Values from DB
        int nPercentage = 33;
        COLORREF color = RGB(255, 0, 0);

        rcPercentage = rcDraw;
        rcPercentage.right = rcPercentage.left + (rcDraw.Width() * nPercentage) / 100;
        CPoint pt(5, 5);
        pDC->RoundRect(&rcDraw, pt);
        CBrush ProgressBrush(color);
        CBrush* pOldBrush = pDC->SelectObject(&ProgressBrush);
        pDC->RoundRect(&rcPercentage, pt);
        pDC->SelectObject(pOldBrush);
    }

    ReleaseDC(pDC);
}

Du skal så bare lade være med at fjerne FWS_ADDTOTITLE style'en.
Som du kan se, har jeg tilføjet kode, så progress bar'en kun tegnes, hvis der er plads nok.
Avatar billede the_bma_man Nybegynder
16. marts 2004 - 20:40 #6
Super - det ser fornuftigt ud.
Jeg checker det lige i morgen - når jeg kommer i nærheden af en compiler :-)

I'll B back ...
Avatar billede the_bma_man Nybegynder
17. marts 2004 - 09:05 #7
Hejsan.
Så er han på jobbet - og prøver at få den anden udgave af løsningen til at fungere.
Jeg har impelementeret void CChildFrame::OnNcPaint(), og i .h-filen defineret en virtual metode - altså override OnNcPaint.
Men jeg må mangle et eller andet - min OnNcPaint bliver _ikke_ kaldt.
???
Er der et sted, jeg skal angive (i ressourcen) at den er userdrawn, for at det vil virke?
Avatar billede jpk Nybegynder
17. marts 2004 - 09:07 #8
Bruger du VC++ 6 eller 7?
Avatar billede the_bma_man Nybegynder
17. marts 2004 - 09:17 #9
VC++ 6 ED
Avatar billede the_bma_man Nybegynder
17. marts 2004 - 09:46 #10
Det er et projekt, der bruger Document/View arktitekturen. Men det bør vel ikke give den store forskel?
Avatar billede jpk Nybegynder
17. marts 2004 - 09:46 #11
Hmm, er den nyeste version af embedded VC++ ikke nr 4..?

Du kan bruge ClassWizard'en til at tilføje message handlers.
Jeg har ikke VCe installeret her, men jeg mener det er noget lign:

1) Med filen åben, trykker du Ctrl+w
2) Vælg fanebladet med messages
3) Find WM_NCPAINT og dobbeltklik
Avatar billede jpk Nybegynder
17. marts 2004 - 09:47 #12
Eller mener du EE, Enterprise Edition?
Avatar billede the_bma_man Nybegynder
17. marts 2004 - 10:30 #13
Ja - han mente EE. Sorry!!!
Avatar billede the_bma_man Nybegynder
17. marts 2004 - 10:40 #14
Ja, men bliver den message ikke postet af CMDIChildWnd?
Jeg har overstyret metoden - men den blive ikke kaldt.
(Har selvfølgelig sat et breakpoint, og prøvet at checke det)
Det er lavet på samme måde som min CChildFrame::PreCreateWindow(CREATESTRUCT& cs), og den bliver kaldt.
Avatar billede jpk Nybegynder
17. marts 2004 - 10:46 #15
Du skal jo gøre 3 ting:

1) Tilføje "afx_msg void OnNcPaint();" i din header
2) Tilføje "ON_WM_NCPAINT()" i message map'et i .cpp
3) Implementere funktionen i .cpp

Du har muligvis glemt nr. 2..?

For at gøre processen med at tilføje message handlers hurtige og lettere, kan du bruge wizard'en, da den gør det for dig...
Avatar billede the_bma_man Nybegynder
17. marts 2004 - 10:57 #16
Arhh - det prøves lige.
Jeg læste dit "override OnNvPaint" i dit oprindelige svar som, at det var en virtuel metode, jeg skulle overstyre.
Hep - vender tilbage ....
Avatar billede the_bma_man Nybegynder
17. marts 2004 - 11:24 #17
Jamen FOR HUNDEN.

Det virker jo - Perfekt.

Dine point er vel fortjente!!
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

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