Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Табуляция в EDIT 
V
    Опции темы
Earnest
Дата 12.10.2012, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 33
Всего: 183



Споткнулась на дурацкой проблеме: хочу, чтобы когда пользователь нажимает TAB в мультилайн-эдите, этот самый TAB туда и вставлялся - ну то есть отступ возникал. Казалось бы, делов-то... но не тут-то было! Эдит засовываемый в него TAB полностью игнорирует.А именно, когда посылаешь ему TAB в виде WM_KEYDOWN - соответствующий WM_CHAR не приходит. И даже когда засылаешь WM_CHAR с TAB - ноль реакции. Единственное, что сработало - перехватывать WM_KEYDOWN \ TAB и вставлять его в поле руками, т.е. через ReplaceSel. Но это же дичь какая-то!
Ладно, решила посмотреть, как с этим делом справляется нотепад, который и есть Edit. Засунула его под Спай... Результат - WM_KEYDOWN, потом WM_CHAR... вроде все. Никаких следов REPLACESEL (но все работает). Ну там еще чертова прорва всякого мусора - WM_GETTEXT, например, запрашивается стопицот раз минуту, не поймешь, связано ли это со вставкой TAB... Либо там просто программная обработка, либо я где-то туплю. Стили сравнивала, различий нет, кроме флага WANTRETURN (что, кстати, наводит на мысль о ручной обработке, т.к. без него RETURN'ы игонорируются).

Какие мысли, друзья? 



--------------------
...
PM   Вверх
feodorv
Дата 12.10.2012, 16:58 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Теоретически должно помочь снятие с контрола стиля WS_TABSTOP.
Практически возможны варианты...


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
feodorv
Дата 12.10.2012, 19:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата

    case VK_TAB:

        /*
         * If this multiline edit control is in a dialog box, then we want the
         * TAB key to take you to the next control, shift TAB to take you to the
         * previous control. We always want CTRL-TAB to insert a tab into the
         * edit control regardless of weather or not we're in a dialog box.
         */
        if (scState == CTRLDOWN)
            MLChar(ped, virtKeyCode, keyMods);
        else if (ped->fInDialogBox)
            SendMessage(ped->hwndParent, WM_NEXTDLGCTL, scState == SHFTDOWN, 0L);

        return ;


То есть вместо просто TAB помогает CTRL-TAB...

Но нужно именно TAB или разобраться с Notepad'ом?


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
YDean
Дата 13.10.2012, 08:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 7.9.2009

Репутация: 1
Всего: 1



Переходом по TAB занимается IsDialogMessage.
Он же шлёт WM_GETDLGCODE 

на примере MFC - CWnd::IsDialogMessage 
Код

BOOL CMyDlg::PreTranslateMessage( msg )
{
    if( IsDialogMessage( msg ) )       <<<< если это убрать, перехода по TAB не будет.
        return TRUE;
    else
        return CWnd::PreTranslateMessage( msg );
}

Для нативного кода - он вызывается в цикле выборки сообщений.
Код

while(GetMessage(&msg, NULL, 0, 0))
{
   if(!IsDialogMessage(&msg))
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);  
   }
}
Вроде так
PM   Вверх
feodorv
Дата 13.10.2012, 14:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(YDean @  13.10.2012,  09:42 Найти цитируемый пост)
Переходом по TAB занимается IsDialogMessage.

Увы, переход по TAB жёстко вшит в мультилайн-эдит. Потому шаманство с WM_GETDLGCODE и/или IsDialogMessage не даёт результатов.

 
Код

/***************************************************************************\
* MLEditWndProc
*
* Class procedure for all multi line edit controls.
* Dispatches all messages to the appropriate handlers which are named
* as follows:
* SL (single line) prefixes all single line edit control procedures while
* EC (edit control) prefixes all common handlers.
*
* The MLEditWndProc only handles messages specific to multi line edit
* controls.
*
* WARNING: If you add a message here, add it to gawEditWndProc[] in
* kernel\server.c too, otherwise EditWndProcA/W will send it straight to
* DefWindowProcWorker
*
* History:
\***************************************************************************/

LRESULT MLEditWndProc(
    HWND hwnd,
    PED ped,
    UINT message,
    WPARAM wParam,
    LPARAM lParam)
{
...
    switch (message) {
...
    case WM_CHAR:

        /*
         * wParam - the value of the key
         * lParam - modifiers, repeat count etc (not used)
         */
        MLChar(ped, (UINT)wParam, 0);
        break;
...
    case WM_KEYDOWN:

        /*
         * wParam - virt keycode of the given key
         * lParam - modifiers such as repeat count etc. (not used)
         */
        MLKeyDown(ped, (UINT)wParam, 0);
        break;
...
    }

    return 1L;
} /* MLEditWndProc */



Цитата(Earnest @  12.10.2012,  16:07 Найти цитируемый пост)
А именно, когда посылаешь ему TAB в виде WM_KEYDOWN - соответствующий WM_CHAR не приходит.

Код

void MLKeyDown(
    PED ped,
    UINT virtKeyCode,
    int keyMods)
{
...
    scState = ECGetModKeys(keyMods);

    switch (virtKeyCode) {
...
    case VK_TAB:

        /*
         * If this multiline edit control is in a dialog box, then we want the
         * TAB key to take you to the next control, shift TAB to take you to the
         * previous control. We always want CTRL-TAB to insert a tab into the
         * edit control regardless of weather or not we're in a dialog box.
         */
        if (scState == CTRLDOWN)
            MLChar(ped, virtKeyCode, keyMods);
        else if (ped->fInDialogBox)
            SendMessage(ped->hwndParent, WM_NEXTDLGCTL, scState == SHFTDOWN, 0L);

        return ;
...
    }
}



Цитата(Earnest @  12.10.2012,  16:07 Найти цитируемый пост)
И даже когда засылаешь WM_CHAR с TAB - ноль реакции. 

Код

void MLChar(
    PED ped,
    DWORD keyValue,
    int keyMods)
{
    WCHAR keyPress;
    BOOL updateText = FALSE;

    /*
     * keyValue is either:
     *    a Virtual Key (eg: VK_TAB, VK_ESCAPE, VK_BACK)
     *    a character (Unicode or "ANSI")
     */
    if (ped->fAnsi)
        keyPress = LOBYTE(keyValue);
    else
        keyPress = LOWORD(keyValue);

    if (ped->fMouseDown || keyPress == VK_ESCAPE) {

        /*
         * If we are in the middle of a mousedown command, don't do anything.
         * Also, just ignore it if we get a translated escape key which happens
         * with multiline edit controls in a dialog box.
         */
        return ;
    }

    ECInOutReconversionMode(ped, FALSE);

    {
        int scState;
        scState = ECGetModKeys(keyMods);

        if (ped->fInDialogBox && scState != CTRLDOWN) {

            /*
             * If this multiline edit control is in a dialog box, then we want the
             * TAB key to take you to the next control, shift TAB to take you to the
             * previous control, and CTRL-TAB to insert a tab into the edit control.
             * We moved the focus when we received the keydown message so we will
             * ignore the TAB key now unless the ctrl key is down. Also, we want
             * CTRL-RETURN to insert a return into the text and RETURN to be sent to
             * the default button.
             */
            if (keyPress == VK_TAB ||
                    (keyPress == VK_RETURN && !TestWF(ped->pwnd, EFWANTRETURN)))
                return ;
        }

        /*
         * Allow CTRL+C to copy from a read only edit control
         * Ignore all other keys in read only controls
         */
        if ((ped->fReadOnly) && !((keyPress == 3) && (scState == CTRLDOWN))) {
            return ;
        }
    }

    switch (keyPress) {
...
   }
}



Цитата(Earnest @  12.10.2012,  16:07 Найти цитируемый пост)
как с этим делом справляется нотепад

Вот никак понять не могу smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
YDean
Дата 14.10.2012, 10:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 7.9.2009

Репутация: 1
Всего: 1



У меня пример с PreTranslateMessage работает.
PM   Вверх
feodorv
Дата 14.10.2012, 12:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(YDean @  14.10.2012,  11:41 Найти цитируемый пост)
У меня пример с PreTranslateMessage работает. 

Супер! Значит решение есть  smile 


Цитата(feodorv @  13.10.2012,  15:41 Найти цитируемый пост)
Вот никак понять не могу

Думаю, что в ноутраде TAB работает из-за того, что мультилайн-эдит не находится в диалоге, ped->fInDialogBox
Код

typedef struct tagED {
...
    UINT     fInDialogBox  : 1; /* True if the ml edit control is in a dialog
                                * box and we have to specially treat TABS and
                                * ENTER
                                */
...
} ED, *PED, **PPED;

при этом принимает значение 0, перехвата TAB'а при WM_CHAR не происходит:
Код

       if (ped->fInDialogBox && scState != CTRLDOWN) {
...
           if (keyPress == VK_TAB ||
                    (keyPress == VK_RETURN && !TestWF(ped->pwnd, EFWANTRETURN)))
                return ;
        }


Бит fInDialogBox выставляется в MLEditWndProc при обработке сообщения WM_GETDLGCODE:
Код

    case WM_GETDLGCODE: {
            LONG code = DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS | DLGC_WANTALLKEYS;

            /*
             ** !!! JEFFBOG HACK !!!
             ** Only set Dialog Box Flag if GETDLGCODE message is generated by
             ** IsDialogMessage -- if so, the lParam will be a pointer to the
             ** message structure passed to IsDialogMessage; otherwise, lParam
             ** will be NULL. Reason for the HACK alert: the wParam & lParam
             ** for GETDLGCODE is still not clearly defined and may end up
             ** changing in a way that would throw this off
             **
             */
            if (lParam)
               ped->fInDialogBox = TRUE; // Mark ML edit ctrl as in a dialog box

            /*
             ** If this is a WM_SYSCHAR message generated by the UNDO keystroke
             ** we want this message so we can EAT IT in "case WM_SYSCHAR:"
             */
            if (lParam && (((LPMSG)lParam)->message == WM_SYSCHAR) &&
                    ((DWORD)((LPMSG)lParam)->lParam & SYS_ALTERNATE) &&
                    ((WORD)wParam == VK_BACK))
                 code |= DLGC_WANTMESSAGE;
            return code;
        }


И точно! Опрос WM_GETDLGCODE с ненулевым lParam идёт из под IsDialogMessage:
Код

BOOL IsDialogMessageW(
    HWND hwndDlg,
    LPMSG lpMsg)
{
...
    switch (lpMsg->message) {
...
    case WM_SYSCHAR:
...
    /*
     *** FALL THRU **
     */

    case WM_CHAR:

        /*
         * Ignore chars sent to the dialog box (rather than the control).
         */
        if (pwnd == pwndDlg) {
            ThreadUnlock(&tlpwnd);
            if (fLockDlg)
                ThreadUnlock(&tlpwndDlg);
            return TRUE;
        }

        code = (UINT)SendMessage(lpMsg->hwnd, WM_GETDLGCODE, lpMsg->wParam,
                (LPARAM)lpMsg);

        /*
         * If the control wants to process the message, then don't check for
         * possible mnemonic key.
         */
        if ((lpMsg->message == WM_CHAR) && (code & (DLGC_WANTCHARS | DLGC_WANTMESSAGE)))
            break;

        /* If the control wants tabs, then don't let tab fall thru here
         */
        if ((lpMsg->wParam == VK_TAB) && (code & DLGC_WANTTAB))
            break;
...
...
    case WM_KEYDOWN:
        code = (UINT)SendMessage(lpMsg->hwnd, WM_GETDLGCODE, lpMsg->wParam,
                (LPARAM)lpMsg);
        if (code & (DLGC_WANTALLKEYS | DLGC_WANTMESSAGE))
            break;

        switch (lpMsg->wParam) {
        case VK_TAB:
            if (code & DLGC_WANTTAB)
                break;
...
...
    }

    ThreadUnlock(&tlpwnd);
    if (fLockDlg)
        ThreadUnlock(&tlpwndDlg);

    TranslateMessage(lpMsg);
    DispatchMessage(lpMsg);

    return TRUE;
}


Вывод: если избегать IsDialogMessage (насколько это правильно - вопрос, поскольку затрагивает весь диалог в целом, не только мультилайн-эдит), то можно решить проблему. Функции DialogBox* вызывают IsDialogMessage внутри цикла обработки сообщений, а в MFC при реализации диалога как раз используется свой цикл, не связанный с DialogBox*.

Если же использовать мультилайн-эдит в диалоге, то нужно не просто сабклассировать мультилайн-эдит так, чтобы он возвращал ещё и DLGC_WANTTAB (а он этого не делает), так ещё и обнулять lParam при обращении к оригинальной функции окна (если хотя бы раз опросить WM_GETDLGCODE с ненулевым lParam, то бит fInDialogBox во внутренней структуре мультилайн-эдита примет значение 1, да так и останется). От lParam зависит ещё какая-то обработка VK_BACK, но тут надо разбираться...

Ну, или не использовать мультилайн-эдит в диалогах, не вызывая при этом IsDialogMessage  smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Earnest
Дата 15.10.2012, 07:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 33
Всего: 183



YDean, насчет PreTranslate и прочего IsDialogMessage я же писала, что обошла это и прямо засылала TAB в контрол, с нулевоцй реакцией.

feodorv, убирание TABSTOP не помогает - я же уже все это перехватила и работаю прямо с эдитом, и фокус никуда не девается. 
Насчет GetDlgCode \ WANTTAB тоже думала, но посмотрела на нотепад и не обнаружила там следов GetDlgCode. В голову не пришло, что эдит может по-разному работать в диалоге и не в диалоге.  
Спасибо за идею... мне это дело нужно в одном конкретном месте, там переход по TAB не нужен. В общем, раз понятно, почему, придумаю, как обойти не очень криво.


--------------------
...
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0512 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.