Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > Наращиваем CComboBox


Автор: Rapalex 4.7.2006, 12:46
Дело такое: есть комбобокс (редактируемый) в который нужно ввести число типа double.

В момент когда юзер жмёт не на ту клавишу выскакивет тултип (облачко) с текстом ...

Вот для появления тултипа ему нужно точку на экране дать, ну и как пологается эта точка должна быть на нижней чясти курсора в комбо.

И как найти эту точку?

Всем спасибо!!! 

Автор: Earnest 4.7.2006, 15:35
Посмотри GetCaretPos, если под курсором ты имеешь в виду каретку.

Добавлено @ 15:37 
Возвращаемое значение будет в клиентских координатах окна, содержащего каретку, т.е. комбобоксного эдита. 

Автор: Coocky 4.7.2006, 15:58
Я б попробывал следующий вариант. Создал Косбобокс и свои классы, производные от CEdit  и СListBox.
Вызвал бы функцию CComboBox::GetComboBoxInfo(  PCOMBOBOXINFO pcbi);

Код

typedef struct tagCOMBOBOXINFO {
    DWORD cbSize;
    RECT rcItem;
    RECT rcButton;
    DWORD stateButton;
    HWND hwndCombo;
    HWND hwndItem;
    HWND hwndList;
} COMBOBOXINFO, *PCOMBOBOXINFO, *LPCOMBOBOXINFO;


  HWND hwndItem;
    HWND hwndList; 

Итнересующие нас поля я отметил жирным щрифтом. Чем же они меня заинтресовали? Да дело в том. что можно просто засабкласить эти окна CWnd:: SubclassWindow( HWND hWnd );
myEdt.SubclassWindow(hwndItem);
myListCtrl.SubclassWindow(hwndList);
Это означает, что все сообщения для Edit  CListCtrl будут попадать в наши окна. Ну а там сам бог руки развязал. Все сообщения и методы окноные доступны. smile  Сам не пробобывал, но должно получится. Тогда по настоящему получится 
Цитата

Наращиваем CComboBox

 smile 
Сам бы сделал минут за 20, но реально нет времени. Даже топик лописать. Извини. Побежал smile 
  

Автор: Dart 4.7.2006, 17:18
В твоем случае CComboBox абсолютно ни при чем - то, что ты редактируешь в основном поле - это CEdit.
Тебе нужна функция PosFromChar (правда это левый верхний угол, так что придется еще помудрить smile
А вот как узнать позицию курсора, сейчас не помню. Попробуй GetSel - возможно это поможет. Навскидку MSDN просмотрел - не нашел. Но точно знаю, что можно - года 2 назад такое делал сам

Добавлено @ 17:22 
Цитата(Earnest @  4.7.2006,  15:35 Найти цитируемый пост)
Посмотри GetCaretPos, если под курсором ты имеешь в виду каретку.

Ну, точно, как залез в MSDN - вспомнил smile
Естественно CWnd::GetCaretPos 

Автор: Rapalex 5.7.2006, 10:37
Coocky, за идею субкласинга спасибо, пригодится даже очень, огромное спасибо, пришол тот момент когда я понял зачем это нужно . smile 

EarnestDart, спасибо, CWnd::GetCaretPos это именно то, что нужно. Одно только удручает, что возвращается верхяя точка курсора а нужна нижняя.
 

Автор: Rapalex 5.7.2006, 11:02
Полученная точка находится по центру символа который находится перед кореткой (но с этим я смогу жить)

А в полученой точке Y == 0. Тут размер шрифта не поможет  smile  
 

Автор: Coocky 5.7.2006, 11:08
У нас такой способ работы на работе называют-"костыль"
Впроде бы использовать нужно всего одну функцию-быстро и халявно. Но всегда возникают проблемы smile 
Лучше не ленится, а всегда делать свои классы. производные от нужных.
GetCaretPos-вызывал у меня подозрения. но я промолчал. А что б не парится я б все таки сделал свой вариант. Универсальней не бывает. А вдруг дополнительная функциональность понадобится? smile

Добавлено @ 11:17 
Цитата(Rapalex @  5.7.2006,  11:02 Найти цитируемый пост)
А в полученой точке Y == 0. Тут размер шрифта не поможет

Ты всегда можешь воспользоваться GetWindowRect  для получения координат. Тебе нужна вертикаль, а для горизонтали поможет уже полюбившийся в этом топике GetCaretPos .
Получи координаты окна, переведи клиентские координаты GetCaretPos в оконые ClientToScreen - и ты получишь координаты для создания окна
 

Автор: Rapalex 5.7.2006, 12:22
Получаю и привожу, деляю свои классы, всё как надо, щяс делаю CEdit потом субкласю с комбо, надеюсь проблемм не будет.

GetCaretPos работает как надо, но возвращает верхнюю  точку каретки. Щяс просто прибовляю к  точке (GetCaretPos) высоту клиенткой части окна и получается что подсказка появляется по окном. С этим жить можно но в самой винде немного подругому, вот спрашиваю можно ли узнать нижнюю точку мигающей каретки?

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

Автор: Rapalex 5.7.2006, 13:39
Ну вот дошол до субкласинга и нарвался на камни.

В CEdit я перегрузил PreTranslateMessage и там смотрел если подходящяя цифра то вызывал метод родителя, если нет возвращял TRUE.

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

И что делать???  smile  

Автор: Rapalex 5.7.2006, 14:20
Разобрался, отсубкласил в OnCtlColor.

Остался последний вопрос: Можно-ли узнать нижнюю точку мигающей каретки? 

Автор: Earnest 5.7.2006, 14:44
Edit является дочкой комбобокса, так что можно его получить через GetWindow (GW_CHILD). 
Насчет перехода от верней части каретки к нижней. Спросить TextMetrics у HDC и вычесть высоту не пробовал? Непонятно, почему это может не получиться. 

Автор: Rapalex 5.7.2006, 15:45
Прбывал, у точки полученой от GetCaretPos y = 0, и прибавив высоту не очень красиво получается, посреди буквы, ну да ладно. Спасибо!!! 

Автор: Rapalex 21.7.2006, 12:04
Возвращяюсь я сново к этой темме.
Напомню я пытаюсь создать контрол который будет позволять вводить чило типа double.

Легенда:
1 - сделал я CEdit который содержит функию:
Код

BOOL CEditDouble::PreTranslateMessage(MSG* pMsg)
{
    if (pMsg->message == WM_CHAR)
    {
        CString strText;
        TCHAR cChar = (TCHAR)pMsg->wParam;
        switch (cChar)
        {
            case VK_BACK:    // BackSpase
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            case '0':
                {
                    HideToolTip();
                    break;    // OK
                }
            case ',': 
                pMsg->wParam = (WPARAM)'.';
            case '.':
                {
                    GetWindowText(strText);
                    if ( (strText.GetLength() > 0) && (strText.Find('.') == -1) )
                    {
                        HideToolTip();
                        break;        // OK
                    }
                    else
                    {
                        ShowToolTip();
                        return TRUE;    // NO WAY
                    }
                }
            default:
                {
                    ShowToolTip();
                    return TRUE;    // NO WAY
                }
        }
    }
    return CEdit::PreTranslateMessage(pMsg);
}

а также:
Код

void CEditDouble::OnEnKillfocus()
{
    HideToolTip();
}


В едите всё работает в норме.

2 - нужно создать комбобокс с такимиже требованиями
И тут как нормальный чел, наследую свой класс CCombobox
в нём ТОЛЬКО субкласю его эдит своим едитом, запускаю и проблеммы:
  а - стрелки влево вправо не выплняют навигацию в эдите
  б - кнопка дел не работет
  в - потеря фокуса не отробатывает (не прячет подсказку).

ПАМАГИТЕ!!!

Есть идеи?
 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)