我正在妈妈的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消息的处理程序。调整窗口大小时将发送此消息。

在该处理程序内部,您将调用MoveWindowSetWindowPos函数来更改子窗口(即控件;即按钮)的位置。

这是一些示例代码:

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上找到使用过的副本。

10-05 18:13