16. oktober 2001 - 11:02Der er
18 kommentarer og 1 løsning
Optegning indefra en klasse.
Jeg arbejder på et modulopbygget system, der skal kunne simulere et simpelt væskeflow. Til dette har vi lavet en klasse med grundegenskaberne for disse moduler, og nedarvet denne i 4 afledede klasser. (Pumper, junctions, ventiler og rør).
Problemet er nu at vi skal have dem til at optegne sig selv i vores vindue. Vi har prøvet at gøre dette tidligere, ved at give klassen HWND til vinduet, for derefter at lade klassen indhente HDC og forsøge en optegning. Men dette gav ingen optegning. Det var som om at klassen ikke kunne bruge hwnd til noget. (Jeg prøvede at kaste nogle messageboxes til det, men forgæves)
Det originale design er baseret på at tegne direkte i client-området på et MDI vindue, men lige nu under udviklingen af dette her sæt klasser tegner vi i clientområdet på et standardvindue.
Bare en designovervejelse: Har i overvejet at lave et mellemlag, således objekterne ikke skal tegne sig selv (for at adskille data og visning)?
Men... Ellers vil jeg foreslå, at draw-metoderne i objekterne får en CDC* som argument og så tegner sig selv på dette (device context). Herved kan i lettere understøtte fx print (da man i MFC typisk vil oprette et CDC for en printer ligeledes)
C++ Builder (der var den igen) har et eksempel, hvor man lader tre forskellige tråde (TThreads) tegne sine data på en og samme client. Den eneste challenge her, er at sikre exclusivitet, dvs. at to forskellige tråde ikke tilgår den samme client på een gang. I deres eksempel gjorde man dette vha. Synchronize() metoden.
Humlen i deres løsning var imidlertid det at klasserne ikke tegnede noget selv, men derimod kaldte en hovedmetode til tegning, men navnet på trådens (= klassens) egen tegne metode som parameter. Hermed er både exclusivitet og uafhængighed sikret.
void __fastcall TSortThread::DoVisualSwap() { // Her hægter vi os på hoved canvas\'en (Borland\'s navn for en Device Context) TCanvas *canvas; canvas = FBox->Canvas; canvas->Pen->Color = TColor(clBtnFace);
// Her tegner vi så vha. lokale/klassespecifikke // metoder. PaintLine(canvas, FI, FA); PaintLine(canvas, FJ, FB); canvas->Pen->Color = clRed; PaintLine(canvas, FI, FB); PaintLine(canvas, FJ, FA); } void __fastcall TSortThread::VisualSwap(int A, int B, int I, int J) { // Wrapper variabler til parameter overførsel // til den parameterløses synchronize metode. FA = A; FB = B; FI = I; FJ = J;
Synchronize(DoVisualSwap); }
(Synchronize metoden kræver navnet på en void function(void) metode.) Pointeren til hoved canvas\'et får tråden i sin constructor:
Med stikordene Pumper, junctions, ventiler og rør tror jeg man kan forvente en del objekter og at lade hver af disse objekter tegne sig selv i en seperat tråd er vist lige i overkanten...
Et lag der gør, at dine data ikke behøver at have noget med grafisk repræsentation at gøre og at dit vindue ikke behøver at kende til strukturen i dine data.
Jeg har lidt svært ved at forestille mig hvordan vi skal kunne få den lagdeling ind i designet.
Men anyways.
Vi regner med at lave et CDC i hukommelsen og optegne i dette. Al optegningen foregår via rekursive kald ind igennem flow-netværket, så vi er sikre på at der ikke tegnes samtidigt.
Derefter vil vi forsøge at anvende BitBlt til at overføre billedet til brugergrænsefladen.
Er der nogen der synes det her lyder helt åndsvagt? :)
Vi sidder netop og diskuterer om det ville være smart at lave et statisk public bitmap i vores moderklasse. (Den der er forælder til alt der skal tegnes) For at alle de afledede klasser kunne tegne i den. På den måde kunne man via en getHandleTilBitmap() funktion blitte bare man havde adgang til et enkelt af netobjekterne.
Jeg forstår ikke hvorfor du først vil tegne dit objekt på en lokal bitmap, for derefter at tegne den (bitmappen) på en central bitmap. Er det ikke unødvendig dobbeltkonfekt ?
Jeg bryder mig ikke om ideen med et statisk bitmap! Lad dog være med at lave jeres design mere kompliceret end nødvendig!!!
Her er hvad jeg forestiller mig/har forstået på jer:
I skal kunne repræsentere et væskeflow grafisk. Forestil jer en klasse CFluidFlow, der ligner denne:
class CFluidFlow { public: CFluidFlow(); AddModule(CModule Module); Draw(CDC* pDC); // Denne klasse har ligeledes en draw-metode, der gennemløber vectoren og kalder hver objekt\'s Drawmetode // Altså kan man tegne hele sit flow med et enkelt kald til CFluidFlow objektets Draw-metode
protected: vector<CModule*> m_Modules; }
En instans af CFluidFlow indeholder alle de moduler der indgår i et flow. Jeres specifikke moduler nedarver alle fra en fælles baseklasse CModule. dette muliggør, at man i en datastruktur som fx vector eller list kan have samtlige moduler
class CModule // Baseklasse { virtual void Draw(CDC* pDC) = 0; // Skal implementeres i alle nedarvinger }
class CPump : public CModule { public: // Methods void Draw(CDC* pDC); // Denne metode tegner objektet på dc\'et (man kan således kalde Draw() med andre typer af dc\'s, fx for en printer og man har udskrivning uden extra arbejde)
CFluidFlow\'s Draw-metode kan jo gøre noget lign. dette:
CDC dcMem; dcMem.CreateCompatibleDC(pDC); // pDC er en pointer til skærmens dc BITMAP bm; CBitmap bitmap; bitmap.GetBitmap(&bm); CBitmap* pOldBitmap = dcMem.SelectObject(&bitmap);
// Kald så hvert moduls Draw-metode med &dcMem som argument
// Til sidst kaldes pDC->BitBlt (også med &dcMem som argument) for at overføre det tegnede til skærmen
Synes godt om
Ny brugerNybegynder
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.