Как сделать несколько окон, используя Win32 API - PullRequest
10 голосов
/ 22 мая 2010

Я вижу множество учебных пособий и статей, показывающих, как сделать простую программу для Windows, и это здорово, но ни одна из них не показывает, как создать несколько окон.

Прямо сейчас у меня есть рабочий код, который создает и рисует многоуровневое окно, и я могу перетаскивать вещи, используя GDI, чтобы рисовать на нем все, что я хочу, перетаскивать, даже делать его прозрачным и т. Д.

Но я хотел вторую прямоугольную область, в которую можно рисовать, перетаскивать и т. Д. Другими словами, второе окно. Вероятно, хотите, чтобы это было дочернее окно. Вопрос в том, как мне это сделать?

Кроме того, если кто-нибудь знает какие-либо хорошие ресурсы (желательно онлайн), такие как статьи или учебные пособия для управления окнами в Windows API, пожалуйста, поделитесь.

Ответы [ 5 ]

10 голосов
/ 28 августа 2015

Чтобы создать более одного окна, повторите все шаги, которые вы сделали, когда создали первое окно, чтобы создать второе окно. Хороший способ сделать это - скопировать и вставить весь код из первого окна. Затем выполните поиск и замените, в котором вы заменяете все имена первого окна уникальными именами для второго окна. Код, в котором я это делаю, приведен ниже.

Самое важное, на что следует обратить внимание, - это то, что класс windows для второго окна должен иметь уникальное имя в коде line "windowclassforwindow2.lpszClassName =" window class2 ". Если у него нет уникального имени, регистрация окон завершится неудачей.

    #include <windows.h>

LRESULT CALLBACK windowprocessforwindow1(HWND handleforwindow1,UINT message,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK windowprocessforwindow2(HWND handleforwindow2,UINT message,WPARAM wParam,LPARAM lParam);

bool window1closed=false;
bool window2closed=false;

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
    bool endprogram=false;

    //create window 1

    WNDCLASSEX windowclassforwindow1;
    ZeroMemory(&windowclassforwindow1,sizeof(WNDCLASSEX));
    windowclassforwindow1.cbClsExtra=NULL;
    windowclassforwindow1.cbSize=sizeof(WNDCLASSEX);
    windowclassforwindow1.cbWndExtra=NULL;
    windowclassforwindow1.hbrBackground=(HBRUSH)COLOR_WINDOW;
    windowclassforwindow1.hCursor=LoadCursor(NULL,IDC_ARROW);
    windowclassforwindow1.hIcon=NULL;
    windowclassforwindow1.hIconSm=NULL;
    windowclassforwindow1.hInstance=hInst;
    windowclassforwindow1.lpfnWndProc=(WNDPROC)windowprocessforwindow1;
    windowclassforwindow1.lpszClassName=L"windowclass 1";
    windowclassforwindow1.lpszMenuName=NULL;
    windowclassforwindow1.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClassEx(&windowclassforwindow1))
    {
        int nResult=GetLastError();
        MessageBox(NULL,
            L"Window class creation failed",
            L"Window Class Failed",
            MB_ICONERROR);
    }

    HWND handleforwindow1=CreateWindowEx(NULL,
        windowclassforwindow1.lpszClassName,
            L"Parent Window",
            WS_OVERLAPPEDWINDOW,
            200,
            150,
            640,
            480,
            NULL,
            NULL,
            hInst,
            NULL                /* No Window Creation data */
);

    if(!handleforwindow1)
    {
        int nResult=GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(handleforwindow1,nShowCmd);

    // create window 2

    WNDCLASSEX windowclassforwindow2;
    ZeroMemory(&windowclassforwindow2,sizeof(WNDCLASSEX));
    windowclassforwindow2.cbClsExtra=NULL;
    windowclassforwindow2.cbSize=sizeof(WNDCLASSEX);
    windowclassforwindow2.cbWndExtra=NULL;
    windowclassforwindow2.hbrBackground=(HBRUSH)COLOR_WINDOW;
    windowclassforwindow2.hCursor=LoadCursor(NULL,IDC_ARROW);
    windowclassforwindow2.hIcon=NULL;
    windowclassforwindow2.hIconSm=NULL;
    windowclassforwindow2.hInstance=hInst;
    windowclassforwindow2.lpfnWndProc=(WNDPROC)windowprocessforwindow2;
    windowclassforwindow2.lpszClassName=L"window class2";
    windowclassforwindow2.lpszMenuName=NULL;
    windowclassforwindow2.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClassEx(&windowclassforwindow2))
    {
        int nResult=GetLastError();
        MessageBox(NULL,
            L"Window class creation failed for window 2",
            L"Window Class Failed",
            MB_ICONERROR);
    }

    HWND handleforwindow2=CreateWindowEx(NULL,
        windowclassforwindow2.lpszClassName,
            L"Child Window",
            WS_OVERLAPPEDWINDOW,
            200,
            150,
            640,
            480,
            NULL,
            NULL,
            hInst,
            NULL);

    if(!handleforwindow2)
    {
        int nResult=GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(handleforwindow2,nShowCmd);
    SetParent(handleforwindow2,handleforwindow1);
    MSG msg;
    ZeroMemory(&msg,sizeof(MSG));
    while (endprogram==false) {
        if (GetMessage(&msg,NULL,0,0));
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        if (window1closed==true && window2closed==true) {
            endprogram=true;
        }
    }
    MessageBox(NULL,
    L"Both Windows are closed.  Program will now close.",
    L"",
    MB_ICONINFORMATION);
    return 0;
}

LRESULT CALLBACK windowprocessforwindow1(HWND handleforwindow,UINT msg,WPARAM wParam,LPARAM lParam)
{
    switch(msg)
    {
        case WM_DESTROY: {
            MessageBox(NULL,
            L"Window 1 closed",
            L"Message",
            MB_ICONINFORMATION);

            window1closed=true;
            return 0;
        }
        break;
    }

    return DefWindowProc(handleforwindow,msg,wParam,lParam);
}

LRESULT CALLBACK windowprocessforwindow2(HWND handleforwindow,UINT msg,WPARAM wParam,LPARAM lParam)
{
    switch(msg)
    {
        case WM_DESTROY: {
            MessageBox(NULL,
            L"Window 2 closed",
            L"Message",
            MB_ICONINFORMATION);

            window2closed=true;
            return 0;
        }
        break;
    }

    return DefWindowProc(handleforwindow,msg,wParam,lParam);
}

Более сложный пример использования функций для создания окон.

Создание каждого окна без функции может привести к тому, что код будет загроможден, особенно если это в операторах if. Код ниже использует отдельную функцию для создания каждого окна. В первых трех окнах есть кнопка «Создать окно» для создания следующего окна.

    #include <Windows.h>

LRESULT CALLBACK windowprocessforwindow1(HWND handleforwindow1,UINT message,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK windowprocessforwindow2(HWND handleforwindow1,UINT message,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK windowprocessforwindow3(HWND handleforwindow1,UINT message,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK windowprocessforwindow4(HWND handleforwindow1,UINT message,WPARAM wParam,LPARAM lParam);

#define createwindowbuttoninwindow1 101
#define createwindowbuttoninwindow2 201
#define createwindowbuttoninwindow3 301

bool window1open,window2open,window3open,window4open=false;
bool windowclass1registeredbefore,windowclass2registeredbefore,
    windowclass3registeredbefore,windowclass4registeredbefore=false;

enum windowtoopenenumt {none,window2,window3,window4};

windowtoopenenumt windowtoopenenum=none;

void createwindow2(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd);
void createwindow3(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd);
void createwindow4(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd);

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
    bool endprogram=false;
    WNDCLASSEX windowclassforwindow2;   
    WNDCLASSEX windowclassforwindow3;
    WNDCLASSEX windowclassforwindow4;
    HWND handleforwindow2;
    HWND handleforwindow3;
    HWND handleforwindow4;

    //create window 1
    MSG msg;
    WNDCLASSEX windowclassforwindow1;
    ZeroMemory(&windowclassforwindow1,sizeof(WNDCLASSEX));
    windowclassforwindow1.cbClsExtra=NULL;
    windowclassforwindow1.cbSize=sizeof(WNDCLASSEX);
    windowclassforwindow1.cbWndExtra=NULL;
    windowclassforwindow1.hbrBackground=(HBRUSH)COLOR_WINDOW;
    windowclassforwindow1.hCursor=LoadCursor(NULL,IDC_ARROW);
    windowclassforwindow1.hIcon=NULL;
    windowclassforwindow1.hIconSm=NULL;
    windowclassforwindow1.hInstance=hInst;
    windowclassforwindow1.lpfnWndProc=(WNDPROC)windowprocessforwindow1;
    windowclassforwindow1.lpszClassName=L"window class 1";
    windowclassforwindow1.lpszMenuName=NULL;
    windowclassforwindow1.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClassEx(&windowclassforwindow1))
    {
        int nResult=GetLastError();
        MessageBox(NULL,
            L"Window class creation failed",
            L"Window Class Failed",
            MB_ICONERROR);
    }

    HWND handleforwindow1=CreateWindowEx(NULL,
            windowclassforwindow1.lpszClassName,
            L"Window 1",
            WS_OVERLAPPEDWINDOW,
            200,
            150,
            640,
            480,
            NULL,
            NULL,
            hInst,
            NULL                /* No Window Creation data */
);

    if(!handleforwindow1)
    {
        int nResult=GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(handleforwindow1,nShowCmd);
    bool endloop=false;
    while (endloop==false) {
        if (GetMessage(&msg,NULL,0,0));
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        if (windowtoopenenum !=none) {
            switch (windowtoopenenum) {
                case window2:
                    if (window2open==false) {                                                       
                        createwindow2(windowclassforwindow2,handleforwindow2,hInst,nShowCmd);
                    }
                    break;
                case window3:
                    if (window3open==false) {           
                        createwindow3(windowclassforwindow3,handleforwindow3,hInst,nShowCmd);
                    }
                    break;
                case window4:               
                    if (window4open==false) {               
                        createwindow4(windowclassforwindow4,handleforwindow4,hInst,nShowCmd);
                    }
                    break;
            }
        windowtoopenenum=none;
    }
    if (window1open==false && window2open==false && window3open==false && window4open==false)
        endloop=true;

    }
    MessageBox(NULL,
            L"All Windows are closed.  Program will now close.",
            L"Message",
            MB_ICONINFORMATION);

}

void createwindow2(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd) {
    if (windowclass2registeredbefore==false) {
    ZeroMemory(&wc,sizeof(WNDCLASSEX));
    wc.cbClsExtra=NULL;
    wc.cbSize=sizeof(WNDCLASSEX);
    wc.cbWndExtra=NULL;
    wc.hbrBackground=(HBRUSH)COLOR_WINDOW;
    wc.hCursor=LoadCursor(NULL,IDC_ARROW);
    wc.hIcon=NULL;
    wc.hIconSm=NULL;
    wc.hInstance=hInst;
    wc.lpfnWndProc=(WNDPROC)windowprocessforwindow2;
    wc.lpszClassName=L"wc2";
    wc.lpszMenuName=NULL;
    wc.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClassEx(&wc))
    {
        int nResult=GetLastError();
        MessageBox(NULL,
            L"Window class creation failed",
            L"Window Class Failed",
            MB_ICONERROR);
    }
    else
        windowclass2registeredbefore=true;
    } 
    hwnd=CreateWindowEx(NULL,
            wc.lpszClassName,
            L"Window 2",
            WS_OVERLAPPEDWINDOW,
            200,
            170,
            640,
            480,
            NULL,
            NULL,
            hInst,
            NULL                /* No Window Creation data */
);

    if(!hwnd)
    {
        int nResult=GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(hwnd,nShowCmd);
}

void createwindow3(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd) {
    if (windowclass3registeredbefore==false) {
    ZeroMemory(&wc,sizeof(WNDCLASSEX));
    wc.cbClsExtra=NULL;
    wc.cbSize=sizeof(WNDCLASSEX);
    wc.cbWndExtra=NULL;
    wc.hbrBackground=(HBRUSH)COLOR_WINDOW;
    wc.hCursor=LoadCursor(NULL,IDC_ARROW);
    wc.hIcon=NULL;
    wc.hIconSm=NULL;
    wc.hInstance=hInst;
    wc.lpfnWndProc=(WNDPROC)windowprocessforwindow3;
    wc.lpszClassName=L"window class 3";
    wc.lpszMenuName=NULL;
    wc.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClassEx(&wc))
    {
        int nResult=GetLastError();
        MessageBox(NULL,
            L"Window class creation failed",
            L"Window Class Failed",
            MB_ICONERROR);
    }
    else
        windowclass3registeredbefore=true;
    }
    hwnd=CreateWindowEx(NULL,
            wc.lpszClassName,
            L"Window 3",
            WS_OVERLAPPEDWINDOW,
            200,
            190,
            640,
            480,
            NULL,
            NULL,
            hInst,
            NULL                /* No Window Creation data */
);

    if(!hwnd)
    {
        int nResult=GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(hwnd,nShowCmd);
}

void createwindow4(WNDCLASSEX& wc,HWND& hwnd,HINSTANCE hInst,int nShowCmd) {
    if (windowclass4registeredbefore==false) {
        ZeroMemory(&wc,sizeof(WNDCLASSEX));
    wc.cbClsExtra=NULL;
    wc.cbSize=sizeof(WNDCLASSEX);
    wc.cbWndExtra=NULL;
    wc.hbrBackground=(HBRUSH)COLOR_WINDOW;
    wc.hCursor=LoadCursor(NULL,IDC_ARROW);
    wc.hIcon=NULL;
    wc.hIconSm=NULL;
    wc.hInstance=hInst;
    wc.lpfnWndProc=(WNDPROC)windowprocessforwindow4;
    wc.lpszClassName=L"window class 4";
    wc.lpszMenuName=NULL;
    wc.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClassEx(&wc))
    {
        int nResult=GetLastError();
        MessageBox(NULL,
            L"Window class creation failed",
            L"Window Class Failed",
            MB_ICONERROR);
    }
    else
        windowclass4registeredbefore=true;
    }
    hwnd=CreateWindowEx(NULL,
            wc.lpszClassName,
            L"Window 4",
            WS_OVERLAPPEDWINDOW,
            200,
            210,
            640,
            480,
            NULL,
            NULL,
            hInst,
            NULL                /* No Window Creation data */
);

    if(!hwnd)
    {
        int nResult=GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(hwnd,nShowCmd);
}

// windows process functions

LRESULT CALLBACK windowprocessforwindow1(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) {
    switch(message) {
        case WM_CREATE:
                window1open=true;
                CreateWindowEx(NULL,
                L"BUTTON",
                L"Open Window 2",
                WS_TABSTOP|WS_VISIBLE|
                WS_CHILD|BS_DEFPUSHBUTTON,
                50,
                220,
                150,
                24,
                hwnd,
                (HMENU)createwindowbuttoninwindow1,
                GetModuleHandle(NULL),
                NULL);
            break;
            case WM_DESTROY:
                window1open=false;
                break;
        case WM_COMMAND:
            switch LOWORD(wParam) {
                case createwindowbuttoninwindow1:
                    windowtoopenenum=window2;
                    break;
            }
    }
    return DefWindowProc(hwnd, message, wParam, lParam);

}

LRESULT CALLBACK windowprocessforwindow2(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) {
    switch(message) {
        case WM_CREATE:
                window2open=true;
                CreateWindowEx(NULL,
                L"BUTTON",
                L"Open Window 3",
                WS_TABSTOP|WS_VISIBLE|
                WS_CHILD|BS_DEFPUSHBUTTON,
                50,
                220,
                150,
                24,
                hwnd,
                (HMENU)createwindowbuttoninwindow2,
                GetModuleHandle(NULL),
                NULL);
            break;
            case WM_DESTROY:
                window2open=false;
                break;
        case WM_COMMAND:
            switch LOWORD(wParam) {
                case createwindowbuttoninwindow2:
                    windowtoopenenum=window3;
                    break;
            }
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

LRESULT CALLBACK windowprocessforwindow3(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) {
    switch(message) {
        case WM_CREATE:
                window3open=true;
                CreateWindowEx(NULL,
                L"BUTTON",
                L"Open Window 4",
                WS_TABSTOP|WS_VISIBLE|
                WS_CHILD|BS_DEFPUSHBUTTON,
                50,
                220,
                150,
                24,
                hwnd,
                (HMENU)createwindowbuttoninwindow3,
                GetModuleHandle(NULL),
                NULL);
                break;
                case WM_DESTROY:
                window3open=false;
                break;
        case WM_COMMAND:
            switch LOWORD(wParam) {
                case createwindowbuttoninwindow3:
                    windowtoopenenum=window4;
                    break;
            }
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

LRESULT CALLBACK windowprocessforwindow4(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) {
    switch(message) {
        case WM_DESTROY:
            window4open=false;
            break;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

Что если вы закроете и снова откроете окно?

Если вы нажмете кнопку закрытия и снова откроете то же самое окно, обратите внимание на следующее. Когда окно закрывается после закрытия кнопки закрытия, оно будет уничтожено. Но уничтожение окна не разрушает класс windows. Уничтожает только окно из функции createwindow. Это делает необходимым оператор if в вышеприведенной программе, который создает класс Windows только в том случае, если окно отображается впервые.

Некоторые примечания

Вы можете создать несколько окон, используя только один класс окон. Но проблема в том, что у вас есть одна оконная функция для работы с несколькими окнами. Это будет хорошо работать в этом простом примере. Но чем более разнородны окна, тем больше будет необходимости создавать отдельный класс окон для каждого окна.

Также несколько функций createwindow можно было бы объединить в одну функцию. Обратите внимание, что единственной разницей между ними была строка кода wc.lpszClassName. Но Windows, вероятно, будет отличаться друг от друга, поэтому объединять функции в одну не нужно - это скорее предпочтение просто не иметь кода, повторяющего вещи.

Дополнительная литература

Ссылка на веб-сайт с функцией домена x содержит более подробную информацию о концепциях дизайна окон. Ссылка здесь

Домашняя страница на functionx.com имеет хорошие учебные ресурсы по программированию. Особенно важна эта страница, на которой есть справочные материалы по программированию для таких вещей, как изменение класса окон, создание списков и других элементов управления окнами. Это также хороший ресурс для обучения программированию на win32 в целом. functionx.com win32 программирование

functionx.com win32 программирование

8 голосов
/ 22 мая 2010

Вы можете нажать CreateWindow () более одного раза, если хотите. Цикл сообщений в вашем WinMain будет передавать события всем окнам, которые создает WinMain. Вы даже можете создать два перекрывающихся окна и установить родительское окно 2-го окна в качестве дескриптора 1-го, если хотите.

3 голосов
/ 22 мая 2010

Звучит так, как будто вы хотите Многодокументный интерфейс .Вот пример одного:

http://www.codeproject.com/KB/winsdk/Sigma.aspx

2 голосов
/ 01 ноября 2017

Я знаю, что на это уже был дан ответ, но я просто писал программу, которая открывает произвольное количество окон через цикл for.

Вот моя версия. По сути, он использует один и тот же генератор классов для создания нескольких окон. Вы можете создать столько, сколько хотите. Просто убедитесь, что вы соответственно настроили массивы HWND [] и WNDCLASSEX wc [].

Примечание 1. Этот фрагмент кода использует глобальный экземпляр ApplicationInstance, производный от функции WinMain. В вашем WinMain назначьте полученный hInstance ApplicationInstance, который в этом примере предполагается доступным глобально. Это ваш основной экземпляр окна приложения.

Примечание 2: Конечно, у вас должна быть предварительно написанная подпрограмма WinProc, включенная где-то в другой заголовочный файл или чуть выше (не показано в этом примере.) В этом коде она называется WinProc, когда он передается в PopulateClass (процесс WNDPROC)

Примечание 3: SpawnWindow поддерживает флаги «по центру» и «максимизировано». То, что они делают, говорит само за себя.

Кроме того, имя класса окна генерируется автоматически, поэтому вам не нужно беспокоиться о его именовании, просто присвойте ему хорошее базовое имя.

int WindowCounter = 0;
WNDCLASSEX wc[1000];
HWND hwnd[1000];
char class_name[256]; // for auto class name generation

void PopulateClass(WNDPROC process) {
    ZeroMemory(&wc[WindowCounter], sizeof(WNDCLASSEX));
    wc[WindowCounter].cbSize = sizeof(WNDCLASSEX);
    wc[WindowCounter].style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
    wc[WindowCounter].lpfnWndProc = process;
    wc[WindowCounter].cbClsExtra = 0;
    wc[WindowCounter].cbWndExtra = 0;
    wc[WindowCounter].hInstance = ApplicationInstance;
    wc[WindowCounter].hIcon = LoadIcon(nullptr, IDI_APPLICATION);
    wc[WindowCounter].hCursor = LoadCursor(nullptr, IDC_ARROW);
    wc[WindowCounter].hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
    wc[WindowCounter].lpszMenuName = nullptr;
    sprintf(class_name, "WindowClass%d", WindowCounter);
    wc[WindowCounter].lpszClassName = class_name;
    wc[WindowCounter].hIconSm = nullptr;
}

Теперь давайте соберем все вместе, предоставив функцию SpawnWindow!

HWND SpawnWindow(int x,
                 int y,
                 int width,
                 int height,
                 bool centered = false,
                 bool maximized = false) {
    PopulateClass(WinProc);
    RegisterClassEx(&wc[ WindowCounter ]);
    int config_style = WS_OVERLAPPEDWINDOW;
    if (maximized) { width = GetSystemMetrics(SM_CXFULLSCREEN); height =     GetSystemMetrics(SM_CYFULLSCREEN); config_style = WS_OVERLAPPEDWINDOW |     WS_MAXIMIZE;  }
    if (centered) { x = (GetSystemMetrics(SM_CXFULLSCREEN) / 2) - (width /     2); y = (GetSystemMetrics(SM_CYFULLSCREEN) / 2) - (height / 2); }
    hwnd[WindowCounter] = CreateWindowEx(NULL,
        wc[WindowCounter].lpszClassName,
        config.namever(),
        WS_OVERLAPPEDWINDOW,
        x,
        y,
        width,
        height,
        nullptr,
        nullptr,
        ApplicationInstance,
        nullptr);
    HWND returnID = hwnd[WindowCounter];
    ShowWindow(hwnd[WindowCounter++], SW_SHOW);
    return returnID;
}

Наконец, создайте столько окон, сколько вы хотите, используя всего одну строку кода:

void CreateWindows() {
    HWND PrimaryWindow1 = SpawnWindow(500, 500, 250, 250);
    HWND PrimaryWindow2 = SpawnWindow(500, 500, 250, 250, true);
    HWND PrimaryWindow3 = SpawnWindow(500, 500, 250, 250, true, true);
    HWND PrimaryWindow4 = SpawnWindow(100, 100, 150, 150);
    HWND PrimaryWindow5 = SpawnWindow(450, 500, 350, 150);
}

Вызовите CreateWindows () из WinMain перед входом в основной цикл.

Надеюсь, это кому-нибудь поможет.

Использование одного WinProc для всех окон

Обратите внимание, для этого потребуется дополнительная модификация вышеуказанного кода. В частности, передача пользовательского имени класса в функцию SpawnWindow, представляющую каждое окно. Например: «WindowClass_App», где «WindowClass_» может быть статической частью имени, а фактический идентификатор будет просто: «Приложение», «Панель инструментов», «Боковая панель», «AnotherCustomWindow» и т. Д. Сначала определите их:

#define WindowClass_App                    0
#define WindowClass_Layers                 2
#define WindowClass_OpenGL                 3
/* ...etc... */

Я написал функцию, которая преобразует строку в int ID. Этот идентификатор будет использоваться для разветвления в пределах одной функции WinProc, в зависимости от того, к какому классу окна было получено сообщение:

int IdentifyWindowClassID(const char *lpClassName) {
    int WindowClassID = -1;
    // Convert string names to integers, because C++ switch does not support strings
    if (strcmp(lpClassName, "WindowClass_App") == 0) WindowClassID = WindowClass_App;
    if (strcmp(lpClassName, "WindowClass_Layers") == 0) WindowClassID = WindowClass_Layers;
    if (strcmp(lpClassName, "WindowClass_OpenGL") == 0) WindowClassID = WindowClass_OpenGL;
    /* etc */
    return WindowClassID;
}

И, наконец, сам WinProc:

long __stdcall WinProc(HWND hwnd, unsigned int msg, WPARAM wparam, LPARAM lparam)
{
    char lpClassName[128];
    GetClassName(hwnd, lpClassName, 128);

    int WindowClassID = IdentifyWindowClassID( lpClassName );

    switch (WindowClassID)
    {
        /* 1.) Main application window */
        case WindowClass_App: { 
            switch (msg) {    
                case WM_CREATE: {
                    /* ...code... */
                }
            /* ...code... */
        }

        /* 2.) Layers window */
        case WindowClass_Layers: {
            switch (msg) {    
                case WM_CREATE: {
                    /* ...code... */
                }
            /* ...code... */
        }

        /* 3.) OpenGL view window... */

       ...

Это основной шаблон. Конечно, вы можете сделать это любым способом, каким только захотите, просто так я и сделал, он прост и работает для меня.

2 голосов
/ 22 мая 2010

Вы можете создать столько окон, сколько вы хотите, используя CreateWindow / CreateWindowEx, с отношениями между ними, как вы пожелаете (владелец / ребенок).

Вы можете сделать окно "принадлежащим" другому с помощью:

SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONG_PTR) hwndParent);

Чтобы преобразовать окно в дочернее, используйте SetParent.

Обратите внимание, что вызов SetWindowLongPtr с GWLP_HWNDPARENT не ведет себя как SetParent (я думаю, что MSDN неверен). GWLP_HWNDPARENT не преобразует окно в «дочерний», а в «принадлежащий».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...