For my own amusement, I have been creating a 3D graphics program in C++ with Win32 that does not use any floating point numbers. For some reason, the window flickers sometimes when window is updated. I believe this to be caused by the window updating after what was previously shown in the window was erased and before what will be drawn next is drawn. I have found several web pages and questions with answers about what appears to be the same issue, except the solutions do not work.
Some examples{
Do not use CS_HREDRAW|CS_VREDRAW. (No noticeable effect)
Return 1 for the window message 'WM_ERASEBKGND'. (I need to erase what was previously drawn. This stops the flicker by preventing it from erasing.)
Instead of erasing, draw a rectangle in the case of WM_PAINT. (This made it worse)
}
How do I actually prevent window flicker?
// compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
boolean Draw;
//Trigonometry tables in increments of 1/256 of a rotation and multiplied by 65536
const int Total=3,Sine[256]={0,1608,3216,4821,6424,8022,9616,11204,12785,14359,15924,17479,19024,20557,22078,23586,25080,26558,28020,29466,30893,32303,33692,35062,36410,37736,39040,40320,41576,42806,44011,45190,46341,47464,48559,49624,50660,51665,52639,53581,54491,55368,56212,57022,57798,58538,59244,59914,60547,61145,61705,62228,62714,63162,63572,63944,64277,64571,64827,65043,65220,65358,65457,65516,65536,65516,65457,65358,65220,65043,64827,64571,64277,63944,63572,63132,62714,62228,61705,61145,60547,59914,59244,58538,57798,57022,56212,55368,54491,53581,52639,51665,50660,49624,48559,47464,46341,45190,44011,42806,41576,40320,39040,37736,36410,35062,33692,32303,30893,29466,28020,26558,25080,23586,22078,20557,19024,17479,15924,14359,12785,11204,9616,8022,6424,4821,3216,1608,0,-1608,-3216,-4821,-6424,-8022,-9616,-11204,-12785,-14359,-15924,-17479,-19024,-20557,-22078,-23586,-25080,-26558,-28020,-29466,-30893,-32303,-33692,-35062,-36410,-37736,-39040,-40320,-41576,-42806,-44011,-45190,-46341,-47464,-48559,-49624,-50660,-51665,-52639,-53581,-54491,-55368,-56212,-57022,-57798,-58538,-59244,-59914,-60547,-61145,-61705,-62228,-62714,-63162,-63572,-63944,-64277,-64571,-64827,-65043,-65220,-65358,-65457,-65516,-65536,-65516,-65457,-65358,-65220,-65043,-64827,-64571,-64277,-63944,-63572,-63162,-62714,-62228,-61705,-61145,-60547,-59914,-59244,-58538,-57798,-57022,-56212,-55368,-54491,-53581,-52639,-51665,-50660,-49624,-48559,-47464,-46341,-45190,-44011,-42806,-41576,-40320,-39040,-37736,-36410,-35062,-33692,-32303,-30893,-29466,-28020,-26558,-25080,-23586,-22078,-20557,-19024,-17479,-15924,-14359,-12785,-11204,-9616,-8022,-6424,-4821,-3216,-1608},Cosine[256]={65536,65516,65457,65358,65220,65043,64827,64571,64277,63944,63572,63132,62714,62228,61705,61145,60547,59914,59244,58538,57798,57022,56212,55368,54491,53581,52639,51665,50660,49624,48559,47464,46341,45190,44011,42806,41576,40320,39040,37736,36410,35062,33692,32303,30893,29466,28020,26558,25080,23586,22078,20557,19024,17479,15924,14359,12785,11204,9616,8022,6424,4821,3216,1608,0,-1608,-3216,-4821,-6424,-8022,-9616,-11204,-12785,-14359,-15924,-17479,-19024,-20557,-22078,-23586,-25080,-26558,-28020,-29466,-30893,-32303,-33692,-35062,-36410,-37736,-39040,-40320,-41576,-42806,-44011,-45190,-46341,-47464,-48559,-49624,-50660,-51665,-52639,-53581,-54491,-55368,-56212,-57022,-57798,-58538,-59244,-59914,-60547,-61145,-61705,-62228,-62714,-63162,-63572,-63944,-64277,-64571,-64827,-65043,-65220,-65358,-65457,-65516,-65536,-65516,-65457,-65358,-65220,-65043,-64827,-64571,-64277,-63944,-63572,-63162,-62714,-62228,-61705,-61145,-60547,-59914,-59244,-58538,-57798,-57022,-56212,-55368,-54491,-53581,-52639,-51665,-50660,-49624,-48559,-47464,-46341,-45190,-44011,-42806,-41576,-40320,-39040,-37736,-36410,-35062,-33692,-32303,-30893,-29466,-28020,-26558,-25080,-23586,-22078,-20557,-19024,-17479,-15924,-14359,-12785,-11204,-9616,-8022,-6424,-4821,-3216,-1608,0,1608,3216,4821,6424,8022,9616,11204,12785,14359,15924,17479,19024,20557,22078,23586,25080,26558,28020,29466,30893,32303,33692,35062,36410,37736,39040,40320,41576,42806,44011,45190,46341,47464,48559,49624,50660,51665,52639,53581,54491,55368,56212,57022,57798,58538,59244,59914,60547,61145,61705,62228,62714,63162,63572,63944,64277,64571,64827,65043,65220,65358,65457,65516};
int HorizontalAxis,VerticalAxis,SemiHorizontalAxis,SemiVerticalAxis,Speed=1,Phi=64,Theta,VelX,VelY,VelZ,SinTheta,CosTheta=65536,SinPhi,CosPhi=-65536,RegX,RegY,RegZ,Quadrilaterals[3][6]={{0,1,2,3,1,0},{0,3,4,5,0,1},{6,7,8,9,1,2}};
LONG64 AxAv,X,Y,Z,XCoordinates[10]={-5,-5,5,5,5,-5,60,60,120,120},YCoordinates[10]={-5,5,5,-5,-5,-5,80,140,140,80},ZCoordinates[10]={10,10,10,10,30,30,100,100,200,200},q$,w$,e$,r$,t$,y$,u$,i$;
POINT Points[3][4]={{{0,0},{0,0},{0,0},{0,0}}};
RECT WindowRect;
const HPEN Pens[2]={CreatePen(PS_NULL,0,0),CreatePen(PS_SOLID,1,RGB(0,0,0))};
const HBRUSH Brushes[3]={CreateSolidBrush(RGB(0,0,0)),CreateSolidBrush(RGB(128,128,128)),CreateSolidBrush(RGB(255,255,255))};
HINSTANCE hInst;
HWND hWnd;
PAINTSTRUCT ps;
HDC hdc;
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam){
switch(message){
case WM_KEYDOWN:
if(GetAsyncKeyState(16)){Speed=1+3*Speed/2;}
if(GetAsyncKeyState(17)){
Speed=2*Speed/3-1;
if(Speed<1){Speed=1;}
}if(GetAsyncKeyState(82)){
X=0;Y=0;Z=0;Theta=0;Phi=0;RegX=0;RegY=0;RegZ=0;
SinTheta=0;CosTheta=65536;SinPhi=0;CosPhi=65536;
}return 0;
case WM_SIZE:
GetWindowRect(hWnd,&WindowRect);
HorizontalAxis=WindowRect.right-WindowRect.left;
SemiHorizontalAxis=HorizontalAxis/2;
VerticalAxis=WindowRect.bottom-WindowRect.top-100;
SemiVerticalAxis=VerticalAxis/2;
AxAv=(HorizontalAxis+VerticalAxis)/2;
return 0;
case WM_PAINT:
hdc=BeginPaint(hWnd,&ps);
if(GetAsyncKeyState(83)){
if(Phi>0){
Phi--;
SinPhi=Cosine[Phi];CosPhi=-Sine[Phi];
}
}if(GetAsyncKeyState(87)){
if(Phi<128){
Phi++;
SinPhi=Cosine[Phi];CosPhi=-Sine[Phi];
}
}if(GetAsyncKeyState(65)){
Theta--;
if(Theta<0){Theta=255;}
SinTheta=Sine[Theta];CosTheta=Cosine[Theta];
}if(GetAsyncKeyState(68)){
Theta++;
if(Theta>255){Theta=0;}
SinTheta=Sine[Theta];CosTheta=Cosine[Theta];
}if(GetAsyncKeyState(39)){VelZ=-SinTheta*Speed;VelX=-CosTheta*Speed;}
if(GetAsyncKeyState(38)){VelZ+=CosTheta*Speed;VelX-=SinTheta*Speed;}
if(GetAsyncKeyState(37)){VelZ+=SinTheta*Speed;VelX+=CosTheta*Speed;}
if(GetAsyncKeyState(40)){VelZ-=CosTheta*Speed;VelX+=SinTheta*Speed;}
if(GetAsyncKeyState(81)){VelY=65536*Speed;}
if(GetAsyncKeyState(69)){VelY=-65536*Speed;}
RegX+=VelX;RegY+=VelY;RegZ+=VelZ;
X+=RegX/65536;Y+=RegY/65536;Z+=RegZ/65536;
RegX%=65536;RegY%=65536;RegZ%=65536;
VelX=0;VelY=0;VelZ=0;
q$=0;
while(q$<Total){
Draw=false;
w$=Quadrilaterals[q$][0];
e$=65536*(XCoordinates[w$]-X);
r$=65536*(YCoordinates[w$]-Y);
t$=65536*(ZCoordinates[w$]-Z);
y$=(CosTheta*e$+SinTheta*t$)/65536;
e$=(CosTheta*t$-SinTheta*e$)/65536;
u$=(CosPhi*r$+SinPhi*e$)/65536;
i$=(CosPhi*e$-SinPhi*r$)/65536;
if(i$<0){
Draw=true;
Points[q$][0].x=SemiHorizontalAxis+AxAv*y$/i$;
Points[q$][0].y=SemiVerticalAxis+AxAv*u$/i$;
}w$=Quadrilaterals[q$][1];
e$=65536*(XCoordinates[w$]-X);
r$=65536*(YCoordinates[w$]-Y);
t$=65536*(ZCoordinates[w$]-Z);
y$=(CosTheta*e$+SinTheta*t$)/65536;
e$=(CosTheta*t$-SinTheta*e$)/65536;
u$=(CosPhi*r$+SinPhi*e$)/65536;
i$=(CosPhi*e$-SinPhi*r$)/65536;
if(i$<0){
Draw=true;
Points[q$][1].x=SemiHorizontalAxis+AxAv*y$/i$;
Points[q$][1].y=SemiVerticalAxis+AxAv*u$/i$;
}w$=Quadrilaterals[q$][2];
e$=65536*(XCoordinates[w$]-X);
r$=65536*(YCoordinates[w$]-Y);
t$=65536*(ZCoordinates[w$]-Z);
y$=(CosTheta*e$+SinTheta*t$)/65536;
e$=(CosTheta*t$-SinTheta*e$)/65536;
u$=(CosPhi*r$+SinPhi*e$)/65536;
i$=(CosPhi*e$-SinPhi*r$)/65536;
if(i$<0){
Draw=true;
Points[q$][2].x=SemiHorizontalAxis+AxAv*y$/i$;
Points[q$][2].y=SemiVerticalAxis+AxAv*u$/i$;
}w$=Quadrilaterals[q$][3];
e$=65536*(XCoordinates[w$]-X);
r$=65536*(YCoordinates[w$]-Y);
t$=65536*(ZCoordinates[w$]-Z);
y$=(CosTheta*e$+SinTheta*t$)/65536;
e$=(CosTheta*t$-SinTheta*e$)/65536;
u$=(CosPhi*r$+SinPhi*e$)/65536;
i$=(CosPhi*e$-SinPhi*r$)/65536;
if(i$<0){
Draw=true;
Points[q$][3].x=SemiHorizontalAxis+AxAv*y$/i$;
Points[q$][3].y=SemiVerticalAxis+AxAv*u$/i$;
}if(Draw){
SelectPen(hdc,Pens[Quadrilaterals[q$][4]]);
SelectBrush(hdc,Brushes[Quadrilaterals[q$][5]]);
Polygon(hdc,Points[q$],4);
}q$++;
}EndPaint(hWnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:return DefWindowProc(hWnd,message,wParam,lParam);
}
}
int CALLBACK WinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPSTR lpCmdLine,_In_ int nCmdShow){
GetWindowRect(GetDesktopWindow(),&WindowRect);
HorizontalAxis=WindowRect.right;
SemiHorizontalAxis=HorizontalAxis/2;
VerticalAxis=WindowRect.bottom-100;
SemiVerticalAxis=VerticalAxis/2;
AxAv=(HorizontalAxis+VerticalAxis)/2;
WNDCLASSEX wcex;
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW|CS_VREDRAW;
wcex.lpfnWndProc=WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hInstance;
wcex.hIcon=LoadIcon(hInstance,IDI_APPLICATION);
wcex.hCursor=LoadCursor(NULL,IDC_ARROW);
wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName=NULL;
wcex.lpszClassName=_T("DesktopApp");
wcex.hIconSm=LoadIcon(wcex.hInstance,IDI_APPLICATION);
if(!RegisterClassEx(&wcex)){
MessageBox(NULL,_T("RegisterClassEx failed!"),_T("Something"),NULL);
return 1;
}hInst=hInstance;
hWnd=CreateWindow(_T("DesktopApp"),_T("Something Application"),WS_OVERLAPPEDWINDOW,0,0,HorizontalAxis,VerticalAxis,NULL,NULL,hInstance,NULL);
if(!hWnd){
MessageBox(NULL,_T("CreateWindow failed!"),_T("Something"),NULL);
return 1;
}ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
Sleep(10);
InvalidateRect(hWnd,NULL,true);
}return(int)msg.wParam;
}
This is the core of most, but not all, of the noticeable flicker:
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
Sleep(10);
InvalidateRect(hWnd,NULL,true);
}return(int)msg.wParam;
You are putting a Sleep statement and an InvalidateRect call not just between every WM_PAINT call, but behind EVERY windows message. That's going to cause all kinds of problems. Further, your InvalidateRect is passing true for the erase flag. Here's an improvement:
Create a timer either in WM_CREATE or right before you start pumping messages.
SetTimer(hWnd, 999, 33, NULL); // 999 is just a random timer id, "33" is the milliseconds to wait between WM_TIMER messages
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}return(int)msg.wParam;
And then handle the timer as follows in your WndProc.
case WM_TIMER:
{
InvalidateRect(hWnd, NULL, FALSE);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:return DefWindowProc(hWnd, message, wParam, lParam);
}
Notice that I changed the redraw interval from 10 milliseconds to 33 milliseconds. I have a 4k monitor that can't go past 60 frames/second. A 10 millisecond interval is pushing that to go 100 frames/second. That's another element of flicker. So I reduced it to 30fps. We can try to push that back up after we get through some other fixes.
And since we've bought into InvalidateRect not clearing the whole screen, we can go ahead and add this to the WndProc as well so that all other redraw events won't erase it either.
case WM_ERASEBKGND:
{
return 1;
}
At this point with all the changes I've made so far, there's just a minimal amount of flicker left, especially when I resize your window down from full screen to a quarter of my 4k screen. Also, when I build your code for Release instead of Debug, it's even further reduced. That almost proves that all the math code between BeginPaint/Endpaint is taking too long and not drawing the frame within 1 frame tick.
One other minor optimization that I sometimes use, but can't definitively say if this will help is to not use the HDC provided by the BeginPaint call which might have a clipping region associated with it. It's sometimes faster to just get an unclipped HDC and redraw with that. You could try this mod to WM_PAINT. YMMV:
case WM_PAINT:
// validate that HWND
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
// fetch the unclipped DC so that subsequent drawing operations don't get boundary checked
hdc = GetDC(hWnd);
...
}if (Draw) {
SelectPen(hdc, Pens[Quadrilaterals[q$][4]]);
SelectBrush(hdc, Brushes[Quadrilaterals[q$][5]]);
Polygon(hdc, Points[q$], 4);
}q$++;
}
ReleaseDC(hWnd, hdc);
hdc = NULL;
return 0;
As I said above, most, but not all of the flickering is eliminated. Now to get rid of the rest, follow the instructions in the link provided by Alan Birtles. That is, in your WM_PAINT handler, create an offscreen memory DC and paint to that. Then blit from that offscreen DC to the real window DC. Your modified WM_PAINT should paint the entire space the memory DC as well including the background. When you do that, you can likely increase the framerate.
In a basic program, I need to know how to make a text display widget and image display that can both be changed to different strings and images on command. These will display on a basic GUI.
Any specific help would be tremendously appreciated as I have been stuck on this for more than 10 weeks! Asking online here is my last resort.
I am making a basic program that asks questions (which is my text I want to print) and images for the questions come up underneath it. I have successfully made this program in a console command window (the code I will share below) but this of course meant no images could be displayed, so I am having to remake it in a GUI that supports images.
This is my first project ever done in C++, and only know the basics (the full extent of my limited knowledge got me through making that console command window program without help).
I first used WinAPI as it came with my computer in microsoft visual studio, and tried many different suggestions by other's similar questions already answered, but always either had one of two problems; 1. The code they supplied had many errors of which most read "_ is undefined" or wasn't imported properly, or 2. created basic text successfully but didn't specify how to change it after it had been created (I have had no successful image prints so far). I have tried 3 question/answers from cplusplus.com and 3 from stack overflow (links will be below), and all of them have had these 2 problems that are created from my lack of C++ bug fixing skills.
Suggestions using WinAPI would be prefferred over QT as I have no idea what I am doing in Qt and get double digit numbers worth of errors when I import code (even though I import the correct directories), whereas WinAPI doesn't get importing errors.
Code for command console program:
//G-Learning
//#author: James Monk
//#completed: 7/6/16
//#version 1.0
//These are the libraries (external files) to include at the start.
#include <cstdio>
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
//Defining the [global] variables that will be used throughout the program
int running = 1;
int menuSelection;
int questionsLeft = 5;
int questionTextPicked;
int questionImagePicked;
int questionRandomised;
int score = 0;
int userInput;
int userInputDummy;
string stringPointer;
int intPointer;
string questionText[10] = {
"Would this most likely be, (1) an enemy (2) a player?\n",
"Is this (1) how many hearts the player has inside their body, or (2) a number of lives the player has?\n",
"Is this (1) a health bar, or (2) a set of red lights?\n",
"Is this (1) a money counter, or (2) a yellow ball counter?\n",
"Would this be a good object to touch with your character? (1) no or (2) yes?\n",
"What would this object likely have in it? (1) rewards, or (2) punishments\n",
"What does 'Game Over' mean? (1) your session has ended, or (2) the game is no longer playable\n",
"What would an icon like this likely be for? (1) show wheels, or (2) options\n",
"In a racing game, what would this be for? (1) health bar, or (2) fuel tank meter\n",
"What would this button likely do? (1) exit or cancel, or (2) mark a spot with an x\n" };
//Defining what happens with the different functions
void introduction() {
printf("\nG-Learning is a program built to teach people who know little about games the basic features of them. \n\n\
Questions will be asked, and you will need to answer them by choosing the correct answer.\n\
You will need to press 1, 2, or 3 followed by enter to choose.\n\n\
Press any number key followed by enter to return to the main menu.\n\n");
cin >> userInputDummy;
menuSelection = 0;
}
void start() {
printf("\nThe questions will now start, good luck!\n\n");
while (questionsLeft > 0) {
questionTextPicked = (rand() % 10);
if (questionTextPicked == 0) {
questionRandomised = (rand() % 4);
questionImagePicked = (7 + questionRandomised);
}
else if (questionTextPicked == 4) {
questionRandomised = (rand() % 3);
questionImagePicked = (11 + questionRandomised);
}
else {
questionImagePicked = questionTextPicked;
}
printf("after calculations, questionTextPicked is %d, questionRandomised is %d, and questionImagePicked is %d\n\n", questionTextPicked, questionRandomised, questionImagePicked);
//answering questions should be here
stringPointer = questionText[questionTextPicked];
intPointer = questionAnswer[questionImagePicked];
printf("answer is %d\n\n", intPointer);
printf("%s\n", stringPointer, intPointer);
printf("answer is %d\n\n", intPointer);
cin >> userInput;
if (userInput == questionAnswer[questionImagePicked]) {
printf("\nCorrect!\n\n");
score++;
}
else {
printf("\nIncorrect answer.\n\n");
}
questionsLeft--;
if (questionsLeft > 0) {
printf("%d questions to go!\n\n", questionsLeft);
}
if (questionsLeft == 0) {
printf("All questions have been answered, you scored %d/5.\n\nReturning you to the main menu\n\n", score);
score = 0;
}
} //end of start's while loop
menuSelection = 0;
} //end of start's function
void exit() {
menuSelection = 0;
running = 0;
}
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//Main function, where everything starts
int main(int argc, char ** argv) {
while (running == 1) {
//Welcoming the user to the program, and asking them what they want to do (starts functions)
printf("welcome to G-Learning! Press a key to get started.\n1: Instructions\n2: Start\n3: Exit\n\n");
questionsLeft = 5; //Resetting this so that the start function can begin again
cin >> menuSelection;
if (menuSelection == 1) {
introduction();
}
else if (menuSelection == 2) {
start();
}
else if (menuSelection == 3) {
exit();
}
else {
printf("Invalid input, please use the 1, 2, or 3 key.");
}
}
return 0;
return EXIT_SUCCESS;
} //end of main function
Code for my best working WinAPI iteration (can print text, but not again on command; also without image functionality. Would like to know how to improve this one!):
//These are the libraries (external files) to include at the start.
#include <cstdio>
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
int textHorizontal = 10;
int textVertical = 10;
//Variables used in making the program window
int numberInput;
char charictorInput;
string stringInput;
const char g_szClassName[] = "myWindowClass";
HINSTANCE hInstance;
// Function to get the size of the text
int GetTextSize(LPSTR a0)
{
for (int iLoopCounter = 0; ; iLoopCounter++)
{
if (a0[iLoopCounter] == '\0')
return iLoopCounter;
}
}
LPSTR TextArray[] = {
"Hello World"
};
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;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
TextOut(hdc,
// Location of the text
textHorizontal,
textVertical,
// Text to print
TextArray[0],
// Size of the text, my function gets this for us
GetTextSize(TextArray[0]));
EndPaint(hwnd, &ps);
}
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int WINAPI WinMain(HINSTANCE hInstanace, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WindowClass;
WindowClass.cbClsExtra = 0;
WindowClass.cbWndExtra = 0;
WindowClass.cbSize = sizeof(WNDCLASSEX);
WindowClass.lpszClassName = "1";
WindowClass.lpszMenuName = NULL;
WindowClass.lpfnWndProc = WndProc;
WindowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WindowClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClass.style = 0;
WindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClassEx(&WindowClass);
HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
"1",
"G-Learning by James Monk",
WS_OVERLAPPEDWINDOW,
315, 115,
1080, 720,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, SW_SHOWNORMAL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (VK_ESCAPE == msg.wParam)
break;
}
return 0;
}
I am limited to only 2 links, so to view the 3 cplusplus.com pages I tried and the 3 stack overflow pages I tried, the links to them are on a google document here:
https://docs.google.com/document/d/1IX2hxzAVka3UmVkaAgv-gXv_cwwmP3FkTYQuFWrrqyE/edit?usp=sharing
How I installed QT into Microsoft Visual Studio:
https://www.youtube.com/watch?v=P6Mg8FpFPS8
Thank you for reading through my issue and even more in advance for helping!
HINSTANCE hInstance;
int WINAPI WinMain(HINSTANCE hInstanace...
CreateWindowEx(... hInstance ...)
You have spelling errors here. hInstanace and hInstance are not the same. Visual Studio should give you warnings. Set the warning level to 4. Address all the warnings and fix them. Only in rare cases is it okay to ignore warnings.
Moreover, in declaration of WNDCLASSEX WindowClass; you missed initializing hInstance, so the code will go nowhere. In C++ 14 you can do this
WNDCLASSEX WindowClass = {0}
This will initialize all members to zero. Try to always do this when declaring data on stack. Also avoid putting random code in to message loop.
#include <cstdio>
#include <iostream>
#include <windows.h>
Above header files are for C input/output, C++ input/output, and WinAPI. Usually you don't need them all. Pick one.
LPSTR TextArray[] = {
"Hello World"
};
Above is a character array, or just "text". If you access TextArray[0] it gives you the character 'H'
int GetTextSize(LPSTR a0)
{
for (int iLoopCounter = 0; ; iLoopCounter++)
{
if (a0[iLoopCounter] == '\0')
return iLoopCounter;
}
}
Above code is the equivalent of strlen. Your code is all over the place. You have C++14 classes like std::string, C header files, useless functions like GetTextSize which is mostly for learning C/C++, more advanced WinAPI, and some mention of Qt cross development. I recommend you spend more time with a C++ book. Here is example of what you are trying to do:
#include <windows.h>
#include <string>
#include <vector>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND combobox;
static std::vector<std::string> vec = {
"Would this most likely be, (1) an enemy (2) a player?\n",
"Is this (1) how many hearts the player has inside their body, or (2) a number of lives the player has?\n",
"Is this (1) a health bar, or (2) a set of red lights?\n",
"Is this (1) a money counter, or (2) a yellow ball counter?\n",
"Would this be a good object to touch with your character? (1) no or (2) yes?\n",
"What would this object likely have in it? (1) rewards, or (2) punishments\n",
"What does 'Game Over' mean? (1) your session has ended, or (2) the game is no longer playable\n",
"What would an icon like this likely be for? (1) show wheels, or (2) options\n",
"In a racing game, what would this be for? (1) health bar, or (2) fuel tank meter\n",
"What would this button likely do? (1) exit or cancel, or (2) mark a spot with an x\n"
};
switch (msg)
{
case WM_CREATE:
combobox = CreateWindow("ComboBox", 0, CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 0, 100, 700, 30, hwnd, HMENU(100), 0, 0);
for (auto line : vec) SendMessage(combobox, CB_ADDSTRING, 0, LPARAM(line.c_str()));
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break;
case WM_COMMAND:
if (HIWORD(wParam) == CBN_SELCHANGE)
InvalidateRect(hwnd, NULL, TRUE);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
int sel = SendMessage(combobox, CB_GETCURSEL, 0, 0);
if (sel < 0) sel = 0;
TextOut(hdc, 0, 0, vec[sel].c_str(), vec[sel].size());
EndPaint(hwnd, &ps);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpszClassName = "ClassName";
wcx.lpfnWndProc = WndProc;
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClassEx(&wcx);
HWND hwnd = CreateWindowEx(0, wcx.lpszClassName, "G-Learning by James Monk", WS_VISIBLE|WS_OVERLAPPEDWINDOW, 0,0,800,600, NULL, NULL, hInstance, NULL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}