Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: serg_hd от Январь 22, 2011, 20:04



Название: Автоматический контроль QSlider'ов
Отправлено: serg_hd от Январь 22, 2011, 20:04
Всем привет. Задача в том, что имеется несколько QSlider'ов, но сумма всех values этих слайдеров всегда должна быть равна 100 (по аналогии 100%). Иначе говоря, двигая ползунок одного слайдера на увеличение, у других ползунки автоматически двигаются на уменьшение (там где это возможно конечно) и наоборот. Вроде как реализовал, но из-за того, что сигнал valueChanged(int) шлётся как-то нестабильно - чем быстрее двигать ползунок, тем реже шлётся - то сама затея наследования QSlider'a и уменьшение/увеличение значений у слайдеров, кроме текущего, в слоте на сигнал valueChanged(int) не возымела успеха (обход рекурсии соблюдён). Может быть есть какие-либо альтернативы (не QSlider) решения данного вопроса? Спасибо.


Название: Re: Автоматический контроль QSlider'ов
Отправлено: dd от Январь 22, 2011, 20:20
По отпускании мыша ведь вызвается последний valueChanged, который должен нормализовать состояния всех слайдеров.
В чтом тогда проблема?


Название: Re: Автоматический контроль QSlider'ов
Отправлено: merke от Январь 22, 2011, 21:00
Вот накидал тебе примерчик, посмотри


Название: Re: Автоматический контроль QSlider'ов
Отправлено: serg_hd от Январь 22, 2011, 21:08
Вот накидал тебе примерчик, посмотри
спасибо, но не всё так просто)

По отпускании мыша ведь вызвается последний valueChanged, который должен нормализовать состояния всех слайдеров.
В чтом тогда проблема?
Я уже когда создал тему подумал примерно также. Т.е. решил делить разницу между старым и новым значениями слайдера между всеми оставшимися слайдерами (всего у меня их от 4х и больше) с учётом их текущих values и доступностей на изменения. До этого просто добавлял/удалял единицу (не знал на тот момент что сигнал шлётся не на каждый шаг движения ползунка). Хотел тему удалить, но тут так почему-то нельзя.


Название: Re: Автоматический контроль QSlider'ов
Отправлено: dd от Январь 22, 2011, 21:15
А ты что, единицу добавлял / удалял чтоли? о_0
Конечно не будет работать.
Нужно по сигналу смотреть текущее значение двигаемого слайдера и на основе него менять остальные.
Тогда вообще проблемы нет.


Название: Re: Автоматический контроль QSlider'ов
Отправлено: serg_hd от Январь 22, 2011, 21:21
А ты что, единицу добавлял / удалял чтоли? о_0
Конечно не будет работать.
Вот именно что работало бы, если б сигнал слался каждый раз после изменения на величину, заданную через setSingleStep() - в моём случае setSingleStep(1) - как это должно было быть теоретически.


Название: Re: Автоматический контроль QSlider'ов
Отправлено: Kolobok от Январь 22, 2011, 21:25
Думаю, тут лучше использовать сигнал sliderMoved ( int value )


Название: Re: Автоматический контроль QSlider'ов
Отправлено: dd от Январь 22, 2011, 21:30
>> Вот именно что работало бы, если б сигнал слался каждый раз после изменения на величину, заданную через setSingleStep()

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


Название: Re: Автоматический контроль QSlider'ов
Отправлено: Fess от Январь 22, 2011, 22:16
Смотри, набросал то, что тебе нужно.
Работает корректно.


Название: Re: Автоматический контроль QSlider'ов
Отправлено: serg_hd от Январь 23, 2011, 00:40
Смотри, набросал то, что тебе нужно.
Работает корректно.

Да, действительно то, что я и искал. Я даже свой вариант (с перегрузкой QSlider'а) заменил на этот, т.к. удобнее. Предлагаю выложить в "готовые решения", потому как вещь полезная - контролирует фиксированную величину.
п.с. не понял только почему циклы с использованием итераторов построены так:
Код
C++ (Qt)
for(QMap<QSlider*,float>::iterator it = m_Sliders.begin(), itEnd = m_Sliders.end(); it != itEnd; it++) { ... }
 

а не просто
Код
C++ (Qt)
for (QMap<QSlider*,float>::iterator it = m_Sliders.begin(); it != m_Sliders.end(); ++it) {...}
 


Название: Re: Автоматический контроль QSlider'ов
Отправлено: asvil от Январь 23, 2011, 00:43
Qt-creator style programming. Я так понимаю компилятор не оптимизирует it != m_Sliders.end(), и вызов функции end происходит на каждой итерации цикла, чего впринципе не должно быть если m_Sliders в цикле не изменяется. Вообщем оптимизация делается вручную.


Название: Re: Автоматический контроль QSlider'ов
Отправлено: serg_hd от Январь 23, 2011, 00:44
Qt-creator style programming. Я так понимаю компилятор не оптимизирует it != m_Sliders.end(), и вызов функции end происходит на каждой итерации цикла, чего впринципе не должно быть если m_Sliders в цикле не изменяется. Вообщем оптимизация делается вручную.
понятно


Название: Re: Автоматический контроль QSlider'ов
Отправлено: serg_hd от Январь 23, 2011, 02:21
хотя замечено случайное бесконечное зацикливание, в моём случае 4 слайдера


Название: Re: Автоматический контроль QSlider'ов
Отправлено: Fess от Январь 23, 2011, 10:09
хотя замечено случайное бесконечное зацикливание, в моём случае 4 слайдера
Это чисто идея. Доводи "до ума".. Выкладывай куда хочешь.
Рад, что помогло.
Qt-creator style programming. Я так понимаю компилятор не оптимизирует it != m_Sliders.end(), и вызов функции end происходит на каждой итерации цикла, чего впринципе не должно быть если m_Sliders в цикле не изменяется. Вообщем оптимизация делается вручную.
Qt-creator - чисто IDE. Не думаю, что mingw/gcc не оптимизировали этот момент. Просто привычка, да и так надежнее :)


Название: Re: Автоматический контроль QSlider'ов
Отправлено: asvil от Январь 23, 2011, 10:38
Qt-Creator coding-style.qdoc
Для итераторов только для чтения Qt строго-настрого советует использовать constBegin/End().


Название: Re: Автоматический контроль QSlider'ов
Отправлено: Igors от Январь 23, 2011, 11:23
Смотри, набросал то, что тебе нужно.
Работает корректно.
А можно (конструктивную) критику?  :)
Я посмотрел текст и мне не понравилось что расчеты смешаны с UI. Здесь легко выделить ф-цию которая никак от UI не зависит.

Код
C++ (Qt)
template <class T>
void Balance( QVector<T> & vec,    // вектор значений (по 1 на слайдер)
             T sum,               // нужная сумма      
             size_t lockIndex )   // индекс элемента которого нельзя менять
{
...  // балансируем
}
 
После этого UI станет проще: не нужен никакой QMap, может и класс Controller не нужен, а обойтись контейнером указателей на слайдеры. Если понадобится более сложная балансировка, можно спокойно развивать ф-цию Balance не ковыряя UI


Название: Re: Автоматический контроль QSlider'ов
Отправлено: Fess от Январь 23, 2011, 12:47
А можно (конструктивную) критику?  :)
Я посмотрел текст и мне не понравилось что расчеты смешаны с UI. Здесь легко выделить ф-цию которая никак от UI не зависит.

Код
C++ (Qt)
template <class T>
void Balance( QVector<T> & vec,
             T sum,
             size_t lockIndex )
{
...
}
 
После этого UI станет проще: не нужен никакой QMap, может и класс Controller не нужен, а обойтись контейнером указателей на слайдеры. Если понадобится более сложная балансировка, можно спокойно развивать ф-цию Balance не ковыряя UI
Спасибо за критику.
Не вижу проблемы в том, что код, дорабатывающий поведение UI завязан на UI. Едва ли это будет применяться где-то еще, кроме как в этой конкретной ситуации,  поэтому нет смысла совершать лишние телодвижения для его обобщения. KISS принцип :)

QSlider оперирует только int, а в данной ситуации (принцип сообщающихся сосудов) этого мало. Изменение на 1 должно распределиться на N слайдеров и это реальное значение для каждого слайдера нужно где-то хранить.
Вообще говоря, сумма значений слайдеров, полученная через pSlider.Value(), будет лишь приблизительно равна необходимой величине, а реальные значения знает лишь контроллер. Либо нужно ставить задачу иначе и при балансировке отдавать какому-то слайдеру предпочтение (что ИМХО еще запутаннее).