I'd like to add a menu system to my simple OpenGL program. I've used GLUT before but that was way back in 1998 and when I mentioned it here on SO you advised not to use GLUT and therefore I want to know what menu building libraries I can use, preferably platform-independent like GLUT, since I see GLUT is still used in many of the examples. My program doesn't use GLUT but I'd like to add menu system to learn more how to make I more complete program.
#include <windows.h>
#include <gl/gl.h>
LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
void EnableOpenGL(HWND hwnd, HDC*, HGLRC*);
void DisableOpenGL(HWND, HDC, HGLRC);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wcex;
HWND hwnd;
HDC hDC;
HGLRC hRC;
MSG msg;
BOOL bQuit = FALSE;
float theta = 0.0f;
/* register window class */
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_OWNDC;
wcex.lpfnWndProc = WindowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "GLSample";
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);;
if (!RegisterClassEx(&wcex))
return 0;
/* create main window */
hwnd = CreateWindowEx(0,
"GLSample",
"OpenGL Sample",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
256,
256,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, nCmdShow);
/* enable OpenGL for the window */
EnableOpenGL(hwnd, &hDC, &hRC);
/* program main loop */
while (!bQuit)
{
/* check for messages */
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
/* handle or dispatch messages */
if (msg.message == WM_QUIT)
{
bQuit = TRUE;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
/* OpenGL animation code goes here */
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(theta, 0.0f, 0.0f, 1.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(0.0f, 1.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(0.87f, -0.5f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(-0.87f, -0.5f);
glEnd();
glPopMatrix();
SwapBuffers(hDC);
theta += 1.0f;
Sleep (1);
}
}
/* shutdown OpenGL */
DisableOpenGL(hwnd, hDC, hRC);
/* destroy the window explicitly */
DestroyWindow(hwnd);
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_DESTROY:
return 0;
case WM_KEYDOWN:
{
switch (wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
}
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC)
{
PIXELFORMATDESCRIPTOR pfd;
int iFormat;
/* get the device context (DC) */
*hDC = GetDC(hwnd);
/* set the pixel format for the DC */
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
iFormat = ChoosePixelFormat(*hDC, &pfd);
SetPixelFormat(*hDC, iFormat, &pfd);
/* create and enable the render context (RC) */
*hRC = wglCreateContext(*hDC);
wglMakeCurrent(*hDC, *hRC);
}
void DisableOpenGL (HWND hwnd, HDC hDC, HGLRC hRC)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hRC);
ReleaseDC(hwnd, hDC);
}
For example in the answer here
OpenGL - GLUT - Displaying different pop-up menus
It says not to use GLUT but not what to use instead so it doesn't really say where to begin. Can you tell me what to use instead of GLUT?
For platform-independent OpenGL development, use a cross-platform GUI toolkit like Qt or wxWidgets.
Of these I only have personal experience with Qt's OpenGL module. It comes with many examples of how to set up an OpenGL rendering context and interact with it with the mouse and keyboard. It will allow you to pop up a menu when you right click in your scene. Qt also comes with utility classes for vector and matrix manipulation.
Related
As the question, how to draw the 3d ice cream? I have draw a cone and a ball. But the ball cannot fit inside the cone.....I try with many way, but the ball is either bihind the cone or whole one infornt the cone... Can anyone exust me on this. I have follow the note from lecturer but still not able to get.
#include <Windows.h>
#include <gl/GL.h>
#include <math.h>
#include <time.h>
#include <gl/GLU.h>
#pragma comment (lib, "OpenGL32.lib")
#pragma comment (lib, "GLU32.lib")
#define WINDOW_TITLE "OpenGL Window"
LRESULT WINAPI WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
//--------------------------------------------------------------------
bool initPixelFormat(HDC hdc)
{
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
pfd.cAlphaBits = 8;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 0;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iLayerType = PFD_MAIN_PLANE;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
// choose pixel format returns the number most similar pixel format available
int n = ChoosePixelFormat(hdc, &pfd);
// set pixel format returns whether it sucessfully set the pixel format
if (SetPixelFormat(hdc, n, &pfd))
{
return true;
}
else
{
return false;
}
}
//--------------------------------------------------------------------
void display()
{
glPushMatrix();
glRotatef(120, 1.0, 0, 0);
GLUquadricObj * cylinder = NULL;
cylinder = gluNewQuadric();
glColor3f(1, 0, 0);
gluQuadricDrawStyle(cylinder, GLU_FILL);
gluCylinder(cylinder, 0.52, 0.0, 2.0, 30, 20);
gluDeleteQuadric(cylinder);
GLUquadricObj * sphere = NULL;
sphere = gluNewQuadric();
glColor3f(1, 1, 1);
gluQuadricDrawStyle(sphere, GLU_LINE);
gluSphere(sphere, 0.5, 20, 20);
gluDeleteQuadric(sphere);
glPopMatrix();
}
//--------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int nCmdShow)
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = WindowProcedure;
wc.lpszClassName = WINDOW_TITLE;
wc.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClassEx(&wc)) return false;
HWND hWnd = CreateWindow(WINDOW_TITLE, WINDOW_TITLE, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 640,
NULL, NULL, wc.hInstance, NULL);
//--------------------------------
// Initialize window for OpenGL
//--------------------------------
HDC hdc = GetDC(hWnd);
// initialize pixel format for the window
initPixelFormat(hdc);
// get an openGL context
HGLRC hglrc = wglCreateContext(hdc);
// make context current
if (!wglMakeCurrent(hdc, hglrc)) return false;
//--------------------------------
// End initialization
//--------------------------------
ShowWindow(hWnd, nCmdShow);
MSG msg;
ZeroMemory(&msg, sizeof(msg));
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2.0f, +3.0f, -2.0f, +2.0f, -10.0f, +10.0f);
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
display();
SwapBuffers(hdc);
}
UnregisterClass(WINDOW_TITLE, wc.hInstance);
return true;
}
//--------------------------------------------------------------------
Note, that drawing by glBegin/glEnd sequences, the fixed function pipeline matrix stack and fixed function pipeline per vertex light model, is deprecated since decades.
Read about Fixed Function Pipeline and see Vertex Specification and Shader for a state of the art way of rendering.
anyway, In the PIXELFORMATDESCRIPTOR the depth buffer is proper specified:
pfd.cDepthBits = 24;
now you have to use the depth buffer.
Side note, the number of the color buffer bits should be 24 instead of 32 see the documentation of cColorBits:
Specifies the number of color bitplanes in each color buffer. For RGBA pixel types, it is the size of the color buffer, excluding the alpha bitplanes. For color-index pixels, it is the size of the color-index buffer.
To use the depth buffer the Depth Test has to be enabled by glEnable.
Further the color buffer and the depth buffer of the default framebuffer has to be cleared at the begin of every frame by glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
void display()
{
glEnable( GL_DEPTH_TEST );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glRotatef(120, 1.0, 0, 0);
GLUquadricObj * cylinder = NULL;
cylinder = gluNewQuadric();
glColor3f(1, 0.5, 0);
gluQuadricDrawStyle(cylinder, GLU_FILL);
gluCylinder(cylinder, 0.52, 0.0, 2.0, 30, 20);
gluDeleteQuadric(cylinder);
GLUquadricObj * sphere = NULL;
sphere = gluNewQuadric();
glColor3f(1, 1, 0.5);
gluQuadricDrawStyle(sphere, GLU_FILL);
gluSphere(sphere, 0.5, 20, 20);
gluDeleteQuadric(sphere);
glPopMatrix();
}
See the preview, where i changed the gluQuadricDrawStyle for the sphere from GLU_LINE to GL_FILL:
I am replacing BeginPaint-EndPaint in a simple window with GetDC-ReleaseDC.
I am reading Charles Petzold Programming Windows 5th Edition.
Here is my code with the changes and the lines changed as comments:
#include<Windows.h>
#include<mmsystem.h>
LRESULT CALLBACK myWndProc(HWND windowHandle, UINT winMessage, WPARAM wParam, LPARAM lParam);
int
WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
WNDCLASSEX myWndClass;
MSG msg;
HWND myWndHandle;
wchar_t szmyWndClassName[] = TEXT("SotoWindClass");
wchar_t szmyWndowName[] = TEXT("SotoWindow");
myWndClass.cbClsExtra = 0;
myWndClass.cbSize = sizeof(WNDCLASSEX);
myWndClass.cbWndExtra = 0;
myWndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
myWndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
myWndClass.hIcon = LoadIcon(NULL, IDI_HAND);
myWndClass.hIconSm = NULL;
myWndClass.hInstance = hInstance;
myWndClass.lpfnWndProc = myWndProc;
myWndClass.lpszClassName = szmyWndClassName;
myWndClass.lpszMenuName = NULL;
myWndClass.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClassEx(&myWndClass))
{
MessageBoxEx(NULL, TEXT("I need at least WINNT"), szmyWndClassName, MB_ICONERROR, 0);
}
myWndHandle = CreateWindowEx(
WS_EX_LEFT,
szmyWndClassName,
szmyWndowName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(myWndHandle, iCmdShow);
UpdateWindow(myWndHandle);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK myWndProc(HWND windowHandle, UINT winMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
//PAINTSTRUCT ps;
RECT rc;
wchar_t displayText[] = TEXT("Display My Text!!!!");
switch (winMessage)
{
case WM_CREATE:
{
PlaySound(TEXT("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC);
return(0);
}break;
case WM_PAINT:
{
/*
hdc = BeginPaint(WindowHandle, &ps);
DrawText(hdc, TEXT("Hello Win 7!!!"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(WindowHandle, &ps);
return(0);
*/
hdc = GetDC(windowHandle);
GetClientRect(windowHandle, &rc);
//ValidateRect(windowHandle, &rc);
DrawText(hdc, displayText, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
ReleaseDC(windowHandle, hdc);
return(0);
}
case WM_DESTROY:
{
PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC);
PostQuitMessage(0);
return(0);
}
}
return(DefWindowProc(windowHandle, winMessage, wParam, lParam));
}
My question is:
Why DrawText is still displaying the message when i haven't called ValidateRect?
From what i understand(which is obviously incorrect) the text inside RECT rc shouldn't appear, unless I call ValidateRect.
When the window is displayed the text drawn is flickering which i assume happens because Windows are calling WM_PAINT and are trying to validate rc (my client area) but DrawText still manages to display the text line every time.
I am a bit confused.
Your text is rendered again and again, because you haven't called ValidateRect. EndPaint calls ValidateRect to mark the area rendered during this paint cycle as valid, i.e. doesn't need rendering.
Leaving an area marked as invalid doesn't stop you drawing to it, it just means the system won't think you have drawn to it and will keep asking you to.
(posted as community wiki, since the question was answered in the comments)
I am experimenting on Windows 7 64 bit OS with win32 API.When i run my Program on debug mode my window appears but i have 2 bugs. Firt things first here is my api code modified from Charles Petzold book Ch3:
#include<Windows.h>
#include<mmsystem.h>
LRESULT CALLBACK HandleMyWindowsClassMessages(HWND WindowHandle, UINT Message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreviousInstance, PSTR szCmdLine, int iCmdShow)
{
WNDCLASSEX MyWindowsClass;
static wchar_t szMyWindowsClassName[] = TEXT("The Name of My Window Class");
static wchar_t szAppName[] = TEXT("AppName");
HWND myWindowHandle;
MSG msg;
MyWindowsClass.hInstance = hInstance;
MyWindowsClass.style = CS_HREDRAW | CS_VREDRAW;
MyWindowsClass.lpfnWndProc = HandleMyWindowsClassMessages;
MyWindowsClass.lpszClassName = szMyWindowsClassName;
MyWindowsClass.cbSize = sizeof(WNDCLASSEX);
MyWindowsClass.cbClsExtra = 0;
MyWindowsClass.cbWndExtra = 0;
MyWindowsClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
MyWindowsClass.hCursor = LoadCursor(NULL, IDC_ARROW);
MyWindowsClass.hIcon = LoadIcon(NULL, IDI_SHIELD);
MyWindowsClass.hIconSm = NULL;
MyWindowsClass.lpszMenuName = NULL;
if (!RegisterClassEx(&MyWindowsClass))
{
MessageBoxEx(0, TEXT("This Programm Requires WINNT!"), szMyWindowsClassName, MB_ICONERROR, 0);
return(0);
}
myWindowHandle = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW,
szMyWindowsClassName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(myWindowHandle, iCmdShow);
UpdateWindow(myWindowHandle);
while (GetMessage(&msg, myWindowHandle, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return(msg.wParam);
}
LRESULT CALLBACK HandleMyWindowsClassMessages(HWND WindowHandle, UINT Message, WPARAM wParam, LPARAM lParam)
{
//wchar_t szGreeting[] = TEXT("Heeeey");
HDC hdc;
PAINTSTRUCT ps;
switch (Message)
{
case WM_CREATE:
{
PlaySound(TEXT("D:\\mp3\\aywy._&_EphRem_-_Adderall.wav"), NULL, SND_FILENAME | SND_ASYNC);
return(0);
} break;
case WM_PAINT:
{
hdc = BeginPaint(WindowHandle, &ps);
DrawText(hdc, TEXT("Hello Win 7!!!"), -1, &ps.rcPaint, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
//TextOut(hdc, 0, 0, szGreeting, (int)wcslen(szGreeting));
EndPaint(WindowHandle, &ps);
return(0);
}break;
case WM_DESTROY:
{
PostQuitMessage(0);
return(0);
}break;
}
return(DefWindowProc(WindowHandle, Message, wParam, lParam));
}
Bug1:PlaySound keeps playing the wav even when i have closed-destroyed the Window.When I used the original example with plain WNDCLASS the bug dissapeared!
So I must be doing something wrong using WNDCLASSEX ???.
Also in this bug to end execution of debbuging I have to press Shift+F5.
Bug2:TextOut vs DrawText
Info:I have only 1 screen.I program on my laptop.
When I use drawText and the text in my window goes out of my desktop screen borders the text just doesnt update correclty.
When I use TextOut the bug dissapears!!!
Why???
Below i have some pitures ordered to explain this.
The Program starts in debug mode
Moving the window out of Desktop borders(including the displayed text)
Moving the window back inside my desktop area(the text has been mutated)
Window is destroyed and sound will keep playing even when the wav ends.
Any help in any of the 2 bugs would be greatly appreciated.
2nd version of my WndProc:
LRESULT CALLBACK HandleMyWindowsClassMessages(HWND WindowHandle, UINT Message, WPARAM wParam, LPARAM lParam)
{
//wchar_t szGreeting[] = TEXT("Heeeey");
HDC hdc;
PAINTSTRUCT ps;
RECT rc;
rc.left = 50; rc.top = 100; rc.right = 200; rc.bottom = 200;
switch (Message)
{
case WM_CREATE:
{
PlaySound(TEXT("D:\\mp3\\aywy._&_EphRem_-_Adderall.wav"), NULL, SND_FILENAME | SND_ASYNC);
return(0);
} break;
case WM_PAINT:
{
hdc = BeginPaint(WindowHandle, &ps);
DrawText(hdc, TEXT("Hello Win 7!!!"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
//TextOut(hdc, 0, 0, szGreeting, (int)wcslen(szGreeting));
EndPaint(WindowHandle, &ps);
return(0);
}break;
case WM_DESTROY:
{
PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC);
PostQuitMessage(0);
return(0);
}break;
}
return(DefWindowProc(WindowHandle, Message, wParam, lParam));
}
Call PlaySound( NULL, NULL, SND_FILENAME | SND_ASYNC) before PostQuitMessage to stop the sound.
About DrawText - note that BeginPaint returns rectangle rcPaint for the region which needs redraw. If you are using it for start point of DrawText, the text will appear at different places. For example - when first created, the region will start at 0,0. Then you can move another window over DrawText application window and it can require repaint from point 80,100 to lower right corner. Try with absolute (client) coordinates, e.g. define RECT rc and set rc.left = 50; rc.top = 100; rc.right = 200; rc.bottom = 200; (always the same position).
I am trying to learn win32 API using Programming Windows fifth Edition.
As I was experimenting with some Identifiers I noticed something that I am not able to understand why is happening.I` ll be more specific, here is my code:
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int
WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("HELLOWIN");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_SHIELD);
wndclass.hCursor = LoadCursor(NULL, IDC_CROSS);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(0, TEXT("This Programm Requires WINNT!"), szAppName, MB_ICONERROR);
return(0);
}
hwnd = CreateWindow(szAppName, //window class name
TEXT("The Hello Program"), //window caption
WS_OVERLAPPEDWINDOW, //window style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle(we have top-level window)
NULL, //window menu handle
hInstance, //programm instances handle
NULL); //creation parameters
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_CREATE:
{
PlaySound(TEXT("D:\\mp3\\aywy._&_EphRem_-_Adderall.wav"), NULL, SND_FILENAME | SND_ASYNC);
return 0;
} break;
case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(hdc, TEXT("Hello, Windows 98!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
} break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
With this code everything works great and as expected but...
when i change:
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
to
wndclass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
the cursor icon is lost on the background and is only visisble in the small line
in which i use drawText().What confuses me is that this doesnt happen when my background is white(WHITE_BRUSH).
Could someone explain why?
PS:If this behaviour is explained later in the book (I am finishing chapter 3 currently) just type Read more so i don`t waste you time.
Thank you in advance.
What is probably happening is that the 'cross' cursor that you are using is a very thin cursor implemented (either by windows or by the hardware) by NEGating the underlying pixels instead of painting above them. This works fine for all colors except the 0x808080 gray, because negating 0x808080 still gives 0x808080, so the cursor is invisible. Try using light gray, dark gray, or another cursor which is not so thin.
I am new to plain winapi c and was wondering if there is any simple method for adding an image to my GUI, if possible I would like this image to essentially part of the code so that I only have to send the single executable file when sending others the GUI.
EDIT:
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HBITMAP g_hbmBall = NULL;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR pCmdLine, int nCmdShow)
{
MSG msg;
HWND hwnd;
WNDCLASSW wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.lpszClassName = L"Window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpszMenuName = NULL;
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassW(&wc);
hwnd = CreateWindowW( wc.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 350, 250, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while( GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
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_PAINT:
{
BITMAP bm;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP hbmOld = (HBITMAP)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:
PostQuitMessage(0);
DeleteObject(g_hbmBall);
return 0;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
You can add the image data to your executable's resources at compile-time via an .rc file, then load the image at runtime via LoadImage(). If you put a STATIC control on your UI, you can send it an STM_SETIMAGE message to display the image.
Image should be a bitmap, you should make it a resource with your resource editor and use LoadBitmap or LoadImage to load it in your exe. Use BitBlt , StretchBlt or TransparentBlt to draw it ( use last two if you want to shrink/enlarge it to fit your window-TransparentBlt also makes parts of your image transparent-see documentation ). Do not forget to delete the resource when you are done-usually in your WM_CLOSE handler with DeleteObject API.
EDIT:
As Remy Lebeau said, you can use workaround by putting a static control on your window and set it to display image. I do not know what suits you better since your post is scarse on information. I still suggest to use GDI to draw a picture since you can try to use all kind of stretching modes to improve images quality.
This tutorial has some examples, and is good in general for learning the Win32 API.
Good luck.
Best regards.