Qt实战(1)

Qt实战

通过两个独立窗口的切换来学习信号和槽

创建项目

新建Qt Widgets应用,项目名称SingelAndSlot ,类名默认为mainWidget,基类默认为QWidget,不勾选创建界面。

  1. 先来认识SingelAndSlot.pro文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #添加模块
    QT += core gui

    #高于4版本,添加QT += widgets,为了兼容Qt4
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

    #应用程序的名字
    TARGET = SingelAndSlot
    #指定SingelAndSlot的类型为app
    TEMPLATE = app

    #源文件 .cpp文件
    SOURCES += main.cpp\
    mainwidget.cpp

    #头文件 .h文件
    HEADERS += mainwidget.h
  2. 创建两个按钮:
    mainwidget.h中添加代码:

    1
    2
    3
    private:
    QPushButton b1;
    QPushButton *b2;

mainwidget.cpp中添加:

1
2
3
4
5
6
b1.setParent(this);
b1.setText(("close");
b1.move(100,100);

b2=new QPushButton(this);//b2是指针,要分配存储空间
b2->setText("abc");

connect函数

用法:
connect( 信号发出者, &发出者类型::信号名字,接受者(this),&接受者类名::槽函数名字)
说明:

  • 信号发送者和接受者均为指针类型(非指针类型添加“&”符号)
  • 槽函数,即信号处理函数

如果是自定义的槽函数,需要注意以下几点:

  • 可以是任意的成员函数,普通全局函数,静态函数;
  • 槽函数需要和信号一致(返回值,参数)
  • 由于信号都是没有返回值的,所以,槽函数一定没有返回值;
  1. 添加b1的槽函数
    MainWidget.cpp中的构造函数中继续添加:

    1
    connect(&b1,&QPushButton::pressed,this,&MainWidget::close);

    代码实现点击b1按钮,主窗口关闭。

  2. 添加b2的槽函数
    在mainwidget.h中添加自定义公有槽函数成员:

1
void myslot();

MainWidget.cpp中的构造函数中添加:

1
2
3
//b2本来就是指针(地址),不需添加地址符
connect(b2,&QPushButton::released,this,&MainWidget::myslot);
connect(b2,&QPushButton::released,&b1,&QPushButton::hide);

MainWidget.cpp中添加函数定义:

1
2
3
void MainWidget::myslot(){
b2->setText("123");
}

以上代码实现释放b2按钮,主窗口实现自定义槽函数,修改按钮b2的内容,b1按钮实现按钮隐藏。

创建新窗口

头文件右击添加新文件,选择c++ class,类名为subwidget,基类为Widget。

  1. 在主窗口的头文件中添加按钮a3,源文件中添加代码:
1
2
3
4
5
b3.setParent(this);
b3.setText("切换到父窗口");
b3.move(50,50);

resize(300,400);//窗口大小设置
  1. 在子窗口文件头文件添加按钮成员b,源文件中添加代码:
    1
    2
    3
    4
    5
    this->setWindowTitle("我是小弟");
    b.setParent(this);
    b.setText("切换到主窗口");

    resize(300,400);

切换槽函数

  1. 主窗口切换为子窗口。

① 头文件中添加公有函数成员:

1
void changeWin();//切换窗口

② 添加槽函数连接和定义:

1
2
3
4
5
6
7
8
9
10
11
//构造函数中添加
connect(&b3,&QPushButton::released,this,&MainWidget::changeWin);

//函数定义
void MainWidget::changeWin(){

//子窗口显示
w.show();
//主窗口隐藏
this->hide();
}

  1. 子窗口切换为主窗口

子窗口发送信号

  • 信号必须有signals关键字
  • 信号没有返回值,但可以有参数
  • 信号就是函数的声明,只需声明,无需定义
  • 使用 emit mysignel();
  • 信号可以重载

① 在子窗口头文件中添加公有信号处理函数和信号成员

1
2
3
4
void sendSlot();

signals:
void mysignal();

② 在子窗口源文件中添加连接及其信号处理函数:

1
2
3
4
5
6
7
//子窗口构造函数中添加
connect(&b,&QPushButton::clicked,this,&subWidget::sendSlot);


void subWidget::sendSlot(){
emit mysignal();//发送信号
}

③ 在主窗口中添加处理信号函数:

1
void dealsubSignal();

④ 在主窗口的源文件中创建信号和槽函数的连接 和处理函数的定义

1
2
3
4
5
6
7
8
9
    //处理主窗口信号
connect(&w,&subWidget::mysignal,this,&MainWidget::dealsubSignal);

void MainWidget::dealsubSignal(){
//子窗口隐藏
w.hide();
//主窗口显示
this->show();
}

这里解释一下:其实这里不是在子窗口中响应子窗口按钮发出的信号,而是通过主窗口来处理信号,只是他的信号发送方是子窗口,但要通过按钮实现,所以按下子窗口的按钮后的调用函数,函数执行的事件是发送一个信号给主窗口,这个信号属于子窗口。主窗口在对信号进行处理。

带参数的信号

  1. 在子窗口继续添加一个带参信号:

    1
    2
    3
    signals:
    void mysignal();
    void mysignal(int,QString);
  2. 在前面按钮按下而发送信号的函数里继续添加发送信号:

1
2
3
4
void subWidget::sendSlot(){
emit mysignal();
emit mysignal(250,"我是子窗口");
}
  1. 在主窗口里添加信号处理函数
1
void dealSlot(int,QString);
  1. 信号连接和处理函数定义:
1
2
3
4
5
6
	connect(&w,&subWidget::mysignal,this,&MainWidget::dealSlot);

//信号处理函数
void MainWidget::dealSlot(int a, QString str){
qDebug()<<a<<str.toUtf8().data();
}

运行程序,发现报错,这是为什么呢?
因为connect里的参数&subWidget::mysignal不知道是含参信号函数还是不含参信号函数啊

解决办法有两种:
① 函数指针

1
2
3
4
5
void (subWidget::*withnotcansignal)()=&subWidget::mysignal;
connect(&w,withnotcansignal,this,&MainWidget::dealsubSignal);

void (subWidget::*withcansignal)(int,QString)=&subWidget::mysignal;
connect(&w,withcansignal,this,&MainWidget::dealSlot);

注意: 加上作用域

② SIGNAL和SLOT(这是qt4的信号连接,安全性不好)

1
2
3
//Qt4
connect(&w,SIGNAL(mysignal()),this,SLOT(dealsubSignal()));
connect(&w,SIGNAL(mysignal(int,QString)),this,SLOT(dealSlot(int,QString)));

Lamda表达式直接处理信号

  1. 在.pro项目文件中添加

    1
    CONFIG +=C++11
  2. 在主窗口的源文件中继续添加

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    QPushButton *b4=new QPushButton(this);
    b4->setText("lambda表达式");
    b4->move(150,150);

    //[]里面放你要对外部那些变量进行操作的变量,否则无法捕捉到,
    //一般最好用“=”表示外面所有局部变量、类中所有成员以值传递方式(就像拷贝一样)
    //()传参,如果这个函数要处理的信号有参数,那括号里需要包含所传参数
    //mutable允许对传入的成员进行操作,否则只读
    int a=2;
    connect(b4,&QPushButton::released,
    [=]()mutable
    {
    b4->setText("123");
    a=11;
    });

Lamda表达式可以创造一个对信号直接处理的函数,不需要重声明和定义一个函数

创建一个主窗口

创建项目

新建Qt Widgets应用,项目名称QWindow ,类名默认MainWindow,基类默认为QMainWindow,不勾选创建界面。
mainwindow.cpp代码如下,根据代码领会,不在解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include "mainwindow.h"
#include<QMenuBar>
#include<QMenu>
#include<QAction>
#include<QDebug>
#include<QToolBar>
#include<QPushButton>
#include<QStatusBar>
#include<QLabel>
#include<QTextEdit>
#include<QDockWidget>
#include<QDialog>
#include<QMessageBox>
#include<QFileDialog>

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
//创建菜单栏
QMenuBar *mybar=menuBar();
// 添加菜单
QMenu *pFile=mybar->addMenu("文件");

// 添加菜单项,添加动作
QAction *pNew=pFile->addAction("新建");
connect(pNew,&QAction::triggered,
[=]()
{
qDebug()<<"新建被按下";
});

pFile->addSeparator();//添加分割线
QAction *pOpen= pFile->addAction("打开");
connect(pOpen,&QAction::triggered,
[=]()
{
qDebug()<<"打开被按下";
});

//工具栏,菜单项的快捷方式
QToolBar *toolbar=addToolBar("ToolBar");

//工具栏添加快捷键
toolbar->addAction(pNew);

//工具栏添加按钮控件
QPushButton *b=new QPushButton(this);
b->setText("工具按钮");
toolbar->addWidget(b);

connect(b,&QPushButton::clicked,
[=]()
{
b->setText("哈哈哈");
});

//状态栏
QStatusBar *sBar=statusBar();
QLabel *label=new QLabel(this);
label->setText("程序正在运行");
sBar->addWidget(label);
//addWidget从左往右添加
sBar->addWidget(new QLabel("2",this));
//从右向左添加
sBar->addPermanentWidget(new QLabel("3",this));

//核心控件
QTextEdit *textedit=new QTextEdit(this);
setCentralWidget(textedit);

//浮动窗口
QDockWidget *dockwidget=new QDockWidget(this);
addDockWidget(Qt::RightDockWidgetArea,dockwidget);

// 设置浮动窗口内容
QTextEdit *textedit1=new QTextEdit(this);
dockwidget->setWidget(textedit1);

//模态与非模态对话框
setMenuBar(mybar);
QMenu *menu1=mybar->addMenu("对话框");
QAction *p1=menu1->addAction("模态对话框");
connect(p1,&QAction::triggered,
[=]()
{
QDialog dlg;
dlg.exec();//一直运行,直到用户操作
});

QAction *p2=menu1->addAction("非模态对话框");
connect(p2,&QAction::triggered,
[=]()
{
//这种用法导致,点击非模态对话框,对话框闪现后就被释放
// QDialog dlg;
// dlg.show();

//运行结束时才会释放,所以你点击多少次,就会创建多少个程序,
//你关闭这个对话框时他分配到空间也不会释放
// QDialog *dlg1=new QDialog(this);
// dlg1->show();

//每次点击关闭内存空间就会释放
QDialog *dlg2=new QDialog(this);
dlg2->setAttribute(Qt::WA_DeleteOnClose);
dlg2->show();
});

mybar->addSeparator();//添加分割线

QAction *p3=menu1->addAction("关于对话框");
connect(p3,&QAction::triggered,
[=]()
{
QMessageBox::about(this,"about","关于Qt");
});

QAction *p4=menu1->addAction("问题对话框");
connect(p4,&QAction::triggered,
[=]()
{
int ret=QMessageBox::question(this,"question",
"Are you ok?",
QMessageBox::Ok|QMessageBox::Cancel);
switch(ret)
{
case QMessageBox::Ok:
qDebug()<<"i am ok";
break;
case QMessageBox::Cancel:
qDebug()<<"i am bad";
break;
default:
break;
}
});

QAction *p5=menu1->addAction("文件对话框");
connect(p5,&QAction::triggered,
[=]()
{
QString path=QFileDialog::getOpenFileName(
this,
"open",
"../",
"souce(*.cpp .h);;"
"Text(*.text);;"
"all(*.*)");
qDebug()<<path;
});
}


MainWindow::~MainWindow()
{

}

运行结果如图:

窗口运行结果

Qt样式表

Qt样式表
Qt样式表样式大全

你可以对我进行打赏哦