Bild in Fenster
-
Hallo Leute,
ich bin Anfänger in C / WinAPI und möchte ein Bild (gif/bmp) in ein Fenster reinsetzen. Wie mache ich das am einfachsten mit WinAPI?
So sieht der Code für das Fenster aus (hab ich aus einem Tutorial):#include <windows.h> const char g_szClassName[] = "myWindowClass"; // Step 4: the Window Procedure LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hwnd; MSG Msg; //Step 1: Registering the Window Class wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } // Step 2: Creating the Window hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, g_szClassName, "The title of my window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hInstance, NULL); if(hwnd == NULL) { MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); // Step 3: The Message Loop while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; }
Es soll zB an Position (20,20) im Fenster ein Bild (bild.bmp) eingesetzt werden.
Vielen Dank für eure Hilfe im voraus.
Grüße,
molli
-
PAINTSTRUCT ps; HDC hdcMem; HBITMAP hbmpOldBits; static HANDLE hBitmap; case WM_PAINT: BeginPaint(hDlg, &ps); hdcMem = CreateCompatibleDC(NULL); hbmpOldBits = reinterpret_cast<HBITMAP>(SelectObject(hdcMem, LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP1)))); BitBlt(ps.hdc, 0, 0, 800, 600, hdcMem, 0, 0, SRCCOPY); DeleteObject(SelectObject(hdcMem, hbmpOldBits)); DeleteDC(hdcMem); EndPaint(hDlg, &ps); return(0);
Allerdings ist das fuer Resourcen gedacht ( Bild : IDB_BITMAP1 ist die Resource )
-
Bitmap ist einfacher:
- Bild laden (vom Dateisystem)
- DC erstellen
- Bild ins DC laden
- mit BitBlt in das DC des Fensters "blitten"Für GIF/JPEG etc. gibts was in der FAQ
-
lol...
@PhoeNix_FasT: Irg wie kenn ich den Code doch
.
static HANDLE hBitmap; ist das nicht irg wie ... überflüssig ?!
-
ja is ja ok ... er wird schon ne Meldung kriegen das die Variable nich benutzt wird dann loescht er sie halt
-
@Airdamn: meinst du so etwas (aus dem Tutorium):
#include <windows.h> #include "resource.h" const char g_szClassName[] = "myWindowClass"; HBITMAP g_hbmBall = NULL; LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE: g_hbmBall = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BALL)); if(g_hbmBall == NULL) MessageBox(hwnd, "Could not load IDB_BALL!", "Error", MB_OK | MB_ICONEXCLAMATION); break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_PAINT: { // Just a note, never use a MessageBox from inside WM_PAINT // The box will cause more WM_PAINT messages and you'll probably end up // stuck in a loop BITMAP bm; PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); HDC hdcMem = CreateCompatibleDC(hdc); HBITMAP hbmOld = SelectObject(hdcMem, g_hbmBall); GetObject(g_hbmBall, sizeof(bm), &bm); BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); SelectObject(hdcMem, hbmOld); DeleteDC(hdcMem); EndPaint(hwnd, &ps); } break; case WM_DESTROY: DeleteObject(g_hbmBall); PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { /* Hier wird das Fenster erzeugt. Code zur besseren Übersicht weggelassen. */ ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; }
Wenn ich das jetzt kompiliere (unter msys: gcc bmp_one.c -o bmp_one.exe -lgdi32), und das Programm ausführe kommt ein message mit "Could not load IDB_BALL!". Mache ich da etwas beim kompilieren falsch?
Grüße,
molli
-
Hm jo der Code sieht richtig aus...muss an der Resourceneinbindung liegen.
-
Borland-Hilfe schrieb:
HBITMAP LoadBitmap(hinst, lpszBitmap)
HINSTANCE hinst; /* handle of application instance /
LPCSTR lpszBitmap; / address of bitmap name */The LoadBitmap function loads the specified bitmap resource from the given module's executable file.
Parameter Description
hinst Identifies the instance of the module whose executable file contains the bitmap to be loaded.
lpszBitmap Points to a null-terminated string that contains the name of the bitmap resource to be loaded. Alternatively, this parameter can consist of the resource identifier in the low-order word and zero in the high-order word. The MAKEINTRESOURCE macro can be used to create this value.Ich glaube, für hinst reicht es, wenn Du hInstance eingibst- das ist ja die aktuelle Instance. GetModuleHandle ist ein Umweg.
-
hmm, was muss denn in der ressource.h drinstehen damit der das richtig lädt? pfadangabe oder?
-
#define IDB_BALL 1200 // Die Zahl kannst Du Dir aussuchen, sie muß nur bezogen auf den Resourcentyp eindeutig sein.
-
@elektronix: vielen dank für deine Antwort.
ok, ich habe jetzt eine ressource.h mit #define IDB_BALL 1200.
das programm läuft aber immernoch nicht. wo muss ich denn den pfad mit dateinamen der BMP-datei eingeben? wie schon gesagt, bin anfänger!
-
Ach, die Bitmap liegt in einer eigenen Datei? Dann legst Du die .bmp-Datei in den selben Ordner wie den Quellcode und lädst sie mit
hBitmap= LoadImage (GetModuleHandle (NULL), "BildDatei.bmp", IMAGE_BITMAP,0, 0,LR_DEFAULTCOLOR | LR_LOADFROMFILE);
Bei "BildDatei.bmp" kannst Du natürlich auch den Suchpfad angeben.
-
Elektronix schrieb:
Ich glaube, für hinst reicht es, wenn Du hInstance eingibst- das ist ja die aktuelle Instance. GetModuleHandle ist ein Umweg.
Wo soll hInstance denn deklariert sein ?
Du kannst:
- GetModuleHandle(NULL) nutzen oder
- die Programminstanz globalisieren (globale Variable) oder
- unter WM_CREATE...dann geht's so:// in deiner WndProc: case WM_CREATE: HINSTANCE hInst = reinterpret_cast<LPCREATESTRUCT>(lParam)->hInstance; break; // ...
.
-
@CodeFinder und alle anderen: vielen Dank für eure Antworten, habe jetzt die version von Codefinder genommen, klappt wunderbar!
big THX
-
Hallo,
hab doch den Code von Elektronix übernommen und habe jetzt auch ein Fenster mit 3 Buttons. Am Anfang wird ein Bild geladen (in der main). Dann soll, wenn man auf einen Button drückt ein anderes Bild geladen werden (in WndProc). Wie stelle ich das an? Wenn ich nun den Code für "Bild anzeigen" in WndProc einfüge (siehe unten Stelle mit Fragezichen) und den Dateinamen der neuen Grafik anpasse ändert sich beim Drücken auf den Button nichts. Ich weiß dass der Button funktioniert und er in die richtige If-Anweisung springt, nur das anzeigen des neuen Bildes funktioniert nicht.
Hier der Code:
#include <windows.h> LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); HWND button1, button2, button3; BITMAP bm; PAINTSTRUCT ps; HDC hdc; HDC hdcMem; HBITMAP hbmOld; HBITMAP pic_tiere; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { WNDCLASS wc; HWND hwnd; MSG msg; wc.style = CS_HREDRAW|CS_VREDRAW|CS_BYTEALIGNCLIENT; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); /*(HBRUSH)(COLOR_WINDOW+1);*/ wc.lpszMenuName = NULL; wc.lpszClassName = "ButtonExample"; RegisterClass(&wc); hwnd = CreateWindow(wc.lpszClassName, "Tiere", // WS_OVERLAPPEDWINDOW, 100, 100, 410, 480, // NULL, NULL, hInstance, NULL); button1 = CreateWindow( "BUTTON", "Hund", // WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 10, 10, 120, 40, // hwnd,NULL,hInstance,NULL); button2 = CreateWindow( "BUTTON", "Katze", // WS_CHILD |WS_VISIBLE| BS_PUSHBUTTON, 140, 10, 120, 40, // hwnd,NULL,hInstance,NULL); button3 = CreateWindow( "BUTTON", "Maus", // WS_CHILD |WS_VISIBLE| BS_PUSHBUTTON, 270, 10, 120, 40, // hwnd,NULL,hInstance,NULL); ShowWindow(hwnd,nCmdShow); //Bild anzeigen pic_tiere = LoadImage (GetModuleHandle (NULL), "tiere.bmp",IMAGE_BITMAP,0, 0,LR_DEFAULTCOLOR | LR_LOADFROMFILE); if(pic_tiere == NULL) MessageBox(hwnd, "Could not load tiere.bmp!", "Error", MB_OK | MB_ICONEXCLAMATION); BITMAP bm; PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); HDC hdcMem = CreateCompatibleDC(hdc); HBITMAP hbmOld = SelectObject(hdcMem, pic_tiere); GetObject(pic_tiere, sizeof(bm), &bm); BitBlt(hdc, 10, 60, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); SelectObject(hdcMem, hbmOld); DeleteDC(hdcMem); EndPaint(hwnd, &ps); //Bild anzeigen Ende UpdateWindow(hwnd); while (GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_COMMAND: { if ((HWND)lParam==button1) { // //??????????????????????????????????????? } if ((HWND)lParam==button2) { // } if ((HWND)lParam==button3) { // } return 0; } case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: { DeleteObject(pic_tiere); PostQuitMessage(0); break; } default: { return DefWindowProc(hwnd,uMsg,wParam,lParam); } } return 0; }
Was mus ich an die Stelle mit den Fragezeichen setzen damit ein neues Bild angezeigt wird?
Grüße,
molli
-
Zunächst einmal sollte man bei der Auswahl der Buttons nicht eine if-Abfrage, sondern eine switch-case-Abfrage nehmen.
Wenn Du pic_tiere global definierst (vor WinMain), kannst Du in der WindProc darauf zugreifen. Dann sollte es reichen, mit der gleichen LoadImage-Routine ein neues Bild zu laden.
-
hallo Elektronix, vielen Dank für deine Antwort.
Elektronix schrieb:
Zunächst einmal sollte man bei der Auswahl der Buttons nicht eine if-Abfrage, sondern eine switch-case-Abfrage nehmen.
ich glaube ich lasse so, es funktioniert ja (hab ich aus nem tutorial)
Elektronix schrieb:
Wenn Du pic_tiere global definierst (vor WinMain), kannst Du in der WindProc darauf zugreifen. Dann sollte es reichen, mit der gleichen LoadImage-Routine ein neues Bild zu laden.
meinst du so wie in Zeile 13?
Grüße,
molli
-
Ja, so meinte ich das.
Edit: Allerdings weiß ich nicht, ob man vorher mit DeleteObject das alte Bild erstmal löschen muß.
-
ok, also das mit dem Button lasse ich jetzt mal bei Seite.
ich möchte jetzt nur, dass er nachdem er das erste Bild angezeigt hat 2 sek wartet und mir ein anderes Bild anzeigt.
hab es so probiert (wobei es bestimmt eleganter geht):... //Bild anzeigen pic_tiere = LoadImage(GetModuleHandle(NULL),"tiere.bmp",IMAGE_BITMAP,0, 0,LR_DEFAULTCOLOR | LR_LOADFROMFILE); if(pic_tiere == NULL) MessageBox(hwnd, "Could not load tiere.bmp!", "Error", MB_OK | MB_ICONEXCLAMATION); hdc = BeginPaint(hwnd, &ps); hdcMem = CreateCompatibleDC(hdc); hbmOld = SelectObject(hdcMem, pic_tiere); GetObject(pic_tiere, sizeof(bm), &bm); BitBlt(hdc, 10, 60, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); SelectObject(hdcMem, hbmOld); DeleteDC(hdcMem); EndPaint(hwnd, &ps1); //Bild anzeigen Ende UpdateWindow(hwnd); DeleteObject(pic_tiere); Sleep(2000); //Bild anzeigen pic_tiere = LoadImage(GetModuleHandle(NULL),"hund.bmp",IMAGE_BITMAP,0, 0,LR_DEFAULTCOLOR | LR_LOADFROMFILE); if(pic_tiere == NULL) MessageBox(hwnd, "Could not load hund.bmp!", "Error", MB_OK | MB_ICONEXCLAMATION); hdc = BeginPaint(hwnd, &ps); hdcMem = CreateCompatibleDC(hdc); hbmOld = SelectObject(hdcMem, pic_tiere); GetObject(pic_tiere, sizeof(bm), &bm); BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); SelectObject(hdcMem, hbmOld); DeleteDC(hdcMem); EndPaint(hwnd, &ps1); //Bild anzeigen Ende UpdateWindow(hwnd); DeleteObject(pic_tiere); ...
wie man sieht ist das zweite Bild auch ein wenig versetzt, nur um sicher zu gehen, dass es nicht exakt unter dem Ersten landet und somit wieder nicht sichtbar ist (wobei es es eigentlich schon drüber gezeichnet werden sollte, aber man weiß ja nie).
Leider funktioniert das nicht. Das erste Bild erscheint doch das zweite bleibt aus.
Lösung?
Grüße,
molli
-
Also deine Posts...sind emm...total falsch
...ich schreib dir mal n Beispiel-Code...
Aber ist NICHT böse gemeint
BTW: Zeichen sollte nach Möglichkeit immer unter WM_PAINT und globale Variablen immer vermeiden.
Außerdem wird bei LoadImage der erste Parameter auf NULL gesetzt wenn man eine Bitmap lädt.Also:
#include <windows.h> enum EBitmapStates { BMS_CAT, BMS_DOG }; #define BTN_SHOW_CAT (6001) #define BTN_SHOW_DOG (6002) LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { TCHAR szAppName[] = TEXT("EXAMPLE_CLASS"); HWND hWndMain; MSG msg; WNDCLASSEX wndclassex = {0}; wndclassex.cbSize = sizeof(WNDCLASSEX); wndclassex.style = CS_HREDRAW | CS_VREDRAW; wndclassex.lpfnWndProc = WndProc; wndclassex.hInstance = hInstance; wndclassex.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclassex.hCursor = LoadCursor(NULL, IDC_ARROW); wndclassex.hbrBackground = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); wndclassex.lpszClassName = szAppName; wndclassex.hIconSm = wndclassex.hIcon; if(!RegisterClassEx(&wndclassex)) { MessageBox(NULL, TEXT("RegisterClassEx fehlgeschlagen!"), szAppName, MB_ICONERROR); return (0); } hWndMain = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, // erweiterter Fensterstil szAppName, // Name der Fensterklasse TEXT ("Beispiel"), // Fenstertitel WS_OVERLAPPEDWINDOW, // Fensterstil CW_USEDEFAULT, // X-Position des Fensters CW_USEDEFAULT, // Y-Position des Fensters CW_USEDEFAULT, // Fensterbreite CW_USEDEFAULT, // Fensterhöhe NULL, // übergeordnetes Fenster NULL, // Menü hInstance, // Programm-Kopiezähler (Programm-ID) NULL); // zusätzliche Parameter ShowWindow(hWndMain, iCmdShow); UpdateWindow(hWndMain); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } // Die Hauptnachrichtenschleife LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam) { static HBITMAP hbmpCat, hbmpDog; static EBitmapStates bmState; static HWND btnDog, btnCat; switch (message) { case WM_CREATE: bmState = BMS_CAT; hbmpCat = LoadImage(NULL, TEXT("katze.bmp"), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_LOADFROMFILE); hbmpDog = LoadImage(NULL, TEXT("hund.bmp"), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_LOADFROMFILE); btnDog = CreateWindow(TEXT("BUTTON"), TEXT("Hund anzeigen"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 10, 120, 40, hWnd, reinterpret_cast<HMENU>(BTN_SHOW_DOG), reinterpret_cast<LPCREATESTRUCT>(lParam)->hInstance, NULL); btnCat = CreateWindow(TEXT("BUTTON"), TEXT("Katze anzeigen"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 10, 120, 40, hWnd, reinterpret_cast<HMENU>(BTN_SHOW_CAT), reinterpret_cast<LPCREATESTRUCT>(lParam)->hInstance, NULL); InvalidateRect(hWnd, NULL, TRUE); break; case WM_COMMAND: switch(LOWORD(wParam)) { case BTN_SHOW_DOG: bmState = BMS_DOG; InvalidateRect(hWnd, NULL, TRUE); break; case BTN_SHOW_CAT: bmState = BMS_CAT; InvalidateRect(hWnd, NULL, TRUE); break; // Weitere Command-Handler... } break; case WM_PAINT: PAINTSTRUCT psStruct; HDC hdcMemory; HBITMAP hbmpPrevBits; RECT rcClient; GetClientRect(hWnd, &rcClient); BeginPaint(hWnd, &psStruct); hdcMemory = CreateCompatibleDC(psStruct.hdc); switch(bmState) { case BMS_CAT: hbmpPrevBits = reinterpret_cast<HBITMAP>(SelectObject(hdcMemory, hbmpCat); break; case BMS_DOG: hbmpPrevBits = reinterpret_cast<HBITMAP>(SelectObject(hdcMemory, hbmpDog); break; } BitBlt(psStruct.hdc, 0, 0, rcClient.right, rcClient.bottom, hdcMemory, 0, 0, SRCCOPY); EndPaint(hWnd, &psStruct); SelectObject(hdcMemory, hbmpPrevBits); DeleteDC(hdcMemory); break; case WM_DESTROY: DeleteObject(hbmpCat); DeleteObject(hbmpDog); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, uiMessage, wParam, lParam)); } return (0L); }