Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Azazello от Октябрь 27, 2018, 12:01



Название: Popup window and button
Отправлено: Azazello от Октябрь 27, 2018, 12:01
Есть всплывающее окно  - setWindowFlags(Qt::Popup) (окно скрывается, когда теряет фокус  - другими словами кляцнули на другом месте, оно скрылось).
Есть кнопочка, которая вызывает это окно. При активном окне кнопочка утоплена. Окно закрылось, кнопочка обратно выпрямилась.

Понятно, что пользователь захочет нажать на эту кнопочку (ожидаемое поведение) чтобы скрыть это окно. НО!, как только он захочет её нажать, окно потеряет фокус и само скроется ( и окно переведет кнопочку в состояние выкл.). И произойдет опять вызов окна (т.к. кнопка уже выпрямилась).

Решено так:
Код:
 void ChoiceWidget::hideEvent(QHideEvent *event)
{
    QWidget::hideEvent(event);
   //disable recurse unset button
    if (mAction != nullptr) {
        QAction *action = mAction; //for capture lambda
        action->blockSignals(true);
        QTimer::singleShot(200,[action]() {
            action->setChecked(false);
            action->blockSignals(false);
        });
    }
}

Т.е. блокируем кнопку на пару милисекунд.
Может есть более нормальное решение?


Название: Re: Popup window and button
Отправлено: lit-uriy от Октябрь 29, 2018, 07:25
А если так:
Код
C++ (Qt)
void ChoiceWidget::buttonClick(bool state)
{
 if (state){
   // показываем всплывашку
 }
}
 
// соединять соответственно так:
connect(button, SIGNAL(clicked(bool)), this, SLOT(buttonClick(bool)));


Название: Re: Popup window and button
Отправлено: Azazello от Октябрь 29, 2018, 10:21
А если так:
Код
C++ (Qt)
void ChoiceWidget::buttonClick(bool state)
{
 if (state){
   // показываем всплывашку
 }
}
 
// соединять соответственно так:
connect(button, SIGNAL(clicked(bool)), this, SLOT(buttonClick(bool)));

Так и сделано. Но дело в том, что state изменит окно, когда закроется и кнопочка выпрямится. Т.е. событие закрытия окна (которое изменяет состояние кнопки) происходит раньше, чем клик на кнопку. Таким образом мы опять вызовем окно.


Название: Re: Popup window and button
Отправлено: ViTech от Октябрь 29, 2018, 11:14
Судя по описанию задачи получается, что окно должно скрываться при потери фокуса, но не должно скрываться при переходе/нажатии на кнопку(она сама закроет окно). Может в эту сторону и нужно копать. Т.е. не закрывать окно безусловно при потери фокуса, а проверять куда/при каких обстоятельствах он изменяется.


Название: Re: Popup window and button
Отправлено: Igors от Октябрь 29, 2018, 11:28
Так и сделано. Но дело в том, что state изменит окно, когда закроется и кнопочка выпрямится. Т.е. событие закрытия окна (которое изменяет состояние кнопки) происходит раньше, чем клик на кнопку. Таким образом мы опять вызовем окно.
Если окно скрывается как угодно (как и положено для popup) - то зачем делать это еще действием? Пусть кнопка только открывает и становится disabled. А окно закрылось - опять enabled



Название: Re: Popup window and button
Отправлено: ViTech от Октябрь 29, 2018, 12:14
Ещё можно попробовать вызывать методы (hide, setChecked, и т.п.) не напрямую, а через QMetaObject::invokeMethod(..., Qt::QueuedConnection), чтобы они в конец очереди сообщений ставились.


Название: Re: Popup window and button
Отправлено: Azazello от Октябрь 29, 2018, 13:57
Если окно скрывается как угодно (как и положено для popup) - то зачем делать это еще действием? Пусть кнопка только открывает и становится disabled. А окно закрылось - опять enabled


Да, цирк в том, что нажатие на кнопку реально не происходит, но пользователь то об этом не знает.

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

Ещё можно попробовать вызывать методы (hide, setChecked, и т.п.) не напрямую, а через QMetaObject::invokeMethod(..., Qt::QueuedConnection), чтобы они в конец очереди сообщений ставились.

Но это ничего не гарантирует

Судя по описанию задачи получается, что окно должно скрываться при потери фокуса, но не должно скрываться при переходе/нажатии на кнопку(она сама закроет окно). Может в эту сторону и нужно копать. Т.е. не закрывать окно безусловно при потери фокуса, а проверять куда/при каких обстоятельствах он изменяется.

Не совсем понял. Условно (считайте), что я пишу Qt Creator - это инструмент, у которого все под рукой, и который не должен отвлекать. Окна, которые закрываются при потере фокуса - самое то, чтобы не отвлекать. И да, хоть он вместо окон использует меню, смысл тот же самый. Да, можно было бы использовать только онКлик..... Но как то некрасиво для самого себя. Не видел я такого поведения. Тем более, можно ж умом тронуться для неокрепших пользователей. Он тыкает, чтобы закрыть, на кнопку, а окно пропадает и сразу появляется.


Название: Re: Popup window and button
Отправлено: ssoft от Октябрь 29, 2018, 14:19
А чем QToolButton не угодило с setPopupMode( QToolButton::MenuButtonPopup )? Вроде как, нужное поведение реализует.
Если не то, тогда можно внутри Qt посмотреть, как реализовано.


Название: Re: Popup window and button
Отправлено: Azazello от Октябрь 29, 2018, 14:27
А чем QToolButton не угодило с setPopupMode( QToolButton::MenuButtonPopup )? Вроде как, нужное поведение реализует.
Если не то, тогда можно внутри Qt посмотреть, как реализовано.

Это и есть QToolButton с фейковым (пустым) меню - для того, чтобы стрелочку рисовало на кнопочке - мол появится что-то.
И второе: в меню весь функционал который мне нужен не влезет.
Можно также сравнить с ComboBox. Но отличие этих всех контролов от того, что мне нужно - их меню или списки встроены в тип. QToolButton знает о меню. Моя же кнопочка ничего ни о ком не знает и знать НЕ СОБИРАЕТСЯ.


Название: Re: Popup window and button
Отправлено: ViTech от Октябрь 29, 2018, 14:56
Но это ничего не гарантирует

Моя же кнопочка ничего ни о ком не знает и знать НЕ СОБИРАЕТСЯ.

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

Можно попробовать перед action->setChecked(false) задействовать QAction::setData() с каким-нибудь флагом/состоянием/данными.


Название: Re: Popup window and button
Отправлено: Igors от Октябрь 29, 2018, 15:16
Но разницу между вашим вариантом и своим я не вижу. Если кнопка станет disable, то сделать его enable должно само окно и мы приходим к тому же самому.
Последовательность событий: нажатие мыши -> закрытие popup окна -> нажатие кнопки. Если сигнал закрытия соединить с enabled кнопки (QueuedConnection), то на момент нажатия кнопка еще disabled и повторного открытия не произойдет. 

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


Название: Re: Popup window and button
Отправлено: Azazello от Октябрь 29, 2018, 15:47
Последовательность событий: нажатие мыши -> закрытие popup окна -> нажатие кнопки. Если сигнал закрытия соединить с enabled кнопки (QueuedConnection), то на момент нажатия кнопка еще disabled и повторного открытия не произойдет. 

Попробую. Потом отпишусь

Цитировать
Не стоит считать юзера таким уж тупым - с др менюшками и попапками он прекрасно разбирается без всяких доп указаний

Он прекрасно разбирается, потому что все программы одинаково себя правильно ведут. Да понятное дело, что разберутся. Но это же разражает. Кому охота иметь программу, которая раздражает.


Название: Re: Popup window and button
Отправлено: Igors от Октябрь 29, 2018, 15:55
Да понятное дело, что разберутся. Но это же разражает. Кому охота иметь программу, которая раздражает.
Кнопка типа "закрой роpup (идиот)" раздражает куда больше  :)


Название: Re: Popup window and button
Отправлено: Azazello от Октябрь 29, 2018, 16:20
Да понятное дело, что разберутся. Но это же разражает. Кому охота иметь программу, которая раздражает.
Кнопка типа "закрой роpup (идиот)" раздражает куда больше  :)

У вас есть хоть один пример, где этот функционал отсутствует?

Я же не добавляю новую кнопку, не махаю флагом перед пользователем, даже не спрашиваю пользователя, хочет ли он выйти из программы (просто из нее нельзя выйти:)). Наоборот, делаю интерфейс найболее ненавязчивый. Скажем так, если всплывает меню - уже все привыкли, что оно само пропадет. Если окно, то нет. Но для контекстного меню то и кнопка не нужна, поэтому проблема отсутствует. Но, даже если забить на юзабилити, все равно что то нужно делать с поведением. Кнопка есть и её не может не быть. Если не заморачиватся с интерфейсом, то конечно, проще сделать его модальным (окно) с кнопочкой закрытия. Но мы не ищем лёгких путей.......Пример программы The BAT. Пруд пруди почтовых клиентов, однако популярность бата, по моему мнению, обусловленно именно юзабилити. И функционал здесь нипричем

Последовательность событий: нажатие мыши -> закрытие popup окна -> нажатие кнопки. Если сигнал закрытия соединить с enabled кнопки (QueuedConnection), то на момент нажатия кнопка еще disabled и повторного открытия не произойдет.  

Итак, сделал вариант с disable + Qt::QueuedConnection.Работает. Скажем так, в принципе пойдёт. Не совсем так уж чтобы красиво. Ну представте, вы нажимаете меню File, вываливается само меню, а File стал заблокированым...... Спасибо (это не сарказм).

Хех. Не. Не работает. Подсознание не позволяло нажать на кнопочку disabled чтобы протестировать. Если я нажимаю на нее (disabled), окно пропадает, она становится enable и срабатывает событие, окно опять появляется


Название: Re: Popup window and button
Отправлено: Igors от Октябрь 29, 2018, 17:29
У вас есть хоть один пример, где этот функционал отсутствует?
Так для юзверя ф-ционал тот же самый, пусть давит на бубочку, окно и закроется. Не нравится  что кнопка стала disabled? Этого можно и не показывать (переставить палитру). Ну или разориться на флажок
Код
C++ (Qt)
void MyButton::SlotPressed( void )
{
 if (!m_flagOpened) {
   ShowPopupWindow();
   m_flagOpened = true;
 }
}
Смысл в том что флажок сбрасывается через QueuedConnection, поэтому когда окно уже закрылось - он еще взведен до окончания текущего события


Название: Re: Popup window and button
Отправлено: Azazello от Октябрь 30, 2018, 09:21
Так для юзверя ф-ционал тот же самый, пусть давит на бубочку, окно и закроется. Не нравится  что кнопка стала disabled? Этого можно и не показывать (переставить палитру). Ну или разориться на флажок
Код
C++ (Qt)
void MyButton::SlotPressed( void )
{
 if (!m_flagOpened) {
   ShowPopupWindow();
   m_flagOpened = true;
 }
}
Смысл в том что флажок сбрасывается через QueuedConnection, поэтому когда окно уже закрылось - он еще взведен до окончания текущего события
QueuedConnection не помогает, сигнал успевает проскочить до сигнала кнопки


Название: Re: Popup window and button
Отправлено: Igors от Октябрь 30, 2018, 10:07
QueuedConnection не помогает, сигнал успевает проскочить до сигнала кнопки
Вот рабочий пример  (аттач)


Название: Re: Popup window and button
Отправлено: Azazello от Октябрь 30, 2018, 10:49
QueuedConnection не помогает, сигнал успевает проскочить до сигнала кнопки
Вот рабочий пример  (аттач)

Обалдеть. Спасибо за решение. Добавлю в коллекцию патернов.

Но особое спасибо за атач, это стОит гораздо большего (ваше время), чем даже само решение.