Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Igors от Июль 02, 2017, 13:38



Название: Выбрать всех
Отправлено: Igors от Июль 02, 2017, 13:38
Добрый день

Простенькая задачка, но не удалось сделать "чисто" (пришлось прибегать к dynamic_cast).

Есть пункт меню "Select All" который должен срабатывать по стандартной комбинации Cmd+A (Ctl+A на Вындоуз). Если действие не имеет эффекта - этот пункт должен быть задизаблен. Ну вроде без проблем, сделал так
Код
C++ (Qt)
// virtual
bool MyBaseWindow::CanSelectAll( void ) const
{
// возвращает true если QLineEdit, QTreeWidget или еще что в фокусе
}
 
// virtual
void MyBaseWindow::DoSelectAll( void )
{
// применяет к текущему фокусу
}
Ну и зову эти методы когда обновляю меню. Но, как всегда, нашлось  маааленькое но мерзкое исключение. Для одного окна нужна доп возможность - если нажато Alt то должны выбираться все айтемы в дереве, иначе - только те кто не имеет флажка Locked. Необязательно что в фокусе будет дерево - другие контролы там тоже есть. Ну и если Alt нажат то надо в меню поменять текст "Select All + Locked". Как быстро развалилась моя стройная система из 2 виртуалов  :) Наверное я что-то не так делаю?  :)

Спасибо


Название: Re: Выбрать всех
Отправлено: Racheengel от Июль 02, 2017, 15:46
а нельзя это сделать дополнительным пунктом меню?

Ctrl+A: "Select All except Locked"
Ctrl+Alt+A: "Select All + Locked"


Название: Re: Выбрать всех
Отправлено: Igors от Июль 02, 2017, 16:18
а нельзя это сделать дополнительным пунктом меню?

Ctrl+A: "Select All except Locked"
Ctrl+Alt+A: "Select All + Locked"
Он имеет смысл только для одного окна, для десятков других никаких locked нет. Хотя в официальной доке apple (якобы) "не рекомендует" модифицировать меню по клавишам - это делают все, и Finder первый :)


Название: Re: Выбрать всех
Отправлено: Racheengel от Июль 03, 2017, 01:12
Мне вот сама идея, честно говоря, не оч. понятна - если юзер зажал Альт, то изменить пункт меню...
Но какой смысл юзеру лезть в меню, зажав альт? Кто так делает? В винде по альту, например, меню пропадает (стандартное поведение).
Поэтому я бы все же 2 пункта сделал. Плюс еще статус-тип показал - поведение то нестандартное..


Название: Re: Выбрать всех
Отправлено: Igors от Июль 03, 2017, 07:41
Мне вот сама идея, честно говоря, не оч. понятна - если юзер зажал Альт, то изменить пункт меню...
Но какой смысл юзеру лезть в меню, зажав альт? Кто так делает?
На каждой платформе существует стандартная практика, и лучше ее придерживаться (а не велосипедить). Уверяю Вас что пользователь Мас сразу же облапает меню со всеми Cmd, Alt, Shift - и всеми их комбинациями. Я же не спрашиваю (и не выражаю неудовольствия) почему в линуксе надо чего-то долбить в командной строке - ну значит там так надо.

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

Ну и вообще-то вопрос был о взаимодействии классов  :)


Название: Re: Выбрать всех
Отправлено: Racheengel от Июль 04, 2017, 17:19
Уверяю Вас что пользователь Мас сразу же облапает меню со всеми Cmd, Alt, Shift - и всеми их комбинациями.

Ну и что? Увидит 2 пункта выбора - чем это мешает? По крайней мере не надо будет ему додумывать, что "а тут же еще альт нада зажать..."

А вообще в меню 99% населения мышом лазят, без альтов и шифтов :)

По поводу структуры классов - я бы наоборот делал - пусть активное окно заполняет меню, а не наоборот. Т.е. окно - контроллер, меню - slave.


Название: Re: Выбрать всех
Отправлено: Igors от Июль 05, 2017, 04:57
Ну и что? Увидит 2 пункта выбора - чем это мешает? По крайней мере не надо будет ему додумывать, что "а тут же еще альт нада зажать..."

А вообще в меню 99% населения мышом лазят, без альтов и шифтов :)
Ладно, толку все равно не будет (с ответом на изначальный вопрос), давайте покалякаем о принципах ГУЯ  :)

Пример: в меню есть пункт Plugins в нем "Plugin 1", "Plugin 2"... "Plugin N"  (сколько нашли на диске). Юзер выбрал плагин из меню - он подключился. Возможно плагин открыл свое окно, но может и нет. Все хорошо. Но вот начинаются мелкие пакости: нужно не подключать плагин, а посмотреть его "About". Плагин имеет интерфейс типа GetInformation возвращающий строку описания, но об UI он может и ничего не знать. Понятно что то "About" нужно в году раз - но нужно.

Решение в духе Mac: открываем меню с зажатой клавишей, теперь уже там "About Plugin 1", "About Plugin 2"... "About Plugin N", выбираем, смотрим About. Лаконично и изящно.

Решение в духе Вындоуз.... а затрудняюсь указать :) Придется наверное тащить "корову на баню" - делать отдельное окно в котором будет список плагинов (чтобы там иметь кнопку About) или вообще отказаться от размещения плагинов в меню. Зато мы точно знаем что делает 99% юзеров  :)  



Название: Re: Выбрать всех
Отправлено: Old от Июль 05, 2017, 06:45
Да уж, "лаконично и изящно". :)
А если плагинов 1000 штук, несчастный пользователь начнет получать неописуемые удовольствия, пытаясь найти нужный плагин в меню. :)


Название: Re: Выбрать всех
Отправлено: Racheengel от Июль 05, 2017, 10:35
Вот у меня как то тоже "дружественность" макаки часто вызывала вопросы и не только...
Нужен нормальный плагин-менеджер, где их можно включить-выключить, глянуть версии, описания и пр.


Название: Re: Выбрать всех
Отправлено: Igors от Июль 05, 2017, 11:01
Нужен нормальный плагин-менеджер, где их можно включить-выключить, глянуть версии, описания и пр.
Ну так это то самое "окно ради кнопки About" о котором я говорил. Понты "плагин-менеджер" опускаем. Включить-выключить тоже за уши притянуто. Что осталось?

Вот у меня как то тоже "дружественность" макаки часто вызывала вопросы и не только...
С "макакой" аккуратнее пожалуйста - я же не употребляю выражений типа "вындозная срань" и.т.п. :) Здесь просто "довлеет" накопленный опыт. типа
Цитировать
Учиться легко - переучиваться трудно


Название: Re: Выбрать всех
Отправлено: Old от Июль 05, 2017, 11:04
Ну так это то самое "окно ради кнопки About" о котором я говорил. Понты "плагин-менеджер" опускаем. Включить-выключить тоже за уши притянуто. Что осталось?
Например, некоторые плагины можно настраивать. Добавим вход в меню с другой зажатой кнопкой? :)

Включить-выключить тоже за уши притянуто.
Да ну ладно.
Если бы в том же QtCreatore не было возможности отключать плагины из командной строки, то его в некоторых случаях было бы невозможно запустить вовсе. :)
А менеджер плагинов, с возможностью вкл/выкл, позволяет иметь разные решения для одних и тех же задач. На примере того же QtCreator, пользователь может выбирать какой бэкэнд будет использоваться для разбора кода, или пользователь может включить только используемые им системы сборки... Много может быть возможностей.


Название: Re: Выбрать всех
Отправлено: Авварон от Июль 05, 2017, 11:30
Добрый день

Простенькая задачка, но не удалось сделать "чисто" (пришлось прибегать к dynamic_cast).

Есть пункт меню "Select All" который должен срабатывать по стандартной комбинации Cmd+A (Ctl+A на Вындоуз). Если действие не имеет эффекта - этот пункт должен быть задизаблен. Ну вроде без проблем, сделал так
Код
C++ (Qt)
// virtual
bool MyBaseWindow::CanSelectAll( void ) const
{
// возвращает true если QLineEdit, QTreeWidget или еще что в фокусе
}
 
// virtual
void MyBaseWindow::DoSelectAll( void )
{
// применяет к текущему фокусу
}
Ну и зову эти методы когда обновляю меню. Но, как всегда, нашлось  маааленькое но мерзкое исключение. Для одного окна нужна доп возможность - если нажато Alt то должны выбираться все айтемы в дереве, иначе - только те кто не имеет флажка Locked. Необязательно что в фокусе будет дерево - другие контролы там тоже есть. Ну и если Alt нажат то надо в меню поменять текст "Select All + Locked". Как быстро развалилась моя стройная система из 2 виртуалов  :) Наверное я что-то не так делаю?  :)

Спасибо

Ну вообще самое простое решение - в ваших виртуалах взять значение QGuiApplication::keyboardModifiers и проверить, зажат ли альт.


Название: Re: Выбрать всех
Отправлено: Igors от Июль 05, 2017, 12:03
Ну вообще самое простое решение - в ваших виртуалах взять значение QGuiApplication::keyboardModifiers и проверить, зажат ли альт.
Злополучное окно-исключение проверило и вернуло true в CanSelectAll, а толку? Tекст в меню меняет не оно само, а вызывающий CanSelectAll. А когда меню открылось - Alt может быть и отпущен до выбора пункта.

"Вызываюший" у меня наследник QApplication. Все изменения в меню выполняются когда юзер нажал в меню бар. Полемика "а нужно ли их менять" беспердметна, по меньшей мере их надо enabled/disabled. Суетиться с этим до открытия меню (всякий раз на изменение данных) явно плохо. С шорткатами там тоже интересно - но то уже др тема.

Рассматривал такой вариант
Код
C++ (Qt)
bool MyBaseWindow::CanSelectAll( QString * txt ) const;
void MyBaseWindow::DoSelectAll( const QString & txt );
 
Ну типа окно может сказать какой текст в меню, а потом его же и использовать. Ну не знаю, как-то смотрится не очень...


Название: Re: Выбрать всех
Отправлено: Авварон от Июль 05, 2017, 16:09
Да нет, вполне норм. Надо только методу переделать название на более логичное.
Код:
std::tuple<bool /*can select*/, QString /*text*/, QVariant /*hint*/> MyBaseWindow::selectionInfo() const;
void MyBaseWindow::DoSelectAll( const QVariant & hint );

Можно вместо тупеля структурку передавать.


Название: Re: Выбрать всех
Отправлено: Old от Июль 05, 2017, 16:23
Можно вместо тупеля структурку передавать.
Можно добавить еще один метод:
Код
C++ (Qt)
QString itemName() const;
возвращающий строку для пункта меню.


Название: Re: Выбрать всех
Отправлено: Racheengel от Июль 05, 2017, 22:35
Я бы сделал так: само приложение ничего не знает про пункты меню.
Когда конкретное окно активируется, оно само добавляет в меню свои экшены (Select All etc).
Пока окно активно, оно имеет доступ к экшенам и может их модифицировать при необходимости.
При деактивации окна, оно подчищает экшены из меню.
Таким образом можно реализовать очень гибкое поведение.


Название: Re: Выбрать всех
Отправлено: Old от Июль 06, 2017, 06:53
Я бы сделал так: само приложение ничего не знает про пункты меню.
Когда конкретное окно активируется, оно само добавляет в меню свои экшены (Select All etc).
Пока окно активно, оно имеет доступ к экшенам и может их модифицировать при необходимости.
При деактивации окна, оно подчищает экшены из меню.
Таким образом можно реализовать очень гибкое поведение.
IMHO, лучше все таки, что бы меню формировалось централизовано, например, главным окном приложения. А активное окно отдавало бы указатели на свои QAction, которыми и управляло самостоятельно (дизаблило, изменяло текст и т.д.). Тогда одни и те-же экшены можно было бы использовать при формировании менюбара, настройки тулбара, формировании контекстных меню.


Название: Re: Выбрать всех
Отправлено: Igors от Июль 06, 2017, 08:35
Да нет, вполне норм. Надо только методу переделать название на более логичное.
Код:
std::tuple<bool /*can select*/, QString /*text*/, QVariant /*hint*/> MyBaseWindow::selectionInfo() const;
void MyBaseWindow::DoSelectAll( const QVariant & hint );

Можно вместо тупеля структурку передавать.
Да, такого можно нагородить много. Но меня смущает что вся эта арматура заряжается на один-единственный частный случай с Select, Вряд ли тут будет какая-то движуха в течение неск лет. Зато в др айтемах она возможна (напр CanCopy, CanPaste и др) - там очень хорошо показать чего копируем/пастим

Я бы сделал так: само приложение ничего не знает про пункты меню.
Когда конкретное окно активируется, оно само добавляет в меню свои экшены (Select All etc).
Пока окно активно, оно имеет доступ к экшенам и может их модифицировать при необходимости.
При деактивации окна, оно подчищает экшены из меню.
Таким образом можно реализовать очень гибкое поведение.
Окно может всяко-разно менять текущие данные, напр тот же select, вот он был - и уже нет. Поэтому порешать все в момент активации окна не удается. А бегать всякий раз апдейтить меню - нереально. Да и действия могут быть перекрыты напр floating окном или вообще модальным диалогом. 


Название: Re: Выбрать всех
Отправлено: Igors от Июль 07, 2017, 05:56
Да, забыл напомнить: вызовы CanSelectAll и DoSelectAll разорваны по времени. Получить какие-то данные от CanSelectAll можно, но их придется где-то хранить, а главное - обеспечить их "релевантность". В моем варианте QString - текст самого пункта меню


Название: Re: Выбрать всех
Отправлено: panAlexey от Июль 07, 2017, 08:22
Ну и что? Увидит 2 пункта выбора - чем это мешает? По крайней мере не надо будет ему додумывать, что "а тут же еще альт нада зажать..."

А вообще в меню 99% населения мышом лазят, без альтов и шифтов :)
Ладно, толку все равно не будет (с ответом на изначальный вопрос), давайте покалякаем о принципах ГУЯ  :)

Пример: в меню есть пункт Plugins в нем "Plugin 1", "Plugin 2"... "Plugin N"  (сколько нашли на диске). Юзер выбрал плагин из меню - он подключился. Возможно плагин открыл свое окно, но может и нет. Все хорошо. Но вот начинаются мелкие пакости: нужно не подключать плагин, а посмотреть его "About". Плагин имеет интерфейс типа GetInformation возвращающий строку описания, но об UI он может и ничего не знать. Понятно что то "About" нужно в году раз - но нужно.

Решение в духе Mac: открываем меню с зажатой клавишей, теперь уже там "About Plugin 1", "About Plugin 2"... "About Plugin N", выбираем, смотрим About. Лаконично и изящно.

Решение в духе Вындоуз.... а затрудняюсь указать :) Придется наверное тащить "корову на баню" - делать отдельное окно в котором будет список плагинов (чтобы там иметь кнопку About) или вообще отказаться от размещения плагинов в меню. Зато мы точно знаем что делает 99% юзеров  :)  

сморим на firefox, пункт меню дополнения и делаем так для всех платформ.
там список плагинов с кнопками управления.


Название: Re: Выбрать всех
Отправлено: Igors от Июль 07, 2017, 09:20
сморим на firefox, пункт меню дополнения и делаем так для всех платформ.
там список плагинов с кнопками управления.
Плагины всякие бывают, не всегда это что-то типа "службы". У меня это просто "объект" (напр сфера) который создается на ходу (а не грузится из файла). Юзер добавит его 5 раз - получит 5 новых сфер. Что ж он, 5 раз должен окно открыть? И включить-выключить никакого нет, удалит все созданные сферы, ну dll'ка и выгрузится.

Всегда найдутся опции которые юзаются редко, валить все подряд в меню рано или поздно захлебнется, что-то делать придется


Название: Re: Выбрать всех
Отправлено: Авварон от Июль 07, 2017, 11:30
Окно может всяко-разно менять текущие данные, напр тот же select, вот он был - и уже нет. Поэтому порешать все в момент активации окна не удается. А бегать всякий раз апдейтить меню - нереально. Да и действия могут быть перекрыты напр floating окном или вообще модальным диалогом. 

Йа писал в свое время манагер экшнов. Вкратце, идея была такая - есть построенное меню в экшонами. Все экшоны имеют ид (например, "copy", "selectAll").
Некоторые виджеты имеют добавленные в них экшоны (QWidget::addAction). Если нам нужен функционал копипасты, добавляем в виджет 2 экшона "copy", "paste".
Далее, при смене фокуса пробегаемся от текущего виджета в фокусе в верх по дереву и соединяем экшоны из виджетов с экшонами в меню. Те экшоны, которые в меню остались без соединения "гасим" (дизейблим или прячем (setVisible(false)).
Ваш функционал реализуется следующим образом - пихаем в меню два экшона - "selectAll","selectAllAlt". И в виджет два экшона. При показе меню проверяем флажок что экшон "альтернативный" и прячем или показываем.
Но это много кода писать.


Название: Re: Выбрать всех
Отправлено: Igors от Июль 07, 2017, 12:44
Если нам нужен функционал копипасты, добавляем в виджет 2 экшона "copy", "paste"...
...И в виджет два экшона.
Ой нет, такой хоккей нам не нужен

Йа писал...
Цитировать
- Ванька!
- Я!
- Это ты костер развел?
- Я..
- Туши быстро, немцы увидят, прилетят
- Йа-Йа