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

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

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

Сообщений: 1805



Просмотр профиля WWW
« : Январь 14, 2014, 03:53 »

Описание алгоритма:
Если при перемещении или изменения размера окна расстояние между краем рабочего стола и окном меньше какого то значения, то перемещаем окно к тому краю.

Создал наследника QWidget, переопределил методы resizeEvent и moveEvent, доступ к геометрии рабочего стола получал через QDesktopWidget().availableGeometry(). Понял, что применение алгоритма в resizeEvent и moveEvent плохая идея - вызывается бесконечная рекурсия, а других идей нет Грустный

Как решить эту проблему? Улыбающийся
Записан

Bepec
Гость
« Ответ #1 : Январь 14, 2014, 06:59 »

Просто посылайте сигнал при ресайзе, мовинге. А в принимаемом слоте уже рассчитывайте всё.

У меня аналогичный класс так и работает - у родителя перехватывается resize и move, которые посылают сигнал "прилипалкину". А там уже вызывается слот, который рассчитывает, учитывает состояние (прилип, не прилип) и перемещает.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #2 : Январь 14, 2014, 07:45 »

Просто посылайте сигнал при ресайзе, мовинге. А в принимаемом слоте уже рассчитывайте всё.

У меня аналогичный класс так и работает - у родителя перехватывается resize и move, которые посылают сигнал "прилипалкину". А там уже вызывается слот, который рассчитывает, учитывает состояние (прилип, не прилип) и перемещает.
Только, наверное, стоит сказать, что connect нужно делать с Qt::QueuedConnection, иначе опять получишь рекурсию.
Имхо, зарядить таймер будет проще.

Кстати, в обработчиках событий за исключением таймерных в любом тулките нужно стараться избегать действий приводящих к генерации новых событий.
Это аксиома)
« Последнее редактирование: Январь 14, 2014, 07:48 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #3 : Январь 14, 2014, 08:00 »

А можно подробнее насчет таймера? Улыбающийся
Записан

GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #4 : Январь 14, 2014, 08:12 »

А можно подробнее насчет таймера? Улыбающийся
int QObject::startTimer ( int interval )
Записан

Qt 5.11/4.8.7 (X11/Win)
Bepec
Гость
« Ответ #5 : Январь 14, 2014, 08:19 »

Ну не знаю, в любом случае будет вызов слота и соединение.

Но принцип тот же. Что отделяем зёрна от плевел. Или ставим задачу в очередь (сигнал), или ставим таймер в очередь Веселый
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #6 : Январь 14, 2014, 08:37 »

Ну не знаю, в любом случае будет вызов слота и соединение.
С чего это? Разве разговор шел про QTimer?

Цитировать
Но принцип тот же. Что отделяем зёрна от плевел. Или ставим задачу в очередь (сигнал), или ставим таймер в очередь Веселый
Не всегда удобно, да и излишне для своих внутренних дел самому испускать и обрабатывать свои же сигналы.
Записан

Qt 5.11/4.8.7 (X11/Win)
Bepec
Гость
« Ответ #7 : Январь 14, 2014, 08:52 »

Тогда я тоже заинтересован. Как же тогда обрабатывать таймер?

Я вижу варианты:
1) проверочный цикл.
2) слот timerEvent.

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

Сообщений: 2921



Просмотр профиля
« Ответ #8 : Январь 14, 2014, 10:22 »

2) слот timerEvent.
Только это не слот, а
Код
C++ (Qt)
void QObject::timerEvent ( QTimerEvent * event ) [virtual protected]
и в выше приведённой ссылке есть пример.
Записан

Qt 5.11/4.8.7 (X11/Win)
Bepec
Гость
« Ответ #9 : Январь 14, 2014, 10:31 »

Каюсь, глаз замылился Улыбающийся
Тоже вариант.

С таймером  быстрее, но тут решать нужно самому. Кому то понятнее сигналы, кому то таймер. Хотя попробовать надо как нить. Ни разу не использовал его так.
Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #10 : Январь 14, 2014, 11:53 »

Для максимального приближения к реальной задачи написал окно без системной рамки - MovableWindow.
От него отнаследовался и в наследнике реализовал вот такой алгоритм. Нормально? Улыбающийся

Код
C++ (Qt)
#include <QWidget>
#include <QMoveEvent>
#include <QResizeEvent>
#include <QTimer>
#include <QApplication>
#include <QDesktopWidget>
#include <QDebug>
#include <QPainter>
#include <QSizeGrip>
#include <QHBoxLayout>
 
class MovableWindow: public QWidget
{
public:
   MovableWindow( QWidget * parent = 0 )
       : QWidget( parent )
   {
       setWindowFlags( Qt::Window | Qt::FramelessWindowHint );
 
       QHBoxLayout * layout = new QHBoxLayout();
       layout->setContentsMargins( 0, 0, 0, 0 );
       layout->addWidget( new QSizeGrip( this ), 0, Qt::AlignLeft | Qt::AlignTop );
       layout->addWidget( new QSizeGrip( this ), 0, Qt::AlignRight | Qt::AlignBottom );
       setLayout( layout );
 
       setMinimumSize( 50, 50 );
       resize( 150, 150 );
   }
 
private:
   bool isMousePress;
   QPoint oldPosition;
 
protected:
   void mousePressEvent( QMouseEvent * event )
   {
       if ( event->button() == Qt::LeftButton )
       {
           oldPosition = event->pos();
           isMousePress = true;
       }
   }
   void mouseReleaseEvent( QMouseEvent * )
   {
       isMousePress = false;
   }
   void mouseMoveEvent( QMouseEvent * event )
   {
       if ( isMousePress )
       {
           QPoint delta = event->pos() - oldPosition;
           move( pos() + delta );
       }
   }
   void paintEvent( QPaintEvent * )
   {
       QPainter painter( this );
       painter.setPen( QPen( Qt::black, 2.0 ) );
       painter.drawRect( rect() );
   }
};
 
class AttachableWindow: public MovableWindow
{
   Q_OBJECT
 
public:
   explicit AttachableWindow( QWidget * parent = 0 )
       : MovableWindow( parent )
   {
   }
 
private:
   int timerId;
 
protected:
   void timerEvent( QTimerEvent * event )
   {
       const QRect & availableGeometry = QDesktopWidget().availableGeometry();
       int d_x = availableGeometry.x();
       int d_y = availableGeometry.y();
       int d_width = availableGeometry.width();
       int d_height = availableGeometry.height();
 
       int distance = 10;
 
       if ( x() >= d_x && x() <= distance )
           move( d_x, y() );
 
       if ( y() >= d_y && y() <= distance )
           move( x(), d_y );
 
       if ( x() + width() >= d_width - distance && x() + width() <= d_width )
           move( d_width - width(), y() );
 
       if ( y() + height() >= d_height - distance && y() + height() <= d_height )
           move( x(), d_height - height() );
   }
   void mousePressEvent( QMouseEvent * event )
   {
       MovableWindow::mousePressEvent( event );
       timerId = startTimer( 333 );
   }
   void mouseReleaseEvent( QMouseEvent * event )
   {
       MovableWindow::mouseReleaseEvent( event );
       killTimer( timerId );
   }
};
 

UPDATE. Убрана лишняя проверка и уничтожение "левых" таймеров
« Последнее редактирование: Январь 14, 2014, 12:42 от gil9red » Записан

GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #11 : Январь 14, 2014, 12:11 »

В AttachableWindow::timerEvent() не мешало бы сделать проверку на QTimerEvent::timerId () == timerId и
killTimer( timerId ) делать там же, а то пока не отпустишь кнопку таймер будет срабатывать.
Записан

Qt 5.11/4.8.7 (X11/Win)
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #12 : Январь 14, 2014, 12:30 »

В AttachableWindow::timerEvent() не мешало бы сделать проверку на QTimerEvent::timerId () == timerId и
killTimer( timerId ) делать там же, а то пока не отпустишь кнопку таймер будет срабатывать.

Такой проверки хватит? Улыбающийся
Код
C++ (Qt)
   void timerEvent( QTimerEvent * )
   {
       if( event->timerId() != timerId )
       {
           killTimer( event->timerId() );
           return;
       }
...
 
Записан

GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #13 : Январь 14, 2014, 12:32 »

А зачем же в этом случае прибивать таймер Непонимающий
Прибивать его следует только при QTimerEvent::timerId () == timerId.
Записан

Qt 5.11/4.8.7 (X11/Win)
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #14 : Январь 14, 2014, 12:36 »

А зачем же в этом случае прибивать таймер Непонимающий
Прибивать его следует только при QTimerEvent::timerId () == timerId.

Значит неправильно понял вашу идею Улыбающийся
А смысл прибивать таймер, если его и так прибьет после того как будет отпущена мышь? Улыбающийся
Таймер ведь работает пока зажата кнопка мыши Улыбающийся
Записан

Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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