Тема: Resource-Definition Statements. PUSHBUTTON control

Я створив такий діалог (в .rc)

About DIALOG 65, 0, 100, 50
STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME
CAPTION "Про програму"
{
    CTEXT "Демонстрація зв'язку процесів", -1, 12, 4, 72, 25
    PUSHBUTTON "Закрити", IDOK, 10, 24, 80, 12
}

В документації написано: "The control sends a message to its parent whenever the user chooses the control" - я з цього нічого не зрозумів, тобто повідомлення надсилається до "DIALOG" ?
Як мені обробити кнопку по ідентифікатору "IDOK", наприклад, коли натиснути на кнопку "Закрити" то закрити діалог (DIALOG) з ідентифікатором "About" ?

2

Re: Resource-Definition Statements. PUSHBUTTON control

Betterthanyou
У вас є в ресурсах опис вікна. Щоб воно з'явилося на екрані, вам треба його створити, викликавши спеціальну системну функцію. Одним з параметрів цієї функції буде так звана віконна процедура. Саме її викликатиме система кожного разу, коли вікно отримуватиме повідомлення WM_COMMAND від кнопки. А що робити у відповідь на це повідомлення, вирішувати вам. Можете своєму вікну WM_CLOSE послати.

Подякували: Betterthanyou1

3

Re: Resource-Definition Statements. PUSHBUTTON control

Torbins дякую за допомогу !

Куму буде потрібно то ось

wchar_t szClassName[] = L"WinRcv";//Ім'я класу вікна-приймача
wchar_t szTitle[] = L"Перший додаток";//Заголовок вікна-приймача
/*Головна функція WinMain*/
int WINAPI WinMain(HINSTANCE hlnst, HINSTANCE, LPSTR, int) 
{
    MSG Msg;
    WNDCLASS wc;
    ZeroMemory(&wc, sizeof(WNDCLASS));//обнулити структуру
    wc.lpfnWndProc = WndProc;//зворотня функція головного вікна
    wc.hInstance = hlnst; //дескриптор додатку
    wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);//іконка
    wc.hCursor = LoadCursor(nullptr, IDC_ARROW);//курсор
    wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));//фонова заливка
    wc.lpszMenuName = L"Main";//назва меню
    wc.lpszClassName = szClassName;//назва класу вікна
    RegisterClass(&wc);//реєструє клас вікна для подальшого використання у викликах функції CreateWindow
    HWND hwnd = CreateWindow(//Створимо вікно
        szClassName, // ім'я класу
        szTitle, //назва вінка
        WS_OVERLAPPEDWINDOW,//стиль
        210, 10, 200, 100,//x, y, width, height
        HWND_DESKTOP,//батько вікна
        nullptr,//дескриптор меню (не знайшов як взяти дескриптор .rc файлу !)
        hlnst, //дескриптор додатку
        nullptr//lpParam
    );
    ShowWindow(hwnd, SW_NORMAL); //Покажемо вікно
    while (GetMessage(&Msg, nullptr, 0, 0)) //цикл обробки повідомлень
            DispatchMessage(&Msg);//відправляє повідомлення в процедуру вікна
    return 0;
}

/*віконна функція головного вікна*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{    
    switch (msg) 
    {
        case WM_PAINT: OnPaint(hwnd); break;//вивести текст
        case WM_COMMAND: OnCommand(hwnd, wParam); break;//обробити команду від пунктів меню
        case WM_DESTROY: OnDestroy(hwnd); break;//закрити
        default://стандартна обробка повідомлень
        return(DefWindowProc(hwnd, msg, wParam, lParam));
    }
}

/*тут WM_PAINT, WM_DESTROY та інші функції що не пов'язані з темою*/

void OnCommand(HWND hwnd, int id)
{
    switch (id)
    {//Ідентифікатор пункту меню
        case MI_ABOUT: //Відкрити діалог
            DialogBoxW(hlnstance, L"About", hwnd, DlgProc);
            break;
        case MI_EXIT: //Завершення процесу
            DestroyWindow(hwnd);
    }
}

BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) 
    {
        case WM_INITDIALOG: DlgOnInitDialog(); break;
        case WM_COMMAND: DlgOnCommand(hwnd, wParam); break;
        default:
        return FALSE;
    }
}

void DlgOnCommand(HWND hwnd, int id) 
{
    switch (id)
    {//Код елемента керування(кнопки)
        case IDOK://Натиснута кнопка "Закрити"
        case IDCANCEL://Дана команда закрити діалог через його системне меню
        EndDialog(hwnd, 0);//Закриття діалогового вікна
    }
}

В книзі "Win32 Основьі программирования, Финогенов" знайшов такий макрос HANDLE_MSG він знаходиться в windowsx, але я не знайшов до нього документації (MSDN). На форумах знайшов інформацію що ця бібліотека є небезпечною, тому її не став використовувати

але все таки такий варіант теж працює

#include <windowsx.h>
...
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    HANDLE_MSG(hwnd, WM_PAINT, OnPaint);
    HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
    HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy);
    default:
    return(DefWindowProc(hwnd, msg, wParam, lParam));
    }
}

4

Re: Resource-Definition Statements. PUSHBUTTON control

2Betterthanyou
Щойно працював з чимось схожим, не знаю як робляться ресурси в Resource-Definition Statements, але як контроли взаємодіть між собою трохи розібрався.

Для обробки повідомлень з інших контролів пишеться окрема процедура, схожа на WndProc. Зверніть увагу сигнатура в нєї трохи інша. Для того щоб оброблювати нею повідомлення від кнопки її треба зареєструвати але, не на кнопку, а на батьківський контрол кнопки(!), бо хоч повідомлення відправляє і кнопка та відправляє вона їх на батьківський контрол. Ниже приклад з поясненням.


Отже в нас є дочірнє вікно - панель (ряд. 85) і кнопка на цій панелі (ряд 102), для якої ця панель є батьківським контролом (ряд. 111). Також у кнопки є свій ідентифікатор (ряд.112) по якому потім можна буде її знайти.
Панель "реєструється" з кастомним WndProc - MyBeautifullWndProc (ряд. 8 ) за допомогою функції SetWindowSubclass (ряд. 99).
Коли якийсь контрол, для якого панель є батьківським контролом, відправляє повідомлення то воно приходить в наш MyBeautifullWndProc. А в MyBeautifullWndProc ми вже знаємо тип повідомлення (ряд. 10), і знаємо хто його відправив (ряд. 15) - відповідно реагуємо.


#include "stdafx.h"
#include <windows.h>
#include <CommCtrl.h>

static const long ID_CHILD_PANEL = 1;
static const long ID_BUTTON_PRESS_ME = 2;

LRESULT CALLBACK MyBeautifullWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (msg)
    {
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case ID_BUTTON_PRESS_ME:
            MessageBox(NULL, L"You've pressed the \"Press me\" button??!", L"Wtf...?!", MB_ICONINFORMATION | MB_OK);
            break;
        }
        break;

    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        break;
    }
    return DefSubclassProc(hwnd, msg, wParam, lParam);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // Register wsndow class
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = L"SOME_CLASS_NAME";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassEx(&wc);

    
    // Create the main windows
    HWND vMainWindow = CreateWindowEx(
        WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT,
        L"SOME_CLASS_NAME",
        L"Test app",
        WS_OVERLAPPED | WS_SYSMENU,
        700, 500,
        840, 360,
        NULL,
        NULL,
        hInstance,
        (PVOID)NULL);


    // Create the control panel
    HWND vChildControl = CreateWindowEx(
        WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME,
        L"STATIC",
        (PCTSTR)NULL,
        WS_CHILD | WS_VISIBLE,
        0,
        260,
        840,
        50,
        vMainWindow,
        (HMENU)ID_CHILD_PANEL,
        hInstance,
        (LPVOID)NULL);

    SetWindowSubclass(vChildControl, MyBeautifullWndProc, 0, 0);

    // Create the button "Press me!"
    HWND vButtomAtChildWindow = CreateWindowEx(
        0,
        L"BUTTON",
        L"Press me!",
        WS_VISIBLE | WS_CHILD | BS_FLAT,
        705,
        5,
        100,
        30,
        vChildControl,
        (HMENU)ID_BUTTON_PRESS_ME,
        hInstance,
        NULL);

    ShowWindow(vMainWindow, SW_SHOW);


    MSG Msg;
    BOOL ret;
    while ((ret = GetMessage(&Msg, NULL, 0, 0)) != 0)
    {
        if (ret == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }
    }
    return (int)Msg.wParam;

}

Надіюсь це буде корисним. Код робочий, тільки треба буде підключити в проект бібліотеку Comctl32.lib

Подякували: Betterthanyou1