c++ - 直接调用函数与发出信号(Qt - 信号和槽)

标签 c++ qt signals-slots

此时我陷入了两难境地:何时发出信号与直接调用另一个类中的方法(同一线程)。例如,在我正在做的教程中,我将 Instrument 类(模型)的 NotifyConnected 信号连接到“this”(又名 View 管理器)的 onConnected 插槽,请参阅SetupViewManager::WireButtons(),代码中的第三行。 (我正在使用 MVVM 设计模式)。这里信号和槽是有意义的,因为仪器类(模型)不应该知道有关 View 管理器的任何信息。 (即,将 View 管理器的引用传递给模型是不行的,因为它会破坏 MVVM 设计模式。)太棒了。

我遇到的问题是,接下来在教程中,ViewManager 的 onConnected 插槽会发出其他信号,然后我必须继续手动连接到另一个 View 类的插槽,即 SetupTab (引用 void SetupViewManager::onConnected 和 void代码中的SetupViewManager::WireDisplayUpdate())。

我的问题是,为什么不直接调用SetupTab的方法来替换onConnected槽中的所有发出?对我来说,感觉代码过于复杂。

付出额外的努力来发出信号并且必须连接所有内容只是为了简单地从我有引用的另一个类调用公共(public)函数(信号)有什么好处?它不是多线程应用程序(我知道信号和槽是线程安全的)。

请赐教。

谢谢。

setupviewmanager.cpp:

#include "setupviewmanager.h"
#include "View/setuptab.h"
#include "Model/instrument.h"
#include "Model/settings.h"
#include "utils.h"

namespace Ps
{
    SetupViewManager::SetupViewManager(QObject *parent,
                                       SetupTab &tab,
                                       Instrument &inst,
                                       Settings &config) :
        QObject(parent),
        m_setupTab(tab),
        m_instrument(inst)
    {
        WireSettings(config);
        config.ParseJsonData();
        WireHostAndPort();
        WireMessages();
        WireButtons();
        WireDisplayUpdate();

        m_setupTab.SetHostName(config.getHostName());
        m_setupTab.SetPort(config.getPortNumber());
        m_setupTab.SetCommands(config.getCommandsAsModel());
        auto long_wait = config.getLongWaitMs();
        auto short_wait = config.getShortWaitMs();
        m_instrument.SetlongWaitMs(long_wait);
        m_instrument.SetShortWaitMs(short_wait);
        emit NotifyStatusUpdated(tr("Long wait Ms: %1").arg(long_wait));
        emit NotifyStatusUpdated(tr("Short Wait Ms: %1").arg(short_wait));
        onDisconnected();
    }

    SetupViewManager::~SetupViewManager()
    {
        Utils::DestructorMsg(this);
    }

    void SetupViewManager::WireSettings(Settings &config)
    {
        connect(&config, &Settings::NotifyStatusMessage, &m_setupTab, &SetupTab::onStatusUpdated);
    }

    void SetupViewManager::WireHostAndPort()
    {
        connect(&m_setupTab, &SetupTab::NotifyHostNameChanged, &m_instrument, &Instrument::onHostNameChanged);
        connect(&m_setupTab, &SetupTab::NotifyPortChanged, &m_instrument, &Instrument::onPortChanged);
    }

    void SetupViewManager::WireMessages()
    {
        connect(&m_instrument, &Instrument::NotifyErrorDetected, &m_setupTab, &SetupTab::onStatusUpdated);
        connect(&m_instrument, &Instrument::NotifyStatusUpdated, &m_setupTab, &SetupTab::onStatusUpdated);
        connect(this, &SetupViewManager::NotifyStatusUpdated, &m_setupTab, &SetupTab::onStatusUpdated);
    }

    void SetupViewManager::WireButtons()
    {
        connect(&m_setupTab, &SetupTab::NotifyConnectClicked,&m_instrument, &Instrument::Connect);
        connect(&m_instrument, &Instrument::NotifyConnected, &m_setupTab, &SetupTab::onConnected);
        connect(&m_instrument, &Instrument::NotifyConnected, this, &SetupViewManager::onConnected);

        connect(&m_setupTab, &SetupTab::NotifyDisconnectClicked,&m_instrument, &Instrument::Disconnect);
        connect(&m_instrument, &Instrument::NotifyDisconnected, &m_setupTab,&SetupTab::onDisconnected);
        connect(&m_instrument, &Instrument::NotifyDisconnected, this, &SetupViewManager::onDisconnected);

        connect(&m_setupTab, &SetupTab::NotifySendClicked,&m_instrument, &Instrument::onSendRequest);
        connect(&m_instrument, &Instrument::NotifyDataSent,&m_setupTab, &SetupTab::onDataSent);

        connect(&m_setupTab, &SetupTab::NotifyReceiveClicked,&m_instrument, &Instrument::onReceiveRequest);
        connect(&m_instrument, &Instrument::NotifyDataReceived,&m_setupTab, &SetupTab::onDataReceived);
    }

    void SetupViewManager::WireDisplayUpdate()
    {
       connect (this, &SetupViewManager::NotifyConnectEnabled, &m_setupTab, &SetupTab::onConnectEnabled);
       connect (this, &SetupViewManager::NotifyDisconnectEnabled, &m_setupTab, &SetupTab::onDisconnectEnabled);
       connect (this, &SetupViewManager::NotifyDirectCommandsEnabled, &m_setupTab, &SetupTab::onDirectCommandsEnabled);
       connect (this, &SetupViewManager::NotifyControlTabEnabled, &m_setupTab, &SetupTab::onControlTabEnabled);
    }

    void SetupViewManager::onConnected()
    {
        emit NotifyConnectEnabled(false); // HERE. Why not just call method directly with m_setupTab.onConnectEnabled(false); etc...?
        emit NotifyDisconnectEnabled(true);
        emit NotifyDirectCommandsEnabled(true);
        emit NotifyControlTabEnabled(true);
    }

    void SetupViewManager::onDisconnected()
    {
        emit NotifyConnectEnabled(true);
        emit NotifyDisconnectEnabled(false);
        emit NotifyDirectCommandsEnabled(false);
        emit NotifyControlTabEnabled(false);
    }
}

最佳答案

信号槽机制的优点:

  • 当您的类(class)没有有关其客户的信息时,易于使用;
  • 可用于线程安全调用;
  • 您不得手动记住所有对象来通知它们;
  • 连接两个对象的唯一规则是它们都必须是 QObject 子类。

缺点:

  • 调用速度较慢(每个信号发出扫描所有连接对象的列表);
  • 可能是复杂的意大利面条式代码;您不知道谁以及何时会调用任何插槽或谁会收到发出的信号。

你应该考虑一下你自己的情况。如果SetupViewManager之外没有信号“监听器”,请尝试直接调用。如果其他人可以连接到此信号,您​​的选择就是发出它们。

使用信号可能还有其他原因。但没有理由仅仅使用它们来调用函数。至少在一个线程中。

关于c++ - 直接调用函数与发出信号(Qt - 信号和槽),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37919309/

相关文章:

qt - 如何防止 QWidget 绘制,但仍响应事件?

c++ - 在 Visual Studio 2017 中构建 Qt 可执行文件

c++ - Qt问题将参数传递给插槽

c++ - Qt 信号可以返回一个值吗?

c++ - C++中的异常处理

c++ - 如何将 DWORDLONG 转换为 char *?

c++ - 使用 log4cxx 记录 C++ 中的特定类

qt - 更改多列过滤的 QSortFilterProxyModel 行为

c++ - Next_permutation 和效率

Python PyQt4 发送和接收自定义信号