Сменна фокуса ввода в новигационном сообщении TVN_SELCHANGED
От: Melamed Россия  
Дата: 26.04.23 10:49
Оценка:
Здравствуйте
Хотелось бы при выборе определенного узла в TreeView фокус ввода автоматически передавался бы на в другой контроль в этом же главном окне. Для этого в новигационом сообщении TVN_SELCHANGED, полученном от моего TreeView Control вызываю API функцию SetFocus(). Но она почему то не работает.
Операционная система MS Windows 10.
Подскажите пожалуйста, в чем тут дело.
Заранее благодарен
Re: Сменна фокуса ввода в новигационном сообщении TVN_SELCHANGED
От: Carc Россия https://vk.com/gosha_mazov
Дата: 30.04.23 17:46
Оценка:
Здравствуйте, Melamed, Вы писали:

M>Здравствуйте

M>Хотелось бы при выборе определенного узла в TreeView фокус ввода автоматически передавался бы на в другой контроль в этом же главном окне. Для этого в новигационом сообщении TVN_SELCHANGED, полученном от моего TreeView Control вызываю API функцию SetFocus(). Но она почему то не работает.
M>Операционная система MS Windows 10.
M>Подскажите пожалуйста, в чем тут дело.
M>Заранее благодарен
Где фокус в момент получения TVN_SELCHANGED?
Где обрабатывается TVN_SELCHANGED?
И вообще код в студию!
Aml Pages Home
Re[2]: Сменна фокуса ввода в новигационном сообщении TVN_SELCHANGED
От: Melamed Россия  
Дата: 30.04.23 18:33
Оценка:
Здравствуйте, Carc, Вы писали:

C>Здравствуйте, Melamed, Вы писали:


M>>Здравствуйте

M>>Хотелось бы при выборе определенного узла в TreeView фокус ввода автоматически передавался бы на в другой контроль в этом же главном окне. Для этого в новигационом сообщении TVN_SELCHANGED, полученном от моего TreeView Control вызываю API функцию SetFocus(). Но она почему то не работает.
M>>Операционная система MS Windows 10.
M>>Подскажите пожалуйста, в чем тут дело.
M>>Заранее благодарен
C>Где фокус в момент получения TVN_SELCHANGED?
В Момент обработки сообщения фокус находился на TreeView, от которого пришло данное сообщения
C>Где обрабатывается TVN_SELCHANGED?
В Родительском окне
C>И вообще код в студию!

Обработка сообщения TVN_SELCHANGED следующая
    case IDC_TREEVIEW:
    {
        switch (pHdr->code)
        {
        case TVN_SELCHANGED:
        {
            LPNMTREEVIEW pNTV = (LPNMTREEVIEW)pHdr;
            CShFolder *pFolder = (CShFolder*)pNTV->itemNew.lParam;
            TCHAR szBuffer[MAX_PATH];
            pFolder->GetFullName(szBuffer, MAX_PATH);
            SendMessage(
                m_hwndStatusBar,
                SB_SETTEXT,
                0,
                (LPARAM)szBuffer
            );
            if (_tcslen(szBuffer) > 0)
            {
                Check_Win(SetCurrentDirectory(szBuffer));
                SendMessage(
                    m_hwndImageTable,
                    ITM_FILLFILEBYMASK,
                    (WPARAM)szBuffer,
                    0
                );
                int nImageCount = SendMessage(
                    m_hwndImageTable,
                    ITM_GETIMAGECOUNT,
                    0,
                    0
                );
                if (nImageCount > 0)
                {
                    SetFocus(m_hwndImageTable);
                }
            }
            break;
        }
        }
        break;
    }
Re[3]: Сменна фокуса ввода в новигационном сообщении TVN_SELCHANGED
От: Carc Россия https://vk.com/gosha_mazov
Дата: 30.04.23 20:24
Оценка:
Здравствуйте, Melamed, Вы писали:

M>Здравствуйте, Carc, Вы писали:



M>Обработка сообщения TVN_SELCHANGED следующая

M>
M>    case IDC_TREEVIEW:
M>    {
M>        switch (pHdr->code)
M>        {
M>        case TVN_SELCHANGED:
M>        {
M>            LPNMTREEVIEW pNTV = (LPNMTREEVIEW)pHdr;
M>            CShFolder *pFolder = (CShFolder*)pNTV->itemNew.lParam;
M>            TCHAR szBuffer[MAX_PATH];
M>            pFolder->GetFullName(szBuffer, MAX_PATH);
M>            SendMessage(
M>                m_hwndStatusBar,
M>                SB_SETTEXT,
M>                0,
M>                (LPARAM)szBuffer
M>            );
M>            if (_tcslen(szBuffer) > 0)
M>            {
M>                Check_Win(SetCurrentDirectory(szBuffer));
M>                SendMessage(
M>                    m_hwndImageTable,
M>                    ITM_FILLFILEBYMASK,
M>                    (WPARAM)szBuffer,
M>                    0
M>                );
M>                int nImageCount = SendMessage(
M>                    m_hwndImageTable,
M>                    ITM_GETIMAGECOUNT,
M>                    0,
M>                    0
M>                );
M>                if (nImageCount > 0)
M>                {
M>                    SetFocus(m_hwndImageTable);
M>                }
M>            }
M>            break;
M>        }
M>        }
M>        break;
M>    }
M>


В TVN_SELCHANGED как получается? С клавиатуры или мышом? (NMTREEVIEW::action ?) Вообще говоря SetFocus должна работать, если m_hwndImageTable для SetFocus работает в том же потоке, что и TreeView.
Aml Pages Home
Re[4]: Сменна фокуса ввода в новигационном сообщении TVN_SEL
От: Melamed Россия  
Дата: 01.05.23 07:21
Оценка:
Здравствуйте, Carc, Вы писали:

C>В TVN_SELCHANGED как получается? С клавиатуры или мышом? (NMTREEVIEW::action ?) Вообще говоря SetFocus должна работать, если m_hwndImageTable для SetFocus работает в том же потоке, что и TreeView.


Сooбщение TVN_SELCHANGED получается с клавиатуры или мышью без разницы. Есть подозрение, так часть сообщения ITM_FILLFILEBYMASK выполняется в фоновом потоке и во время ее выполнения выводится диалоговое окно, показывающее ход ее выполнения, то не исключено, что из-за этого.
Отредактировано 01.05.2023 9:53 Melamed . Предыдущая версия .
Re[5]: Сменна фокуса ввода в новигационном сообщении TVN_SEL
От: Carc Россия https://vk.com/gosha_mazov
Дата: 01.05.23 13:53
Оценка:
Здравствуйте, Melamed, Вы писали:

M>Здравствуйте, Carc, Вы писали:


C>>В TVN_SELCHANGED как получается? С клавиатуры или мышом? (NMTREEVIEW::action ?) Вообще говоря SetFocus должна работать, если m_hwndImageTable для SetFocus работает в том же потоке, что и TreeView.


M>Сooбщение TVN_SELCHANGED получается с клавиатуры или мышью без разницы.

В общем случае должно быть без разницы...

M>Есть подозрение, так часть сообщения ITM_FILLFILEBYMASK выполняется в фоновом потоке и во время ее выполнения выводится диалоговое окно, показывающее ход ее выполнения, то не исключено, что из-за этого.

1) Ну а GetWindowThreadProcessId(HWND обработчика TVN_SELCHANGED) == GetWindowThreadProcessId(hwnd куда бросаем фокус)?
В одном потоке или нет?

2) Что возвращает SetFocus()? Что говорит ::IsWindow(Hwnd куда фокус)?

3) В оконной процедуре (HWND куда фокус) приходят всякие WM_ACTIVATE? WM_KILLFOCUS в оконную процедуру дерева приходит?

Проще говоря:
а) окна дерева и куда_фокус (прости меня за русский, хаспади ) в одном потоке или нет?
б) Фокус с дерева уходит ли? И если да, то доходит ли он до таргет-окна?
Я б «раскопки» начинал в таком направлении.

Можно, конечно, еще попробовать ReleaseCapture позвать перед SetFocus, но имхо это не решение. Надо в происходящем разбираться, ну и далее в причинах. Ибо какое-то странное поведение.
Не должно так быть. А то как-то получается, что "пищит-мигает, куда известно не попападает"... А должно
Aml Pages Home
Отредактировано 01.05.2023 13:55 Carc . Предыдущая версия .
Re[6]: Сменна фокуса ввода в новигационном сообщении TVN_SEL
От: Melamed Россия  
Дата: 03.05.23 11:16
Оценка:
Здравствуйте, Carc, Вы писали:

C>Здравствуйте, Melamed, Вы писали:



C>1) Ну а GetWindowThreadProcessId(HWND обработчика TVN_SELCHANGED) == GetWindowThreadProcessId(hwnd куда бросаем фокус)?

C>В одном потоке или нет?
Окна сделаны в одном потоке. Проверено в Spy++.
C>2) Что возвращает SetFocus()? Что говорит ::IsWindow(Hwnd куда фокус)?
SetFocus возвращает не нулевое значения.
После вызова SetFocus() вставил следующую строку
    Check_Win(SetFocus(m_hwndImageTable));
    assert(GetFocus() == m_hwndImageTable);

Исключения нет. Значит фокус получает окно, которое мне нужно.
C>3) В оконной процедуре (HWND куда фокус) приходят всякие WM_ACTIVATE? WM_KILLFOCUS в оконную процедуру дерева приходит?
Поставил обработчик сообщения WM_KILLFOKUS окно, куда передаю фокус (Благо этот контроль я сам разрабатываю). Он вызывается. Значит окно получает фокус, и почему-то его тут же отдает. По кадру стека понял, что это происходит не в моем коде, а в системном.
Самое интересное в сообщении WM_LButtonDown окна, которому передается фокус, функция SetFocus() работает безупречно.
C>Проще говоря:
C>а) окна дерева и куда_фокус (прости меня за русский, хаспади ) в одном потоке или нет?
C>б) Фокус с дерева уходит ли? И если да, то доходит ли он до таргет-окна?
C>Я б «раскопки» начинал в таком направлении.

C>Можно, конечно, еще попробовать ReleaseCapture позвать перед SetFocus, но имхо это не решение. Надо в происходящем разбираться, ну и далее в причинах. Ибо какое-то странное поведение.

C>Не должно так быть. А то как-то получается, что "пищит-мигает, куда известно не попападает"... А должно
Отредактировано 03.05.2023 11:34 Melamed . Предыдущая версия .
Re[7]: Сменна фокуса ввода в новигационном сообщении TVN_SEL
От: Carc Россия https://vk.com/gosha_mazov
Дата: 03.05.23 14:16
Оценка: 2 (1)
Здравствуйте, Melamed, Вы писали:

M>Окна сделаны в одном потоке. Проверено в Spy++.

C>>2) Что возвращает SetFocus()? Что говорит ::IsWindow(Hwnd куда фокус)?
M>SetFocus возвращает не нулевое значения.
M>После вызова SetFocus() вставил следующую строку
M>
M>    Check_Win(SetFocus(m_hwndImageTable));
M>    assert(GetFocus() == m_hwndImageTable);
M>

M>Исключения нет. Значит фокус получает окно, которое мне нужно.
C>>3) В оконной процедуре (HWND куда фокус) приходят всякие WM_ACTIVATE? WM_KILLFOCUS в оконную процедуру дерева приходит?
M>Поставил обработчик сообщения WM_KILLFOKUS окно, куда передаю фокус (Благо этот контроль я сам разрабатываю). Он вызывается. Значит окно получает фокус, и почему-то его тут же отдает. По кадру стека понял, что это происходит не в моем коде, а в системном.
M>Самое интересное в сообщении WM_LButtonDown окна, которому передается фокус, функция SetFocus() работает безупречно.
Ну вот и разобрались... Видимо фокус все-таки приходит, но его кто-то забирает.
Что видим в WPARAM в обработчике WM_KILLFOCUS? Там по идее может быть HWND окна, которое забирает фокус.

Хм... Вообще я такие вещи делал несколько иначе. А именно отложенная передача фокуса.
Если в 2-ух словах: то в обработчике TVN_SELCHANGED запоминался выделенный узел (HTREEITEM), и взводился таймер.
А по таймеру проверялось, если выделенный айтем (TVGN_CARET) совпадает с запомненным узлом, то фокус куда-то там в правую панель передавался. Если нет, то нет.

Это было нужно когда-то давно в одной софтине, чтобы переходить куда-то там в правую панель. Причем по выделению узла в дереве при выделении именно с клавы. А таймер был нужен, только для того, чтобы можно было спокойно "бегать" по дереву клавой и фокус и не уходил с дерева мгновенно.

Потом я в той софтине как-то все иначе и очевиднее сделал (клавиши-акселераторы, переход в правую панель по Enter в дереве и.т.п.).
Но сам приём был именно такой.
Технические детали конечно могут различаться: это может быть не таймер, а фоновый спящий поток. Который собсна периодически будится по TVN_SELCHANGED. Ну да это всё нюансы.

Как-то так. Можно попробовать отложенную передачу фокуса, тогда кто-б там не забрал фокус раньше, он все равно должен будет вернуться в окно назначения, ибо по идее это произойдет позже.
Aml Pages Home
Отредактировано 03.05.2023 14:17 Carc . Предыдущая версия .
Re[8]: Сменна фокуса ввода в новигационном сообщении TVN_SEL
От: qaz77  
Дата: 04.05.23 14:55
Оценка:
Здравствуйте, Carc, Вы писали:
C>Хм... Вообще я такие вещи делал несколько иначе. А именно отложенная передача фокуса.
C>Если в 2-ух словах: то в обработчике TVN_SELCHANGED запоминался выделенный узел (HTREEITEM), и взводился таймер.
C>А по таймеру проверялось, если выделенный айтем (TVGN_CARET) совпадает с запомненным узлом, то фокус куда-то там в правую панель передавался. Если нет, то нет.

С таймером — это уже тяжелая артиллерия.
Иногда нужно чтобы текущий стек оконных процедур размотался до ближайшего цикла обработки сообщений.
Может SetFocus(куда-то там) вызывается в default обработке одного из текущих сообщений (WM_MOUSEACTIVATE и т.п.).
В таком случае помогает PostMessage(WM_APP + N, ...), а в его обработчике уже вызывать SetFocus куда хотим.
Re[9]: Сменна фокуса ввода в новигационном сообщении TVN_SEL
От: Carc Россия https://vk.com/gosha_mazov
Дата: 04.05.23 16:26
Оценка:
Здравствуйте, qaz77, Вы писали:

Q>Здравствуйте, Carc, Вы писали:

C>>Хм... Вообще я такие вещи делал несколько иначе. А именно отложенная передача фокуса.
C>>Если в 2-ух словах: то в обработчике TVN_SELCHANGED запоминался выделенный узел (HTREEITEM), и взводился таймер.
C>>А по таймеру проверялось, если выделенный айтем (TVGN_CARET) совпадает с запомненным узлом, то фокус куда-то там в правую панель передавался. Если нет, то нет.

Q>С таймером — это уже тяжелая артиллерия.

Я же выше написал

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

Aml Pages Home
Re[10]: Сменна фокуса ввода в новигационном сообщении TVN_SEL
От: qaz77  
Дата: 04.05.23 16:45
Оценка:
Здравствуйте, Carc, Вы писали:
C>

C>Технические детали конечно могут различаться: это может быть не таймер, а фоновый спящий поток....


Отдельный поток для такого — это еще более тяжелая артиллерия.

Да, у потока отдельный стек.
Но прием, о котором я написал с PostMessage, решает проблемы со стеком самым дешевым способом и по ресурсам, и по объему кодирования.
Re[11]: Сменна фокуса ввода в новигационном сообщении TVN_SEL
От: Carc Россия https://vk.com/gosha_mazov
Дата: 04.05.23 17:08
Оценка:
Здравствуйте, qaz77, Вы писали:

Q>Здравствуйте, Carc, Вы писали:

C>>

C>>Технические детали конечно могут различаться: это может быть не таймер, а фоновый спящий поток....


Q>Отдельный поток для такого — это еще более тяжелая артиллерия.

Q>Да, у потока отдельный стек.

Для тех кто в бронепоезде после выходных...
Еще раз. По слогам.

Технические детали конечно могут различаться

Я суть человеку рассказал, всего лишь иллюстрация «как примерно». А как именно сделать в отложенность там вариантов тьма. И выбор конкретного будет зависеть от задачи чуть более чем на 120 процентов. Ненамного, конечно. Чутка. Но всё ж более чем 120 процентов.

Q>Но прием, о котором я написал с PostMessage, решает проблемы со стеком самым дешевым способом и по ресурсам, и по объему кодирования.

Нет, не решает.
Оный прием решает проблемы разработчика. А нужно было решить проблему пользователя.
Aml Pages Home
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.