Элементы управления окна

Элементы управления окна

Главным элементом программы в среде Windows является окно. Окно может содержать элементы управления: кнопки, списки, поля редактирования и др.

Эти элементы также являются окнами, но обладающими особым свойством: события, происходящие с этими элементами (и самим окном), приводят к приходу сообщений в процедуру окна.

Системный класс Предназначение
BUTTON Кнопка
COMBOBOX   Комбинированное окно (окно со списком и поля выбора)
EDIT   Окно редактирования текста
LISTBOX   Окно со списком
SCROLLBAR   Полоса прокрутки
STATIC   Статический элемент (текст)

Создание элементов управления окна  осуществляется функцией

 
 
 
 
 
 
 
 
 
 
 
 
HWND WINAPI CreateWindow(
_In_opt_ LPCTSTR lpClassName, // имя предопределенного класса
_In_opt_ LPCTSTR lpWindowName, // текст
_In_ DWORD dwStyle, // стиль
_In_ int x, // координата x
_In_ int y, // координата y
_In_ int nWidth, // ширина
_In_ int nHeight, // высота
_In_opt_ HWND hWndParent, // дескриптор родительского окна
_In_opt_ HMENU hMenu, // номер пункта меню
_In_opt_ HINSTANCE hInstance, // дескриптор приложения
_In_opt_ LPVOID lpParam ); // NULL

Указанная функция возвращает дескриптор элемента управления окна, который может быть впоследствии использован для анализа элемента управления, с которым связано обрабатываемое событие. Дескриптор кнопки, например, передается в оконную функцию в качестве параметра lparam.

Таблицу стилей элементов управления окна можно  устанавливать в параметре dwStyle как и для создания родительского окна. При этом обязательно указывается, что создаваемое окно является дочерним — WS_CHILD.

Кнопка

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

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

Состояния кнопки

При нажатии кнопки операционная система генерирует сообщение WM_COMMAND с параметром lParam, соответствующим дескриптору кнопки.

Обработка нажатия кнопки:

 
 
 
 
 
 
 
 
 
 
 
 
 
 
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam) 
{
  …
  switch (Message) 
  {
    case WM_COMMAND:
      if(lparam == (LPARAM)hBtn) 
      {
        //обработка нажатия кнопки
      }
      break;
    …
  }
}

В данном коде параметр lparam сравнивается с дескриптором каждой кнопки (в данном случае hbtn.

Поле редактирования

Поле редактирования — прямоугольное дочернее окно, внутри которого пользователь может напечатать с клавиатуры текст. Пользователь выбирает орган управления и дает ему фокус клавиатуры, щелкая по нему мышью или перемещая в него, каретку путем нажатия клавиши ТАБУЛЯЦИИ (TAB).

Пользователь может вводить текст, когда окно редактирования текста отображает мигающую каретку.

Для считывания информации из поля редактирования используется функция

 
 
 
 
int WINAPI GetWindowText(
_In_   HWND hWnd,   // дескриптор поля
_Out_  LPTSTR lpString,   // указатель на текстовую строку
_In_   int nMaxCount );       // максимальное количество символов

Возвращаемое значение – длина считанной текстовой строки.

Для установки текста в поле редактирования используется функция

 
 
 
BOOL WINAPI SetWindowText(
_In_      HWND hWnd,   // дескриптор поля
_In_opt_  LPCTSTR lpString ); // указатель на текстовую строку

В случае успешного завершения функция возвращает ненулевое значение.

Статический текст

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

Для установки статического текста используется та же функция SetWindowText.

Пример на С++: Найти сумму двух чисел.

Программа создает два поля редактирования для ввода чисел и кнопку «Рассчитать», при нажатии на которую выводится статический текст, соответствующий сумме.

Для перевода строки в целое число и обратно использованы функции StrToInt и IntToStr, описанные в статье Преобразование строки в число и обратно. Только для соответствия символьных типов используется тип TCHAR.

Также использовалась многобайтовая кодировка.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <windows.h>
#include <tchar.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam);
int StrToInt(TCHAR* s)
{
    int temp = 0; // число
    int i = 0;
    int sign = 0; // знак числа 0- положительное, 1 - отрицательное
    if (s[i] == '-')
    {
        sign = 1;
        i++;
    }
    while (s[i] >= 0x30 && s[i] <= 0x39)
    {
        temp = temp + (s[i] & 0x0F);
        temp = temp * 10;
        i++;
    }
    temp = temp / 10;
    if (sign == 1)
        temp = -temp;
    return(temp);
}
// Функция преобразования числа в строку
TCHAR* IntToStr(int n)
{
    TCHAR s[40], t, *temp;
    int i, k;
    int sign = 0;
    i = 0;
    k = n;
    if (k < 0)
    {
        sign = 1;
        k = -k;
    }
    do {
        t = k % 10;
        k = k / 10;
        s[i] = t | 0x30;
        i++;
    } while (k > 0);
    if (sign == 1)
    {
        s[i] = '-';
        i++;
    }
    temp = new TCHAR[i];
    k = 0;
    i--;
    while (i >= 0) {
        temp[k] = s[i];
        i--; k++;
    }
    temp[k] = '\0';
    return(temp);
}
// Стартовая функция
int  WINAPI  WinMain(HINSTANCE  hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd; // дескриптор окна
    MSG msg;   // структура сообщения
    WNDCLASS w; // структура класса окна
    memset(&w, 0, sizeof(WNDCLASS)); // очистка памяти для структуры
    w.style = CS_HREDRAW | CS_VREDRAW;
    w.lpfnWndProc = WndProc;
    w.hInstance = hInstance;
    w.hbrBackground = CreateSolidBrush(0x00FFFFFF);
    w.lpszClassName = _T("MyClass");
    RegisterClass(&w); // регистрация класса окна
    // Создание окна
    hwnd = CreateWindow(_T("MyClass"), _T("Сумма двух чисел"),
        WS_OVERLAPPEDWINDOW,
        500, 300, 500, 380,
        NULLNULL, hInstance, NULL);
    ShowWindow(hwnd, nCmdShow); // отображение окна
    UpdateWindow(hwnd);         // перерисовка окна
    // Цикл обработки сообщений
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
// Функция обработки сообщений
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
    HDC hdc;
    HINSTANCE hInst;
    PAINTSTRUCT ps;
    static HWND hBtn; // дескриптор кнопки
    static HWND hEdt1, hEdt2; // дескрипторы полей редактирования
    static HWND hStat; // дескриптор статического текста
    TCHAR StrA[20];
    int a, b, sum, Len;
    switch (Message) {
    case WM_CREATE: // сообщение создания окна
        hInst = ((LPCREATESTRUCT)lparam)->hInstance; // дескриптор приложения
        // Создаем и показываем первое поле редактирования
        hEdt1 = CreateWindow(_T("edit"), _T("0"),
            WS_CHILD | WS_VISIBLE | WS_BORDER | ES_RIGHT, 50, 50, 60, 20,
            hwnd, 0, hInst, NULL);
        ShowWindow(hEdt1, SW_SHOWNORMAL);
        // Создаем и показываем второе поле редактирования
        hEdt2 = CreateWindow(_T("edit"), _T("0"),
            WS_CHILD | WS_VISIBLE | WS_BORDER | ES_RIGHT, 150, 50, 60,
            20, hwnd, 0, hInst, NULL);
        ShowWindow(hEdt2, SW_SHOWNORMAL);
        // Создаем и показываем кнопку
        hBtn = CreateWindow(_T("button"), _T("Рассчитать"),
            WS_CHILD | WS_VISIBLE | WS_BORDER,
            50, 100, 120, 30, hwnd, 0, hInst, NULL);
        ShowWindow(hBtn, SW_SHOWNORMAL);
        // Создаем и показываем поле текста для результата
        hStat = CreateWindow(_T("static"), _T("0"), WS_CHILD | WS_VISIBLE,
            150, 180, 120, 20, hwnd, 0, hInst, NULL);
        ShowWindow(hStat, SW_SHOWNORMAL);
        break;
    case WM_COMMAND:  // сообщение о команде
        if (lparam == (LPARAM)hBtn)    // если нажали на кнопку
        {
            Len = GetWindowText(hEdt1, StrA, 20);
            a = StrToInt(StrA); // считываем число из первого поля
            Len = GetWindowText(hEdt2, StrA, 20);
            b = StrToInt(StrA); // считываем число из второго поля
            sum = a + b;  // находим сумму двух чисел
            SetWindowText(hStat, IntToStr(sum)); // выводим результат в статическое поле
        }
        break;
    case WM_PAINT// перерисовка окна
        hdc = BeginPaint(hwnd, &ps); // начало перерисовки
        TextOut(hdc, 50, 20, _T("Введите два числа"), 18); // вывод текстовых сообщений
        TextOut(hdc, 50, 180, _T("Результат:"), 10);
        EndPaint(hwnd, &ps); // конец перерисовки
        break;
    case WM_DESTROY// закрытие окна
        PostQuitMessage(0);
        break;
    default: // обработка сообщения по умолчанию
        return DefWindowProc(hwnd, Message, wparam, lparam);
    }
    return 0;
}

Результат выполнения программы

16 комментариев к “Элементы управления окна”

  1. Владислав Чёрный

    Код сразу не заработал, выдавал ошибки. Запускал код в Code::Blocks 20.03. Для функции WndProc заменил тип с LONG WINAPI на LRESULT CALLBACK и всё заработало. Исправный код представлен ниже.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    #include <windows.h>

    LRESULT CALLBACK WndProc(HWNDUINTWPARAMLPARAM); // функция обработки сообщений окна
    // Функция преобразования строки в число
    int StrToInt(char *s)
    {
      int temp = 0; // число
      int i = 0;
      int sign = 0; // знак числа 0- положительное, 1 — отрицательное
      if (s[i] == '-')
      {
        sign = 1;
        i++;
      }
      while (s[i] >= 0x30 && s[i] <= 0x39)
      {
        temp = temp + (s[i] & 0x0F);
        temp = temp * 10;
        i++;
      }
      temp = temp / 10;
      if (sign == 1)
        temp = -temp;
      return(temp);
    }
    // Функция преобразования числа в строку
    char* IntToStr(int n)
    {
      char s[40], t, *temp;
      int i, k;
      int sign = 0;
      i = 0;
      k = n;
      if (k<0)
      {
        sign = 1;
        k = -k;
      }
      do {
        t = k % 10;
        k = k / 10;
        s[i] = t | 0x30;
        i++;
      } while (k>0);
      if (sign == 1)
      {
        s[i] = '-';
        i++;
      }
      temp = new char[i];
      k = 0;
      i—;
      while (i >= 0) {
        temp[k] = s[i];
        i—; k++;
      }
      temp[k] = '\0';
      return(temp);
    }
    // Стартовая функция
    int  WINAPI  WinMain(HINSTANCE  hInstance,
      HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
      HWND hwnd; // дескриптор окна
      MSG msg;   // структура сообщения
      WNDCLASS w; // структура класса окна
      memset(&w, 0, sizeof(WNDCLASS)); // очистка памяти для структуры
      w.style = CS_HREDRAW | CS_VREDRAW;
      w.lpfnWndProc = WndProc;
      w.hInstance = hInstance;
      w.hbrBackground = CreateSolidBrush(0x00FFFFFF);
      w.lpszClassName = "MyClass";
      RegisterClass(&w); // регистрация класса окна
      // Создание окна
      hwnd = CreateWindow("MyClass", "Сумма двух чисел",
        WS_OVERLAPPEDWINDOW,
        500, 300, 500, 380,
        NULLNULL, hInstance, NULL);
      ShowWindow(hwnd, nCmdShow); // отображение окна
      UpdateWindow(hwnd);         // перерисовка окна
      // Цикл обработки сообщений
      while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      return msg.wParam;
    }
    // Функция обработки сообщений
    LRESULT CALLBACK WndProc(HWND hwnd, UINT Message,
      WPARAM wparam, LPARAM lparam) {
      HDC hdc;
      HINSTANCE hInst;
      PAINTSTRUCT ps;
      static HWND hBtn; // дескриптор кнопки
      static HWND hEdt1, hEdt2; // дескрипторы полей редактирования
      static HWND hStat; // дескриптор статического текста
      TCHAR StrA[20];
      int a, b, sum, Len;
      switch (Message) {
      case WM_CREATE: // сообщение создания окна
        hInst = ((LPCREATESTRUCT)lparam)->hInstance; // дескриптор приложения
        // Создаем и показываем первое поле редактирования
        hEdt1 = CreateWindow("edit", "0",
          WS_CHILD | WS_VISIBLE | WS_BORDER | ES_RIGHT, 50, 50, 60, 20,
          hwnd, 0, hInst, NULL);
        ShowWindow(hEdt1, SW_SHOWNORMAL);
        // Создаем и показываем второе поле редактирования
        hEdt2 = CreateWindow("edit", "0",
          WS_CHILD | WS_VISIBLE | WS_BORDER | ES_RIGHT, 150, 50, 60,
          20, hwnd, 0, hInst, NULL);
        ShowWindow(hEdt2, SW_SHOWNORMAL);
        // Создаем и показываем кнопку
        hBtn = CreateWindow("button", "Рассчитать",
          WS_CHILD | WS_VISIBLE | WS_BORDER,
          50, 100, 120, 30, hwnd, 0, hInst, NULL);
        ShowWindow(hBtn, SW_SHOWNORMAL);
        // Создаем и показываем поле текста для результата
        hStat = CreateWindow("static", "0", WS_CHILD | WS_VISIBLE,
          150, 180, 120, 20, hwnd, 0, hInst, NULL);
        ShowWindow(hStat, SW_SHOWNORMAL);
        break;
      case WM_COMMAND:  // сообщение о команде
        if (lparam == (LPARAM)hBtn)    // если нажали на кнопку
        {
          Len = GetWindowText(hEdt1, StrA, 20);
          a = StrToInt(StrA); // считываем число из первого поля
          Len = GetWindowText(hEdt2, StrA, 20);
          b = StrToInt(StrA); // считываем число из второго поля
          sum = a + b;  // находим сумму двух чисел
          SetWindowText(hStat, IntToStr(sum)); // выводим результат в статическое поле
        }
        break;
      case WM_PAINT// перерисовка окна
        hdc = BeginPaint(hwnd, &ps); // начало перерисовки
        TextOut(hdc, 50, 20, "Введите два числа", 18); // вывод текстовых сообщений
        TextOut(hdc, 50, 180, "Результат:", 10);
        EndPaint(hwnd, &ps); // конец перерисовки
        break;
      case WM_DESTROY// закрытие окна
        PostQuitMessage(0);
        break;
      default: // обработка сообщения по умолчанию
        return DefWindowProc(hwnd, Message, wparam, lparam);
      }
      return 0;
    }

  2. Анатолий

    Здравствуйте! А как добавить DataGridView? У Вас написано в коде по поводу Кнопки (Botton) так: static HWND hBtn; // дескриптор кнопки
    И, вообще, где взять весь список возможных элементов управления с их названием в коде, как у Вас static HWND hBtn ?

    1. Анатолий

      Кстати, я увидел код создания кнопки: // Создаем и показываем кнопку
      hBtn = CreateWindow("button", "Рассчитать",
      WS_CHILD | WS_VISIBLE | WS_BORDER,
      50, 100, 120, 30, hwnd, 0, hInst, NULL);
      ShowWindow(hBtn, SW_SHOWNORMAL);
      Но это всё равно никак не помогает создать DataGridView.

          1. Анатолий

            В какой тогда элемент управления выводить данные из БД?

          2. Елена Вставская

            Дело в том, что DataGridView появился позже, чем возможность создавать элементы управления окна через WinAPI.
            И я, честно говоря, не работала с DataGridView на C++.
            На C# опыт есть (в том числе и с базой данных).

    2. Анатолий

      Вообще-то DataGridView это объект из .NET Framework а тут речь идёт о GUI, которое работfет на Win API. Я посмотрел палитру компонентов которые можно добавлять. Из объектов поддерживаемых отображения таблиц или иерархических таблиц есть 2 это: ListControl и TreeControl. Первый будет отображать соотвестенно 1 таблицу из бд, а 2-ой иерархию таблиц. Если вы рабоаете на С++ или Си это исключает использование данного объекта. Хотя конечно можно написать модуль на С# и таскать туда данные. но по любому это буде работать под .NET Framework иначе никак. Проще написать код на С# и использовать WinForms или WPF или ASP.NET(для веб проекта) или массу др возможностей где используется .NET Framework. Какая версия? да есть начиная с 1.1(1ю0 глючная) Но сейчас ниже 4.6 не используется. Обычно 4.8… А есл ивы хотите без фреймворков(они тормознутые и жрут много ресурсов) то только эти 2 объекта а далье всё вручную. Но работать будет хорошо и без доп ПО. это нативный вариант…

  3. Руслан

    Здравствуйте! Сможете подсказать как быть если нужно работать не с целыми, а с дробными числами? float или double. Столько инфы перерыл, много чего пробовал, и atof(). Сама то функция работает, но в теле данной программы почему-то нет. Ну еще ведь нужно обратно как-то из числа в строку перевести!

  4. Игорь Орещенков

    Приведенная программа "Пример на C++" содержит ошибку, приводящую к утечке памяти. При каждом нажатии экранной кнопки "Рассчитать" в строке 129 выполняется вызов функции IntToStr (sum), в ходе выполнения которой в строке 49 выделяется динамическая память, которая не возвращается системе.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх