C++ Qt:访问uitools/uiloader生成的小部件的信号/插槽

C++ Qt:访问uitools/uiloader生成的小部件的信号/插槽,c++,qt,C++,Qt,我的应用程序显示一个主窗口ui,它在运行时获得新的ui部分。主窗口的ui在编译时创建,而新窗口小部件在运行时加载。(qrc中带有.ui和uiloader) 我的问题是:尽管Qt报告QObject::connect()全部成功,但我无法获得要触发的运行时小部件的信号和插槽 我已经在这里和其他地方读过很多关于信号和插槽的故障排除建议(如这些),但我开始怀疑这是使用uitools/uiloader获取运行时ui元素的独特之处。这是因为主窗口的信号和插槽都可以工作 我在Windows7 Professi

我的应用程序显示一个主窗口ui,它在运行时获得新的ui部分。主窗口的ui在编译时创建,而新窗口小部件在运行时加载。(qrc中带有.ui和uiloader)

我的问题是:尽管Qt报告
QObject::connect()
全部成功,但我无法获得要触发的运行时小部件的信号和插槽

我已经在这里和其他地方读过很多关于信号和插槽的故障排除建议(如这些),但我开始怀疑这是使用uitools/uiloader获取运行时ui元素的独特之处。这是因为主窗口的信号和插槽都可以工作

我在Windows7 Professional上使用Qt5.2.1和QtCreator3.0.1。我还使用boost线程和no-QThreads

图片能表达千言万语

MainWindow.ui

ChildWidget.ui

合并的。 主窗口垂直布局中的2个子窗口小部件

在这个程序实例中,我在主窗口中硬编码了两个子窗口

我将主窗口的
按钮
单击信号连接到一个
test()
插槽,该插槽在主窗口的文本框中写入“OH PUSH”。相同的信号连接到所有子窗口的
test()
插槽,这些插槽在其所有文本框上都应执行相同的操作。什么也没出现

程序中隐藏着一个带有自定义QObject的Boost::Thread。其信号每2秒触发一次,并同样连接到所有
test()
插槽。只有主窗口显示“哦推”

我还尝试将
切换暂停
按钮的单击与所有插槽连接起来。在这种情况下,单击时甚至不会触发信号

现在没有代码,因为我希望这是一个简单的问题,专业人士可以很快发现。如果不是这样,我将显示代码


编辑: 在编写包含代码的编辑时,我无意中发现了解决方案。 我将在这里展示我的文章,并将解释为什么我的程序不起作用

主要玩家有MainController、MainWindow、ChildController、ChildWidget

/*
main spawns a mainController.
mainController::ctor spawns a QApplication.
mainController::ctor spawns a MainWindow.
The MainWindow spawns its ui.  ( `ui->setupUI( this );` )

// back in main, after spawning MainWindow
main calls mainController's init()
mainController::init() spawns a ChildController.
ChildController::ctor spawns a boost::thread that idles.
mainController::init() spawns a ChildWidget.* // see below for code
mainController::init() connects MainWindow with all ChildWidgets, as well as all signals/slots**. // see below for the code
mainController::init() loops to spawn another pair of ChildController/ChildWidget, if required.

// back in main, after calling mainController's init()
main calls mainController's run()
mainController::run() calls MainWindow's show()
mainController::run() calls (every) ChildController's unpause(), so the boost::threads stop idling and starts emitting signals every 2 seconds.
mainController::run() calls QApplication's exec() and blocks till the end of the program.
*/
*ChildWidget已生成

class ChildWidget : public QWidget
{
    Q_OBJECT

public:
    ChildWidget( QWidget* parent = 0 );

    QWidget* get_pointer_to_ui();

public slots: 
    void slot_push_text( std::string text );
    void slot_push_image( const std::vector< unsigned char > image );
    void slot_test();

private slots:
    void on_buttonPause_clicked();

private:
    QPlainTextEdit* uiText;
    QLabel* uiImage;
    QPushButton* uiPauseButton;

    QWidget* ui;

private:
    QWidget* load_ui(); // called on construct
};

ChildWidget::ChildWidget( QWidget* parent )
    : QWidget( parent )
{
    QWidget* widg = load_ui();

    uiImage = widg->findChild< QLabel* >( "labelImage" );
    uiText = widg->findChild< QPlainTextEdit* >( "textConsole" );
    uiPauseButton = widg->findChild< QPushButton* >( "buttonPause" );

    ui = widg;

    QMetaObject::connectSlotsByName( this );
}

QWidget* ChildWidget::load_ui()
{
    QUiLoader loader;

    QFile file(":/widgets/ChildWidget.ui");
    file.open(QFile::ReadOnly);

    QWidget *widg = loader.load(&file, this);
    file.close();

    return widg;
}

起初,我把代码放在这里,但它变得非常混乱,所以现在它只是一个感兴趣区域的片段,其余部分是描述性文本。

结果是我犯了一个与Qt无关的基本错误

当通过QUiLoader生成ui元素时,我附带了一个附带的小部件。此小部件用于从ui发出信号,并在触发其插槽时对ui进行更改

所有连接都已正确建立,但不会仅仅因为附带小部件被意外删除而触发,从而使所有连接无效

  • 将编译时ui与运行时加载的ui混合使用是完全有效的
  • 在运行时生成的信号和插槽的行为方式与任何其他信号和插槽的行为方式相同
  • 仔细管理小部件的生命周期

如果您展示子窗口小部件的创建和信号/插槽连接,可能会更好。
void MainController::init()
{
    //FIXME. hard code to spawn two for now.
    for( int i = 0; i < 2; ++i )
    { // routine spawning the child controllers

        /* **** construct the child controllers, which internally contains a small module that emits sigs **** */
        boost::shared_ptr< ChildController > v1 = boost::shared_ptr< ChildController >( new ChildController );

        /* **** each child controller is to have 1-1 corresponding ui element. **** */
        /* We shall spawn ONE ChildWidget for each ChildController.
         * Each ChildWidget itself contains pointer to a widget generated via runtime uic.
         * This widget needs to be passed to The Main Controller so it can be added to its layout.
        */
        boost::shared_ptr< ChildWidget > newWidget = boost::shared_ptr< ChildWidget >( new ChildWidget( w.get() ) );
        // a new ChildWidget is created, whose parent is defined to be the MainWindow, w

        // the main window will now attempt to incorporate the new widget in its layout
        QWidget* newWidgUi = newWidget->get_pointer_to_ui(); // dangerous? returns a pointer to the ui loaded with `loader.load(&file, this)` above
        this->w->add_view( newWidgUi ); // calls MainWindow's VerticalLayout addWidget()


        // all signals and slots are to be connected next.
        if( newWidget != 0 )
        {
            // if main window button pressed, send text to this ChildWidget's text window
            bool isTest = QObject::connect( w.get(), &MainWindow::sig_test,
                                          newWidget.get(), &ChildWidget::slot_push_text );

            // if main window button pressed, send text to the main window's text window.
            QObject::connect( w.get(), &MainWindow::sig_test,
                                          w.get(), &MainWindow::slot_test );

            // if the boost::thread signals, deliver some text to this ChildWidget
            QObject::connect( v1->widget.get(), &ChildController::sig_push_text,
                              newWidget.get(), &ChildWidget::slot_push_text );

            // if this child window's button is pressed, show some text on the main window.
            QObject::connect( v1->widget.get(), &ChildController::sig_push_text,
                         this->w.get(), &MainWindow::slot_test );

            this->vControllers.push_back( v1 );
        }

    }

    // all the connections above succeed.
    // but this is where my problem was.
    // newWidget was not stored beyond this function, so boost::shared_ptr destroys it
}
Q_DECLARE_METATYPE( std::string )
Q_DECLARE_METATYPE( std::vector< unsigned char > )
qRegisterMetaType< std::string >( "std::string" );
qRegisterMetaType< std::string >( "std::vector< unsigned char >" );
Q_INIT_RESOURCE( dynwidgets ); // dynwidgets.qrc contains the ChildWindow's .ui file