Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.78/18: Рейтинг темы: голосов - 18, средняя оценка - 4.78
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633

Обработка нажатий клавиш, как в модальном диалоговом окне

16.06.2023, 09:03. Показов 5235. Ответов 26
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте! Подскажите, пожалуйста, если нужно создать временное(POPUP) окно и в нём создать элементы управления windows(например, listbox-ы), и сделать так чтобы оно, это окно, обрабатывало сообщения так же, как это делают модальные диалоговые окна, то как это делать?
Если я правильно понял, то нужно в процедуре этого окна отлавливать сообщения WM_KEYDOWN, НАПРИМЕР ТАК:
думал, создать массив дескрипторов элементов управления, которые расположены в данном окне, и, если я нажимаю на клавишу TAB, то должен перемещаться фокус с объекта на объект, но это не работает, видимо, я что-то делаю не так.
Я правильно мыслю или вообще не в том направлении?
Кликните здесь для просмотра всего текста
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
case WM_COMMAND:
{
    switch(LOWORD(wParam))
    {
        case WM_KEYDOWN:
        {
            switch(wParam)
            {
                case VK_TAB:
                {
                    SetFocus(hwndLists[index++]);
                    if(index >= 2)
                        index = 0;
                    return 0;
                }
                case VK_ENTER:
                {
                    return 0;
                }
                default:
                    break;
            }
            return 0;
        }
    }
    return 0;
}
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
16.06.2023, 09:03
Ответы с готовыми решениями:

Полосы прокрутки в модальном диалоговом окне
Всем, привет! Прошу помочь, может кто может подсказать... По существу: имеется форма в виде диалогового модального всплывающего окна, на...

Обработка формы в модальном окне
Здравствуйте, нужна помощь. Нужно реализовать обработку формы в модальном окне (как показано на рисунке), поясню словами: 1...

Обработка WM_KEYDOWN и WM_KEYUP в диалоговом окне
С толкнулся с проблемой того, что в диалоге требуется обработка клавиатуры! Однако как оказалось диалог их не ловит! Есть ли способ как...

26
COM‐пропагандист
 Аватар для Замабувараев
936 / 785 / 149
Регистрация: 18.12.2014
Сообщений: 2,256
Записей в блоге: 4
25.06.2023, 09:17
Студворк — интернет-сервис помощи студентам
Ничего не понял.
Функция IsDialogMessage делает то что нужно: передаёт фокус по TAB и стрелочкам.
Это именно то, что нужно.
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
26.06.2023, 06:02  [ТС]
Я что-то никак не дождусь ответа, как организовать прокрутку окна, но не просто окна, а окна в котором расположены стандартные элементы управления windows, в данном случае listbox-ы, я так понимаю эта тема никому не интересна...
Я хз что должна прокручивать функция ScrollWindowEx(), но у меня она ничего не прокручивает.
Читал про двойную буферизацию, но, видимо, это не мой случай, не могу понять, как организовать эту работу, что я имею ввиду под работой, нужно при прокрутке окна часть объектов скрыть, часть показать. Объекты содержат информацию, хотя может быть не все объекты используются на данный момент, всё что я понял, это то что нужно действовать как-то так.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
case WM_PAINT:
{
    HDC hdc = BeginPaint(hwnd, &ps);
    
    HDC hMemDC = CreateCompatibleDC(hdc);
    HBITMAP hBitmap = CreateCompatibleBitmap(hdc, cxClient, cyClient);
    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
    
    BitBlt(hdc, 0, 0, cxClient, cyClient, hMemDC, 0, 0, SRCCOPY);
    
    SelectObject(hMemDC, hOldBitmap);
    DeleteObject(hBitmap);
    DeleteDC(hMemDC);
    
    EndPaint(hwnd, &ps);
    return 0;
}

Но тогда, как организовать создание новых listbox-ов, если я прокручиваю вниз на одну строку-listbox, допустим на один listbox, один объект должен уйти за верхнюю границу окна, а снизу должен появиться новый элемент, ну или со значением, если до этого он использовался. Сделать копию окна в памяти и что дальше... при скроллинге, нужно обновить окно InvalidateRect,
в сообщении WM_PAINT нужно вывести то, что сохранено в памяти в контекст устройства, но всё это очень очень туманно, не могу понять, как это сделать....
Как рисовать в совместимом контексте я понял, не ясно, как делать то, что мне нужно, то что описал выше.

Ещё, как вариант, можно имитировать прокрутку так, копированием информации, если она присутствует в listbox-ах в буфер , и в случае скроллинга вверх-вниз что-то достаём из стека, что-то сохраняем в стек.
Для примера прокрутка вниз, если в массиве элементов(HWND listbox) в первых позициях есть информация, то скопировать её в буфер, на её место перезаписать информацию их следующего элемента и так в цикле до последнего объекта, который находится на странице. В конце самая последняя строка должна оказаться пустой, если до этого в буфер была сохранена информация, то с вершины стека она копируется в этот объект.
но это будет очень медленно, так сказать за неимением лучшего.....
Кликните здесь для просмотра всего текста
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
case LINEDOWN:
            {
                TCHAR szBuf1[MAX_PATH]; //IndexFirest - указывает на индекс первого объекта в массиве объектов 
                                                                         //listbox
                GetWindowText(aLists[IndexFirst], &szBuf1); //aLists[] - массив в котором сохранены указатели на
                                                                                                  //listbox
                if(_tcslen(szBuf1))
                {
                    TCHAR szBuf2[MAX_PATH];
                    GetWindowText(aLists[IndexFirst+1], &szBuf2);
                    stUP.push(pair(szBuf1, szBuf2));
                    for(int i = IndexFirst+2; i < IndexLast; ++i)
                    {
                        GetWindowText(aLists[i], &szBuf1);
                        if(!_tcslen(dzBuf1))
                            break;
                        GetWindowText(aLists[i+1], &szBuf2);
                        SetWindowText(aLists[i - 2], szBuf1);
                        SetWindowText(aLists[i - 1], szBuf1);
                    }
                }
                //----
                if(!stDOWN.empty())
                {
                    SetWindowText(aLists[IndexLast], stUP.top()); //IndexLast - это индекс последнего элементы
                                                                                                            //в наборе объектов listbox
                    stUP.pop();
                    SetWindowText(aLists[IndexLast+1], stUP.top()) //stUp, stDOWN - стеки, куда сохраняется 
                                                                                                               //информация-данные из объектов listbox
                                                                                                               //stUP - здесь будет содержаться информация от
                                                                                                               //объектов, расположенных вверху страницы
                                                                                                               //и в случае, если сколлят вниз, то суда 
                                                                                                               //сохраняют строки, которые уходят за верхнюю 
                                                                                                               //границу. stDOWN - ПРЯМО ПРОТИВОПОЛОЖНО.
                    stUP.pop();
                }
                return 0;
            }
0
COM‐пропагандист
 Аватар для Замабувараев
936 / 785 / 149
Регистрация: 18.12.2014
Сообщений: 2,256
Записей в блоге: 4
26.06.2023, 08:12
Цитата Сообщение от Liss29 Посмотреть сообщение
Я что-то никак не дождусь ответа, как организовать прокрутку окна, но не просто окна, а окна в котором расположены стандартные элементы управления windows, в данном случае listbox-ы, я так понимаю эта тема никому не интересна...
Зачем списки прокручивать? Списки сами умеют прокручивать своё содержимое.
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
26.06.2023, 08:39  [ТС]
Цитата Сообщение от Замабувараев Посмотреть сообщение
Зачем списки прокручивать?
Уточнять обязательно... Пусть будут кнопки.
0
2736 / 891 / 331
Регистрация: 10.02.2018
Сообщений: 2,128
26.06.2023, 09:39
Liss29, если у вас один элемент уходит, а другой приходит, то можно не делать миллион контролов под все элементы. Можно сделать контролы только под видимые элементы и менять в них информацию при смене области видимости.

Я делал у себя скролинг встраиваемых диалоговых окон. Диалоги большие, а захотелось умещать их в ограниченном пространстве. На родительском диалоге создавал окно со скролами и в это окно назначал встраиваемый диалог. В окне со скролами следил за изменением его размеров, положений его скролов и вызывал для него ScrollWindow всей клиентской области. Проект использовал MFC, но оно по синтаксису очень близко к WinAPI, при желании можно разобраться. Ниже простенький класс со скролами, в который встраивались диалоги:
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
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
// ScrollArea.cpp: файл реализации
//
 
#include "stdafx.h"
#include "ScrollArea.h"
 
 
// CScrollArea
 
IMPLEMENT_DYNAMIC(CScrollArea, CWnd)
 
CScrollArea::CScrollArea()
{
}
 
CScrollArea::~CScrollArea()
{
}
 
void CScrollArea::Create(CWnd* parent, CWnd* replaced)
{
    RECT rc;
    replaced->GetWindowRect(&rc);
    replaced->ShowWindow(SW_HIDE);
 
    parent->ScreenToClient(&rc);
 
    LPCTSTR className = AfxRegisterWndClass(0, 0, GetSysColorBrush(COLOR_3DFACE));
    CWnd::Create(className, 0, WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL/* | WS_BORDER*/, rc, parent, replaced->GetDlgCtrlID());
}
 
void CScrollArea::Resize()
{
    RECT rc = {};
 
    // текущая позиция
    int x = GetScrollPos(SB_HORZ);
    int y = GetScrollPos(SB_VERT);
 
    // позиция после ресайза
    int xx = x;
    int yy = y;
 
    // что бы узнать максимальный размер области отображения отключаем скролбары
    ShowScrollBar(SB_BOTH, FALSE);
    EnableScrollBarCtrl(SB_BOTH, FALSE);
 
    // максимальный размер области отображения
    GetClientRect(&rc);
    SIZE viewSize = {};
    viewSize.cx = rc.right - rc.left;
    viewSize.cy = rc.bottom - rc.top;
 
    // размеры отображаемой области (только один потомок без дополнительных рамок)
    SIZE childSize = { 0, 0 };
    CWnd* child = GetWindow(GW_CHILD);
    if (child)
    {
        child->GetClientRect(&rc);
        childSize.cx = rc.right - rc.left;
        childSize.cy = rc.bottom - rc.top;
    }
 
    // включение скролбаров, если нужно
    if ((viewSize.cx < childSize.cx) || (viewSize.cy < childSize.cy))
    {
        ShowScrollBar(SB_BOTH);
        EnableScrollBarCtrl(SB_BOTH);
        //EnableScrollBar(SB_BOTH);
 
        GetClientRect(&rc);
        viewSize.cx = rc.right - rc.left;
        viewSize.cy = rc.bottom - rc.top;
 
        // включение горизонтального скролбара, если нужно
        if (viewSize.cx < childSize.cx)
        {
            SetScrollRange(SB_HORZ, 0, childSize.cx - viewSize.cx);
 
            // окно увеличилось, можно больше вместить
            if (xx + viewSize.cx > childSize.cx)
            {
                xx = childSize.cx - viewSize.cx;
                if (xx < 0)
                    xx = 0;
            }
        }
        else
        {
            ShowScrollBar(SB_HORZ, FALSE);
            EnableScrollBarCtrl(SB_HORZ, FALSE);
 
            xx = 0;
        }
 
        // включение вертикального скролбара, если нужно
        if (viewSize.cy < childSize.cy)
        {
            SetScrollRange(SB_VERT, 0, childSize.cy - viewSize.cy);
 
            // окно увеличилось, можно больше вместить
            if (yy + viewSize.cy > childSize.cy)
            {
                yy = childSize.cy - viewSize.cy;
                if (yy < 0)
                    yy = 0;
            }
        }
        else
        {
            ShowScrollBar(SB_VERT, FALSE);
            EnableScrollBarCtrl(SB_VERT, FALSE);
 
            yy = 0;
        }
    }
    else
    {
        xx = yy = 0;
    }
 
    // смещение отображаемой области
    if ((x != xx) || (y != yy))
    {
        SetScrollPos(SB_HORZ, xx);
        SetScrollPos(SB_VERT, yy);
        ScrollWindow(x-xx, y-yy);
    }
}
 
BEGIN_MESSAGE_MAP(CScrollArea, CWnd)
    ON_WM_HSCROLL()
    ON_WM_VSCROLL()
    ON_WM_SIZE()
END_MESSAGE_MAP()
 
void CScrollArea::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    SCROLLINFO si = { sizeof(si) };
    GetScrollInfo(SB_HORZ, &si);
    int pos = si.nPos;
 
    switch (nSBCode)
    {
        case SB_LINELEFT:
            pos--;
            break;
        case SB_PAGELEFT:
            pos -= 20;
            break;
        case SB_LINERIGHT:
            pos++;
            break;
        case SB_PAGERIGHT:
            pos += 20;
            break;
        case SB_THUMBPOSITION:
        case SB_THUMBTRACK:
            pos = nPos;
            break;
    }
 
    if (pos < si.nMin)
        pos = si.nMin;
    if (pos > si.nMax)
        pos = si.nMax;
 
    if (pos != si.nPos)
    {
        SetScrollPos(SB_HORZ, pos);
        ScrollWindow(si.nPos - pos, 0);
    }
 
    CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
}
 
void CScrollArea::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    SCROLLINFO si = { sizeof(si) };
    GetScrollInfo(SB_VERT, &si);
    int pos = si.nPos;
 
    switch (nSBCode)
    {
        case SB_LINELEFT:
            pos--;
            break;
        case SB_PAGELEFT:
            pos -= 20;
            break;
        case SB_LINERIGHT:
            pos++;
            break;
        case SB_PAGERIGHT:
            pos += 20;
            break;
        case SB_THUMBPOSITION:
        case SB_THUMBTRACK:
            pos = nPos;
            break;
    }
 
    if (pos < si.nMin)
        pos = si.nMin;
    if (pos > si.nMax)
        pos = si.nMax;
 
    if (pos != si.nPos)
    {
        SetScrollPos(SB_VERT, pos);
        ScrollWindow(0, si.nPos - pos);
    }
 
    CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
}
 
void CScrollArea::OnSize(UINT nType, int cx, int cy)
{
    CWnd::OnSize(nType, cx, cy);
 
    if (!m_resize)
    {
        m_resize = true;
        Resize();
        m_resize = false;
    }
}
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
27.06.2023, 04:05  [ТС]
Цитата Сообщение от Ygg Посмотреть сообщение
если у вас один элемент уходит, а другой приходит, то можно не делать миллион контролов под все элементы. Можно сделать контролы только под видимые элементы и менять в них информацию при смене области видимости.
Я именно такой метод и описал выше, если я правильно понял то, что вы описали в своём посте. Но это не очень эффективно. И не могу придумать, как реализовать прокрутку в случае sb_thumtreack, если использовать именно такой метод.

Цитата Сообщение от Ygg Посмотреть сообщение
В окне со скролами следил за изменением его размеров, положений его скролов и вызывал для него ScrollWindow всей клиентской области.
А где у вас в коде вызов ScrollWindow(), что она вообще делает эта функция, я имею ввиду функцию WINAPI. У вас в коде она, видимо, обёрнута в метод класса.
0
11 / 11 / 11
Регистрация: 28.12.2015
Сообщений: 164
09.05.2026, 18:54
я имел ввиду совсем другой дескриптор, да, это дескриптор окна, но создаю я это окно в функции WndProc, а не в WinMain. Стал бы я спрашивать, если бы было всё так просто.
Проблема - область видимости hwnd окна, ограничена функцией WinProc().
поэтому нету возможности передать hwnd окна в функцию IsDialogMessage().

Решение:
В главном цикле есть переменная MSG msg.
msg.hwnd - любое окно для которого пришло сообщение, в том числе и дочерние окна.
Вызываем IsDialogMessage() для любого не дочернего окна:
C
1
2
3
4
5
6
7
8
9
10
MSG msg;
BOOL bRet;
HWND hwnd;
while(1){  bRet = GetMessage( &msg, NULL, 0, 0 );
    if(bRet == 0 || bRet == -1) break;
    hwnd = GetAncestor(msg.hwnd, GA_ROOT); // Любое не дочернее окно приложения
    if(IsDialogMessage(hwnd, &msg))continue;
    TranslateMessage( &msg );
    DispatchMessage( &msg );
}
Ещё другой случай, когда нужно обработать в IsDialogMessage, не любое окно а допустим только всплывающее;
Для этого я создаю нужное окно с флагом WS_EX_CONTROLPARENT, а в главном цикле проверяю этот флаг.

C
1
2
3
4
5
6
CreateWindowEx(WS_EX_CONTROLPARENT, L"popupWinClass", L"", WS_CAPTION|WS_SYSMENU|WS_POPUP|WS_VISIBLE, ...);
 
...
 
if(GetWindowLongPtr(msg.hwnd, GWL_EXSTYLE)&WS_EX_CONTROLPARENT) // если окно помечено флагом
    if(IsDialogMessage(hwnd, &msg))continue;
Этот флаг имеет значения только для диалоговых окон. Поэтому я использую его не по прямому назначению.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
09.05.2026, 18:54

Отлавливание нажатий клавиш при неактивном(или свернутом) окне
Здравствуйте! Пишу программу подсчитывающую количество нажатий определенной кнопки(или их сочетания). Реализовал через keyPressEvent. ...

Обработка нажатий клавиш
Добрый день! Решил сделать небольшую обработку нажатий клавиш в приложении, списал один из распространённых примеров, но он не...

Обработка нажатий клавиш
подскажите как обрабатывать нажатия клавиш символов (цифры, буквы) в WinApi C++, служебные клавиши обрабатываются как то так: switch...

Обработка нажатий клавиш
Есть у меня .net приложение и есть необходимость обрабатывать клавиатуру в чужом окне (thread id и hwnd у меня есть). Сказано - сделано,...

Обработка нажатий клавиш
У меня есть программа с несколькими потоками, один из них - это обработка нажатий клавиш, но я не знаю как при выходе из программы прервать...


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

Или воспользуйтесь поиском по форуму:
27
Ответ Создать тему
Новые блоги и статьи
сукцессия 29. Переход от одних деревьев на другие делать более или менее вероятностным?
anaschu 12.07.2026
Насколько смена типов микоризы — исключительное событие в двухвековой сукцессии? Оценка вероятности в пространстве параметров В текущей версии модели успешно реализован ключевой механизм. . .
сукцессия 27. Думаю, как переделывать уже написанную статью с планами на сукцессию.
anaschu 12.07.2026
Анализ соответствия модели требованиям Реализованные компоненты: Механизм закисления почвы через протонную помпу Конкуренция между типами микориз pH как триггер сукцессии C/ P соотношение. . .
Сукцессия 26. Мат модель создана.
anaschu 12.07.2026
Модель смены растительных сукцессий посредством управления грибами работает внутри небольшой ячейки почвы, восстанавливающейся после пожара, где ненадолго бывшее царство хвойных снова захватили. . .
Решил проблему с ошибкой пагинации сообщений с сервера на алгоритме обхода дерева "Эстафета хвоста".
Hrethgir 12.07.2026
Проблема была в том, что удалялась именно новая кнопка, а не старая. Ни один ИИ не обнаружил это, а сам я смог только когда с работой стало попроще и когда заставил работать будущее автономное. . .
сукцессия 25. Хронология ошибок
anaschu 12.07.2026
# От 50-тонного гриба до устойчивого леса: хроника ошибок при построении модели вековой сукцессии микоризы ## О чём эта статья В процессе построения ОДУ-модели (система дифференциальных. . .
сукцессия 24. Промежуточное общее описание модели
anaschu 12.07.2026
Хендофф: модель АМ→ЭКМ сукцессии микоризы (ризосфера, 50 лет) Содержание проекта Симуляция вековой (50 лет) экологической сукцессии в почве леса Основные участники: АМ-гриб, ЭКМ-гриб,. . .
сукцессия 23. Более физиологичная физиология, более экологичная экология, более диффурные диффуры.
anaschu 12.07.2026
Что реально нашли и починили за эти 5 часов Правило Линдемана (КПД конверсии сахара в тело, kEff) — раньше 100% полученного углерода шло прямо в биомассу гриба; теперь только kEff=0. 5 (после. . .
сукцессия 22. От артефактов к физиологии: калибровка агентной модели грибной сукцессии для воспроизведения сезонной динамики и pH-плато
anaschu 11.07.2026
Аннотация В данной работе представлена калибровка агентной модели динамики грибных сообществ (fungal-succession), направленная на устранение нефизичных артефактов (коллапс биомассы, мгновенное. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru