Russian Qt Forum
Ноябрь 22, 2024, 10:28 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Драг  (Прочитано 6721 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Ноябрь 09, 2018, 14:12 »

Добрый день

Юзер выделяет мышью пр-к в окне (QRect). Это действие реализовано "модально" (ну почти, псевдокод)
Код
C++ (Qt)
while (MouseDown()) {
 QPoint pt = GetMousePos();
 ...
}
return selectedRect;
И этот код повторяется десятки раз (если не сотни), и пишется еще и еще. Вот какой ф-ционал обычно реализован

- ну естественно надо вернуть результат QRect (если драг не состоялся, то пустой)

- почти всегда надо рисовать пр-к драга (образец - QRubberBand)

- почти всегда есть еще пр-к "ограничитель" (выделение возможно только внутри него)

- часто (по меньшей мере в половине случаев) есть autoScroll, т.е. если мыша оказалась за пределами "ограничителя" - область просмотра скроллится по вертикали/горизонтали

 Есть ли смысл это обобщить? Если да, то как Вы видите общие классы?

Спасибо
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Ноябрь 12, 2018, 09:26 »

И молчок Улыбающийся Ну хорошо хоть нет вопросов типа "а для чего нужно выделять мышью ?". Ладно, попробуем с чего-то начать. Простецкий вариант: да написать просто ф-цию (утилиту) - и все дела. Напр
Код
C++ (Qt)
QRect ExecDragRect(
   const QPoint & startPt,   // точка начала драга
   const QRect * limitR      //  ограничивающий пр-к (can be NULL)
);
Очень неплохо, ф-ция сама разберется с мышью и с отрисовкой пр-ка (это верхнее "overlay" окно). Кстати в старом ОС подобная ф-ция была. Можно еще добавить параметров, напр "минимальный" пр-к и.т.п. - но это не принципиально.

Чего не хватает? Вот autoScroll'а никакого нет, добрая половина случаев не покрывается. Ну понятно как/что скроллить - ф-ция знать не должна. Опять пойдем по пути наименьшего сопротивления: добавим аргумент QWidget/QObject и пусть ф-ция пуляет в него сигналами. 

Что Вы об этом думаете?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #2 : Ноябрь 14, 2018, 16:16 »

Ну я бы сделал классик-контроллер драга с соответствующими полями и функционалом.
И пусть он сигналы и "пуляет", что то типа
emit dragRectChanged(QRectF newRect);
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Ноябрь 14, 2018, 17:08 »

Ну я бы сделал классик-контроллер драга с соответствующими полями и функционалом.
И пусть он сигналы и "пуляет", что то типа
emit dragRectChanged(QRectF newRect);
Впервые слышу о классик-контроллере, просветите. Ну и вообще развейте мысль, а то так.. намек.

Да, и это Вы к молодняка переняли моду подавать структуры по значению?  Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Ноябрь 14, 2018, 18:06 »


Да, и это Вы к молодняка переняли моду подавать структуры по значению?  Улыбающийся

Ну это зависит от того, что передавать. Qrect пожалуй не стоит, а вот QPoint или там QStringView - пожалуйста
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #5 : Ноябрь 14, 2018, 20:25 »

Ну я бы сделал классик-контроллер драга с соответствующими полями и функционалом.
И пусть он сигналы и "пуляет", что то типа
emit dragRectChanged(QRectF newRect);
Впервые слышу о классик-контроллере, просветите. Ну и вообще развейте мысль, а то так.. намек.

Да, и это Вы к молодняка переняли моду подавать структуры по значению?  Улыбающийся

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

Насчет контроллера - я имел в виду, сделать отдельный класс, что то типа CRectDragController, который собственно должен обрабатывать мышиные события и отправлять в мир сигнал "рект поменялся, товарищи!" Ну наверное и рект этот самый отрисовывать, если в этом задача.

как то так...
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Ноябрь 15, 2018, 05:35 »

Насчет контроллера - я имел в виду, сделать отдельный класс, что то типа CRectDragController, который собственно должен обрабатывать мышиные события и отправлять в мир сигнал "рект поменялся, товарищи!" Ну наверное и рект этот самый отрисовывать, если в этом задача.

как то так...
Так собсно это уже и реализовано в приведенном выше псевдокоде. MouseDown крутит вторичный цикл (processEvents) блокируя клаву и возвращает true если мышь двинулась или false если кнопка мыши отпущена. Простой драг выглядит так
Код
C++ (Qt)
QPoint startPt = GetMousePos();
QRect limitR = GetBounds();         // пр-к ограничитель
COverShape  shape(type_Rect);    // индикатор (окно) выделения          
QRect oldR = MkRect(startPt, startPt, &limitR);                          
while (MouseDown()) {
 QRect dragR = MkRect(startPt, GetMousePos(), &limitR);
 if (dragR == oldR) continue;     // ничего не изменилось
 oldR = dragR;
 shape.Adjust(dragR);
// emit dragRectChanged(dragR);  // ???
}
// выделение закончено, обрабатываем рез-т
....
 
Ну ладно, втулим сюда сигнал "рект поменялся". Что получатель будет с ним делать? Организовывать autoScroll ему все равно придется с нуля - брать текущую позицию мыша, смотреть оказалась ли она за пределами области прокрутки (и насколько), заводить (или глушить) таймер и.т.п. Уникален только сам скролл (когда пришло событие таймера), а остальной ф-ционал явно общий - куда его поселить?

Еще такой момент. Вот напр переставляются строки в дереве. Здесь "выделения" как такового нет, и логика навороченная, как-то тулить ее каллбэком в класс-контроллер мне не хочется. А вот песня с autoScroll та же самая. Надо как-то сделать чтобы "добро не пропадало"
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #7 : Ноябрь 15, 2018, 11:34 »

Пусть базовый класс контроллера тогда и реализует обработку мыши и автоскролл вьюпорта.
А уже наследники его могли бы переопределить метод (вместо сигнала) типа

virtual void OnDragRegionChanged(const QRect& newRect)

и иметь в нем специфичную логику, как, например, выделение в дереве.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Ноябрь 15, 2018, 13:43 »

Пусть базовый класс контроллера тогда и реализует обработку мыши и автоскролл вьюпорта.
А как он его реализует? В результате скролла должна измениться стартовая точка драга (startPt) - сместиться в противоположную сторону(ы) на число "проскролленных пыкселей" - а откуда это смещение взять? Причем скролл произойдет по таймеру, MouseDown на него не среагирует.
А уже наследники его могли бы переопределить метод (вместо сигнала) типа

virtual void OnDragRegionChanged(const QRect& newRect)

и иметь в нем специфичную логику, как, например, выделение в дереве.
Ну для выделения в дереве QRect не годится - интересует подрезанная (клипом) текущая точка мыша (куда вставлям). Ну и организация классов неудобна. Хотелось бы сделать этот драг просто методом конкретного окна, там объявить на стеке контроллер чтобы делал черновую работу. А тут - наследоваться от контроллера, перекрывать виртуал, а из него опять лезть к методам окна. Коряво
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #9 : Декабрь 15, 2018, 02:53 »

1. ну тут просто смотрим,  за какую из границ порта вылезли мышом, и по таймеру скролим в обратном направлении на фиксированное кол.во пикселей.

2. тут не понял, что значит контроллер на стеке.?
« Последнее редактирование: Декабрь 15, 2018, 02:56 от Racheengel » Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Декабрь 15, 2018, 18:57 »

2. тут не понял, что значит контроллер на стеке.?
За истекший месяц успел не только сделать, но и основательно забыть Улыбающийся Что помню: нужно сделать класс гибким, в простом случае он делает все автоматом
Код
C++ (Qt)
QPoint startPt = GetMousePos();
QRect limitR = GetBounds();  
bool createDragShape = true;
CDragControl ctl(widget, startPt, limitR, createDragShape);  // вот этот контроллер на стеке
QRect selection = ctl.Exec();
Возвращает выделенный rect. В более сложном случае берем драг на себя, а контроллер используем для аутоскролла
Код
C++ (Qt)
CDragControl ctl(widget, startPt, limitR, createDragShape);  
while (MouseDown()) {
 QPoint pt = GetMousePos();
 bool changed = ctl.Update(pt);
 if (changed) {
  ...
}
 
Метод CDragControl::Update( QPoint & pt )  разберется с текущей позицией мыша, загонит ее в пр-к ограничитель и отскроллит если надо. Ну конечно "ретроспективно" (есть такое вумное словечко) это кажется совсем простым  Улыбающийся

1. ну тут просто смотрим,  за какую из границ порта вылезли мышом, и по таймеру скролим в обратном направлении на фиксированное кол.во пикселей.
А откуда возьмете "кол-во пикселей"? Как минимум нужен скроллбар (а его часто и нет, скролл = пробел + драг) + шаг скролла (напр может скроллиться по айтемам). Собсно я тоже ничего не придумал и решил не связываться ни с какими обобщениями. Для каждого конкретного окна пишу ф-цию
Код
C++ (Qt)
virtual bool СDragControl::AutoScroll( QWidget * widget, int dx, int dy);
Где dx/dy - насколько мышь вылез за пределы. В ф-ции выходит до 20 строк. Ну и наследуюсь от  СDragControl.

Мда, что-то не густо с "логикой гуя", не густо..
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.146 секунд. Запросов: 23.