2013-11-23 156 views
0

我正在學習C++,但我在將圖像放在屏幕上時遇到問題。win32 C++在屏幕上放置圖像

我已經搜索了互聯網尋求幫助,但我找不到任何。

我想創建一個窗口,並在調用WM_Paint消息時在客戶區放置一個簡單的顏色,但程序只是照例顯示灰色屏幕。我正在使用代碼::塊10.05。

#include <windows.h> 
#include <iostream> 

using namespace std; 

int winx = 500; 
int winy = 500; 
int winbpp = 24; 


    static char     m_bibuf[ sizeof(BITMAPINFOHEADER) + 12 ]; 
    static BITMAPINFO    &m_bi = *(BITMAPINFO*)&m_bibuf; 
    static BITMAPINFOHEADER  &m_bih = m_bi.bmiHeader; 
    int* buffer = new int[winx*winy*winbpp]; 





int setbuffer() 
{ 

    for(int x = 0; x < winx; x++) 
       { 
        for(int y=0; y < winy; y++) 
        { 
          for(int z =0; z < winbpp; z++) 
          { 
           buffer[x*y*z] = 1; 
          } 
        } 

       } 

       return 0; 

} 



/* Declare Windows procedure */ 
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); 

/* Make the class name into a global variable */ 
char szClassName[ ] = "CodeBlocksWindowsApp"; 

int WINAPI WinMain (HINSTANCE hThisInstance, 
        HINSTANCE hPrevInstance, 
        LPSTR lpszArgument, 
        int nCmdShow) 
{ 
    HWND hwnd;    /* This is the handle for our window */ 
    MSG messages;   /* Here messages to the application are saved */ 
    WNDCLASSEX wincl;  /* Data structure for the windowclass */ 

    /* The Window structure */ 
    wincl.hInstance = hThisInstance; 
    wincl.lpszClassName = szClassName; 
    wincl.lpfnWndProc = WindowProcedure;  /* This function is called by windows */ 
    wincl.style = CS_DBLCLKS;     /* Catch double-clicks */ 
    wincl.cbSize = sizeof (WNDCLASSEX); 

    /* Use default icon and mouse-pointer */ 
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); 
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); 
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW); 
    wincl.lpszMenuName = NULL;     /* No menu */ 
    wincl.cbClsExtra = 0;      /* No extra bytes after the window class */ 
    wincl.cbWndExtra = 0;      /* structure or the window instance */ 
    /* Use Windows's default colour as the background of the window */ 
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; 

    /* Register the window class, and if it fails quit the program */ 
    if (!RegisterClassEx (&wincl)) 
     return 0; 

    /* The class is registered, let's create the program*/ 
    hwnd = CreateWindowEx (
      0,     /* Extended possibilites for variation */ 
      szClassName,   /* Classname */ 
      " project 1 ",  /* Title Text */ 
      WS_OVERLAPPEDWINDOW, /* default window */ 
      CW_USEDEFAULT,  /* Windows decides the position */ 
      CW_USEDEFAULT,  /* where the window ends up on the screen */ 
      winx,     /* The programs width */ 
      winy,     /* and height in pixels */ 
      HWND_DESKTOP,  /* The window is a child-window to desktop */ 
      NULL,    /* No menu */ 
      hThisInstance,  /* Program Instance handler */ 
      NULL     /* No Window Creation data */ 
      ); 

    /* Make the window visible on the screen */ 
    ShowWindow (hwnd, nCmdShow); 

    /* Run the message loop. It will run until GetMessage() returns 0 */ 
    while (GetMessage (&messages, NULL, 0, 0)) 
    { 
     /* Translate virtual-key messages into character messages */ 
     TranslateMessage(&messages); 
     /* Send message to WindowProcedure */ 
     DispatchMessage(&messages); 
    } 

    /* The program return-value is 0 - The value that PostQuitMessage() gave */ 
    return messages.wParam; 
} 


/* This function is called by the Windows function DispatchMessage() */ 

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    switch (message)     /* handle the messages */ 
    { 

     case WM_CREATE: 
     { 


     m_bih.biWidth = winx; 
     m_bih.biHeight = winy; 
     m_bih.biBitCount = winbpp; 
     m_bih.biSize = sizeof(m_bih); 
     m_bih.biPlanes = 1;      // DIBs are upside down 
     m_bih.biCompression = BI_BITFIELDS; 
     m_bih.biSizeImage = 0; 
     m_bih.biXPelsPerMeter = 0; 
     m_bih.biYPelsPerMeter = 0; 
     m_bih.biClrUsed = 0; 
     m_bih.biClrImportant = 0; 

     setbuffer(); 

     InvalidateRect(hwnd, NULL, TRUE); 

     } break; 

     case WM_PAINT: 

     { 


      PAINTSTRUCT ps; 
     HDC hDC = BeginPaint(hwnd, &ps); 

      RECT client; 

      GetClientRect(hwnd, &client); 



     StretchDIBits   (  hDC, 
           0,     // Destination top left hand 
                // corner X Position 
           0,     // Destination top left hand 
                // corner Y Position 
           client.right,  // Destinations width 
           client.bottom,  // Destinations height 
           0,     // Source top left hand 
                // corner's X Position 
           0,     // Source top left hand 
                // corner's Y Position 
           winx,    // Sources width 
           winy,    // Sources height 
           buffer,   // Source's data 
           &m_bi,    // Bitmap Info 
           DIB_RGB_COLORS, // operations 
           SRCCOPY); 


      EndPaint(hwnd, &ps); 

     } break; 



     case WM_DESTROY: 

      delete buffer; 
      PostQuitMessage (0);  /* send a WM_QUIT to the message queue */ 
      break; 
     default:      /* for messages that we don't deal with */ 
      return DefWindowProc (hwnd, message, wParam, lParam); 
    } 

    return 0; 
} 

的程序編譯通常,但代替顯示的「緩衝」在客戶區, 它只是顯示的灰度顏色等通常的內容。

是'buffer'格式正確嗎?

=更新的代碼下面=

#include <windows.h> 

int winx = 500; 
int winy = 400; 

int bpp = 24; 
size_t pwidth; 


int scanlinewidth = 0; 
int numscanlines = 0; 

bool setscanline = 1; 
bool setbitmap = 1; 

BITMAPINFO m_bi; 
struct BGR{ char blue; char green; char red;}; 

BGR* buffer; 



void setframebuffer() 
{ 
    m_bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 

    m_bi.bmiHeader.biPlanes = 1; 
    m_bi.bmiHeader.biBitCount = bpp; 
    m_bi.bmiHeader.biCompression = BI_RGB; 
    m_bi.bmiHeader.biSizeImage = 0; 
    m_bi.bmiHeader.biXPelsPerMeter = 100; 
    m_bi.bmiHeader.biYPelsPerMeter = 100; 
    m_bi.bmiHeader.biClrUsed = 0; 
    m_bi.bmiHeader.biClrImportant = 0; 

    if (setbitmap) 
    { 
    m_bi.bmiHeader.biWidth = scanlinewidth; 
    m_bi.bmiHeader.biHeight = numscanlines; 
    setbitmap = 0; 


    } 



    if (!setbitmap) 
    { 
    pwidth = (scanlinewidth * 3 + 3) & ~3; 
    buffer = new BGR[(scanlinewidth + pwidth)*numscanlines]; 

    } 



    for (int i = 0; i < ((scanlinewidth + pwidth) * numscanlines); i++) 
    { 
     buffer[i].blue = 0; 
     buffer[i].green = 0; 
     buffer[i].red = 255; 

    } 


} 




/* Declare Windows procedure */ 
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); 

/* Make the class name into a global variable */ 
char szClassName[ ] = "CodeBlocksWindowsApp"; 

int WINAPI WinMain (HINSTANCE hThisInstance, 
        HINSTANCE hPrevInstance, 
        LPSTR lpszArgument, 
        int nCmdShow) 
{ 
    HWND hwnd;    /* This is the handle for our window */ 
    MSG messages;   /* Here messages to the application are saved */ 
    WNDCLASSEX wincl;  /* Data structure for the windowclass */ 

    /* The Window structure */ 
    wincl.hInstance = hThisInstance; 
    wincl.lpszClassName = szClassName; 
    wincl.lpfnWndProc = WindowProcedure;  /* This function is called by windows */ 
    wincl.style = CS_DBLCLKS;     /* Catch double-clicks */ 
    wincl.cbSize = sizeof (WNDCLASSEX); 

    /* Use default icon and mouse-pointer */ 
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); 
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); 
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW); 
    wincl.lpszMenuName = NULL;     /* No menu */ 
    wincl.cbClsExtra = 0;      /* No extra bytes after the window class */ 
    wincl.cbWndExtra = 0;      /* structure or the window instance */ 
    /* Use Windows's default colour as the background of the window */ 
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; 

    /* Register the window class, and if it fails quit the program */ 
    if (!RegisterClassEx (&wincl)) 
     return 0; 

    /* The class is registered, let's create the program*/ 
    hwnd = CreateWindowEx (
      0,     /* Extended possibilites for variation */ 
      szClassName,   /* Classname */ 
      "framebuffer project for win32",  /* Title Text */ 
      WS_OVERLAPPEDWINDOW, /* default window */ 
      CW_USEDEFAULT,  /* Windows decides the position */ 
      CW_USEDEFAULT,  /* where the window ends up on the screen */ 
      winx,     /* The programs width */ 
      winy,     /* and height in pixels */ 
      HWND_DESKTOP,  /* The window is a child-window to desktop */ 
      NULL,    /* No menu */ 
      hThisInstance,  /* Program Instance handler */ 
      NULL     /* No Window Creation data */ 
      ); 

    /* Make the window visible on the screen */ 
    ShowWindow (hwnd, nCmdShow); 

    /* Run the message loop. It will run until GetMessage() returns 0 */ 
    while (GetMessage (&messages, NULL, 0, 0)) 
    { 
     /* Translate virtual-key messages into character messages */ 
     TranslateMessage(&messages); 
     /* Send message to WindowProcedure */ 
     DispatchMessage(&messages); 
    } 

    /* The program return-value is 0 - The value that PostQuitMessage() gave */ 
    return messages.wParam; 
} 


/* This function is called by the Windows function DispatchMessage() */ 

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    DWORD result; 

    switch (message)     /* handle the messages */ 
    { 
     case WM_CREATE: 
     { 


     InvalidateRect(hwnd,0,0); 

     }break; 

     case WM_PAINT: 
     { 
      PAINTSTRUCT ps; 
      HDC hDC = BeginPaint(hwnd, &ps); 
      RECT client; 
      GetClientRect(hwnd,&client); 
      if(setscanline) { 
      scanlinewidth = client.right; 
      numscanlines = client.bottom; 
      setscanline = 0; 
      } 
      setframebuffer(); 

      result = StretchDIBits(hDC, 
            0, 0, 
            client.right, client.bottom, 
            0, 0, 
            scanlinewidth, numscanlines, 
            buffer, &m_bi, DIB_RGB_COLORS, SRCCOPY); 
      if(result != winy) 
      { 
       //Drawing failed 
       DebugBreak(); 
      } 
      EndPaint(hwnd, &ps); 




     }break; 

     case WM_KEYDOWN:{ int escpressed = GetAsyncKeyState(27); if(escpressed){PostQuitMessage(0);}}break; 


     case WM_DESTROY: { 
      PostQuitMessage (0);  /* send a WM_QUIT to the message queue */ 
      }break; 
     default:      /* for messages that we don't deal with */ 
      return DefWindowProc (hwnd, message, wParam, lParam); 
    } 

    return 0; 
} 

EDIT改變INT setbuffer在WM_CREATE

EDIT#2到setbuffer改變GETDC開始塗料。

編輯#3改變了BPP至24,也改變了WM_CREATE設置我已經找到了解決感謝你的幫助,所有的位圖屬性

編輯#4。我之前並不瞭解掃描線填充,但現在我完全理解了它。更新的代碼在屏幕上打印純色,您可以自己編譯並更改顏色。感謝您幫助我解決問題,現在我可以使用自己的代碼開始在屏幕上繪圖。

+0

你想畫什麼?只有一個圖像?有很多方法可以繪製到窗口。 WPF,GDI +,Direct2D,Direct3D ...取決於你想放在那裏,一些API比其他API更合適。假設你只是想要一個圖像,我建議使用Direct2D。實際上,已經有一個示例圖像查看器的代碼[在這裏]發佈(http://msdn.microsoft.com/en-us/library/windows/desktop/ee720057(v = vs.85).aspx)。 – MooseBoys

+0

我只是想把圖像放到屏幕上。我只想使用windows.h在客戶區域提供純色。 – user3023723

+0

您可以對圖片使用靜態控件。矩形更像是對「矩形」的調用。 – chris

回答

1

我不確定所有這些問題仍然相關,因爲我在開始編輯之前複製了代碼。無論哪種方式,這都有效,你應該能夠很容易地看到差異。

BITMAPINFO結構未正確初始化。

緩衝區被錯誤地創建,它太大,並且不一定正確對齊以用作位圖。寬度需要填充到4的倍數,對於寬度爲500的寬度,寬度爲499的寬度不會有問題。

我還添加了一個檢查以確保StretchDIBits成功,如果它失敗,它會將您轉儲到調試器中。如果你喜歡,你可以添加更多適當的錯誤檢查。

爲了保持儘可能短的內容,我也做了一些評論。

#include <windows.h> 

const int winx = 500; 
const int winy = 500; 
const int winbpp = 3; 

BITMAPINFO m_bi; 
char* buffer = 0; 

void setbuffer() 
{ 
    m_bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    m_bi.bmiHeader.biWidth = winx; 
    m_bi.bmiHeader.biHeight = winy; 
    m_bi.bmiHeader.biPlanes = 1; 
    m_bi.bmiHeader.biBitCount = 24; 
    m_bi.bmiHeader.biCompression = BI_RGB; 
    m_bi.bmiHeader.biSizeImage = 0; 
    m_bi.bmiHeader.biXPelsPerMeter = 100; 
    m_bi.bmiHeader.biYPelsPerMeter = 100; 
    m_bi.bmiHeader.biClrUsed = 0; 
    m_bi.bmiHeader.biClrImportant = 0; 

    size_t paddedWidth = (winx * 3 + 3) & ~3; 
    buffer = new char[paddedWidth * winy * winbpp]; 

    for(int y = 0; y < winy; ++y) 
    { 
     for(int x = 0; x < winx; ++x) 
     { 
      for(int z = 0; z < 3; ++z) 
      { 
       buffer[y * paddedWidth + x * winbpp + z] = z * x; 
      } 
     } 
    } 
} 

LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM); 

char szClassName[] = "CodeBlocksWindowsApp"; 

int WINAPI WinMain(HINSTANCE hThisInstance, 
        HINSTANCE hPrevInstance, 
        LPSTR lpszArgument, 
        int nCmdShow) 
{ 
    HWND hwnd;    /* This is the handle for our window */ 
    MSG messages;   /* Here messages to the application are saved */ 
    WNDCLASSEX wincl;  /* Data structure for the windowclass */ 

    wincl.hInstance = hThisInstance; 
    wincl.lpszClassName = szClassName; 
    wincl.lpfnWndProc = WindowProcedure;  /* This function is called by windows */ 
    wincl.style = CS_DBLCLKS;     /* Catch double-clicks */ 
    wincl.cbSize = sizeof (WNDCLASSEX); 
    wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
    wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 
    wincl.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wincl.lpszMenuName = NULL;     /* No menu */ 
    wincl.cbClsExtra = 0;      /* No extra bytes after the window class */ 
    wincl.cbWndExtra = 0;      /* structure or the window instance */ 
    wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND; 

    if(!RegisterClassEx(&wincl)) 
     return 0; 

    hwnd = CreateWindowEx(
     0,     /* Extended possibilites for variation */ 
     szClassName,   /* Classname */ 
     " project 1 ",  /* Title Text */ 
     WS_OVERLAPPEDWINDOW, /* default window */ 
     CW_USEDEFAULT,  /* Windows decides the position */ 
     CW_USEDEFAULT,  /* where the window ends up on the screen */ 
     winx,     /* The programs width */ 
     winy,     /* and height in pixels */ 
     HWND_DESKTOP,  /* The window is a child-window to desktop */ 
     NULL,    /* No menu */ 
     hThisInstance,  /* Program Instance handler */ 
     NULL     /* No Window Creation data */ 
     ); 

    ShowWindow(hwnd, nCmdShow); 

    while(GetMessage(&messages, NULL, 0, 0)) 
    { 
     TranslateMessage(&messages); 
     DispatchMessage(&messages); 
    } 

    return messages.wParam; 
} 

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    PAINTSTRUCT ps; 
    HDC hDC; 
    RECT client; 
    DWORD result; 

    switch(message)     /* handle the messages */ 
    { 
     case WM_CREATE: 
      setbuffer(); 
      InvalidateRect(hwnd, NULL, TRUE); 
      break; 

     case WM_PAINT: 
      hDC = BeginPaint(hwnd, &ps); 
      GetClientRect(hwnd, &client); 
      result = StretchDIBits(hDC, 
            0, 0, 
            client.right, client.bottom, 
            0, 0, 
            winx, winy, 
            buffer, &m_bi, DIB_RGB_COLORS, SRCCOPY); 
      if(result != winy) 
      { 
       //Drawing failed 
       DebugBreak(); 
      } 
      EndPaint(hwnd, &ps); 
      break; 

     case WM_DESTROY: 
      delete buffer; 
      PostQuitMessage(0);  /* send a WM_QUIT to the message queue */ 
      break; 
     default:      /* for messages that we don't deal with */ 
      return DefWindowProc(hwnd, message, wParam, lParam); 
    } 
    return 0; 
} 
+0

這個數學是將寬度填充到4的倍數。基本上增加3,然後掩蓋額外的位。 –

+0

感謝您的幫助。它終於在屏幕上顯示了一些東西! – user3023723

+0

感謝您的幫助,我現在可以有一個黑色的屏幕,而不是一個灰色的!我一直想這麼做幾個月,並且沒有在互聯網上的任何地方可以找到幫助!非常感謝! – user3023723