【问题标题】:C++ GUI button stuck to the bottomC++ GUI按钮卡在底部
【发布时间】:2019-07-06 20:47:50
【问题描述】:

我在 windows.h 中为我妈妈制作了一个 C++ GUI 表单,但我不知道如何让 "adaugare" 、 "iesire" 、 "refresh" 等按钮粘在底部窗口形式。我想让它们在我调整表单大小时自动移动,这样它们就可以始终位于右下角。 请帮助我,因为我是 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;
}

【问题讨论】:

    标签: c++ user-interface winapi button


    【解决方案1】:

    不幸的是,没有自动执行此操作的机制。您必须编写代码来监听大小事件,计算每个控件的适当大小和位置,并相应地移动它。一旦您了解了流程,这相对简单,但相当繁琐,尤其是当您需要调整大量控件时。

    首先将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 版。较新的版本涵盖了不同的编程语言/框架。您可以在亚马逊上找到二手副本。

    【讨论】:

      猜你喜欢
      • 2021-06-10
      • 2015-01-27
      • 2019-03-11
      • 1970-01-01
      • 2018-07-02
      • 1970-01-01
      • 2017-02-10
      • 2020-03-07
      相关资源
      最近更新 更多