Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

CTreeCtrl

831
17 ноября 2004 года
S_T
117 / / 23.10.2002
Не совсем понятное поведение CTreeCtrl. Есть большое приложение. В нем есть CTreeCtrl. Рассмотрим ситуацию, когда элементов в CTreeCtrl очень много и появляется вертикальный скролбар.
Теперь, если пользователь делает двойной клик на элементе, который находится в верхней половине окна CTreeCtrl, то происходит множество сложных действий, создаются новые документы, запускаются дополнительные потоки итп. При этом меняется само содержимое дерева. Для этого работает такой код:
 
Код:
SetRedraw(FALSE);
    int iVScrollPos = GetScrollPos(SB_VERT);
    int iHScrollPos = GetScrollPos(SB_HORZ);

    //Изменение содержимого дерева

    SetScrollPos(SB_VERT, iVScrollPos, FALSE);
    SetScrollPos(SB_HORZ, iHScrollPos, FALSE);
    SetRedraw(TRUE);

После всего совершенного действа почему то вертикальный скролбар улетает в самый низ дерева. При этом горизонтальный остается на месте. Это воспроизводится только в том случае, если пользователь кликает на элемент в верхней половине окна CTreeCtrl.

Может кто знает, в чем может быть проблема? Почему вертикальный скролбар не остается на месте? Приведенный код - единственное место, где программно устанавливается позиция скролбара - проверял - устанавливаются верные значения.
368
17 ноября 2004 года
rostyslav
629 / / 13.07.2004
Ф-ия EnsureVisible() не лучше работает?
831
17 ноября 2004 года
S_T
117 / / 23.10.2002
Цитата:
Originally posted by rostyslav
Ф-ия EnsureVisible() не лучше работает?



Проблема вся в том, что дерево может перестроиться очень сильно - в результате чего код перестройки работает следующим образом - дерево полностью уничтожается, затем строится новое с нуля, затем восстанавливается позиция скролбара.
Если же пользоваться EnsureVisible при такой логике, то указанный в EnsureVisible элемент может перескочить на самый верх, что не очень будет приятно выглядеть.

Причем, более того, конструкция с запоминанием\восстановлением позиции скролбара - работает в 90% случаев правильно. Описанный мною случай проявляется в тех 10%, когда идут громоздкие вычисления, запускаются другие потоки - в общем при определенных обстоятельствах.
То есть, можно сделать вывод, что какой-то код что то самопроизвольно портит... Вот я и хочу услышать идею, в какую сторону мне копать, чтобы отловить эту ошибку.

368
17 ноября 2004 года
rostyslav
629 / / 13.07.2004
Цитата:
Originally posted by S_T

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


Это не код портит, а TreeCtrl не знает настоящий размер ScrollRange.

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

831
17 ноября 2004 года
S_T
117 / / 23.10.2002
Цитата:
Originally posted by rostyslav

Это не код портит, а TreeCtrl не знает настоящий размер ScrollRange.

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


Не совсем понятна идея. Как я уже написал, вначале мы запоминаем позицию скроллинга, например 50 пикселей. Затем полностью убиваем дерево - оно пустое - позиция скролинга я так понимаю тоже обнуляется. Затем полностью его пересоздаем (текущая позиция скроллинга равна 0), затем мы восстанавливаем старую позицию. При этом не понятно, почему дерево не знает свой ScrollRange?

Так же я прикрепил два варианта начальной позиции скролбара. В первом варианте, элемент на который кликаем дважды (выделен - SV_3Q) находится выше середины окна дерева - в этом варианте при двойном клике скролбар улетает в самый низ (там этот элемент вообще не виден, хотя селекция остается на нем). Во втором варианте этот же элемент находится чуть ниже середины окна дерева. И при прочих равных условиях двойной клик оставляет скролбар на месте...

368
17 ноября 2004 года
rostyslav
629 / / 13.07.2004
Цитата:
Originally posted by S_T

Не совсем понятна идея.


Это была не идея. Где-то 5 лет тому назад у меня была подобная проблема с Builder-овским TreeCtrl.
И если хорошу помню, причина была в том, что TreeView не знал настоящий размер скроллинга(точнее высоту дерева).

Но можно проверить.
1 вариант. Сперва пойти в самый вниз, потом вверх, чтоб получился рис1 и так щелкнуть на SV_3Q.

2 вариант. После создания нового дерева сперва пойти вниз программно на последний элемент дерева и после этого установить Scroll pos.

Если все еще плохо будет позиционироваться, значит не то...

831
17 ноября 2004 года
S_T
117 / / 23.10.2002
Цитата:
Originally posted by rostyslav

1 вариант. Сперва пойти в самый вниз, потом вверх, чтоб получился рис1 и так щелкнуть на SV_3Q.

2 вариант. После создания нового дерева сперва пойти вниз программно на последний элемент дерева и после этого установить Scroll pos.



Не прокатило ни то ни другое. Я провел "замеры".
1. Вариант, когда скролбар улетает вниз.
а) Запомненное положение скролбара - 19
б) Перед восстановлением положения скролбара функция GetScrollRange(SB_VERT, &iMin, &iMax); возвращает iMin = 0, iMax = 64
2. Вариант, когда все ок.
а) Положение - 10
б) iMin = 0, iMax = 64
Так что грешить на то, что не вычисляются размеры Scroll Range не нужно.

368
17 ноября 2004 года
rostyslav
629 / / 13.07.2004
Цитата:
Originally posted by S_T


Не прокатило ни то ни другое. Я провел "замеры".
1. Вариант, когда скролбар улетает вниз.
а) Запомненное положение скролбара - 19
б) Перед восстановлением положения скролбара функция GetScrollRange(SB_VERT, &iMin, &iMax); возвращает iMin = 0, iMax = 64
2. Вариант, когда все ок.
а) Положение - 10
б) iMin = 0, iMax = 64
Так что грешить на то, что не вычисляются размеры Scroll Range не нужно.


Значит (возможно) не то. Теперь нет времени проверить.

Но ты после создания нового дерева перед SetSrollPos дал команду EnsureVisible(самый_нижний_элемент) ?

831
17 ноября 2004 года
S_T
117 / / 23.10.2002
Цитата:
Originally posted by rostyslav

Значит (возможно) не то. Теперь нет времени проверить.

Но ты после создания нового дерева перед SetSrollPos дал команду EnsureVisible(самый_нижний_элемент) ?



Да, написал цикл вроде следующего:

Код:
HTREEITEM hLastItem = NULL;
HTREEITEM hNextItem = TVI_ROOT;
while (hNextItem)
{
    while (hNextItem)
    {
        //Спускаемся вниз до самого последнего брата
        hNextItem = GetNextItem(hLastItem, TVGN_NEXT);
        if (hNextItem)
        {
            hLastItem = hNextItem;
        }
    }
    //Как только братья кончились
    //Спускаемся к первому ребенку последнего брата
    hNextItem = GetNextItem(hLastItem, TVGN_CHILD);
    if (hNextItem)
    {
        hLastItem = hNextItem;
    }
    //И повторяем процедуру
}
if (hLastItem)
{
    EnsureVisible(hLastItem);
}

SetScrollPos(...)
SetRedraw(TRUE);
Invalidate(FALSE);


При этом проверил, что EnsureVisible(hLastItem); происходит на самом деле для самого последнего элемента дерева. Замечу, что от изменения позиции строк
SetRedraw(TRUE);
Invalidate(FALSE);
ничего не меняется.
368
17 ноября 2004 года
rostyslav
629 / / 13.07.2004
Цитата:
Originally posted by S_T
ничего не меняется.


:(

странно. Если первое и второе дерево один к одному совпадают...

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог