Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.86/7: Рейтинг темы: голосов - 7, средняя оценка - 4.86
0 / 0 / 0
Регистрация: 29.01.2017
Сообщений: 9

WindowProcedure в собственном классе

29.01.2017, 16:16. Показов 1375. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Прошу прощения за долгое вступление, но по другому никак:
У меня возникла необходимость написать свой класс элемента управления, чтобы в программе можно было свободно создавать экземпляры этого класса и использовать их как угодно. Например надо две кнопки, по нажатию каждой родительскому окну приходить сообщение VM_COMMAND с разным значением. Для этого значение передается сразу при создании контрола.

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

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
LRESULT CALLBACK CVox::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    CVox *  vox = (CVox *)GetWindowLongPtr(hwnd, 0);
    if (msg == WM_NCCREATE)
    {
        // Allocate a new CustCtrl class for this window.
        vox = new CVox();
        SetWindowLong(hwnd, 0, (LONG)vox);
        return (vox != NULL);
    }
    if (msg == WM_NCDESTROY) delete vox;
    if (msg == WM_PAINT)     return vox->OnPaint(hwnd, wParam, lParam);
    if (msg == WM_LBUTTONUP) return vox->OmLButtonUp(hwnd, wParam, lParam);
    if (msg == WM_ERASEBKGND) return 1;
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
Как видно из оконной процедуры, у меня просто рисуется контрол и кое-что происходит при нажатии левой кнопки мыши.
Так же для удобства дальнейшего использования я прописал функцию-оболочку создания контрола, здесь видно, что я сразу передаю номер команды в глобальную переменную:

C++
1
2
3
4
5
6
7
HWND CVox::VoxCreate(HWND hwndParent, int x, int y, int command, HINSTANCE hInst)
{
    this->hMenu = command;//Сохраняю код команды в глобальной переменной класса
    HWND wnd = CreateWindow(TEXT("VoxClass"), NULL, WS_CHILD | WS_VISIBLE,
        x, y, 100, 100, hwndParent, NULL, hInst, NULL);//Создаем окошко
    if (wnd) return this->hwnd = wnd;
}
Код, который вставляет этот контрол, приведен ниже (обратите внимание, что я передаю число 100 как некоторую команду:
C++
1
2
3
    CVox * voxA = new CVox();
    if (!voxA->VoxRegisterWC(hInst)) {}
    voxA->VoxCreate(this->VectorWnd.at(0), 20, 20,  100, hInst);
Далее мне необходимо, чтобы при нажатии на контрол, он вызывал функцию SendMessage, в которой должен передать это число 100 как некоторую команду!

C++
1
2
3
4
5
LRESULT CVox::OmLButtonUp(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    SendMessage(GetParent(hwnd), WM_COMMAND, this->hMenu, 0);
    return true;
}

а родительское окно в своей процедуре проверяет
C++
1
if (LOWORD(wParam) == 100) {/* сообщение(текст)*/}
Однако, после нажатия, сообщение отправляется вовсе не с числом 100 а с каким-то мусором! если прописать в функции
вместо this->hMenu число 100, то все работает. Но мне то надо, чтобы каждый контрол отправлял свое собственное сообщение, которое я назначаю ему при создании. А когда я произвожу дебаг, то в this->hMenu лежит мусор
C++
1
2
3
4
5
[CPP]LRESULT CVox::OmLButtonUp(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    SendMessage(GetParent(hwnd), WM_COMMAND, 0, 0);
    return true;
}
[/CPP]

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

Кто может ,помогите пожалуйста!
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
29.01.2017, 16:16
Ответы с готовыми решениями:

Обработка ON_WM_PAINT в собственном классе
Всем добрый день. Я пишу класс для вывода графика сигнала y = s(t). Создал MFC приложение с единственным окном представления. Планирую,...

Vector собственных классов в собственном классе
Создал собственный класс myProject, для использования в MyForm. В классе myProject нужен vector<кооперативов>, но я не знаю как...

Ошибка в собственном классе кнопки. Не работает событие OnMouseDown и OnMouseUp
Пишу класс кнопки, все бы хорошо но есть одно но! Protected Overloads Sub OnMouseDown(e As MouseEventArgs) MouseClicked = 0 ...

8
0 / 0 / 0
Регистрация: 29.01.2017
Сообщений: 9
29.01.2017, 16:29  [ТС]
Не нашел, как редактировать сообщение, поэтому добавлю картинку в ответе, вот так это выглядит
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
29.01.2017, 18:43
Цитата Сообщение от Orangutang Посмотреть сообщение
CVox * vox = (CVox *)GetWindowLongPtr(hwnd, 0);
А это вообще работает?
0 - это DWLP_MSGRESULT, а тебе нужна другая константа - GWLP_USERDATA.
0
0 / 0 / 0
Регистрация: 29.01.2017
Сообщений: 9
29.01.2017, 19:17  [ТС]
Конечно работает! Иначе бы картинку с кнопочкой не получилось бы.
По сути информация об окне содержится в виде некоторого стека переменных. И с помощью функции SetWindowLong можно перезаписать информацию в этом стеке, а идентификаторами типа GWL_EXSTYLE или GWLP_WNDPROC ты задаешь смещение от начала этого стека, таким путем перезаписывая определенную строго определенную информацию.

Так вот весь этот стек можно сместить на определенное число байт при регистрации класса окна, таким образом можно зарегистрировать под свои нужды эту область данных:
C++
1
wc.cbWndExtra = sizeof(CVox*);
Далее функцией
C++
1
SetWindowLong(hwnd, 0, (LONG)vox)
записали в стек данных с нулевым смещением (то есть в самое начало) указатель на класс.
теперь можно брать его по дескриптору окна, так же с нулевым смещением:
C++
1
CVox *  vox = (CVox *)GetWindowLongPtr(hwnd, 0);
Есть и другие методики, подробнее здесь можно прочитать:
http://www.catch22.net/tuts/custom-controls
0
0 / 0 / 0
Регистрация: 29.01.2017
Сообщений: 9
29.01.2017, 20:27  [ТС]
В этом, пожалуй, прав ты! Однако в данной ситуации меня беспокоит другое.
Как мне таки вытащить данные из своего класса?
C++
1
2
3
4
5
6
7
8
9
10
LRESULT CALLBACK CVox::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    CVox *  vox = (CVox *)GetWindowLongPtr(hwnd, 0);
    if (msg == WM_NCCREATE)
    {
        // Allocate a new CustCtrl class for this window.
        vox = new CVox();
        SetWindowLong(hwnd, 0, (LONG)vox);
        return (vox != NULL);
    }
Он когда записывает указатель создает новый экземпляр и все параметры, которые я передал перед этим видимо стираются.
0
31 / 31 / 15
Регистрация: 02.02.2015
Сообщений: 152
29.01.2017, 20:59
Лучший ответ Сообщение было отмечено Orangutang как решение

Решение

Orangutang, друг, вот так сделай и всё будет у тебя работать.
Регистрируешь класс окна (своего элемента), в методе Create():
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Регистрируем класс.
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = StaticWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(this);
wc.hInstance = m_hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszClassName = MY_CONTROL;
 
...
...
// Создаем элемент.
m_hWnd = CreateWindow(MY_CONTROL, NULL, dwStyle, m_posX, m_posY, m_width, m_height, m_hParent, (HMENU)m_id, m_hInstance, this);
Далее описываешь два метода, один из которых статический, в описание класса:
C++
1
2
static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Реализация:
C++
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
//
// MyControl::StaticWndProc().
//
// Статическая функция обработки сообщений.
//
LRESULT CALLBACK MyControl::StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    MyControl *self = 0;
    LRESULT lr = 0;
    if (uMsg == WM_CREATE)
    {
        self = (MyControl *)((CREATESTRUCT*)lParam)->lpCreateParams;
        SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)self);
    }
    else
    {
        self = (MyControl *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
    }
    if (self)
    {
        return self->WndProc(hWnd, uMsg, wParam, lParam);
    }
    else
    {
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return lr;
}
 
//
// MyControl::WndProc().
//
// Обработчик сообщений. 
//
LRESULT CALLBACK MyControl::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT lr = 0;
    
    switch (uMsg)
    {
        case WM_CREATE:
            // Окно создано, вызываем функцию после создания.
            lr = OnCreate(hWnd, uMsg, wParam, lParam);
        break;
        case WM_DESTROY:
            // Удаление окна.
            lr = OnDestroy(hWnd, uMsg, wParam, lParam);
        break;
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return lr;
}
Нестатический метод MyControl::WndProc() как раз и будет вызываться для конкретного объекта и ты будешь иметь все данные этого объекта.
Обрати внимание, что в функции CreateWindow() сразу указывается указатель на объект this.
1
0 / 0 / 0
Регистрация: 29.01.2017
Сообщений: 9
29.01.2017, 21:10  [ТС]
Спасибо!
Как ни странно, я делал нечто подобное для создания самого окна. Оно у меня тоже определено внешним собственным классом.
А при создании контрола, решил пробовать другой метод!
В общем попробую переписать, как ты написал. Позже отпишусь если заработает!
0
31 / 31 / 15
Регистрация: 02.02.2015
Сообщений: 152
29.01.2017, 21:15
Orangutang, будет работать!)
Здесь же нет ни какой магии.)
0
0 / 0 / 0
Регистрация: 29.01.2017
Сообщений: 9
31.01.2017, 19:03  [ТС]
Все заработало! Спасибо!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
31.01.2017, 19:03
Помогаю со студенческими работами здесь

Ошибки компиляции при создании переменной типа String^ в собственном классе
ref class UtilCallOptions { private: String^ currentPath; }; приводит к: UtilCallOptions.h(4): error C2143:...

Доля отличников в классе больше 2/5, но меньше 3/7, а всего в классе не более 15 учеников. Сколько всего в классе учеников?
Добрый вечер! Подскажите, пожалуйста! "Доля отличников в классе больше 2/5, но меньше 3/7, а всего в классе не более 15 учеников....

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

Макрос в собственном блоке
Попытался ради интереса написать макрос в выделенном блоке (или как это правильно называется) не работае, а почему? int main(int...

Поиск в собственном массиве
Есть класс using System.Collections.ObjectModel; namespace NormyRashoda { public class Список : Protected { ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
Жизнь в неопределённости
kumehtar 23.03.2026
Жизнь — это постоянное существование в неопределённости. Например, даже если у тебя есть список дел, невозможно дойти до точки, где всё окончательно завершено и больше ничего не осталось. В принципе,. . .
Модель здравоСохранения: работники работают быстрее после её введения.
anaschu 23.03.2026
geJalZw1fLo Корпорация до введения программа здравоохранения имела много невыполненных работниками заданий, после введения программы количество заданий выросло. Но на выплатах по больничным это. . .
1С: Контроль уникальности заводского номера
Maks 23.03.2026
Алгоритм контроля уникальности заводского (или серийного) номера на примере документа выдачи шин для спецтехники с табличной частью. Данные берутся из регистра сведений, по которому настроено. . .
Хочу заставить корпорации вкладываться в здоровье сотрудников: делаю мат модель здравосохранения
anaschu 22.03.2026
e7EYtONaj8Y Z4Tv2zpXVVo https:/ / github. com/ shumilovas/ med2. git
1С: Программный отбор элементов справочника по группе
Maks 22.03.2026
Установка программного отбора элементов справочника "Номенклатура" из модуля формы документа. В качестве фильтра для отбора справочника служит группа номенклатуры. Отбор по наименованию группы. . .
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс. Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
1С: Программный отбор элементов справочника по значению перечисления
Maks 21.03.2026
Установка программного отбора элементов справочника "Сотрудники" из модуля формы документа. В качестве фильтра для отбора служит значение перечислений. / / Событие "НачалоВыбора" реквизита на форме. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru