Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Отловить клик по checkbox у TreeView


Автор: Qwe2 19.3.2012, 14:41
Создал TreeView с чекбоксами и заполнил его. Хочу по нажатию на чекбокс устанавливать галки в дочерних чекбоксах или если клик был по дочернему - то уставливать родительский (если все смежные установлены). Почти как 3 состояния, только проще. С помощью сабклассинга сделал и на клик мышки и на пробел перехват событий. С пробелом все отлично работает, а клик ведет себя не понятно: не после каждого клика вызывается моя функция анализа галок в WM_LBUTTONUP.

Код

// корректировка чекбоксов для родительских узлов в зависимости от состояния дочерних
bool MyFunc_CorrectCheck(HWND hWndTV, HTREEITEM hItem)
{
    HTREEITEM hItemFirst;
    int iCheckCount, iUnCheckCount;

    hItemFirst = hItem;
    iCheckCount = iUnCheckCount = 0;
    if(hItem == NULL)
        return 1;
    do
    {
        if(TreeView_GetChild(hWndTV, hItem) != NULL)
            MyFunc_CorrectCheck(hWndTV, TreeView_GetChild(hWndTV, hItem));
        if(TreeView_GetCheckState(hWndTV, hItem))
            iCheckCount++;
        else
            iUnCheckCount++;
    }
    while((hItem = TreeView_GetNextItem(hWndTV, hItem, TVGN_NEXT)) != NULL);
    
    if(iCheckCount && !iUnCheckCount)
    {TreeView_SetCheckState(hWndTV, TreeView_GetParent(hWndTV, hItemFirst), 1);}
    else
    {TreeView_SetCheckState(hWndTV, TreeView_GetParent(hWndTV, hItemFirst), 0);}

    return 0;
}

// установка чекбоксов у всех элементов относительно узла "hItem": на одном уровне и глубже
bool MyFunc_SetCheck(HWND hWndTV, HTREEITEM hItem, bool bState)
{
    if(hItem == NULL)
        return 1;
    do
    {
        if(TreeView_GetChild(hWndTV, hItem) != NULL)
            MyFunc_SetCheck(hWndTV, TreeView_GetChild(hWndTV, hItem), bState);
        TreeView_SetCheckState(hWndTV, hItem, bState);
    }
    while((hItem = TreeView_GetNextItem(hWndTV, hItem, TVGN_NEXT)) != NULL);

    return 0;
}

//
LRESULT CALLBACK MyFuncTVProc(HWND hWndTV, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_KEYDOWN:
        {
            if(wParam == VK_SPACE)
            {
                if(TreeView_GetSelection(hWndTV))
                    PostMessage(hWndTV, WM_KEYUP, wParam, lParam);
            }
        }
        break;

    case WM_KEYUP:
        {
            if(wParam == VK_SPACE)
            {
                HTREEITEM hItem = TreeView_GetSelection(hWndTV);
                if(hItem)
                {
                    if(TreeView_GetChild(hWndTV, hItem) != NULL)
                        MyFunc_SetCheck(hWndTV, TreeView_GetChild(hWndTV, hItem), TreeView_GetCheckState(hWndTV, hItem)?1:0);
                    MyFunc_CorrectCheck(hWndTV, TreeView_GetRoot(hWndTV));
                }
            }
        }
        break;

    case WM_LBUTTONDOWN:
        {
            TVHITTESTINFO hti;
            hti.pt.x = LOWORD(lParam);
            hti.pt.y = HIWORD(lParam);
            if(TreeView_HitTest(hWndTV, &hti) && hti.hItem && (hti.flags & TVHT_ONITEMSTATEICON))
            {
                PostMessage(hWndTV, WM_LBUTTONUP, 0, lParam);
                TreeView_SelectItem(hWndTV, hti.hItem);
            }
        }
        break;
    
    case WM_LBUTTONUP:
        {
            TVHITTESTINFO hti;
            hti.pt.x = LOWORD(lParam);
            hti.pt.y = HIWORD(lParam);
            if(TreeView_HitTest(hWndTV, &hti) && hti.hItem && (hti.flags & TVHT_ONITEMSTATEICON))
            {
                if(TreeView_GetChild(hWndTV, hti.hItem) != NULL)
                    MyFunc_SetCheck(hWndTV, TreeView_GetChild(hWndTV, hti.hItem), TreeView_GetCheckState(hWndTV, hti.hItem)?1:0);
                MyFunc_CorrectCheck(hWndTV, TreeView_GetRoot(hWndTV));
            }
            else
                TreeView_SelectItem(hWndTV, NULL);
        }
        break;

    }
    return CallWindowProc(OldMyFuncTVProc, hWndTV, msg, wParam, lParam);
}

Автор: GremlinProg 20.3.2012, 07:43
Цитата(Qwe2 @  19.3.2012,  16:41 Найти цитируемый пост)
не после каждого клика вызывается моя функция анализа галок в WM_LBUTTONUP.

если в классе стоит CS_DBLCLKS, то двойной клик пошлет только один WM_LBUTTONDOWN, следующим, после WM_LBUTTONUP будет уже WM_LBUTTONDBLCLK

добавь перед 76 строкой:
Код

case WM_LBUTTONDBLCLK:

Автор: Qwe2 20.3.2012, 15:37
Спасибо, заработало! Но заметил еще одну особенность: если мышкой щелкнуть по чекбоксу и не отпуская кнопки переместить в сторону и отпустить кнопку - чекбокс переключается, а WM_LBUTTONUP не срабатывает (т.к. не вызываеются все теже функции корретировки).

Автор: GremlinProg 20.3.2012, 15:42
Цитата(Qwe2 @  20.3.2012,  17:37 Найти цитируемый пост)
если мышкой щелкнуть по чекбоксу и не отпуская кнопки переместить в сторону и отпустить кнопку - чекбокс переключается, а WM_LBUTTONUP не срабатывает (т.к. не вызываеются все теже функции корретировки).

тогда "захватывай" мышь на WM_LBUTTONDOWN и отпускай на WM_LBUTTONUP,

p.s.: см. темы с SetCapture

Автор: Qwe2 20.3.2012, 16:41
Попробовал - не получилось (результат тот же):
Код

case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
    {
         SetCapture(hWndTV);
        <...>

Автор: GremlinProg 21.3.2012, 06:44
Цитата(Qwe2 @  20.3.2012,  18:41 Найти цитируемый пост)
Попробовал - не получилось (результат тот же):

а может он тот же не потому что не вызываются функции корректировки, а потому что на WM_LBUTTONUP стоит условие:
Цитата(Qwe2 @  19.3.2012,  16:41 Найти цитируемый пост)
if(TreeView_HitTest(hWndTV, &hti) && hti.hItem && (hti.flags & TVHT_ONITEMSTATEICON))

?

Автор: Qwe2 21.3.2012, 16:30
Передалал по аналогии с описанным http://support.microsoft.com/kb/261289/en-us. Работает.

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