Qt:信号/插槽设计和性能

时间:2012-11-13 14:32:31

标签: c++ qt oop signals class-design

我最近开始使用Qt,我需要对信号/插槽机制做一些澄清。我理解它是一个很好的工具,用于生成在不同线程中的对象之间的GUI和通信,但我不确定是否应该在下面的简单情况下使用它。

我有三个类,我们称之为MainWindow,DataManager和DataWorker。 DataWorker位于一个单独的线程中,并在新数据准备好收集时发出信号。然后在一些处理后在MainWindow小部件中可视化。我创建了DataManager类,以便不使用处理代码污染GUI类。

现在,我该如何处理DataManager和MainWindow之间的通信。


选项#1 - 将指向MainWindow的指针作为成员,并调用其方法

class MainWindow
{
private:
    DataManager* dm;

public:
    MainWindow() : dm(new DataManager(this)) { }
    displayData(const char* processedData);
}

class DataManager : QObject
{
private:
    MainWindow *mw;

private slots;
    eventNewData()
    {
        // get and process the data
        mw = this->QObject.parent();
        mw->displayData(const char* processedData);
        // release data
    }
}

选项#2 - 发出新数据信号以调用MainWindow插槽

class MainWindow
{
private:
    DataManager* dm;

private slots:
    displayData(const char* processedData);

public:
    MainWindow() : dm(new DataManager(this)) { QObject::connect(dm, SIGNAL(newData(const char*)), this, SLOT(displayData(const char*)); }

};

class DataManager : QObject
{    
signals:
    newData(const char* processedData);

private slots;
    eventNewData()
    {
        // get and process the data
        emit newData(processedData);
        // release data
    }
}

选项1对我来说似乎更直观,但是我再一次对Qt不太了解。如果有更多的类我想对newData()信号作出反应,我可以看到使用信号和插槽的好处。

那么什么是更好的选择,两者之间的表现有什么不同?

3 个答案:

答案 0 :(得分:3)

您无法直接从线程调用GUI函数。因此,除非DataWorker和DataManager :: eventNewData()之间存在信号/插槽连接,否则选项#1将不起作用。从另一个线程调用GUI函数的唯一方法是通过信号/插槽连接。

信号/插槽通信总是会产生开销,因为它纯粹是基于运行时的,并且对字符串进行操作(插槽的名称在编译时生成,然后在运行时进行比较。)它是动态调度。直接函数调用总是更快。

所以答案很简单:如果你不需要信号,请不要使用。在这种特殊情况下,看起来你不需要它来进行DataManager和MainWindow之间的通信,因为你想要的只是调用MainWindow :: displayData()。看起来你不需要动态地改变它并调用不同的函数。信号和插槽用于提供线程间通信和类似交换机的连接。如果您不需要,则无需使用信号。

答案 1 :(得分:3)

第一个选项确实提供了比使用信号/插槽机制更好的性能,但它的缺点是MainWindowDataManager之间存在紧密耦合。两者都互相认识,所以不能真正单独使用。 仅这一点就应该是重构代码的理由。

也就是说,作为第三种选择,你可以让MainWindow拥有从DataWorker接收信号的插槽,让DataManager成为一个帮助类,只需将数据转换为可用的MainWindow的格式。

class MainWindow
{
private:
    DataManager* dm;

public:
    MainWindow() : dm(new DataManager()) { }
    displayData(QString processedData);
private slots;
    eventNewData()
    {
        // get the data
        QString processedData = dm->preprocessData(data);
        displayData(processedData);
        // release data
    }
};

class DataManager
{
public:
    QString preprocessData(...);
};

答案 2 :(得分:0)

我不确切知道QT是如何工作的所以我不确定是否有性能损失,但我的直觉说 1.应该没有太大的区别 2.无论如何,在GUI环境中它可能无关紧要。

使用标准QT机制的选项具有DataManager无需了解GUI的任何好处。许多人都认为这是一个好的设计,因为它可以让你在不改变内部结构的情况下更换你的GUI。