Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Hellrider от Январь 03, 2013, 15:41



Название: Переопределенные события для класса и новый виджет
Отправлено: Hellrider от Январь 03, 2013, 15:41
Пример класса
Код:
class Test : public QLabel{
private:
QPoint point;
QWidget wgt;
protected:
    virtual void mousePressEvent(QMouseEvent* pe){
        if(pe->button() & Qt::LeftButton)
            point = pe->pos();
                    }
    virtual void mouseMoveEvent(QMouseEvent* pe){
        move(pe->globalPos() - point);
           }
    virtual void keyPressEvent(QKeyEvent* pe){
        if(pe->key() & Qt::Key_Enter){
            slotStart();
        }
            }
public:
Test(QWidget* parent = 0) : QLabel(parent){
// основное окно
//.....
//.....
wgt.show();
}
Как сделать, чтобы виджет wgt работал с переопределенными событиями класса?  В главном виджете класса события работают, а в созданном нет.


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Old от Январь 03, 2013, 15:50
Если я правильно тебя понял, то в переопределенных методах нужно вызывать их парент-реализации.
Код
C++ (Qt)
virtual void mousePressEvent(QMouseEvent* pe)
{
   QLabel::mousePressEvent( pe );
   if(pe->button() & Qt::LeftButton)
       point = pe->pos();
}
 


Название: Re: Переопределенные события для класса и но&
Отправлено: Hellrider от Январь 03, 2013, 16:09
Если я правильно тебя понял, то в переопределенных методах нужно вызывать их парент-реализации.
Код
C++ (Qt)
virtual void mousePressEvent(QMouseEvent* pe)
{
   QLabel::mousePressEvent( pe );
   if(pe->button() & Qt::LeftButton)
       point = pe->pos();
}
 

Ну  QLabel добавлять не нужно, он и так работает, а вот виджет wgt не взаимодействует с этими событиями. Пробовал добавить QWidget::mousePressEvent(pe); не помогло.


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Old от Январь 03, 2013, 16:19
Напиши, что хочешь сделать. Потому, что не понятно, как этот виджет должен взаимодействовать и с чем.


Название: Re: Переопределенные события для класса и но&
Отправлено: Hellrider от Январь 03, 2013, 16:27
Напиши, что хочешь сделать. Потому, что не понятно, как этот виджет должен взаимодействовать и с чем.

Мне нужно, чтобы виджет wgt таким же способом перемещался мышкой, как главный виджет в классе, который использует переопределенные события мыши.


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Dancing_on_water от Январь 03, 2013, 16:44
тогда тебе нужно в конструторе:
Код:
 wgt.setParent(this);


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Hellrider от Январь 03, 2013, 16:56
тогда тебе нужно в конструторе:
Код:
 wgt.setParent(this);
wgt.setParent(this); засовывает wgt в главный виджет. wgt идет отдельным окном.


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Old от Январь 03, 2013, 16:58
wgt идет отдельным окном.
Тогда, делай отдельный класс-наследник QWidget и переопределяй обработчики событий мыши. Ну и используй го в классе Test.


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Dancing_on_water от Январь 03, 2013, 17:03
wgt.setParent(this); засовывает wgt в главный виджет. wgt идет отдельным окном.
А теперь все сначала. Давай обрисовывай ситуацию целиком, иначе все советы -  это пальцем в небо. Нужно что есть, что хотим и какие проблемы.



Название: Re: Переопределенные события для класса и новый виджет
Отправлено: kambala от Январь 03, 2013, 17:25
насколько я понял, автор хочет, чтобы реализация событий «принадлежала» как унаследованному лейблу, так и виджету, содержащемуся в нем. должно подойти множественное наследование, только придется хранить указатели на методы move() и slotStart().


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Hellrider от Январь 03, 2013, 17:26
wgt.setParent(this); засовывает wgt в главный виджет. wgt идет отдельным окном.
А теперь все сначала. Давай обрисовывай ситуацию целиком, иначе все советы -  это пальцем в небо. Нужно что есть, что хотим и какие проблемы.


У меня есть класс унаследованный от QLabel.
Код:
class Timer : public QLabel
{
    Q_OBJECT
private:
QPoint point;
QWidget wh;
protected:
    virtual void Timer::mousePressEvent(QMouseEvent* pe){
        if(pe->button() & Qt::LeftButton)
            point = pe->pos();
         }
    virtual void Timer::mouseMoveEvent(QMouseEvent* pe){
        move(pe->globalPos() - point);
           }
    virtual void Timer::keyPressEvent(QKeyEvent* pe){
        if(pe->key() & Qt::Key_Enter){
            slotStart();
        }
            }
public:
    Timer(QWidget *parent = 0);
}

В конструкторе создается гуи и т.д. для wh виджета и для главного виджета. Главный виджет с флагом Qt::FramelessWindowHint, поэтому переопределены события мыши.
 В главном виджете через кнопку вызывается слот, который отображает виджет в отдельном окне wh.show(). В отдельное окно я тоже хочу поставить флаг  Qt::FramelessWindowHint,
но wh виджет не взаимодействует с событиями, которые в классе. Мне нужно както переопределить события мыши для wh виджета или связать этот виджет с событиями в классе.


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Hellrider от Январь 03, 2013, 17:28
насколько я понял, автор хочет, чтобы реализация событий «принадлежала» как унаследованному лейблу, так и виджету, содержащемуся в нем. должно подойти множественное наследование, только придется хранить указатели на методы move() и slotStart().

Так точно. Можно пример, как это правильно реализовать?


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: kambala от Январь 03, 2013, 18:30
думал как-то так можно сделать, но не получается добраться до реального виджета в mouseMoveEvent (reinterpret_cast тоже не помогает):
Код
C++ (Qt)
class A
{
public:
   A() {}
 
protected:
   void mousePressEvent(QMouseEvent* pe)
   {
       qDebug() << Q_FUNC_INFO << "\n";
       if (pe->button() & Qt::LeftButton)
           point = pe->pos();
   }
 
   void mouseMoveEvent(QMouseEvent* pe)
   {
       qDebug() << Q_FUNC_INFO << "\n";
       QWidget *w = self();
       w->move(pe->globalPos() - point);
   }
 
   void keyPressEvent(QKeyEvent* pe)
   {
       if(pe->key() & Qt::Key_Enter)
       {
           start();
       }
   }
 
   void start() { qDebug() << Q_FUNC_INFO << "\n"; }
   QWidget *self() { return 0; }
 
private:
   QPoint point;
};
 
class Widget : public QWidget, public A
{
   Q_OBJECT
public:
   Widget(QWidget *parent = 0) : QWidget(parent), A()
   {
 
   }
 
protected:
   void mousePressEvent(QMouseEvent* pe) { qDebug() << Q_FUNC_INFO; A::mousePressEvent(pe); }
   void mouseMoveEvent(QMouseEvent* pe) { qDebug() << Q_FUNC_INFO; A::mouseMoveEvent(pe); }
   void keyPressEvent(QKeyEvent* pe) { qDebug() << Q_FUNC_INFO; A::keyPressEvent(pe); }
 
   QWidget *self() { return this; }
 
private slots:
   void slotStart() { start(); }
};
 
class Timer : public QLabel, public A
{
   Q_OBJECT
private:
   Widget *wh;
 
private slots:
   void slotStart() { start(); }
 
protected:
   void mousePressEvent(QMouseEvent* pe) { qDebug() << Q_FUNC_INFO; A::mousePressEvent(pe); }
   void mouseMoveEvent(QMouseEvent* pe) { qDebug() << Q_FUNC_INFO; A::mouseMoveEvent(pe); }
   void keyPressEvent(QKeyEvent* pe) { qDebug() << Q_FUNC_INFO; A::keyPressEvent(pe); }
 
   QWidget *self() { return this; }
 
public:
   Timer(QWidget *parent = 0) : QLabel("label", parent), A), wh(new Widget)
   {
       wh->show();
   }
};


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Old от Январь 03, 2013, 19:01
думал как-то так можно сделать, но не получается добраться до реального виджета в mouseMoveEvent (reinterpret_cast тоже не помогает):
Его можно передавать в качестве параметра.

А для нормального переопределения метод A::self хорошо бы сделать виртуальным.


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: kambala от Январь 03, 2013, 20:47
Его можно передавать в качестве параметра.
тоже об этом подумал потом
А для нормального переопределения метод A::self хорошо бы сделать виртуальным.
согласен


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Igors от Январь 04, 2013, 09:51
Не понял чем не устраивает самый обычный parent/child? Конечно указатель на wh, а не член данных. Методы надо переопределить для обоих классов. wh получит событие, возможно сам его отработает или сочтет нужным вызвать метод парента (пересчитав позицию мыши)


Название: Re: Переопределенные события для класса и но&
Отправлено: Hellrider от Январь 04, 2013, 14:30
думал как-то так можно сделать, но не получается добраться до реального виджета в mouseMoveEvent (reinterpret_cast тоже не помогает):
Код
C++ (Qt)
class A
{
public:
   A() {}
 
protected:
   void mousePressEvent(QMouseEvent* pe)
   {
       qDebug() << Q_FUNC_INFO << "\n";
       if (pe->button() & Qt::LeftButton)
           point = pe->pos();
   }
 
   void mouseMoveEvent(QMouseEvent* pe)
   {
       qDebug() << Q_FUNC_INFO << "\n";
       QWidget *w = self();
       w->move(pe->globalPos() - point);
   }
 
   void keyPressEvent(QKeyEvent* pe)
   {
       if(pe->key() & Qt::Key_Enter)
       {
           start();
       }
   }
 
   void start() { qDebug() << Q_FUNC_INFO << "\n"; }
   QWidget *self() { return 0; }
 
private:
   QPoint point;
};
 
class Widget : public QWidget, public A
{
   Q_OBJECT
public:
   Widget(QWidget *parent = 0) : QWidget(parent), A()
   {
 
   }
 
protected:
   void mousePressEvent(QMouseEvent* pe) { qDebug() << Q_FUNC_INFO; A::mousePressEvent(pe); }
   void mouseMoveEvent(QMouseEvent* pe) { qDebug() << Q_FUNC_INFO; A::mouseMoveEvent(pe); }
   void keyPressEvent(QKeyEvent* pe) { qDebug() << Q_FUNC_INFO; A::keyPressEvent(pe); }
 
   QWidget *self() { return this; }
 
private slots:
   void slotStart() { start(); }
};
 
class Timer : public QLabel, public A
{
   Q_OBJECT
private:
   Widget *wh;
 
private slots:
   void slotStart() { start(); }
 
protected:
   void mousePressEvent(QMouseEvent* pe) { qDebug() << Q_FUNC_INFO; A::mousePressEvent(pe); }
   void mouseMoveEvent(QMouseEvent* pe) { qDebug() << Q_FUNC_INFO; A::mouseMoveEvent(pe); }
   void keyPressEvent(QKeyEvent* pe) { qDebug() << Q_FUNC_INFO; A::keyPressEvent(pe); }
 
   QWidget *self() { return this; }
 
public:
   Timer(QWidget *parent = 0) : QLabel("label", parent), A), wh(new Widget)
   {
       wh->show();
   }
};
Я немного не пойму как работает self() разжуйте по полочкам пожалуйста =). Определил virtual QWidget* self(){return 0;} и все заработало. Хочу понять до конца, как это все работает. Еще есть проблема этим событием, которое уже в Timer классе, оно срабатывает при нажатии любой кнопки, хотя должно только от ентер  ???
Код:
void keyPressEvent(QKeyEvent* pe){
        if(pe->key() & Qt::Key_Enter){
            slotStart();
        }
            }


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: kambala от Январь 04, 2013, 16:34
self() возвращает указатель на «реальный» экземпляр класса, который наследуется от QWidget. это нужно потому, что класс A не наследуется от QWidget, и потому просто this там не прокатит. вот если бы все вызовы методов разрешались в рантайме (как например в Objective-C), то такое не нужно было бы :)

про кнопку — там наверное надо условие pe->key() == Qt::Key_Enter || pe->key() == Qt::Key_Return (Qt::Key_Return — это как раз то, что принято называть энтером, а Qt::Key_Enter — это энтер на нампаде)
Не понял чем не устраивает самый обычный parent/child?
кастомные события же всё равно не будут работать, будь виджет хоть ребенком. к тому же, виджет является отдельным окном, что не особо вяжется с parent/child как по мне.


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Igors от Январь 04, 2013, 18:19
кастомные события же всё равно не будут работать, будь виджет хоть ребенком. к тому же, виджет является отдельным окном, что не особо вяжется с parent/child как по мне.
Ну я полагал что точка где случился mouseDown покрывается обоими виджетами - иначе зачем городить такую реакцию на мышь? Ладно, пусть даже 2 окна. Так или иначе дело сводится к делегированию - и только то что делегировано будет работать. Привлекать множественное наследование не ошибка, но, как часто бывает, простое членство не хуже


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Hellrider от Январь 04, 2013, 18:45
кастомные события же всё равно не будут работать, будь виджет хоть ребенком. к тому же, виджет является отдельным окном, что не особо вяжется с parent/child как по мне.
Ну я полагал что точка где случился mouseDown покрывается обоими виджетами - иначе зачем городить такую реакцию на мышь? Ладно, пусть даже 2 окна. Так или иначе дело сводится к делегированию - и только то что делегировано будет работать. Привлекать множественное наследование не ошибка, но, как часто бывает, простое членство не хуже

Можно пример реализации? Я с делегатами еще толком не сталкивался


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: Igors от Январь 04, 2013, 19:14
Можно пример реализации? Я с делегатами еще толком не сталкивался
Здесь "делегат" - в смысле паттерн программирования. Напр так
Код
C++ (Qt)
void Timer::mousePressEvent(QMouseEvent* pe)
{
qDebug() << Q_FUNC_INFO;
wh->mousePressEvent(pe);  
}
Остальное в том же духе, без класса A. Можно и наоборот, Widget::mousePressEvent вызывает Timer::mousePressEvent. Можно и оба вместе, только пресечь рекурсию. Разницы по существу никакой, kambala просто обобщил этот механизм


Название: Re: Переопределенные события для класса и новый виджет
Отправлено: kambala от Январь 04, 2013, 19:19
Hellrider хочет, чтобы и у Timer и у Widget реализация указанных событий была одинаковая, потому я и пошел через множественное наследование.