[WINAPI] CreateBitmap, Falsche Parameter angabe? BitBlt kopiert den HDC nicht.

FBIagent

Erfahrenes Mitglied
Guten tag,

ich habe mir zwei kleine Klassen geschrieben, mithilfe ich eine Linie pixel für pixel
auf ein HDC zeichnen möchte. Hatte ich bereits mit einem 1px*1px resource Bitmap
realisiert indem ich CreateCompatibleDC(), LoadBitmap() und SelectObject() benutzt habe.
Da dies aber etwas mühsam ist jedes mal ein neues Bitmap zu erstellen, wenn ich eine
Linie mit anderer Farbe zeichnen wollte, habe ich versucht ein Bitmap mit CreateBitmap()
zur runntime ein 1px*1px zu erzeugen. Nun gut habe ich mich ein wenig in der MSDN
schlau gemacht und es versucht. Die Rückgabewerte der aufgerufenen API Funktionen
scheinen erfolgreiche Werte zurück zuliefern.

C++:
#ifndef __DRAWABLE_H__
#define __DRAWABLE_H__

#include <windows.h>

class WINAPI_Drawable
{
public:
    WINAPI_Drawable()
    {
        m_MemDC = CreateCompatibleDC(NULL);
    }

    virtual ~WINAPI_Drawable()
    {
        if (m_MemDC)
            DeleteDC(m_MemDC);
    }

    virtual void Draw(HDC &DC) = NULL;
protected:
    HDC m_MemDC;

    bool IsOk()
    {
        return m_MemDC != NULL;
    }
};

#endif

#ifndef __WINAPI_LINE_H__
#define __WINAPI_LINE_H__

#include "WINAPI_Drawable.h"

#include <windows.h>
#include <math.h>

class WINAPI_Line : public WINAPI_Drawable
{
public:
    WINAPI_Line(unsigned int StartX, unsigned int StartY, unsigned int EndX, unsigned int EndY, unsigned char BitsPerPixel, DWORD PixelColor)
    : WINAPI_Drawable(), m_BitmapHandle(NULL)
    {
        if (!WINAPI_Drawable::IsOk())
            return;

        DWORD Bit[] = {PixelColor};

        m_StartPos.x = StartX;
        m_StartPos.y = StartY;
        m_EndPos.x = EndX;
        m_EndPos.y = EndY;
        m_BitmapHandle = CreateBitmap(1, 1, 1, BitsPerPixel, Bit);
        SelectObject(m_MemDC, m_BitmapHandle);
    }

    virtual ~WINAPI_Line()
    {
        if (m_BitmapHandle)
            DeleteObject(m_BitmapHandle);
    }

    bool IsOk()
    {
        return WINAPI_Drawable::IsOk() && m_BitmapHandle != NULL;
    }

    void Draw(HDC &DC)
    {
        if (!IsOk())
            return;

        int x = m_StartPos.x;
        int y = m_StartPos.y;
        double u = m_EndPos.x - x;
        double v = m_EndPos.y - y;
        double d1x = sgn(u);
        double d1y = sgn(v);
        double d2x = sgn(u);
        double d2y = 0;
        double m = abs(u);
        double n = abs(v);

        if (m <= n)
        {
            d2x = 0;
            d2y = sgn(v);
            m = abs(v);
            n = abs(u);
        }

        double s = (int)(m / 2);

        for (int i=0;i<(int)m;i++)
        {
            BitBlt(DC, x, y, 1, 1, m_MemDC, 0, 0, SRCCOPY);
            s = s + n;

            if (s >= m)
            {
               s = s - m;
               x = x + (int)d1x;
               y = y + (int)d1y;
            }
            else
            {
               x  =  x + (int)d2x;
               y  =  y + (int)d2y;
            }
        }
    }
private:
    HBITMAP m_BitmapHandle;
    POINT m_StartPos;
    POINT m_EndPos;

    char sgn(double a)
    {
        if (a > 0)
            return +1;
        else if (a < 0)
            return -1;

        return 0;
    }
};

#endif

Ich benutze diese Klasse wie folgt:
C++:
static WINAPI_Line *g_Line = NULL;
...
    case WM_CREATE:
        g_Line = new WINAPI_Line(0, 0, 200, 200, 8, 0);

        if (!g_Line->IsOk())
        {
            MessageBoxA(hWnd, "Error in initialisation of WINAPI_Line", "Error", MB_OK);
            delete g_Line;
            g_Line = NULL;
        }

        break;
...
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);

        if (g_Line)
            g_Line->Draw(hdc);
        else
            MessageBoxA(hWnd, "g_Line is NULL", "Error", MB_OK);


        EndPaint(hWnd, &ps);
        break;

Ich in mir ziemlich sicher das es an CreateBimap() liegt, da dies das einzigste ist, was
von meiner Resource Bitmap version verändert habe. Erscheinen tut einfach garnichts in
meinem Fenster. Der linien algorithmus wird auch in der Resource Bitmap Version verwendet
und funktioniert einwandfrei.

Wäre nicht schlecht wenn mir jemand einen Tip geben könnte.

Best wishes
FBIagent
 
Zuletzt bearbeitet von einem Moderator:
Hallo,

das Format von Bitmap und DC muss übereinstimmen, sonst geht nix. Um das zu gewährleisten, verwende lieber "CreateCompatibleBitmap()".
Ansonsten, warum machst du das so umständlich und verwendest nicht die entsprechenden GDI-Funktionen (SetPixel, MoveTo, LineTo...) ? Die dürften wesentlich performanter sein, als deine Lösung.

Gruß
MCoder
 
Ich habe jetzt mal ein performance test gemacht.

1000*1000 pixel mit meiner Klasse ~20ms und mit SetPixel() ~500ms da liegt es wohl
nahe, das ich meine Klasse lieber benutze als SetPixel().

Best wishes
FBIagent
 
Zuletzt bearbeitet:
Hallo,

da hast du schon recht: Für größere "Pixelpackungen" ist SetPixel wirklich die schlechteste Wahl :)
Das Zeichnen von Linien würde ich allerdings nicht pixelweise machen.

Gruß
MCoder
 
Was würdest du denn als performantere Methode zu LineTo() empfehlen?

Was ich mir überlegt habe ist ein HDC zu erstellen in WM_CREATE in welchem ich alles hinein zeichne
und dann in WM_PAINT ein einziges BitBlt genügen würde.

Best wishes
FBIagent
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück