Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Компоненты Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 02.04.2008, 11:51   #1
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию Scroll bar - делаем скин

Приветствую форумчан. Я как обычно с интересными вопросами.

Scroll Bar - ну всем известно что это такое ) Допустим берем TMemo устанавливаем ( ну для начала ) Scroll Bar - Vertical. Появился скролл, все работает - мы радуемся... Вопрос заключается в том, как отрисовать самому. Долго ходил по сети, идея выложена двумя способами: 1. Сделать сколл, как отдельный компонент и наложить на нужный ( скинированный в будущем ) компонент. 2. Перехват WM_NCPAINT. Вроде все бы и хорошо, все так и пишут. Но как я не крутил, ну не пойму что делать когда перехватили тот WM_NCPAINT, когда я знаю что перерисовывается именно скролл а не ерунда другая какайнить ) На примере TMemo тупо перехватываю WM_NCPAINT, возращаю результатом обработки мессаги 1 и что.... Сам мемо рисуется ( область текста ) замечательно, странно ( но прорисовывается местами ) рамка TMemo и Scroll Bar. Хотя бывает он все таки прорисовывается, т.е. значит надо чтот еще ловить ))) Пытался найти исходники скиннеров ( компоненты которые ставят скины в дельфи ) именно .pas файлы, но не нашел.

Ну вот так вот.... Может у кого есть идеи ?
BOBAH13 вне форума Ответить с цитированием
Старый 02.04.2008, 12:29   #2
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

По-моему проще будет первый вариант.
Или вообще, не просто скроллбар, а сам Мемо по своему делать с нуля, почти
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 02.04.2008, 16:04   #3
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Перехват WM_NCPAINT автоматически ведет к перехвату всех остальных WM_NC*** - WM_NCCALCSIZE, WM_NCHITTEST и пр. Потому как где скроллбар, там и рамка, где рамка - там кнопки, раскладку окна нужно держать свою и т.д. Кроме того, та же SetScrollPos рисует скроллбар самостоятельно со всеми вытекающими - приходится переделывать и её, и GetScrollPos и т.п. , а на использование стандартных накладывать запрет. Кроме того у окна есть такая очень неприятная вещь как меню. Одним словом, приходится все структуры данных сопровождать самостоятельно, переопределять добрую половину user32.dll, а ради изоляции этих данных от ошибок или враждебных действий приходится писать драйвер. Такая вот милая цепочка. Есть у меня такая чуть не законченная библиотека - ANSI подверсия - примерно 70 тысяч строк на C, ещё чуть меньше - юникод.
P.S. Так много потому, что переделаны все стандартные контролы, точнее почти все - часть ещё не закончена.

Последний раз редактировалось B_N; 02.04.2008 в 16:06.
B_N вне форума Ответить с цитированием
Старый 02.04.2008, 21:25   #4
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Вообщем вывод - я считаю сделать реализацию компонента саморучно ну и скролл бар реализовать руками )) Мне вообщем то только для себя никому давать не буду... так что можно не углубляться в удобство использования и понимания... Думаю это самый лучший вариант
BOBAH13 вне форума Ответить с цитированием
Старый 24.04.2008, 08:30   #5
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Прошло достаточно времени Сделал я скин две кнопки, ползунок гасает то туда, то сюда И опять же проблема, в том, что при перетаскивании ползунка найти верхний пункт списка и еще ту часть оставшейся видимой перед новым верхним пунктом.

обновление данных скролл бара
Код:
var
  k: Real;
  i: Integer;
begin
  // коэфициент расчитываем, полной области где может ходить ползунок
  // на область всех пунктов списка + часть списка которая остается
  // после последнего пункта списка.
  k := (Height - 98 - 100 - 4 - FStyler.GetImage(VScrollButtonUp).Height -
      FStyler.GetImage(VScrollButtonDown).Height) / (GetTotalHeight + GetBottomSpace(False));
  // Height  - 98 - 100 = область моего списка

  // FListItemTopSpace - та видимая часть, которая получается
  // выше верхнего пункта
    i := -FListItemTopSpace;
  // тут я получаю в переменную i всю высоту пунктов до верхнего 
  // FListItemTop
    p := GetListFirstVisibleItem(NIL);
    while (p <> NIL) and (p <> FListItemTop) do
    begin
      inc(i, ListItemHeight(p));
      p := GetListNextVisibleItem(p);
    end;
  
 // ну тут ясно
    FScrollHeight := Round(k * (Height - 98 - 100));
    FScrollTop := Round((k * i));
теперь часть при MouseMove на ползунке
Код:
var
  i, h: Integer;
  p, pr: PListItem;
begin
// Point - переменная текущей позиции курсора
// FScrollDownPoint - переменная нажатой позиции курсора
i := Point.Y - FScrollDownPoint.Y - 98 - 2 - FStyler.GetImage(VScrollButtonUp).Height;
    if (i < 0) then
      i := 0 else
// по сути это Height - 100 - 98 - 4 - FStyler.GetImage(VScrollButtonUp).
// Height - FStyler.GetImage(VScrollButtonDown).Height есть область где 
// ползунок ходит
    if (i > Height - 100 - 98 - 4 - FStyler.GetImage(VScrollButtonUp).Height -
      FStyler.GetImage(VScrollButtonDown).Height - FScrollHeight) then
      i := Height - 100 - 98 - 4 - FStyler.GetImage(VScrollButtonUp).Height -
        FStyler.GetImage(VScrollButtonDown).Height - FScrollHeight;
// тут расчет пикселя какого то пункта относительно позиции ползунка 
    i := Round(i * (Height - 98 - 100) / FScrollHeight);
// начинаем искать этот пункт, будущий верхний пункт
    h := 0;                          
    pr := NIL;
    p := GetListFirstVisibleItem(NIL);
    while (p <> NIL) do
    begin
      if (h >= i) then // нашли
      begin
        FListItemTopSpace := h - i; // та оставшаяся видимая часть
// выше верхнего пункта
        pr := p; // новый верхний пункт
        Break;
      end;
      inc(h, ListItemHeight(p)); // просто увеличиваем на высоту текущего
// пункта переменную h для сравнения
      p := GetListNextVisibleItem(p);
    end;
Ну кому не лень, проверьте математику ? просто тут мелкий недочет где-то, т.к. скролл бывает ведет себя нормально, а бывает внизу то прыгает, то не доходит то конца области ползунка.
BOBAH13 вне форума Ответить с цитированием
Старый 25.04.2008, 13:55   #6
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
Ну кому не лень, проверьте математику ? просто тут мелкий недочет где-то, т.к. скролл бывает ведет себя нормально, а бывает внизу то прыгает, то не доходит то конца области ползунка.
Честно говоря, долго пытался разобраться в Вашей арифметике, но что-то запутался во всех этих "100", "98" и т.п. Если поможет, могу изложить "теорию" того, как я делал нормально функционирующий (это проверено ) скроллбар.

http://img87.imageshack.us/img87/9217/vscrolldl0.png

Высота h представляет собой "мёртвую" зону. Она равна минимально возможной высоте ползунка и зависит в конечном счёте от скина. Если расстояние между стрелками меньше h, то скроллбар выключается, а ползунок не рисуется.
Высота H равна расстоянию между стрелками за вычетом h. Именно она отражает высоту документа.
Высота t - это и есть "реальный" размер ползунка, определяется как отношение количества строк в пределах экрана к общему количеству строк. Общая, доступная пользователю, высота ползунка складывается из h и t.
Точка A отражает положение верхней видимой на экране строки в документе. Определяется как произведение высоты H на отношение верхней строки к общему количеству строк.

На основе этой арифметики я писал функцию, которая заполняла структуру, описывающую координаты стрелок, ползунка, верхней и нижней шахт скроллбара (собственно, не кординаты, как таковые, а длины элементов в пикселях) и набор флажков, например, флага, отражающего активность скроллбара - если строк на экране больше, чем в документе или расстояние между стрелками меньше высоты h, то скроллбар не активен. Функция вызывается всякий раз, когда возникала необходимость в прорисовке или при щелчке по скроллбару, при перетаскивании ползунка, и передаётся в неё только общая высота всего скроллбара. Данные скроллбара хранятся в виде стандартной структуры SCROLLINFO, кроме того до при перетаскивании ползунка я объявлял локальную (всё делалось в модальном цикле, не возвращаясь из обработчика WM_NCLBUTTONDOWN) переменную, выражающую расстояние от точки A до точки "захвата" ползунка. При движении мыши достаточно было просто пересчитать новые экранные координаты точки A (добавить указанное выше расстояние к текущей координате курсора) и передать в "свою" SetScrollInfo, даже без проверки на предмет выхода за пределы зоны H скроллбара, вся проверка производилась внутри новой функции. Вот собственно и всё. Само собой, всё остаётся в силе для горизонтальных скроллбаров. Я подозреваю, что у Вас не учтена зона h, поэтому, видимо, ползунок и дёргается.
B_N вне форума Ответить с цитированием
Старый 26.04.2008, 11:28   #7
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Спасибо. Буду разбераться.
BOBAH13 вне форума Ответить с цитированием
Старый 26.04.2008, 14:51   #8
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

I
1. Список
Hl - высота видимой области
Hh - высота всей области
Tl - верхняя позиция
2. Скролл бар
Sl - минимальная высота слайдера
Hs - высота области где ходит слайдер

II
1. Вычисляем коэфициент отношения высот списка
k = (Hs - Sl) / Hh
2. Вычисляем высоту слайдера
h = (k * Hl) + Sl
3. Вычисляем отступ (позицию) слайдера сверху
t = Tl * k

Все ли я верно понял ? У меня так вроде работает верно. Большое спасибо.
И в догонку Как устроить плавное пролистывание, а не четкий переход к следующему пункту ? Такое не проходили ? Просто если добавляю при прокрутке вычисляю разницу между новым верхним пунктом и то на сколько позиция слайдера относительно списка больше его ) но когда слайдер внизу то это число прыгает Может есть правильный подход ?

Последний раз редактировалось BOBAH13; 26.04.2008 в 15:22.
BOBAH13 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Научу делать скин JoanM Фриланс 2 29.04.2008 13:45
scroll в webbrouser MaslCS Компоненты Delphi 4 23.01.2008 22:58
Как сделать для своей проги скин? C++ Builder 6. Dunhil Помощь студентам 1 30.12.2007 13:37
Делаем любые программы на Delphi asale Фриланс 3 04.12.2007 14:23
Скин программы OrdJONY Общие вопросы Delphi 10 22.05.2007 23:01