Qt- How to use connect between incompatible signal and slot

点点圈 提交于 2019-12-13 20:27:53

问题


I am trying to do a game. In this I want to call a function, that function will receive a point . But this function should be invoked by a timer's timedout signal. Can anybody say how to achieve this. Below is the required/error code

Point p(a,b);

connect(timer,SIGNAL(timedout()),this,startDestruction(p));

Can anybody say how to achieve this?


回答1:


Create a method to use as an intermediate slot, like this.

Point p(a,b);
connect(timer, SIGNAL(timedout()), this, q);

q() {
    startDestruction(this->p)
}



回答2:


Your design is flawed;

  • you create p on stack
  • you want Qt to prevent this object from dying and reuse it whenever a signal is called



回答3:


Your problem is usually solved by using QSignalMapper, but that only supports QString, int, QWidget*, and QObject* as parameter types.

If you want to use other types, you need to implement your own signal mapper (don't you hate how Qt doesn't let you make class templates derived from QObjects? :) like this:

class PointSignalMapper : public QObject {
    Q_OBJECT
public:
    explicit PointSignalMapper( QObject * parent=0 )
        : QObject( parent ), m_map() {}

    void setMapping( QObject * sender, const Point & p ) {
        if ( sender )
            m_map[sender] = p;
    }

public Q_SLOTS:
    void map() {
        map( sender() );
    }
    void map( QObject * sender ) {
        if ( !sender )
            return;
        const QMap<QObject*,Point>::const_iterator
            it = m_map.constFind( sender );
        if ( it != m_map.constEnd() )
            emit mapped( it.value() );
    }
Q_SIGNALS:
    void mapped( const Point & p );

private:
    QMap<QObject*,Point> m_map;
};

Usage:

PointSignalMapper * mapper = new PointSignalMapper( this );
connect( mapper, SIGNAL(mapped(Point)), this, SLOT(pointDestroyed(Point)) );

mapper->setMapping( qObject1, point1 );
connect( qObject1, SIGNAL(timedout()), mapper, SLOT(map()) );

mapper->setMapping( qObject2, point2 );
connect( qObject2, SIGNAL(timedout()), mapper, SLOT(map()) );

// ...

In your specific case:

Point p(a,b);
PointSignalMapper * mapper = new PointSignalMapper( this ); // added
mapper->setMapping( timer, p );                             // added
connect( timer, SIGNAL(timedout()), mapper, SLOT(map()) );  // added
connect( mapper, SIGNAL(mapped(Point)),                     // modified
         this, startDestruction(Point)) )



回答4:


You usually have to create an intermediate slot that is triggered by the timer and then calls startDestruction with the point.




回答5:


How about redesign your class, so that startDestruction() is a slot of p. While p.startDestruction() is call, it'll emit a signal to notify the main class.

connect(timer,SIGNAL(timedout()),p,startDestruction());
connect(p,SIGNAL(destroyed()),this,destroyHandle());



回答6:


Here's working, not-so-minimal example.

Qt requires that the mocked QObject-derived class is not in the main file, and that's why Pipe is separated. Using object as the wrapper instead of a function gives greater flexibility and does not require you to encapsulate variable in a field (no architecture changes).

Output

Destroyed target at [40, 12]
Destroyed target at [41, 11]
Destroyed target at [42, 10]

main.cpp

#include "Game.h"
#include "Pipe.h"

#include <QtCore/QCoreApplication>
#include <QTimer>

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    Game game;
    Point target(40, 12);
    Pipe pipe(&game, &target);

    pipe.pass();
    QTimer::singleShot(500, &pipe, SLOT(pass()));
    QTimer::singleShot(1000, &pipe, SLOT(pass()));
    QTimer::singleShot(2000, &app, SLOT(quit()));

    return app.exec();
}

Game.h

#ifndef GAME_H
#define GAME_H

#include <iostream>

struct Point {
    int x;
    int y;

    Point(int _x, int _y) : x(_x), y(_y) {}
};

class GameInterface {
public:
    virtual void startDesturction(Point * pt) = 0;
};

class Game : public GameInterface {
public:
    virtual void startDesturction(Point * pt)  {
        std::cout<<"Destroyed target at ["<<pt->x<<", "
                 <<pt->y<<"]"<<std::endl;

        //shift
        pt->x += 1;
        pt->y -= 1;
    }
};

#endif // GAME_H

Pipe.h

#ifndef PIPE_H
#define PIPE_H

#include "Game.h"

#include <QObject>

class Pipe : public QObject {
    Q_OBJECT

public:
    Pipe(GameInterface * game, Point * target)
        : QObject(), m_game(game), m_target(target) {}
    virtual ~Pipe() {}

public slots:
    void pass() {
        m_game->startDesturction(m_target);
    }

private:
    GameInterface * m_game;
    Point * m_target;
};

#endif // PIPE_H


来源:https://stackoverflow.com/questions/5840462/qt-how-to-use-connect-between-incompatible-signal-and-slot

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!