Qt/C++ 子窗口和主窗口通信技术简解(献给初学者)

软件和网站开发以及相关技术探讨
回复
头像
flwwater
帖子: 761
注册时间: 2010-10-31 9:15
系统: kubuntu 24.04

Qt/C++ 子窗口和主窗口通信技术简解(献给初学者)

#1

帖子 flwwater » 2015-12-15 12:31

新工程文件有如下5个文件:
mainwindow.h (主窗口类)
stat.h (子窗口类)
main.cpp (显示窗口,只有2行代码)
mainwindow.cpp(定义主窗口及控件,生成子窗口)
stat.cpp (定义子窗口及控件)



其中main.cpp最简单,就是创建并显示主窗口。

代码: 全选

#include <QApplication>
#include "mainwindow.h"
int main(int argc , char **argv)
{
    QApplication app(argc,argv);
    MainWindow *w = new MainWindow ;
    w->show();
    return app.exec();
}

在mainwindow.h里声明了一个主窗口要用到的控件。

代码: 全选

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui>  //为了简洁明了直接上QtGui头文件,它包含所需要的一切相关类。
class MainWindow : public QMainWindow
{
    Q_OBJECT
private slots:
    void gen1();  //此函数是当用户点击主菜单里的项时,生成子窗口。
public:
    QSpinBox *spinbox ;  
    //非相关的代码,如窗口布局等全部省略。
};
#endif // MAINWINDOW_H

在stat.h里声明子窗口,点击button后就可以刷新spinbox里的值了。

代码: 全选

#include "mainwindow.h"
#include <QtGui>
class genB1Dialog : public QDialog
{
    Q_OBJECT
public:
    genB1Dialog(QWidget *parent = 0);
    void hookMainWindow(MainWindow *w) ;  //创建一个函数,其参数是窗口指针
    MainWindow *p ;                       //创建一个窗口指针
private:
    QSpinBox *spinbox ;
    QPushButton *button ;
signals:
    void ToMainWindow( int );
private slots:
    void monitor() ;  //子窗口里的按钮点击后信号发送给此槽函数,然后函数内实现子窗口里的spinbox和主窗口里的spinbox数据同步
    void updateToMainWindow_Spinbox(int) ;
};

在MainWindow.cpp中的代码是界面布局和生成子窗口。

代码: 全选

#include <QtGui>
#include "mainwindow.h"
#include "stat.h"
MainWindow::MainWindow(QWidget *parent):QMainWindow(parent)
{
   //以下非相关的代码全部用//给注释掉了,只需记得主窗口里有一个QSpinbox,初使值为5
    //createAct();
    //createMenus();
    //textEdit = new QTextEdit ;
    spinbox = new QSpinBox ;
    spinbox->setValue(5);
    //QSplitter *main = new QSplitter(Qt::Vertical);
    //main->addWidget(top);
   // main->addWidget(bottom);
    //setCentralWidget(main);
}
void MainWindow::gen1()
{
    genF1Dialog *dlg = new genF1Dialog(this) ;  //当点击主窗口菜单File下的creator项时,生成此子窗口,

    ......
    //以上省略你要实现的代码,最关键的是下一行代码,把主窗口指针this通过hookMainWindow传给了dlg子窗口
    dlg->hookMainWindow(this);
    
    QObject::connect(dlg , SIGNAL(ToMainTable(int)) , this , SLOT(updateToMainWindow_Spinbox(int)) ;
    dlg->show();
}
void MainWindow::updateToMainWindow_Spinbox(int a)
{
    spinbox->setValue( a ) ;
}

在stat.cpp里是子窗口类的定义

代码: 全选

#include <QDialog>
#include "stat.h"
genF1Dialog::genF1Dialog(QWidget *parent) : QDialog(parent)
{
   //以下非相关的代码全部用//给注释掉
    spinbox = new QSpinBox(this) ;
    spinbox->setValue(0);
    button = new QPushButton("Update") ;
 
    //QVBoxLayout *mainLayout = new QVBoxLayout ;
    //mainLayout->addWidget(table);
    //mainLayout->addWidget(spinbox);
    //setLayout(mainLayout);
    QObject::connect(button , SIGNAL(clicked()) , this , SLOT(monitor()) ) ; //创建按钮点击信号,并与函数monitor关联。
   // resize(800,600);
}
void genF1Dialog::hookMainWindow(MainWindow *w)
{
    p = w ;  //让指针p指向主窗口

}
void genFDialog::monitor()
{
    spinbox->setValue( p->spinbox->value() ) ;  //把主窗口spinbox的数据传到此子窗口的spinbox里
}

最关键的是在void MainWindow::gen1()函数里用语句genF1Dialog *dlg = new genF1Dialog(this)生成子窗口后,再用语句dlg->hookMainWindow(this)把主窗口指针引给dlg子窗口。子窗口头文件stat.h里声明一个窗口指针MainWindow *p ,让它通过 stat.cpp里的void genF1Dialog::hookMainWindow(MainWindow *w)函数把主窗口指针赋给它。这时终于可以在dlg子窗口里通过指针p访问主窗口里的控件了。

反过来,如果我要把子窗口里spinbox的值传给主窗口呢?
那就简单一些了,只要在stat.h里定义一个信号:
signals:
void ToMainWindow( int ); //因为spinbox里的值是一个int型,所以信号里的参数也是int型。
即可。
在你想要传给主窗口的时候用语句:
emit ToMainWindow( spinbox->value() ) ;

发射了信号,接下来就要接收信号了,在mainwindow.cpp文件的void MainWindow::gen1()函数里添加语句:
QObject::connect(dlg , SIGNAL(ToMainTable(int)) , this , SLOT(updateToMainWindow_Spinbox(int)) ;

当然,updateToMainWindow_Spinbox(int)也要在mainwindow.h中声明一下。
最后在mainwindow.cpp中添加如下语句:
void MainWindow::updateToMainWindow_Spinbox(int a)
{
spinbox->setValue( a ) ; //把子窗口spinbox的数据传到主窗口的spinbox里
}


到这里工程就可以完工了。实现了双向通信。小小例子,浪费了我2个小时,希望能帮到有需要又没头绪的初学者。
[/code]
上次由 flwwater 在 2015-12-15 18:41,总共编辑 1 次。
个人收藏的数百个精美动态壁纸:
https://url17.ctfile.com/d/15983117-593 ... 768?p=6220
(访问密码:6220


个人收藏的经典国语音乐和纯音乐(钢琴,笛子,二胡等):
https://url17.ctfile.com/d/15983117-446 ... 33e?p=6220
(访问密码:6220



如果访问密码不对,可试试这个密码 566816
头像
月下叹逍遥
论坛版主
帖子: 33994
注册时间: 2010-10-07 14:23
系统: Archdows10
来自: 某系某星某洲某国某省某市
联系:

Re: Qt/C++ 子窗口和主窗口通信技术简解(献给初学者)

#2

帖子 月下叹逍遥 » 2015-12-15 14:28

:em11 :em11
浮生七十今三十,从此凄惶未可知
头像
astolia
论坛版主
帖子: 6422
注册时间: 2008-09-18 13:11

Re: Qt/C++ 子窗口和主窗口通信技术简解(献给初学者)

#3

帖子 astolia » 2015-12-15 15:45

代码: 全选

genF1Dialog *dlg = new genF1Dialog(this);
这里已经把this传给子窗口了,何必后面再传一次
头像
bzimage
帖子: 716
注册时间: 2006-03-14 10:25

Re: Qt/C++ 子窗口和主窗口通信技术简解(献给初学者)

#4

帖子 bzimage » 2015-12-16 13:49

mark :Music
头像
flwwater
帖子: 761
注册时间: 2010-10-31 9:15
系统: kubuntu 24.04

Re: Qt/C++ 子窗口和主窗口通信技术简解(献给初学者)

#5

帖子 flwwater » 2015-12-20 12:13

astolia 写了:

代码: 全选

genF1Dialog *dlg = new genF1Dialog(this);
这里已经把this传给子窗口了,何必后面再传一次
正所谓条条道路通罗马,既然有朋友提出了建议,那么给出第二种解法:
在stat.h里:
class genF1Dialog : public QDialog
{
Q_OBJECT
public:
genF1Dialog(MainWindow *parent); //直接把主窗口指针传过来,不再初使化为0.
//void hookMainWindow(MainWindow *w) ; //所以这个就不需要了
MainWindow *p ; //创建一个窗口指针

//.....其余代码都一样
};

在stat.cpp里:
genF1Dialog::genF1Dialog(MainWindow *parent) : QDialog(parent)
{
p = parent ; //指针直接赋值,指向主窗口
}
void genFDialog::monitor()
{
spinbox->setValue( p->spinbox->value() ) ; //此处无需更改,p同样有效。
}
个人收藏的数百个精美动态壁纸:
https://url17.ctfile.com/d/15983117-593 ... 768?p=6220
(访问密码:6220


个人收藏的经典国语音乐和纯音乐(钢琴,笛子,二胡等):
https://url17.ctfile.com/d/15983117-446 ... 33e?p=6220
(访问密码:6220



如果访问密码不对,可试试这个密码 566816
mrlin0819
帖子: 1
注册时间: 2016-01-13 10:35
系统: Windows10/ubuntu15.1

Re: Qt/C++ 子窗口和主窗口通信技术简解(献给初学者)

#6

帖子 mrlin0819 » 2016-01-13 10:41

虽然说Dialog可以有父控件且子控件持有父控件的指针不会有空间性能上的问题,不过总感觉这种方式并不“优雅”。觉得在子控件里按键时发出带有spinbox值的信号,在父控件里连接这个自定义的信号,再改变父控件的spinbox的值,这样控件的控制权的管理会清晰些。
头像
flwwater
帖子: 761
注册时间: 2010-10-31 9:15
系统: kubuntu 24.04

Re: Qt/C++ 子窗口和主窗口通信技术简解(献给初学者)

#7

帖子 flwwater » 2016-12-10 13:47

谢谢两位大神的建议 :Haha
个人收藏的数百个精美动态壁纸:
https://url17.ctfile.com/d/15983117-593 ... 768?p=6220
(访问密码:6220


个人收藏的经典国语音乐和纯音乐(钢琴,笛子,二胡等):
https://url17.ctfile.com/d/15983117-446 ... 33e?p=6220
(访问密码:6220



如果访问密码不对,可试试这个密码 566816
回复