АК
Александр Кузьминых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
AD

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

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

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

  • Результат:80бали,
  • Рейтинг балів4
m
  • molni99
  • 26 жовтня 2024 р. 01:29

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

  • Результат:20бали,
  • Рейтинг балів-10
Останні коментарі
ИМ
Игорь Максимов22 листопада 2024 р. 11:51
Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 жовтня 2024 р. 14:37
Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 жовтня 2024 р. 08:19
Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов05 жовтня 2024 р. 07:51
Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas505 липня 2024 р. 11:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Тепер обговоріть на форумі
Evgenii Legotckoi
Evgenii Legotckoi24 червня 2024 р. 15:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 листопада 2024 р. 06:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject04 червня 2022 р. 03:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9Anonim25 жовтня 2024 р. 09:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

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