问题
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 QObject
s? :) 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