Keresés
Hírlevél
 
Kiemelt témák
»Hogyan védjem meg a portálomat?
»Ki legyen a nagytestvér?
»Google wave
»Assembly :: röviden
Állás/munka
»Junior .NET fejlesztő
»Java fejlesztőt keresünk Android fejlesztésre
»Android és iPhone fejlesztőket keresünk
»Grafikust keresünk távmunkában
»Raktárprogram
» több téma
Tudástár
?Ajaxos file betöltése utána alert
?JProgressBar használata
$_SESSION hiba
?Címkefelhő készítés
*JavaScript Selectable probléma
*WCF TCP Streamed transfer mode lehet duplex?
?Képernyő felbontás lekérdezése
Inputok szövegeit függőlegesen középre
?A kép nem találja futtatáskor
C#, Textbox, OnPaint metódus probléma
Delphi + DBGrid + Edit
Main(string[] args) lekérdezés, hogyan?
?Mysql select 3 táblából
?PHP sql insert into hiba
?Else ág hibája
» több téma
Társalgó
»Melyik programozási nyelv ér a legtöbbet?
»ExpressCard vélemények
»Java, vagy C# desktopra (Linux és Windows)?
»Ötödik Microsoft-vizsgájára készült egy 9 éves kisfiú
»Ajánljatok valami tárhelyszolgáltatót pls :)
»Flash 3D Mivel?
»Fut-e a Visual C#...
»Clipper kontra XP
»Melyik a legjobb Java oktató cég
»Weblap véleményezés
» több téma
Cikkek
»Bevezetés a genetikus algoritmusokba
»Bevezetés az adatkezelésbe
»Bevezetés a CSS alapjaiba
»GroupWise-kiegészítők készítése Python-ban
»Aspektus-orientált programozás
» több cikk
ASP  |  C#  |  C++  |  CSS  |  Delphi  |  Flash  |  HTML  |  Java  |  JavaScript  |  Pascal  |  Perl  |  PHP  |  Python  |  Visual Basic  |  Visual C++  |    »    

Cikkek

»

Programozási nyelvek

»

Visual C++

»

Eszközkörnyezetek és bittérképek

A sorozat további cikkei:
szerző: Kumm, idő: 1999.09.15., értékelés: 4 (1 szavazat)
  Betűméret növelése Betűméret csökkentése Kapcsolódó fórum Felvétel kedvencekhez Küldés emailben Nyomtatható verzió
Ahogy az már itt-ott előjött, az ablakra való rajzoláshoz, szövegkiíráshoz egy eszköz-környezet objektumra van szükségünk, amely az adott ablakhoz, vagy eszközhöz van rendelve, amely fogadja az outputot. Ez lehet akár egy nyomtató, vagy a képernyő, vagy csak egy ablak, vagy az ablak egy része.
A példaprogram egy tetris lett.

Tetrist már mindenki látott. Négy blokkból álló figurákat kell egymásra ejteni. Ha betelik egy sor, azt töröljük, ha nem tud több beesni, vesztettük. Nyerni meg nemigen lehet.

A megvalósítás egyszerű (mármint egy quake-hez képest). Arra azért vigyázzunk, hogy senki se írjon Tetris nevű Tetrist, mert az jogilag le vagyon védve. A tetrisprogramozás rejtelmeibe nem nagyon fogok belemélyedni, aki kicsit is tud programozni, van róla fogalma, hogyan kell megoldani a figurák forgatását, mozgatását, eltárolását, sorok törlését stb... Inkább az MFC -vel történő grafikus kezelés és a bittérképek témakörében szeretnék segíteni.

Az Eszköz-környezet Objektum (Device Context)

Ahogy az már itt-ott előjött, az ablakra való rajzoláshoz, szövegkiíráshoz egy eszköz-környezet objektumra van szükségünk, amely az adott ablakhoz, vagy eszközhöz van rendelve, amely fogadja az outputot. Ez lehet akár egy nyomtató, vagy a képernyő, vagy csak egy ablak, vagy az ablak egy része. Az eszköz-környezet tartalmazza a kiválasztott rajzolóeszközöket, az attribútumokat, és a különböző alakzatok rajzolásához, és bittérképműveletekhez szükséges tagfüggvényeket.

Ha egy nézetablakban (View) akarunk grafikát megjeleníteni, akkor annak az OnDraw függvényének átadott eszköz-környezettel tudjuk megtenni. Ha egy Dialógusablakban, akkor pedig az OnPaint függvényben kell újrarajzolni.

void CTetrisWnd::OnPaint()
{
    CPaintDC dc(this); // device context for painting
 

Eszköz-környezet objektumból több típusú is van, de mindegyik a CDC osztályból származtatott.

  • CPaintDC Csak az OnPaint függvényből használható, egy dialógusablak, vagy egy Control- nak az újrarajzolásakor.
  • CClientDC Segítségével a nézetablakba (Client Area) rajzolhatunk
  • CWindowDC Az ablak által használt egész területre rajzolhatunk.
  • CMetafileDC Windows metaFile-ba rajzolhatunk..
Eszköz-környezetek létrehozása:

A CpaintDC, CClientDC és CWindowDC számára meg kell adni a CWnd osztály címét, ahonnan létrehoztuk. Ebből következik, hogy őket csak egy olyan osztályból tudjuk létrehozni, amely a CWnd ből származik. Ez nem okoz gondot, hiszen minden ablak osztály őse.

Pl.
    CClient dc(this);

Ha az ablak görgethető, akkor az OnPrepareDC függvényit is meg kell hívni. De erről már volt szó.

Bittérképek és bitműveletek.

A bittérkép egy kép pontos reprezentációja a memóriában, vagy egy fájlban. Minden egyes pixel színét, tárolja, ez elég a megjelenítéshez.

Ha MFC-ben bittérképet akarunk használni, a CBitmap osztály egy példányát kell használnunk. Ez az osztály biztosítja a bittérképek létrehozását, tárolását, betöltését. Egy példány létrehozása:

CBitmap m_bitmap;

Egy bittérképet létrehozhatunk üresen, betölthetünk file-ból, vagy erőforrásból.

Bittérkép betöltése Erőforrásból.

Egy bittérkép erőforrásként történő kezelése azzal az előnnyel jár, hogy a fordító beleszerkeszti az adatot az .exe állományba, így nem fog külön bmp-ként megjelenni.

Az Insert/Resource menüpontnál, vagy a New gombra nyomunk, ekkor a Visual C++ szerkesztőjében tudjuk megrajzolni. Ha az Import gombot választjuk, egy bmp állomány-t rakhatunk be az erőforrások közé. Ez csak akkor jelenik meg a szerkesztőben, ha kevesebb, mint 256 színű.

Minden bittérképnek, ahogy más erőforrásnak is van azonosítója (ID-je). Ezt az ID-t dupla kattintással a Resource View-ban be tudjuk állítani, és megjegyezni sem árt.

Ha sikerült a bittérképet valahogy betuszkolni az erőforrások közé, a programból valahogy be is kell tölteni.

    m_bitmap.LoadBitmap(IDB_BITMAP);

A LoadBitmap függvénynek átadott paraméter az az azonosító, melyet hozzárendeltünk a szerkesztőben. A bittérkép automatikusan kompatíbilis lesz az outputtal.

Üres bittérkép létrehozása

Szerkesztőben való létrehozás helyett hozhatunk létre bittérképet a memóriában is a program futása közben. Ekkor a képet az MFC rajzolófüggvényeivel, és bittérképműveleteivel tudjuk létrehozni, miután eszköz-környezet objektumot rendeltünk hozzá. A bittérkép létrehozását a CBitmap CreateCompatibleBitmap tagfüggvénye végzi.

Pl.:
    m_pWinDC = new CWindowDC(this);
    m_Bitmap.CreateCompatibleBitmap(m_pWinDC,size.cx,size.cy);

CreateCompatibleBitmap függvény első paramétere egy eszköz-környezet objektum címe, ezzel lesz kompatíbilis a bittérkép. Ez azt jelenti, hogy az adatok ugyanúgy lesznek tárolva, ahogy az outputot végző eszköz tárolja azokat. Például ha a monitor true color módban van 3 byte határozza meg egy pixel színét a képernyő-memóriában. Egy ezzel kompatíbilis bittérképen szintén 3 byte határozza meg a pixelt.
A függvény második paramétere a bittérkép szélessége, a harmadik a magassága pixelekben
A függvény egy memóriablokkot rendel a bittérképhez, melyen a pixelek színei definiálatlanok. A bittérképet a CDC rajzolófüggvényeivel tudjuk megrajzolni. Ahhoz viszont, hogy rajzolni tudjunk a bittérképre, létre kell hozni, és hozzá kell rendelni egy eszköz-környezet objektumhoz. A Windows különleges típusú eszköz-környezet objektumokat biztosít a bittérképek használatára, ezek a memória eszköz-környezetek. Egy ilyen létrehozásához a CDC osztály egy példányát kell definiálnunk, majd a CreateCompatibleDC függvényt meghívva létrehozzuk.

Pl.:
    m_pMemDC = new CDC;
    m_pMemDC->CreateCompatibleDC(m_pWinDC) ;
 

A CreateCompatibleDC függvénynek a paramétere egy eszköz-környezet objektum címe, a kapott eszköz-környezetünk avval az eszközzel lesz kompatíbilis, amely a paraméternek megadotthoz volt hozzárendelve. Így aztán az átadott eszköz-környezetnek ugyanahhoz az eszközhöz kell kapcsolódnia, amihez a CreateCompatibleBitmap-nek megadottnak. Ezt praktikusan úgy érjük el, hogy ugyanazt az eszköz-környezet objektum címet adjuk át mindkét függvénynek.
Tehát esetünkben lett egy a képernyővel kompatíbilis eszköz-környezetünk. Ami ugye nincsen hozzárendelve semmihez sem.
Még hozzá kell rendelni a bittérképhez. A CDC SelectObject tagfüggvényével.

Pl.:
    m_pMemDC->SelectObject( &m_bitmap);

A függvénynek a bittérkép címét kell megadni paraméterként. Visszatérési értéke az eddig hozzárendelt bittérkép.

Ha ezzel megvagyunk, már rajzolhatunk is a bittérképre a memória eszköz-környezet objektumot használva.

Ha bittérképet megsemmisítjük előtte a memória eszköz-környezetet is meg kell semmisíteni, vagy egy másik bittérképet hozzárendelni. Például a régit, amit visszaadott a SelectObject függvény.

Nézzük egyben az egészet:

void CTetrisWnd::CreateBuffer()
{
    CRect rect;
    CSize size;
    GetClientRect(&rect);
    size = rect.Size();
    if(m_pWinDC!=NULL)
    {
        delete m_pWinDC;
        m_pWinDC=NULL;
    }
    m_pWinDC = new CWindowDC(this);
    if (m_Buffer.m_hObject != NULL)
        m_Buffer.DeleteObject();
    m_Buffer.CreateCompatibleBitmap(m_pWinDC,size.cx,size.cy);
    if (m_pMemDC!=NULL)
    {
        m_pMemDC->SelectObject(m_pOldBitmap);
        delete m_pMemDC;
        m_pMemDC = NULL;
        m_pOldBitmap = NULL;
    }
    m_pMemDC = new CDC;
    VERIFY( m_pMemDC->CreateCompatibleDC(m_pWinDC) );
    m_pOldBitmap = m_pMemDC->SelectObject( &m_Buffer );
    m_Size=size;
    m_width=size.cx/m_BlockWidth;
    m_height=size.cy/m_BlockHeight;
}

A függvény készít egy m_Buffer nevű bittérképet, és készít egy memória eszköz-környezetet, melyhez hozzárendeli a bittérképet. Arra is figyel, ha már ezek el vannak készítve, először megsemmisíti őket. A létrehozott memória-eszközkörnyezet a programban Frame Buffer-ként fog funkcionálni.

Bittérképek megjelenítése (másolása)

Egy bittérkép megjelenítése tulajdonképpen csak másolás, eszköz-környezetek közötti adatcsere. Az adatok továbbítása eszköz-környezetek között a CDC osztály BitBlt tagfüggvényével történik.

BOOL BitBlt(int x,
            int y,
            int nWidth,
            int nHeight,
            CDC* pSrcDC,
            int xSrc,
            int ySrc,
            DWORD dwRop);

Az első két paramétere a másolás céljának bal felső sarkának logikai koordinátái, a második kettő a bittérkép szélessége és magassága a következő a forrás eszköz-környezet objektum címe, aztán a másolandó bittérkép bal felső koordinátái, majd a raszterműveleti kód.

A függvény az ötödik paraméterként megadott eszköz-környezethez rendelt eszközről másol át egy adatblokkot arra az eszközre, amely ahhoz az eszközkörnyezethez volt rendelve, amelyre a függvényt meghívtuk.

A raszterműveleti kódokat nem írom le, megtalálhatóak a help-ben. Platform SDK, Graphics and Multimedia Services, GDI, Raster Operation Codes

Ami nekünk most kell az az SRCCOPY, amely változtatás nélküli másolást végez.

Egy példa:

void CTetrisWnd::ShowFrame()
{
    m_pWinDC->BitBlt( 0, 0, m_Size.cx, m_Size.cy, m_pMemDC, 0, 0, SRCCOPY );
}

A függvény a m_pWinDC eszköz-környezethez rendelt ablakra másolja az m_pMemDC eszköz-környezethez rendelt bittérképet mindenféle változtatás nélkül. Röviden kirakjuk a Frame Buffer-ünket. Némileg bonyolultabb a dolog, ha nincs eszköz-környezet objektum rendelve a bittérképhez.

Egy példa, ahol egy mátrixból felépítjük a képet a tetris blokkok másolásával. A blokkok egy bittérképen vannak, amihez nincs eszköz-környezet rendelve, tehát kell egyet készítetnünk.

void CTetrisWnd::BuildFrame()
{
    int x;
    int y;
    BYTE c;
    CDC dc;
    dc.CreateCompatibleDC(NULL);
    dc.SelectObject(&m_Blocks);
    m_pMemDC->PatBlt(0,0,m_Size.cx,m_Size.cy,BLACKNESS);
    for(x=0; x<m_width; x++)
        for(y=0;y<m_height;y++)
        {
            if ((c=*(m_matrix+y*m_width+x))!=0)
            {
                m_pMemDC->BitBlt( x*m_BlockWidth,
                    y*m_BlockHeight,
                    m_BlockWidth,
                    m_BlockHeight,
                    &dc,
                    Colors[c-1]*m_BlockWidth,
                    0, SRCCOPY );
            }
        }
}

Először létrehozunk egy memória eszköz-környezetet, és meghívjuk a CreateCompatibleDC függvényét. Ha a függvényt NULL paraméterrel hívjuk, a képernyővel kompatíbilis eszköz-környezetet készít. A SelectObject függvénnyel hozzárendeljük a bittérképet, majd a BitBlt alkalmazásával a m_pMemDC-re felépítjük a képet a dc eszközkörnyezeten található blokkokból.

A CDC osztály PatBlt tagfüggvényéről még nem esett szó. Evvel tudjuk feltölteni a bittérképet. Az első két paraméter a feltöltendő terület bal felső sarkának logikai koordinátái, a harmadik és negyedik a feltöltendő terület szélessége és magassága, az utolsó pedig a raszterműveleti kód. Esetünkben a BLACKNESS azt jelenti, hogy feketével töltjük fel a bittérképet.

Ennyit a részletekről.

A program dialógusablak alapú, ezért le kellett mondani a szokásos kurzormozgató billentyűkkel történő irányításról. Dialógusablak lévén, ezek a billentyűk a gombok közti mozgásra valók, és az MFC nem töri magát agyon, hogy tudassa velünk mikor melyik nyilat nyomták meg. Például nem jön létre WM_KEYDOWN üzenet, így az OnKeyDown-ban nem tudnánk kezelni őket.

Ezért lett ez a "balkezes" kiosztás.

Az ablak, ahol a játék fut, a CStatic osztályból származtatott. Ebből volt a legegyszerűbb. A ClassWizard-al össze kell rendelni a control-t az objektummal, így a control-t a mi Classunk fogja kezelni.

Ennyi.

- Kumm -
Küldés emailben Küldés emailben Nyomtatható verzió Nyomtatható verzió
Értékeld a cikket!
rossz 1 2 3 4 5     jó  
A sorozat további cikkei:
Belépés
E-mail cím:
Jelszó:

Állásajánlat
Tehetséges C#, .NET fejlesztőket keres vezető videotechnikai cég
RSS források
-Hírek
-Cikkek
-Fórumok
Top pontgyűjtők
»Micu1.450
»Árnyék910
»djjjozsi630
»vinie360
»klorand350
»pelz300
»Riha270
»@sanya200
»mrviceguy180
»Frostech0120
Hírek
»Ötödik Microsoft-vizsgájára készült egy 9 éves kisfiú
»Letölthető a Ruby on Rails 3.0 első bétája
»Letölthető a Moonlight 3.0 előzetes kiadása
»Kidobták a Linux kernelből a Google-t
»Feltörhetők az Oracle adatbázisszerverek
» több hír
PC Fórum hírek
»Született informatikusokat keresnek
»Élőbeszédet is tudnak majd fordítani a Google jövőbeni telefonjai
»A felhasználói tartalom 95%-a használhatatlan vagy veszélyes
»Új internet-protokollra vált a YouTube
»Szerencsétlen számú Windows-javítás érkezik jövő kedden
»Milliárdokért adott el Linuxot a Microsoft
»Jogosítványhoz kötné az internetezést a Microsoft
»Szövetségre lép az USA nemzetbiztonsági hivatalalával a Google
Tagi blogok
»Én és linux
»Coming out
»2010/1
»Webfejlesztő cég indítása