如何在Qt中运行功能时断开所有信号?

时间:2015-11-08 13:13:32

标签: c++ qt signals-slots

我一直在寻找两天,但没有什么可以帮助我。 我想在功能运行时断开所有信号。主要技巧是发出信号的类,接收它的类都是不同的类。我在课堂上有QPushButton发出信号,我的自定义课程Screen接收信号,它们都是连接的。

The class that manages events (class sender)

    Game::Game(QWidget *parent)
         : QGraphicsView(parent)
        {
            //.................................//some declaration

            //add the main screen
            Screen * screen = new Screen();
            screen->SetImageOnTheScreen();
            scene->addItem(screen);

            //make the lunch work
            QPushButton * GO = new QPushButton;
            GO->setText("GO!!!");
            GO->setGeometry(134,-98,134,99);
            scene->addWidget(GO);
            QObject::connect(GO, SIGNAL(clicked(bool)), screen, SLOT(generate())); 
            //want to disconnect this connection while generate() doing its job

            //.................................//some declaration

        }

Class receiver

void Screen::SetImageOnTheScreen()
    {
        //.................................//some declaration
    }

    void Screen::setWinningIcon()
    {
        //.................................//some declaration
    }

    void Screen::generate()
    {
        line = 0;

        std::random_shuffle(mas, mas + 27);

        SetImageOnTheScreen();

        if(mas[0] == mas[1] || mas[0] == mas[2] || mas[1] == mas[2])
        {
            line = 1;

            delay();
            setWinningIcon();

            delay();
            SetImageOnTheScreen();
        }

        if(mas[3] == mas[4] || mas[3] == mas[5] || mas[4] == mas[5])
        {
            line = 2;

            delay();
            setWinningIcon();

            delay();
            SetImageOnTheScreen();
        }

        if(mas[6] == mas[7] || mas[6] == mas[8] || mas[7] == mas[8])
        {
            line = 3;

            delay();
            setWinningIcon();

            delay();
            SetImageOnTheScreen();
        }
    }

我试图使用disconnect,而没有。试图使用 QObject::blockSignals()同样的故事。

请任何帮助都会很棒!!

更新

game.h

#ifndef GAME_H
#define GAME_H

#include <QGraphicsScene>
#include <QGraphicsView>
#include <QPushButton>
#include "screen.h"

class Game : public QGraphicsView
{
private:
    QGraphicsScene * scene;
    QPushButton * GO;
    Screen * screen;

protected:
    virtual void wheelEvent (QWheelEvent * event);

public:
    Game(QWidget *parent = 0);
    ~Game();

};

#endif // GAME_H

game.cpp

#include "game.h"
#include <QGraphicsGridLayout>
#include <QDebug>
#include <QPushButton>
#include "screen.h"
#include <QStyle>

Game::Game(QWidget *parent)
    : QGraphicsView(parent)
{
    scene = new QGraphicsScene(this);
    scene->setSceneRect(0,0,400,200);

    screen = new Screen;
    screen->SetImageOnTheScreen();
    scene->addItem(screen);

    GO = new QPushButton;
    GO->setGeometry(0,0,100,50);
    GO->setText("GO");

    QObject::connect(GO, SIGNAL(clicked(bool)), screen, SLOT(generate()));
    //when generate is processing i want to disconnect the button "GO" and the "screen"

    scene->addWidget(GO);
    setScene(scene);
    show();
}

void Game::wheelEvent(QWheelEvent * event)
{
    if (event->type() == QEvent::Wheel)
        return;
    return;
}

Game::~Game()
{

}

screen.h

#ifndef SCREEN_H
#define SCREEN_H

#include <QGraphicsPixmapItem>
#include <QGraphicsTextItem>

class Screen : public QObject, public QGraphicsPixmapItem
{
    Q_OBJECT

private:
    int mas[27];
    int line;

    QGraphicsTextItem * text;

public:
    Screen(QGraphicsPixmapItem * parent = 0);
    void delay(int msecs);
    void setWinningIcon();
    void SetImageOnTheScreen();

public slots:
    void generate();
};

#endif // SCREEN_H

screen.cpp

#include "screen.h"
#include <QDebug>
#include <QTime>
#include <QCoreApplication>
#include "game.h"

Screen::Screen(QGraphicsPixmapItem * parent)
    : QObject(), QGraphicsPixmapItem(parent)
{
    for(int i = 0, j =1; i < 27; i++, j++)
    {
        if(j == 10)
            j = 1;

        mas[i] = j;
    }

    line = 0;
    text = new QGraphicsTextItem(this);
}

void Screen::delay(int msecs)
{
    QTime dieTime= QTime::currentTime().addMSecs(msecs);
    while (QTime::currentTime() < dieTime)
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

void Screen::setWinningIcon()
{
    switch(line)
    {
    case 1:
        text->setPlainText("TEST_#2 I'm NOT allowed to press /GO/ \nfor 3 seconds but i can");
        text->setDefaultTextColor(Qt::red);
        break;
    case 2:
        text->setPlainText("TEST_#3 I'm NOT allowed to press /GO/ \nfor 3 seconds but i can");
        text->setDefaultTextColor(Qt::red);
        break;
    case 3:
        text->setPlainText("TEST_#4 I'm NOT allowed to press /GO/ \nfor 3 seconds but i can");
        text->setDefaultTextColor(Qt::red);
        break;
    }
}

void Screen::SetImageOnTheScreen()
{
    text->setPlainText("TEST_#1 I'm ALLOWED to press /GO/");
    text->setPos(0,50);
    text->setDefaultTextColor(Qt::green);
}

void Screen::generate()
{
    //In here i want to prevent to press "GO" while "generate()" is processing

    //Screen::grabMouse(); //here it is my solution

    std::random_shuffle(mas, mas + 27);

    SetImageOnTheScreen();

    if(mas[0] == mas[1] || mas[0] == mas[2] || mas[1] == mas[2])
    {
        line = 1;

        delay(500);
        setWinningIcon();

        delay(3000);
        SetImageOnTheScreen();
    }

    if(mas[3] == mas[4] || mas[3] == mas[5] || mas[4] == mas[5])
    {
        line = 2;

        delay(500);
        setWinningIcon();

        delay(3000);
        SetImageOnTheScreen();
    }

    if(mas[6] == mas[7] || mas[6] == mas[8] || mas[7] == mas[8])
    {
        line = 3;

        delay(500);
        setWinningIcon();

        delay(3000);
        SetImageOnTheScreen();
    }

    //Screen::ungrabMouse(); //here it is my solution
}

main.cpp

#include "game.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Game w;
    w.show();

    return a.exec();
}

2 个答案:

答案 0 :(得分:2)

更新

我已经使用了您发布的最新代码并对其进行了一些更改。

摘要

让我们从您的评论开始:

  

我无法从screen.cpp到达“GO”按钮,除非它是全局的。和   我不想使用任何全局变量。

你在试图避免全局变量方面走在正确的轨道上。但是,我认为您的Screen课程 相反,您可以执行我在our discussion中建议的内容,而不是GOconnect按钮GO直接发送到Screen的{​​{1}}位置,您应该将generate()按钮添加到connect类中的单独on_button_clicked事件处理程序中:

  1. 禁用或断开Game按钮
  2. 调用GO的{​​{1}}方法和
  3. screen返回后重新启用或重新连接按钮。
  4. 这也意味着generate()可能不再需要成为一个广告位,但这取决于您。

    您的代码 - 使用我建议的更新

    我做了以下更改:

    generate()中,我向generate()类添加了一个插槽:

    game.h

    Game中,我添加了如下实现:

    private slots:
        void on_go_clicked();
    

    并且还使用以下内容替换您的构造函数的game.cpp调用:

    void Game::on_go_clicked()
    {
        GO->setEnabled(false);  // or QObject::disconnect(....)
        screen->generate();
        GO->setEnabled(true);   // or QObject::connect(....)
    }
    

    现在,您可以让QObject::connect班级不知道您的QObject::connect(GO, SIGNAL(clicked(bool)), this, SLOT(on_go_clicked())); 按钮的存在,这意味着更少的耦合和复杂性,但仍然可以防止用户在此期间使用您的按钮,这就是你想要的。

    原始回复

    基本上,您需要使用Screen,如下所示:

    GO

    您可以在处理完事件后在插槽中执行此操作。

    断开感兴趣对象之间的信号/插槽是比尝试全局断开所有信号的更好方法,原因有多种,包括可能导致错误的意外副作用或其他意想不到的行为。

    在您的特定示例中,您有:

    QObject::disconnect

    所以要断开连接,你可能只需要在开始处理时写这个:

    QObject::disconnect(emitter, SIGNAL(signalName()), receiver, SLOT(slotName()));
    

    然后在完成处理后重新连接。

    或者,正如@Matt在评论中所说,你可以简单地禁用用户界面中的按钮小部件,而不是弄乱信号。如果用户无法单击该按钮,则用户无法发出信号。

    这可能是一种更简单,更可靠的解决方案。

    信号阻止更新

    如果您仍想连接/断开,那么您使用的是Qt 5.3+,那么您应该使用QSignalBlocker,它还会保留并恢复以前的状态。州。引用他们的文档:

    QObject::connect(GO, SIGNAL(clicked(bool)), screen, SLOT(generate()));
    
         因此

    等同于

    QObject::disconnect(GO, SIGNAL(clicked(bool)), screen, SLOT(generate()));
    

    工作示例代码

    下面是一个简短的示例应用,其中包含{ const QSignalBlocker blocker(someQObject); // no signals here } const bool wasBlocked = someQObject->blockSignals(true); // no signals here someQObject->blockSignals(wasBlocked); QPushButton的窗口。

    mainwindow.cpp

    QListWidget

    mainwindow.h

    QMainWindow

    的main.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::on_button_clicked()
    {
        ui->listWidget->addItem(QString("Clicked"));
    
        // this is the important line :o
        QObject::disconnect(ui->button, SIGNAL(clicked(bool)), this, SLOT(on_button_clicked()));
    }
    

    mainwindow.ui

    如果需要,您可以复制粘贴.ui文件的内容以重现简单布局。它在下面:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    namespace Ui {
        class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private slots:
        // this naming convention allows Qt to
        // create connections automatically
        void on_button_clicked();
    
    private:
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H
    

答案 1 :(得分:1)

我使用的是blockSignals,它阻止信令对象发送信号:但它不会阻止接收对象接收它们,这可能是你的情况。

当您想要为Ui小部件设置值但是您不希望这些小部件发送valueChanged信号时,使用blockSignals非常有用。这方面的一个例子就是如果你有一堆独立的小部件都更新了一些计算 - 你不希望每个小部件重新计算,只要它们全部设置就会重新计算一次。

我不会在这里使用disconnect / connect,因为你可能会遇到信号连接两次的问题。