LINUX.ORG.RU

Связанные QSpinBox

 , , , ,


0

2

Пример 1:

Есть два спинбокса в разных местах приложения. Они должны быть синхронизированы, т.е. — например, пользователь установил руками спин1 в значение «8», тогда спин2 должен программно тут же установить такое же значение. То же самое и от обратного, если пользак ставил руками значение в спин2.

Пример 2:

Спинбоксы, работают в режиме «range», где значение спин1 не может превышать значения спин2, а значение спин2 не может быть меньше спин1.

Я сделал для примера 1 и с небольшим заделом для примера 2, но мне кажется сделал криво — навесил свои кастомные сигнал и слот, где сигнал передает (и слот принимает) три параметра: значение, уникальное имя отправителя (кто делал эмит) и булевый флаг «вернуть отправителю». Так же, я перехватываю внутри своего класса, наследника спинбокса, оригинальное valueChanged событие, чтобы отличить, программно ли было установлено значение или это были ручонки пользака.

Для примера 2 есть только размышления — принцип как у первого, но валидатор будет где-то в отдельном месте, и именно валидатор будет подписан своим слотом на сигналы всех спинбоксов-отправителей. Если валидатору не понравится присланное значение, то он ставит третий аргумент в значение истина, может заменить значение на валидное и в любом случае рассылает сигнал всем слушающим слотам, а слоты, смотрят, для них это или нет, по булевому «вернуть отправителю» и уникальному имени отправителя (не валидатора, а самого первого, которого мацал пользак).

Так вот вопрос — а насколько я правильно сделал и как бы сделали это вы?

Если понадобится код, покажу. Но там обычная хрень, я все описал словами.

RazrFalcon, EXL, ya-betmen, CrossFire

Пример 1

Если не смешивать модель и представление, то это реализуется само собой. У тебя есть модель, в которой хранится значение и есть две вьюхи (спин1, спин2), которые слушают модель.

Пример 2

То же через модель. Но теперь она должна хранить два значения. Когда происходит изменение значения, то происходит проверка. Если значение не допустимое, то происходит откат до нужного.

ox55ff ★★ ()
Ответ на: комментарий от ox55ff

Ну.. в моем случае там не совсем модель получится, а так — да, можно назвать это моделью. Но у меня вопрос больше насчет сигналов с пересылкой всяких дополнительных говн и перехвата оригинальных событий. Насколько это чисто и нет ли более верного варианта реализации?

deep-purple ★★★★★ ()
Ответ на: комментарий от deep-purple

Накидал пример, если я правильно понял, что тебе нужно https://github.com/ox55ff/spinboxAndCo

Есть косяк. SpinBox не отправляет сигнал об изменении значения, пока не потеряет фокус. Это можно исправить подписавшись на событие valueChanged.

ox55ff ★★ ()

Пример 1:

Ели я правильно понимаю, то можно сделать так: Определяешь слот valueChanged(может называться по-другому) для первого spinbox и прописываешь ui->spinbox1->value() для spinbox2. так же и наоборот. Ничего сложного. А если еще и в Qt Designer работаешь, то можно просто стрелочки перекинуть друг другу и готово.

Пример 2:

Что-то ты тут намудрил. Извини, но я даже понять ничего не могу.

Release ()

Я бы сработал через модель, при изменении данных кидал эвент об изменении по нему обновлял комбики, в случае 1 - одно поле в модели, в случае 2 - два поля. Валидировал бы модель при изменении данных.

ya-betmen ★★★★★ ()
Последнее исправление: ya-betmen (всего исправлений: 1)
Ответ на: комментарий от ox55ff

Хм, вот я об этом. Меня устраивает что срабатывает событие valueChanged, причем и при скролле мышой и при нажатии энтер и при вставке скопированного откуда-то значения. В твоем варианте (не запускал еще) я понял этого нет, маппер такие штуки не видит, хотя и вяжет меж собой спины. А вот мой тестовый код:

mySpinBox::mySpinBox(QWidget *parent)
    : QSpinBox(parent)
{
    mp_changedByUser = true;
    setObjectName(QString::number(rand()).append("mySpinBox"));
    setRange(1, 999999);
    setSingleStep(1);
    connect(
        this,
        SIGNAL(valueChanged(int)),
        this,
        SLOT(catchInternalValueChanged(int))
    );
}

mySpinBox::~mySpinBox()
{
}

void
mySpinBox::setExternalValue(
    int      value,
    QString *senderObjectName,
    bool     returnToSender
)
{
    mp_changedByUser = false;
    if (
        (objectName() != senderObjectName && false == returnToSender)
            || (objectName() == senderObjectName && true == returnToSender)
    ) {
        if (mp_oldValue != value) {
            mp_oldValue = value;
            setValue(value);
        }
    }
}

void
mySpinBox::catchInternalValueChanged(int value)
{
    if (true == mp_changedByUser) {
        QString senderObjectName(objectName());
        emit wantSetExternalValue(value, &senderObjectName);
    }
    mp_changedByUser = true;
}

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

deep-purple ★★★★★ ()
Ответ на: комментарий от RazrFalcon

Не-не, они в разных местах, а делают одно и то же (в первом примере), но не всегда доступно какое-то одно место, зависит от того что делает пользак. А второй пример чем не нормален? ренж обычный, но нужен не слайдер с двумя ручками а именно спинбоксы.

deep-purple ★★★★★ ()
Ответ на: комментарий от deep-purple

Окей, тогда это так же решается, как и в первом примере. Мудровать что-то сверхсложное не нужно. Просто в слоте проверять значения спинбоксов. и ограничивать range

Release ()
Ответ на: комментарий от Release

Ну вот код мой выше. Я вижу плюс в том что любой созданный спин управляется извне подписав свой слот, и управляет, ему и знать не надо чем, отправляя сигнал. Мысль была «мухи от котлет». Т.е. ты тоже склоняешься к сигналам-слотам, а не к модели прямо нахардкоженой к спинам?

deep-purple ★★★★★ ()
Ответ на: комментарий от Release

Упрощеное это хорошо. Но если пользак воткнул невалидное значение — проверять лучше единственным валидатором в который шлют все спины и тогда обратно в целевой спин должно прилететь валидное значение, но чтобы не париться я собрался слать обратно всем спинам, но с булевым «вернуть отправителю», остальные проигнорируют. Вот это все нормально или полгое г?

deep-purple ★★★★★ ()
Ответ на: комментарий от Release

Суть в том что множество «крутилок», в том числе эти спины, управляют состоянием одной большой херни. Вот в этой херне я считаю и должны быть валидации и обратная связь к вьюшкам (а не ифами в спинах и остальных «крутилках»). Но через сигналы-слоты.

deep-purple ★★★★★ ()
Ответ на: комментарий от deep-purple

В этих слотах же и управляй вьюшкой. Через сигналы. Правда, подозреваю, будет небольшой копипаст. (появилась безумная идея создания своего слота(хотя, можно обойтись и простым методом) для управления вьюшкой. Просто из слотов для спинбоксов сигналы (или вызываешь методы с требуемыми параметрами) и всё)

Release ()
Ответ на: комментарий от Release

Дык я и хочу управлять слотами спинов посылая сигналы после валидации или просто программно выставить значение в рантайме. И у меня в примере есть свой сигнал wantSetExternalValue и свой слот setExternalValue. И вообще, почему спрашиваю насколько это плохо или хорошо — я хочу распространить эту практику не только на эти спины, но и на остальные «крутилки», в том числе и нестандартные.

deep-purple ★★★★★ ()
Ответ на: комментарий от deep-purple

«Валидируй» через if в слотах спинбоксов. Управляй через методы. Я бы так делал. Городить лишние сигналы, где можно обойтись методами - странно и можно потом себе выстрелить в ногу.

Release ()
Ответ на: комментарий от Release

Ну вот два одинаковых спинбокса. А теперь добавь к спинбоксам, например, шкалу градусника по цельсию, пусть показывает красной линией значение. В ней ты тоже будешь ифы руками прописывать как и в спинах?

deep-purple ★★★★★ ()
Ответ на: комментарий от Release

setRange(min, max) согласен, но это должно приехать извне (от большой херни, она знает какие значения будут нужны). Тогда для градусника нужно будет свой setRange запиливать.

Допустим. Однако это не отменяет пересылки сигналов, ксати их станет больше или нет? И не отменяет проверки программно значение поставилось или был пользовательский ввод — иначе в рекурсию улетит пересылая по кругу.

deep-purple ★★★★★ ()
Ответ на: комментарий от Release

Ой и самое главное — методы напрямую вместо слотов, а как же многопоточность и расположение связанных спинов хрен знает где друг от друга находящихся (namespace, scope)?

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

Вот я о чем.

deep-purple ★★★★★ ()
Ответ на: комментарий от deep-purple

С этого надо было начинать. Теперь всё должно делаться по-другому. Но я с многопоточностью не работал, скажу сразу.

Тогда нужны сигналы-слоты. Но валидацию я все равно бы проводил в слоте valueChanged. Можно попробовать создать какой-то метод-обработчик в классе с виджетами.

Release ()
Ответ на: комментарий от Release

Да нормально она работает, многопоточность эта. Есть тут пара проблем с блокировкой и очередью на раздачу доступа, но это другая история.

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

Таким образом я просто расширил базовый класс спина своими плюшками и буду использовать его без каких либо доделок в любом месте где понадобится связанность вьюх.

deep-purple ★★★★★ ()
Ответ на: комментарий от deep-purple

Таким образом я просто расширил базовый класс спина своими плюшками и буду использовать его без каких либо доделок в любом месте где понадобится связанность вьюх.

Пойдет. Обычно я так тоже делаю, наследуюсь и переопределяю то, что мне нужно. Другого выбора я не вижу.

Release ()