我正在妈妈的windows.h中创建一个C ++ GUI窗体,我不知道如何使“ adaugare”,“ iesire”,“ refresh”等按钮粘在Windows窗体的底部。我想让它们在调整表单大小时自动移动,因此它们始终可以位于右下角。
请帮助我,因为我是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;
}
最佳答案
不幸的是,没有自动执行此操作的机制。您必须编写代码来侦听大小调整事件,计算每个控件的适当大小和位置,并相应地移动它。一旦您了解了过程,它就相对简单了,但是相当麻烦,尤其是当您需要调整大量控件时。
首先在主窗口的窗口过程中添加WM_SIZE
消息的处理程序。调整窗口大小时将发送此消息。
在该处理程序内部,您将调用MoveWindow
或SetWindowPos
函数来更改子窗口(即控件;即按钮)的位置。
这是一些示例代码:
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.
}
若要减少重新定位大量子控件时的闪烁,可以使用
DeferWindowPos
功能。这要求您首先开始调用BeginDeferWindowPos
,然后为每个控件调用DeferWindowPos
(就像SetWindowPos
),然后在完成所有控件的调整后最终调用EndDeferWindowPos
。请参阅Raymond Chen博客上的What's the point of DeferWindowPos?。另外,如果您想学习Windows API编程,请给自己一个极大的帮助,并阅读Charles Petzold的经典著作《 Programming Windows》(第5版)。是的,您需要第5版。较新的版本涵盖了不同的编程语言/框架。您可以在Amazon上找到使用过的副本。