Signal and Slot

0

Hej,

Mam 2 klasy A i B. W klasie A wysyłam sygnał: emit signal. Chciałbym w klasie B ten sygnał "odebrać" i go obsłużyć. Jak to zrobić? Próbowałem w ten sposób, że w konstruktorze klasy B tworzyłem wskaźnik na obiekt klasy A. Następnie napisałem w tym konstruktorze connect(A,SIGNAL(signal), this, SLOT(fun)). Ale to nie działa. Proszę o jakieś wskazówki.

1

Łączysz konkretne obiekty, nie klasy. Jeśli w konstruktorze B tworzysz nowy obiekt A to nie ma to żadnego wpływu na podłączenie innych A do tej instancji B. Dodatkowo pewnie masz wyciek pamięci.

0

Pomyłka. Stworzyłem obiekt klasy A: A *obiekt = new A(); Nstępenie

 connect (obiekt,SIGNAL(signal),this, SLOT(fun));
1

Pomijając już korzystanie z nagich wskaźników, próbowałeś na obiekt wywołać signal?

0

Tu pewnie wykaże się brakiem wiedzy.... ale co masz na myśli pisząc wywołać sygnał na obiekt? I jeszcze jedno, jak poprawnie powinno wyglądać połączenie? Stworzyć zwykły obiekt A bez referencji?

connect(&A,SIGNAL(signal),this,SLOT(fun))

?

1

Łączysz konkretne obiekty, nie klasy.

0

Eh, znowu się pomyliłem.... Miałem na myśli:

&obiekt
0

Pytanie Qt czy boost?
Jeśli Qt to musisz mieć odpowienia makro wklepane, żeby w danej klasie w ogóle użyć "connect" i oczywiście dziedziczyc po QObject.

Edit: Jesli sypnął błędem, to go wklej.

0

Zrobiłem poprawki ale dalej mam błąd. To może od początku :)

W main mam zmienna globalna

Game* game

W pliku źródłowym Game mam między innymi

player = new Player()
health = new Health()

W klasie Player mam metodę

game_over()

która usuwa postać z scene

 a także usuwa ze stery. 
W klasie Health mam metodę 
```c
decrease()

która obniża poziom zdrowia do zera. Gdy jest zero metoda emituje sygnał GameOver

Na samym początku mam 
```c
extern Game *game

W konstrukotrze klasy Health mam:

connect(this, SIGNAL(GameOver()),game->player,SLOT(game_over()))

Jest "wywałka" aplkacji właśnie na tym connect :/ Nie ma żadnych informacji o błędach.

0

No to już wiem ;)

W skrócie wygląda to tak: GAME zawiera player i health. Zatem Game wie o obiekcie playera i obiekcie health.
W Twoim connect (konstruktor klasy Health) przekazujesz game->player o którym klasa health chyba nie ma pojęcia.

Rozwiązanie: Zrób connect w klasie Game:

connect(game->health, SIGNAL(GameOver()),game->player,SLOT(game_over))

Jeśli to tylko to to powinno działać.

EDIT: masz extern co prawda, ale spróbuj tego co napisałem.

0

Dalej coś nie działa ;) Posłucham twonek i wkleje kody plików:

Main.cpp

Game *game;
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    game = new Game();
    return a.exec();
}

HealthPpayer.h

class HealthPlayer : public QGraphicsTextItem
{
    Q_OBJECT
public:
    explicit HealthPlayer();
    int getHealth() const;
    void decrease(int i);
signals:
    void GameOver();

public slots:

private:
    int m_Health;
};

Usunąłem dziedziczenie public QObject ponieważ QGraphicsTextItem dziedziczy już po tej klasie.

HelathPlayer.cpp

extern Game *game;
HealthPlayer::HealthPlayer()
{
    m_Health = 100;
    setPlainText(QString("Player: "+QString::number(m_Health)));
    setDefaultTextColor(Qt::red);
    connect(game->B_health, SIGNAL(GameOver()),game->player,SLOT(game_over()));
}

int HealthPlayer::getHealth() const
{
    return m_Health;
}

void HealthPlayer::decrease(int i)
{
    m_Health-=i;
    if(m_Health<=0)
    {
        m_Health=0;
        emit GameOver();
    }
    setPlainText(QString("Player: "+QString::number(m_Health)));
}

MyRec.h

class MyRec : public QObject, public QGraphicsPixmapItem
{
    Q_OBJECT

public:
    explicit MyRec(QObject *parent = 0);    

signals:

public slots:
    void start_shooting();
    void game_over();


    // QGraphicsItem interface
protected:
    void keyPressEvent(QKeyEvent *event) override;

private:

};

MyRec.cpp

MyRec::MyRec(QObject *parent) : QObject(parent)
{    
    setPixmap(QPixmap(":/graphics/rsz_bury_logo.png"));
    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()),this,SLOT(start_shooting()));
    timer->start(400);    ;


}

void MyRec::keyPressEvent(QKeyEvent *event)
{
    if(event->key()==Qt::Key_Right)
    {
        if(pos().x()+pixmap().width()<1000)
        {
        setPos(x()+20,y());
        }
    }
    else if (event->key()==Qt::Key_Left)
    {
        if(pos().x()>0)
        {
        setPos(x()-20,y());
        }
    }
    else if(event->key()==Qt::Key_Up)
    {
        if(pos().y()>100)
        {
        setPos(x(),y()-20);
        }
    }
    else if(event->key()==Qt::Key_Down)
    {
        if(pos().y()+pixmap().height()<600)
        setPos(x(),y()+20);
    }
}



void MyRec::start_shooting()
{
    Bullet *bullet = new Bullet();
    bullet->setPos(x()+50,y());
    scene()->addItem(bullet);
}

void MyRec::game_over()
{
    scene()->removeItem(this);
    delete this;
}
0
  1. Masz #include <game.h> w plikach Health?
  2. To się kompiluje? Czy uruchamia i wywala?
  3. Wrzuć jeszcze .h .cpp z game i playerem.
0
  1. Tak
  2. Postawiłem breakpoint na tym nieszczęsnym connect. Daje F10 i sie wywala.
    3 game.h
class Game : public QObject
{
    Q_OBJECT
public:
    explicit Game(QObject *parent = 0);
    QGraphicsScene *scene;
    MyRec *player;      //tu jest player :) klasa źle nazwana :P
    Enemy *enemy;
    QGraphicsView *view;
    HealthPlayer *B_health;
    M_Health *m_health;
signals:

public slots:
};

game.cpp

Game::Game(QObject *parent) : QObject(parent)
{
    qsrand(QTime::currentTime().msec());
    scene = new QGraphicsScene();
    player = new MyRec();
    player->setFlag(QGraphicsItem::ItemIsFocusable);
    player->setFocus();
    scene->addItem(player);
    scene->setBackgroundBrush(QBrush(QImage(":/graphics/background.png")));
    enemy = new Enemy();
    scene->addItem(enemy);

    B_health = new HealthPlayer();
    scene->addItem(B_health);

    m_health = new M_Health();
    scene->addItem(m_health);

    view = new QGraphicsView(scene);
    view->setFixedSize(1000,600);
    B_health->setPos(0, view->height()/2);
    m_health->setPos(0, view->height()/2+20);
    player->setPos(view->width()/2,view->height()-player->pixmap().height());
    view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scene->setSceneRect(0,0,1000,600);
    view->show();
}

//EDIT

przeniosłem #include "game.h" z healtplayer.cpp do healthplayer.h. Dostaje 2 błędy: MyRec i HealthPlayer does not name a type

//EDIT 2

Błąd z tym name a type związany był z przeniesieniem include. #include "game.h" w healtplayer musi być w .cpp. Inaczej jest "krzyżowe" wywołanie

1

To zróbmy tak:

  1. Usuń connect z konstruktora health.
  2. Dodaj dokładnie to w konstruktorze Game:
connect(this->B_health, SIGNAL(GameOver()), this->player, SLOT(game_over()));
  1. Napisz mi czy działa (a jak czyms sypnie to wklej).
0

DZIAŁA!!!! :)

Teraz się zastanawiam dlaczego nie działa connect z health'a. A w sumie nie ważne. <Piwo>
Dziękuje za pomoc i poświęcony czas :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1