Reputation: 59
I'm making a C++ GUI form in windows.h for my mother and I can't figure out how to make the "adaugare" , "iesire", "refresh" etc. buttons to stick to the bottom side of windows form. I want to make them to auto-move when I resize the form, so they can always be at bottom-right side. Please help me guys because I am a beginner in C++ Gui !
#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
#include <tchar.h>
#include <windows.h>
#include <iostream>
#include <string>
#include <cstring>
#include <fstream>
using namespace std;
ofstream fout;
ifstream fin;
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
HWND hwnd; /* This is the handle for our window */
HWND button[5];
HWND banda[100];
HWND tip[100];
HWND lungime[100];
HWND latime[100];
HWND data1[100];
HWND button_valideaza[100];
int button_index[100];
int i = 0, counter = 1;
char buffer[10];
char textEP[20];
char textTip[20];
char textLungime[20];
char textLatime[20];
char textData[20];
char textAll[101];
/* Make the class name into a global variable */
TCHAR szClassName[] = _T("CodeBlocksWindowsApp");
int getIndex(){
fin.open("record.txt", std::ios_base::in);
string line1;
string line;
while(getline(fin, line1)) {
line = line1;
}
char save[line.size()];
strcpy(save, line.c_str());
char *p = strtok(save, " ");
fin.close();
return atoi(p);
}
void refresh() {
}
int WINAPI WinMain(HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
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 */
_T("Flux Artego"), /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
700, /* The programs width */
300, /* 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() */
void scrie() {
}
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WORD cmd = LOWORD(wParam);
switch (message) /* handle the messages */
{
case WM_CREATE: // fac butoane, label etc
counter = getIndex();
counter++;
fout.open("record.txt", std::ios_base::app);
std::fill_n(button_index, 100, -1);
button[0] = CreateWindow("BUTTON",
"Iesire",
WS_VISIBLE | WS_CHILD | WS_BORDER,
560, 220, 100, 20,
hwnd, (HMENU)1, NULL, NULL); // (HMENU) 1 reprezinta care case din switch se executa
button[1] = CreateWindow("BUTTON",
"Adauga",
WS_VISIBLE | WS_CHILD | WS_BORDER,
450, 220, 100, 20,
hwnd, (HMENU)2, NULL, NULL);
button[2] = CreateWindow("BUTTON",
"Refresh",
WS_VISIBLE | WS_CHILD | WS_BORDER,
340, 220, 100, 20,
hwnd, (HMENU)3, NULL, NULL);
break;
case WM_COMMAND: // fac instructiuni butoane
switch (cmd)
{
case 1:
//::MessageBeep(MB_ICONERROR);
//::MessageBox(hwnd, "Ai salvat ?", "atentie", MB_OKCANCEL);
cout << "GoodBye!";
PostQuitMessage(0);
break;
case 2: // Adaug nou record
banda[i] = CreateWindow("EDIT",
"EP",
WS_BORDER | WS_CHILD | WS_VISIBLE,
20, 30 * i, 30, 25,
hwnd, NULL, NULL, NULL);
tip[i] = CreateWindow("EDIT",
"100",
WS_BORDER | WS_CHILD | WS_VISIBLE,
55, 30 * i, 100, 25,
hwnd, NULL, NULL, NULL);
lungime[i] = CreateWindow("EDIT",
"Lungime",
WS_BORDER | WS_CHILD | WS_VISIBLE,
160, 30 * i, 100, 25,
hwnd, NULL, NULL, NULL);
latime[i] = CreateWindow("EDIT",
"Latime",
WS_BORDER | WS_CHILD | WS_VISIBLE,
265, 30 * i, 100, 25,
hwnd, NULL, NULL, NULL);
data1[i] = CreateWindow("EDIT",
"Data",
WS_BORDER | WS_CHILD | WS_VISIBLE,
370, 30 * i, 100, 25,
hwnd, NULL, NULL, NULL);
button_valideaza[i] = CreateWindow("BUTTON",
"Scrie",
WS_VISIBLE | WS_CHILD | WS_BORDER,
475, 30 * i, 80, 20,
hwnd, (HMENU)(i+5), NULL, NULL);
i++;
break;
case 3: // Refresh
refresh();
break;
case 4: // Compute
break;
default:
if (cmd > 4 && cmd < 103)
{
int index;
if (button_index[cmd-3] == -1){ // daca buton index nu a fost setata
button_index[cmd-3] = counter;
index = counter;
//cout << "Prima apasare a butinului " << cmd-3 << " si primeste index "<<counter<<endl;
counter++;
} else { // a fost setat
index = button_index[cmd-3];
//cout << "Deja apasat butonul "<< cmd-3 << " si are vechiul index " << button_index[cmd-3] << endl;
::MessageBox(hwnd, "Pentru a rescrie apasa pe REFRESH","Suprascriere", MB_OK);
}
int gwtstat = 0;
gwtstat = GetWindowText(banda[cmd-5], &textEP[0], 20);
gwtstat = 0;
gwtstat = GetWindowText(tip[cmd-5], &textTip[0], 20);
gwtstat = 0;
gwtstat = GetWindowText(lungime[cmd-5], &textLungime[0], 20);
gwtstat = 0;
gwtstat = GetWindowText(latime[cmd-5], &textLatime[0], 20);
gwtstat = 0;
gwtstat = GetWindowText(data1[cmd-5], &textData[0], 20);
itoa(index, buffer, 10);
strcpy(textAll, buffer);
strcat(textAll," ");
strcat(textAll,textEP);
strcat(textAll, " ");
strcat(textAll,textTip);
strcat(textAll, " ");
strcat(textAll, textLungime);
strcat(textAll, " ");
strcat(textAll, textLatime);
strcat(textAll, " ");
strcat(textAll, textData);
fout << textAll << "\n";
::MessageBox(hwnd, textAll,"text", MB_OKCANCEL);
}
break;
}
break;
case WM_DESTROY:
fout.close();
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;
}
Upvotes: 0
Views: 334
Reputation: 244692
Unfortunately, there is no mechanism for doing this automatically. You have to write code that listens for sizing events, calculates the appropriate size and position of each control, and moves it accordingly. It is relatively straightforward, once you understand the process, but a fair amount of drudgery, especially when you have a large number of controls to adjust.
Start by adding a handler for the WM_SIZE
message to your main window's window procedure. This message gets sent when the window is being resized.
Inside of that handler, you will call either the MoveWindow
or SetWindowPos
function to change the position of your child windows (i.e., your controls; i.e., your buttons).
Here is some sample code:
case WM_SIZE:
{
const int cxPadding = 12;
const int cyPadding = 12;
// Get client rectangle for parent window.
RECT rcParent;
GetClientRect(hwnd, &rcParent);
RECT rcButton[5];
// Adjust the position of the first button.
// It will be the furthest one to the right.
GetClientRect(button[0], &rcButton[0]);
SetWindowPos(button[0],
NULL,
(rcParent.right - cxPadding - (rcButton[0].right - rcButton[0].left)),
(rcParent.bottom - cyPadding - (rcButton[0].bottom - rcButton[0].top)),
0,
0,
SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
// Adjust the position of the second button.
// It will be the next to the first one.
GetClientRect(button[1], &rcButton[1]);
SetWindowPos(button[1],
NULL,
(rcParent.right - cxPadding - (rcButton[0].right - rcButton[0].left)
- cxPadding - (rcButton[1].right - rcButton[1].left)),
(rcParent.bottom - cyPadding - (rcButton[1].bottom - rcButton[1].top)),
0,
0,
SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
// etc.
}
To reduce flicker when you are repositioning a large number of child controls, you can use the DeferWindowPos
function. This requires that you call BeginDeferWindowPos
at the beginning, then call DeferWindowPos
(just like SetWindowPos
) for each control, and then finally call EndDeferWindowPos
when you are finished adjusting all controls. See What's the point of DeferWindowPos? on Raymond Chen's blog.
Also, if you are trying to learn Windows API programming, do yourself a huge favor and pick up a copy of Charles Petzold's classic book, Programming Windows (5th edition). Yes, you need the 5th edition. The newer editions cover a different programming language/framework. You can find used copies on Amazon.
Upvotes: 3