Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Гурман от Декабрь 27, 2016, 23:32



Название: (РЕШЕНО) Долбаный QSlider...
Отправлено: Гурман от Декабрь 27, 2016, 23:32
Сделал плагин для дизайнера на основе QSlider чтобы можно было задавать изображения ручки и прорези. Слайдер пока только горизонтальный - вертикальный потом доделать несложно. Требуется, чтобы при изменении высоты слайдера пропорционально изменялся размер ручки. А при изменении ширины изменялась только ширина прорези. Поэтому использование таблицы стилей не подходит - с ним невозможно в дизайнере менять размеры ручки. Перегрузил paintEvent(), всё почти заработало сразу. Но проблема - прорезь рисуется на всю ширину виджета, а центр ручки бегает между левым и правым краями прорези. Соответственно, в крайних положениях половина ручки обрезается. И долбаюсь уже второй день, пытаюсь выяснить, как сделать, чтобы ширина прорези была меньше ширины виджета, и центр ручки перемещался только между краями прорези. Требуемую прорезь получил, но при этом выяснил, что все положения ручки родительский класс вычисляет не по ширине прорези, а по ширине виджета. То есть, даже если прорезь меньше виджета, то ручка всё равно бегает между крайними границами виджета и обрезается на краях. Что только не пробовал, ни в какую.

Но ведь должно же как-то правильно работать! Беру оригинальный QSlider - у него всё в порядке. Ничего не обрезается, ручка двигается между краями прорези, которая меньше виджета... :-[ Полез исходники QSlider ковырять - там чёрт ногу сломит. Вижу, где двигается слайдер, где мышиное событие обрабатывается. Но никак не могу найти - где вычисляются "точки останова", их положение в виджете. Ограничитель при перемещении ручки - это значение, а не координаты. То есть, упирается влево он при достижении заданного минимального значения. Но как попадает на свою крайнюю левую позицию? Где она задана? Причём по коду перемещения слайдера вообще не видно, как ручка "тормозит" на промежуточных позициях. Перемещение ручки вообще "плавное"! И этого же не видно в коде отрисовки ручки, там только рисование.

Кто-нибудь расковыривал исходники слайдера? Если не получится сделать, придётся реализовать на таблице стилей, а это ГОРАЗДО хуже, так как размеры ручки нельзя будет менять в дизайнере.


Название: Re: Долбаный QSlider...
Отправлено: Igors от Декабрь 28, 2016, 06:04
Делал свой стиль, вполне реально, ничего страшного. Для слайдера отделался своим subControlRect и drawComplexControl. Это намного дешевле чем разбираться в обильных подробностях styleHint и.т.п


Название: Re: Долбаный QSlider...
Отправлено: Гурман от Декабрь 28, 2016, 11:02
Делал свой стиль
Это в моём случае лишнее. Мне надо только для QSlider картинки в дизайнере указывать. Ну ещё для кнопки и дайала, но там уже всё сделано как следовало, без стилей.

Нашёл наконец-то, где вычисляется позиция ручки, в моём случае это в QCommonStyle::subControlRect(). Там прямая зависимость от ширины слайдера, а не от ширины прорези. ИМХО - это баг. Но по-прежнему не понятно, как получается правильный "фирменный" слайдер, так как его позиция тоже в QCommonStyle::subControlRect() вычисляется.


Название: Re: Долбаный QSlider...
Отправлено: Гурман от Декабрь 28, 2016, 19:17
ВСЁ! Победил... без создания собственного стиля, нафик он не нужен. Разобрался по исходникам, что управление перемещением производится в style()->subControlRect() виджета, и это вызывается прямо из paintEvent(). При этом туда надо передавать  

Код:
    QStyleOptionSlider o;
    initStyleOption(&o);

который принимает параметры текущего виджета. Если у него перед вызовом style()->subControlRect() изменить прямоугольник с помощью

Код:
    o.rect.setWidth( o.rect.width() - knobwidth );
    o.rect.moveLeft( knobwidth/2 );

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

Единственное, что удручает - это то, что в угоду разным стилям subControlRect() по разному вычисляет координаты и размеры в разных ОС. В результате выглядит это всё совсем не одинаково в Kubuntu, Android и Windows. Как надо получилось сначала только в Android. Можно было бы и свой стиль соорудить, но гораздо проще было послать нафик все эти извраты и ещё раз перед рисованием самому всё пересчитать.