Qt- Как использовать соединение между несовместимым сигналом и слотом - PullRequest
0 голосов
/ 30 апреля 2011

Я пытаюсь сделать игру. В этом я хочу вызвать функцию, эта функция получит точку. Но эта функция должна вызываться сигналом тайм-аута таймера. Кто-нибудь может сказать, как этого добиться. Ниже приведен обязательный / код ошибки

Point p(a,b);

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

Кто-нибудь может сказать, как этого добиться?

Ответы [ 6 ]

3 голосов
/ 30 апреля 2011

Ваш дизайн имеет недостатки;

  • вы создаете p в стеке
  • вы хотите, чтобы Qt предотвращал умирание этого объекта и использовал его снова, когда вызывается сигнал
2 голосов
/ 30 апреля 2011

Ваша проблема обычно решается с помощью QSignalMapper, но он поддерживает только QString, int, QWidget* и QObject* в качестве типов параметров.

Если вы хотите использовать другие типы, вам нужно реализовать свой собственный преобразователь сигналов (не ненавидите ли вы, как Qt не позволяет создавать шаблоны классов, полученные из QObject s? :), как это:

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;
};

Использование:

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()) );

// ...

В вашем конкретном случае:

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)) )
1 голос
/ 30 апреля 2011

Создайте метод для использования в качестве промежуточного слота, например:

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

q() {
    startDestruction(this->p)
}
0 голосов
/ 30 апреля 2011

Вот рабочий, не такой минимальный пример.

Qt требует, чтобы макет-производный класс QObject отсутствовал в главном файле, и поэтому Pipe отделен. Использование объекта в качестве оболочки вместо функции дает большую гибкость и не требует инкапсуляции переменной в поле (без изменений архитектуры).

выход

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
0 голосов
/ 30 апреля 2011

Как насчет редизайна вашего класса, чтобы startDestruction () был слотом p. Пока p.startDestruction () является вызовом, он будет подавать сигнал для уведомления основного класса.

connect(timer,SIGNAL(timedout()),p,startDestruction());
connect(p,SIGNAL(destroyed()),this,destroyHandle());
0 голосов
/ 30 апреля 2011

Обычно вам нужно создать промежуточный слот, который запускается таймером, а затем вызывает startDestruction с точкой.

...