Контроль положения родительского окна из CEdit
От: avnazyrov  
Дата: 13.12.10 12:50
Оценка:
Всем привет.
Пишу на MFC небольшой класс-потомок CEdit, помимо прочей функциональности, позволяющий выкидывать подсказку (стандартный tracking tooltip) в произвольный момент времени.
Задача — наиболее простое решение стандартными средствами, т.к. этот класс будет использоваться в и так чересчур сложном комплексе.
Проблема вполне банальна: не могу красиво отловить факт изменения положения родительского окна, чтобы загасить подсказку (остаётся висеть на своём месте, как и положено popup-окну).
Пока что использую таймер, опрашивающий CEdit::GetWindowRect() и сверяющий координаты, однако это решение я считаю его некрасивым, и в проект оно не пройдёт.
Хуки тоже использовать нельзя.
Тема очень похожа на http://www.rsdn.ru/forum/mfc/3736894.aspx
Автор: _kostet_
Дата: 16.03.10
, но там автор остановился именно на хуках.
Может, всё же можно малой кровью изменить CEdit так, чтобы можно было перехватить WM_MOVE и иже с ним, находясь на диалоге, т.к. хотелось бы всё-таки использовать стандартный tooltip?
Re: Контроль положения родительского окна из CEdit
От: rus blood Россия  
Дата: 13.12.10 14:04
Оценка:
Здравствуйте, avnazyrov, Вы писали:

A>остаётся висеть на своём месте, как и положено popup-окну


popup-окну может и положено, а вот tooltip-у — нет.
Что-то ты не договариваешь, или не так делаешь.
Имею скафандр — готов путешествовать!
Re[2]: Контроль положения родительского окна из CEdit
От: avnazyrov  
Дата: 13.12.10 14:20
Оценка:
RB>popup-окну может и положено, а вот tooltip-у — нет.
Это tracking tooltip. Висит, пока не скажу ему обратное.
http://msdn.microsoft.com/en-us/library/bb760252(v=vs.85).aspx#tooltip_sample_tracking
Создаю его так:
...
    // Окно подсказки
    CWnd m_ttWin;
    // Указатель на элемент-родитель
    CWnd* m_pParent;
    // Структура парметров подсказки
    TOOLINFO m_toolItem;
...
    m_ttWin.CreateEx( WS_EX_TRANSPARENT, TOOLTIPS_CLASS, NULL,
        WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | TTS_BALLOON,        
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT, 
        m_pParent->GetParent()->GetSafeHwnd(), NULL);
...
    // Заполняем структуру с параметрами подсказки
    memset(&m_toolItem, 0, sizeof(m_toolItem));
    m_toolItem.cbSize = sizeof(TOOLINFO);
    m_toolItem.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
    m_toolItem.hwnd = m_pParent->GetSafeHwnd();
    m_toolItem.hinst = AfxGetInstanceHandle();
    m_toolItem.lpszText = L"I' m a tooltip!";
    m_toolItem.uId = (UINT_PTR)m_pParent->GetSafeHwnd();
    m_pParent->GetClientRect (&m_toolItem.rect);
    // Регистрируем нашу подсказку
    m_ttWin.SendMessage(TTM_ADDTOOL, 0, (LPARAM) &m_toolItem);
    // Устанавливаем начальные координаты показа
    m_pParent->GetWindowRect (&m_toolItem.rect);
    m_ttWin.SendMessage(TTM_TRACKPOSITION,
        0, (LPARAM)MAKELONG(m_toolItem.rect.left + 5, m_toolItem.rect.bottom + 5));
...


Показываю так:
...
    // Устанавливаем координаты показа
    m_pParent->GetWindowRect (&m_toolItem.rect);
    m_ttWin.SendMessage(TTM_TRACKPOSITION,
        0, (LPARAM)MAKELONG(m_toolItem.rect.left + 5, m_toolItem.rect.bottom));
    // Активируем новую подсказку
    m_ttWin.SendMessage(TTM_TRACKACTIVATE, TRUE, (LPARAM)&m_toolItem);
...


Прячу так:
...
m_ttWin.SendMessage(TTM_TRACKACTIVATE, FALSE, (LPARAM)&m_toolItem);
...


MFC я знаю довольно-таки паршиво, поэтому готов выслушать любые комментарии.
Re[3]: Контроль положения родительского окна из CEdit
От: rus blood Россия  
Дата: 13.12.10 16:11
Оценка:
Здравствуйте, avnazyrov, Вы писали:

A>Это tracking tooltip. Висит, пока не скажу ему обратное.

A>http://msdn.microsoft.com/en-us/library/bb760252(v=vs.85).aspx#tooltip_sample_tracking

А почему именно tracking?
Почему не обычный tooltip, который прячется сам?
Имею скафандр — готов путешествовать!
Re: Контроль положения родительского окна из CEdit
От: Pavel Dvorkin Россия  
Дата: 14.12.10 07:37
Оценка:
Здравствуйте, avnazyrov, Вы писали:

A>Проблема вполне банальна: не могу красиво отловить факт изменения положения родительского окна, чтобы загасить подсказку (остаётся висеть на своём месте, как и положено popup-окну).


1.Сабклассинг (в смысле Win32, то есть SetWindowLongPtr) родителя не пойдет ?
2. Почему эту проблему надо решать у edit ? Почему не решать ее именно у родителя — пусть он пришлет edit какое-нибудь сообщение при своем движении ?
With best regards
Pavel Dvorkin
Re[4]: Контроль положения родительского окна из CEdit
От: avnazyrov  
Дата: 14.12.10 08:00
Оценка:
RB>А почему именно tracking?
RB>Почему не обычный tooltip, который прячется сам?
У меня не получилось заставить появляться обычный тултип в произвольный момент времени (опять же нормальными методами).
К примеру, здесь описано как это реализовать, но уж слишком сложно по сравнению с tracking, при точно таком же результате.
Идеальной ситуацией было бы использовать tracking и иметь возможность самостоятельно (не выше уровня родительского CEdit) обрабатывать сообщения о перемещении и т.д.
Кстати, дополнительный плюс такого подхода в том, что нет необходимости перегружать PreTranslateMessage у родительского окна и вызывать там RelayEvent, как у обычного тултипа. Это повышает прозрачность использования.
Re[2]: Контроль положения родительского окна из CEdit
От: avnazyrov  
Дата: 14.12.10 08:08
Оценка:
PD>1.Сабклассинг (в смысле Win32, то есть SetWindowLongPtr) родителя не пойдет ?
PD>2. Почему эту проблему надо решать у edit ? Почему не решать ее именно у родителя — пусть он пришлет edit какое-нибудь сообщение при своем движении ?

Есть ограничения на возможное решение: всё должно работать без изменения существующего кода. Максимум добавить один обработчик типа RelayEvent() у CToolTipCtrl.
Сабклассинг, хуки и т.д. — слишком тяжёлая артиллерия.
Тем более, что таких полей ввода может быть несколько на одном окне, так что "максимально просто, прозрачно и отказоустойчиво".
Re[4]: Контроль положения родительского окна из CEdit
От: avnazyrov  
Дата: 14.12.10 08:12
Оценка:
RB>Почему не обычный tooltip, который прячется сам?
Обычный тултип, кстати, прячется по уходу мышки, либо таймеру.

Я хочу реализовать аналог CEdit::ShowBalloonTip(), т.к. юникод в нашей системе пока не используется.
Re[3]: Контроль положения родительского окна из CEdit
От: Pavel Dvorkin Россия  
Дата: 14.12.10 08:22
Оценка:
Здравствуйте, avnazyrov, Вы писали:


A>Есть ограничения на возможное решение: всё должно работать без изменения существующего кода. Максимум добавить один обработчик типа RelayEvent() у CToolTipCtrl.

A>Сабклассинг, хуки и т.д. — слишком тяжёлая артиллерия.
A>Тем более, что таких полей ввода может быть несколько на одном окне, так что "максимально просто, прозрачно и отказоустойчиво".

Ну тогда не знаю. Сабклассинг не так уж прост, но и не сложен. 10 строчек и все дела. Если ставится задача, но почему-то начинают ограничивать в способе решения (при том, что предлагается отнюдь не хак, а вполне легальный метод) — тогда я пас.
With best regards
Pavel Dvorkin
Re[4]: Контроль положения родительского окна из CEdit
От: avnazyrov  
Дата: 14.12.10 09:23
Оценка:
PD>Ну тогда не знаю. Сабклассинг не так уж прост, но и не сложен. 10 строчек и все дела. Если ставится задача, но почему-то начинают ограничивать в способе решения (при том, что предлагается отнюдь не
Тут есть несколько нюансов.
1) Контролов может быть несколько на одном окне, что, конечно, легко учитывается, но уже вносит некоторую сложность.
2) В программном комплексе уже и так используются хуки (и их пытаются изжить по требованию начальства). Где — надо узнавать. Не хотелось бы в итоге пересечься.
3) Некоторые окна программы подгружается в сторонних решениях на Delphi, что, опять же, не страшно, но надо учитывать и дополнительно тестировать.
4) Сабклассинг и хуки, конечно, не хаки, но уже очень близки (попахивает немного костылями).

Неужели нет иных штатных методов, основанных на сообщениях?
Re[5]: Контроль положения родительского окна из CEdit
От: Pavel Dvorkin Россия  
Дата: 14.12.10 09:37
Оценка:
Здравствуйте, avnazyrov, Вы писали:

A>Тут есть несколько нюансов.

A>1) Контролов может быть несколько на одном окне, что, конечно, легко учитывается, но уже вносит некоторую сложность.

Сабклассингу безразлично.

A>2) В программном комплексе уже и так используются хуки (и их пытаются изжить по требованию начальства). Где — надо узнавать. Не хотелось бы в итоге пересечься.


Сабклассинг внутри процесса не требует хуков. Хуки используются для сабклассинга в чужом процессе.

A>3) Некоторые окна программы подгружается в сторонних решениях на Delphi, что, опять же, не страшно, но надо учитывать и дополнительно тестировать.


Родитель есть родитель даже на Дельфи

A>4) Сабклассинг и хуки, конечно, не хаки, но уже очень близки (попахивает немного костылями).


Это легальные средства, документированные, а никакие не костыли.

A>Неужели нет иных штатных методов, основанных на сообщениях?


Что значит "штатных методов" ? Не шлет родитель чайлдам сообщений при своем передвижении, вот и все. Сабклассинг и есть штатный метод для таких ситуаций.

Можно еще ловить в петле while GetMessage и пересылать нужному окну.
With best regards
Pavel Dvorkin
Re[6]: Контроль положения родительского окна из CEdit
От: avnazyrov  
Дата: 14.12.10 10:46
Оценка:
A>>Тут есть несколько нюансов.
A>>1) Контролов может быть несколько на одном окне, что, конечно, легко учитывается, но уже вносит некоторую сложность.

PD>Сабклассингу безразлично.


Может, я не правильно понимаю технологию?
К примеру, хуки рекомендуется снимать как можно быстрее.
Если сабклассировать всё время существования edit'а, то проблем не будет, но я видел решение так:
При показе подсказки сохраняем старый адрес функции, ставим свою, в которой в итоге вызывается старая.
При скрытии подсказки возвращаем всё на место.
И это без доработок будет падать...

Но это уже флейм

A>>2) В программном комплексе уже и так используются хуки (и их пытаются изжить по требованию начальства). Где — надо узнавать. Не хотелось бы в итоге пересечься.


PD>Сабклассинг внутри процесса не требует хуков. Хуки используются для сабклассинга в чужом процессе.


В данном случае я имел в виду использование хуков, а не сабклассинга.

A>>3) Некоторые окна программы подгружается в сторонних решениях на Delphi, что, опять же, не страшно, но надо учитывать и дополнительно тестировать.


PD>Родитель есть родитель даже на Дельфи


Не спорю, но тестировать придётся, т.к. были случаи странного поведения вызванных окон.

A>>4) Сабклассинг и хуки, конечно, не хаки, но уже очень близки (попахивает немного костылями).


PD>Это легальные средства, документированные, а никакие не костыли.

Штатные костыли тоже бывают

A>>Неужели нет иных штатных методов, основанных на сообщениях?


PD>Что значит "штатных методов" ? Не шлет родитель чайлдам сообщений при своем передвижении, вот и все. Сабклассинг и есть штатный метод для таких ситуаций.

Если действительно нельзя изменить окно подсказки таким образом, чтобы оно само обрабатывало сообщения, то Вы правы.

PD>Можно еще ловить в петле while GetMessage и пересылать нужному окну.

Хрень редьки...

Ладно, огромное спасибо Вам за помощь, видимо придётся искать какой-то компромис.
Re[5]: Контроль положения родительского окна из CEdit
От: Андрей Россия  
Дата: 14.12.10 11:03
Оценка:
Здравствуйте, avnazyrov, Вы писали:

RB>>Почему не обычный tooltip, который прячется сам?

A>Обычный тултип, кстати, прячется по уходу мышки, либо таймеру.

A>Я хочу реализовать аналог CEdit::ShowBalloonTip(), т.к. юникод в нашей системе пока не используется.


используй напрямую EM_SHOWBALLOONTIP, а не обертки из MFC
на самом деле это сообщение никакого юникода не требует, только commctrl.dll 6-й версии
Re[6]: Контроль положения родительского окна из CEdit
От: avnazyrov  
Дата: 14.12.10 14:08
Оценка:
Здравствуйте, Андрей, Вы писали:

А>используй напрямую EM_SHOWBALLOONTIP, а не обертки из MFC

А>на самом деле это сообщение никакого юникода не требует, только commctrl.dll 6-й версии

То что надо! Спасибо
Меня смутило то, что обёртка без юникода не работала.
Re[7]: Контроль положения родительского окна из CEdit
От: Андрей Россия  
Дата: 14.12.10 14:25
Оценка:
Здравствуйте, avnazyrov, Вы писали:

skip

A>То что надо! Спасибо

A>Меня смутило то, что обёртка без юникода не работала.

да, есть в дизайне MFC и такие косяки
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.