АК
Александр Кузьминых05 грудня 2017 р. 03:47

Скажи привіт обробнику покажчика Qt Quick

Нам відомо, що протягом кількох років підтримка мульти-тач Qt Quick була неадекватна в багатьох випадках її використання. У нас є PinchArea , для обробки масштабування, обертання та перетягування двома пальцями; та MultiPointTouchArea , яка може використовуватися для відображення будь-якого інтерактивного зворотного зв'язку для точок торкання, або, можливо, ви могли б написати машину станів у JavaScript, щоб розпізнати якийсь жест. Що стосується решти Qt Quick, то основними проблемами є: 1) підтримка подій миші; 2) Qt припускає, що є тільки одна миша («основний покажчик миші»); 3) QMouseEvent і QTouchEvent (і ще кілька) не мають відповідного проміжного базового класу, тому вони доставляють незалежно один від одного; 4), що було складним на ранньому етапі, щоб розглядати події торкання як події миші та доставляти їх однаково. Таким чином, результат полягає в тому, що ви не можете взаємодіяти з двома MouseAreas або Flickables одночасно, наприклад. Також це означає, що ви не можете одночасно натиснути дві кнопки або перетягнути два слайдери одночасно, якщо вони реалізовані за допомогою MouseArea.


Спочатку я сподівався виправити це, зробивши MouseArea та Flickable окремими подіями торкання. Патчі для цього були досить складними, і додавали багато дубльованої логіки для повного паралельного шляху доставки: QMouseEvent взяв би один шлях, а QTouchEvent інший, сподіваючись, що взаємодія працювала б якнайкраще. Це були місяці роботи, і в кінці вона в основному працювала... але було складно зберегти проходження всіх існуючих автотестів, і колеги стурбувалися тим, що це зміна поведінки. MouseArea, проголошена своїм ім'ям, обробляє події миші, тому, як тільки вона почала обробляти події торкання окремо, її ім'я стало неправильно вживаним. Несподівано, ви могли б одночасно натиснути дві кнопки, вкладки або радіокнопки в додатках та наборах елементів керування, які не були призначені для цього. (Отже, ми спробували додати властивість bool, яку можна було б задавати, але потреба його установки в кожній MouseArea була б потворною.) MouseArea і Flickable також повинні багато взаємодіяти, тому зміни повинні були бути зроблені разом, щоб усе працювало. Це було можливо, але не було додано до Qt 5.5 через невизначеність.

Тому врешті-решт ми вибрали інший шлях після того, як ми знайшли розумне поєднання запропонованих ідей.

Одна з ідей полягала в тому, що оскільки ми не можемо реорганізувати ієрархію QEvent (поки не можемо) через мандат сумісності з двійковими даними, ми могли б натомість створити класи-оболонки, які роблять події схожими на те, що ми хочемо , в комплекті з властивостями на благо QML, і доставляти ці класи-оболонки замість звичайних, використовуючи єдиний шлях доставки подій QQuickWindow і QQuickItem.

Інша ідея полягала в усвідомленні того, що динамічне створення та знищення цих подій-оболонок безглуздо: натомість ми стали використовувати пул екземплярів, як ми це робили в інших випадках, коли об'єкт «подія» випромінюється сигналом (наприклад, об'єкт, що випускається MouseArea .positionChanged завжди є одним і тим самим екземпляром, починаючи з Qt 5.8). З цією оптимізацією перенесення однієї події на іншу більше не є великим зниженням продуктивності.

Була висловлена й інша ідея: можливо, було б непогано, якби обробка події з вказівного пристрою була такою ж простою, як використання ключів, з якими пов'язана властивість: наприклад, Mouse.onClicked: {...} або PointingDevice.onTapped: {...} Але незабаром після цього прийшло усвідомлення того, що може бути лише один екземпляр прикріпленої властивості на елемент, до якого він прикріплений. Одна з проблем з MouseArea полягає в тому, що він намагається робити занадто багато, тому немає сенсу просто повторно реалізовувати всі функції в монолітній MouseAttached . Ми хотіли мати здатність обробляти клік або натискання, не переймаючись тим, від якого пристрою вони походять, тому що це те, що потрібно зробити кожному елементу управління Button. Те саме з будь-яким жестом, який може бути виконаний за допомогою миші або одного пальця. Можливо, слід бути одному прикріпленому властивості на жест, а чи не одному тип пристрою?

Оскільки QML є декларативною мовою, приємно мати можливість оголошувати обмеження, а не писати оператори if/else у зворотних викликах JavaScript. Якщо об'єкт, який обробляє події, створений так, що він не піклується про те, від якого пристрою прийшов жест, все ж таки будуть випадки, коли ваш додаток подбає про це: ви хочете виконати різні дії залежно від того, чи натиснутий він на сенсорному екрані або клацнути правою кнопкою миші, або ви хочете зробити щось інше, якщо клавіша керування утримується при перетягуванні об'єкта. Надаючи кілька екземплярів цих об'єктів-обробників, ми можемо оголосити обмеження ними, встановивши властивості. Має бути добре, щоб було стільки випадків, скільки вам потрібно. Кожен екземпляр повинен бути легким, щоб ви не боялися мати надто багато екземплярів. Реалізація має бути на C++, і вона має бути простою та зрозумілою. Кожен обробник повинен робити одне або, найбільше, кілька дуже близьких речей, і робити їх добре.

Наразі ці проблеми відвернули нас від ідеї використання прикріплених властивостей. Натомість ми маємо нове сімейство класів у Qt Quick: обробники покажчиків.

Обробник покажчика - це тип об'єкта, який можна оголосити всередині будь-якого елемента, який обробляє події від вказівних пристроїв від цього елемента. Ви можете оголосити стільки, скільки вам потрібно: як правило, по одному для кожного сценарію взаємодії. Всі загальні обмеження, про які ми могли думати, є декларованими: ви можете змусити оброблювача реагувати тільки в тому випадку, якщо ця подія торкається, тільки для певних кнопок миші, тільки якщо правильна кількість пальців натиснута в межах елемента, тільки якщо спеціальна клавіша-модифікатор і т.д.

Кулі, що перетягуються

Звичайні жести представлені власними типами обробників. Наприклад, якщо ви оголошуєте

Rectangle {
    width: 50; height: 50; color: "green"
    DragHandler { }
}

то у вас є прямокутник, який можна перетягувати по сцені за допомогою миші або торкання, без написання Javascript і навіть без необхідності прив'язувати обробник до батьків. Він має властивість target , а значення за умовчанням є його батьком. (Але, встановивши ціль на інший елемент, ви можете захоплювати події всередині одного елемента, але маніпулювати іншим.)

Звичайно, якщо у вас є два ці зелені прямокутники з DragHandlers всередині, ви можете перетягнути їх обох одночасно різними пальцями.

Кожен обробник покажчика - це QObject, але це не QQuickItem, і він не має занадто багато власних змінних, тому кожен екземпляр приблизно такий самий малий, як і підклас QObject.

Кожний одноточковий обробник має властивість point , щоб надати всі деталі про точку торкання або натискання миші, які ми можемо знайти. Існують властивості pressure та ellipseDiameters : деякі пристрої можуть мати датчики сили, тоді як інші можуть вимірювати розмір контактного шляху (але багато пристроїв цього не надають). Такі пристрої мають властивість velocity , яка гарантовано визначається: ми обчислюємо і усереднюємо швидкість за останні кілька рухів для більш плавної реакції. Наявність доступної швидкості може потенційно активувати чутливі до швидкості жести: можливо, клацання має виконуватися з певною мінімальною швидкістю. (Це правильний спосіб відрізнити клацання від перетягування? Було не так просто зробити цю відмінність раніше.) Або, якщо у вас є швидкість під час відпускання, жест перетягування може закінчитися імпульсом: об'єкт переміщається на коротку відстань в одному напрямку. Це робить ваш інтерфейс живішим. Досі ми не формалізували MomentumAnimation у підтримуваний тип анімації, але є прототип pure-QML у tests/manual/pointer/content/MomentumAnimation.qml.

Віспа

TapHandler обробляє всі жести натискання та відпускання: поодинокі швидкі натискання або клацання, подвійні натискання, інша кількість натискань, утримання натискання протягом періоду часу, що настроюється або утримання його протягом різних періодів часу всіма унікальними способами , (Коли ви торкаєтеся сенсорного екрану, він часто не робить ніякого звуку, але ви можете натиснути кнопку миші, тому ми подумали, що «tap» - це більш надійне майбутнє для цього жесту, ніж «клацання».) Ви можете показати зворотний зв'язок пропорційно тому, наскільки довгим є натискання (коло, що розширюється, індикатор виконання або щось в цьому роді).

Ущипни мене, якщо це правда

Існує PinchHandler . Якщо ви оголосите його всередині елемента, ви зможете масштабувати, повертати та перетягувати цей предмет за допомогою жестів "щипок". Ви можете масштабувати будь-яку частину елемента, яка вам сподобається (покращення PinchArea). Він також може обробляти більше пальців: ви можете оголосити PinchHandler {minimumTouchPoints: 3} , щоб вимагати три-пальцевий жест "щипок". Всі перетворення потім відбуваються щодо центральної точки між трьома пальцями, а масштабування відноситься до середнього збільшення або зменшення поширення між ними. Ідея виходила з того, що деякі версії Ubuntu використовують три-пальцевий щипок для керування вікнами: мабуть, вони думали, що вміст у вікні може бути використаний для жестів з двома пальцями, але більшість додатків не використовують три пальці, так що це нормально, щоб зарезервувати три-пальцевий щипок для масштабування та переміщення вікон навколо робочого столу. Тепер, оскільки ви можете написати композитор Wayland QML, ви можете легко відтворити цей досвід.

Добираємося до точок

Нарешті, є PointHandler . На відміну від інших він не маніпулює своїм цільовим елементом: він існує тільки для того, щоб надати властивість point. Він схожий на окремий TouchPoint в MultiPointTouchArea і може використовуватися з тією ж метою: забезпечити інтерактивний зворотний зв'язок як точок торкання або курсор миші, що переміщається сценою. На відміну від MultiPointTouchArea, він захоплює точки дотику або мишу не ексклюзивно, тому наявність цього інтерактивного зворотного зв'язку не перешкоджає взаємодії з іншими обробниками в інших елементах одночасно. В анімації на цій сторінці він використовується, щоб змусити спрайт пальців стежити за моїми пальцями.

Це вже все?

Тепер я перейду до причин, чому цей матеріал знаходиться в Tech Preview в 5.10. Одна з причин полягає в тому, що він неповний: у нас, як і раніше, відсутня підтримка наведення покажчика миші, колеса миші та стілусів планшетів (на даний момент стілус як і раніше розглядається як миша). Жоден із обробників не чутливий до швидкості. Ми можемо уявити ще кілька обробників, які могли б бути написані. Повинен існувати відкритий C++ API, щоб ви могли створювати власні. Обробники і Flickable трохи ладнають, але Flickable - складний монолітний Предмет, і ми думаємо, що він може бути реорганізований пізніше. Існує ручний тест FakeFlickable , який показує, як можна відтворити більшу частину своєї функціональності в QML із двома звичайними елементами, а також із DragHandler та кількома анімаціями.

Інша причина – найменування. «Обробники покажчиків» звучать нормально в ізоляції, але існує вже існуюча термінологія, яка робить її заплутаною: покажчик може бути змінною, яка вказує на комірку пам'яті (але це не те, що ми маємо на увазі тут), і обробник може бути сортуванням функції зворотного виклику, який ви пишете в JavaScript. Якщо ви пишете TapHandler {onActiveChanged: ...} , тоді ви скажете, що ваш обробник має обробник? Натомість ми могли б використовувати слово "зворотний виклик", але в деяких колах це анахронізм, а в QML наші звички зараз важко змінити.

Інша причина полягає в тому, що QtLocation має деякі складні варіанти використання, які ми хочемо використовувати як приклад, щоб довести, що можна переміщати карту (і будь-який інтерактивний контент на неї) з невеликою кількістю коду, що читається.

Можливо, я продовжу це пізніше з іншого повідомлення про інший спосіб розпізнавання жестів і про те, як це може вплинути на те, як ми думатимемо про обробників покажчиків у майбутньому. Я ще не пояснив концепції пасивного захоплення. Існує також більше відомостей про те, як створювати компоненти, які внутрішньо використовують обробники покажчиків, але при цьому автору авторських прав за потреби можна перевизначити поведінку.

Отже, зараз обробники покажчиків перебувають у Tech Preview о 5.10. Ми сподіваємося, що ви довго з ними гратиметеся. Особливо якщо у вас є якісь старі розчарування щодо сценаріїв взаємодії, які раніше не були можливі. Більше того, якщо ви коли-небудь хотіли створити сенсорний інтерфейс користувача (можливо, навіть розрахований на багато користувачів?) Без написання C++ event-forwarding і QObject-event-filtering бруду. Нам потрібно почати отримувати відгуки від усіх з унікальними варіантами використання, у той час як ми маємо свободу вносити великі зміни, якщо це необхідно, щоб полегшити вам роботу.

Досі приклади використання в основному були у tests/manual/pointer . Тестовий вихідний код не входить до пакета збирання релізів, тому, щоб спробувати їх, вам потрібно завантажити вихідні пакети Qt або отримати їх з репозиторію git . Деякі з них можна перетворити на приклади для майбутніх випусків.

Так як це в технічному перегляді, реалізація продовжить удосконалюватися під час серії 5.10, тому слідуйте за гілка 5.10 git , щоб не відставати від останніх функцій та виправлень помилок.

Стаття написана: Shawn Rutledge | Четвер, Листопад 23, 2017р.

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
Дмитрий

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:60бали,
  • Рейтинг балів-1
Дмитрий

C++ - Тест 003. Условия и циклы

  • Результат:92бали,
  • Рейтинг балів8
d
  • dsfs
  • 26 квітня 2024 р. 04:56

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
Останні коментарі
k
kmssr08 лютого 2024 р. 18:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 01:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 грудня 2023 р. 10:30
Boost - статичне зв&#39;язування в проекті CMake під Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 грудня 2023 р. 08:38
Boost - статичне зв&#39;язування в проекті CMake під Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik18 грудня 2023 р. 21:01
Qt/C++ - Урок 056. Підключення бібліотеки Boost в Qt для компіляторів MinGW і MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Тепер обговоріть на форумі
G
George1307 травня 2024 р. 00:27
добавить qlineseries в функции в функции: "GPlotter::addSeries(QString title, QVector &arr)" я вызываю метод setChart(...), я в конструктор передал адрес на QChartView элемент
BlinCT
BlinCT05 травня 2024 р. 05:46
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
PS
Peter Son03 травня 2024 р. 17:57
Best Indian Food Restaurant In Cincinnati OH Ready to embark on a gastronomic journey like no other? Join us at App india restaurant and discover why we're renowned as the Best Indian Food Restaurant In Cincinnati OH . Whether y…
Evgenii Legotckoi
Evgenii Legotckoi02 травня 2024 р. 14:07
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
IscanderChe
IscanderChe30 квітня 2024 р. 04:22
Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…

Слідкуйте за нами в соціальних мережах