一百零九、QMainWindow中常用类的使用
109.1 菜单栏 QMenuBar
- 菜单栏 QMenuBar 最多只能有一个
109.2 工具栏 QToolBar
- 工具栏 QToolBar 可以有多个
109.3 状态栏QStatusBar
- 状态栏 QStatusBar 最多只能有一个
109.4 浮动窗口QDockWidget
- 浮动窗口 可以有多个
109.5 代码示例
- main.cpp
cpp
#include "my_mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
my_MainWindow w;
w.show();
return a.exec();
}
- my_mainwindow.h
cpp
#ifndef MY_MAINWINDOW_H
#define MY_MAINWINDOW_H
#include <QMainWindow>
#include <QMenuBar> // 菜单栏的类
#include <QToolBar>
#include <QPushButton>
#include <QStatusBar>
#include <QLabel>
#include <QDockWidget> // 浮动窗口类 铆接部件
#include <QTextEdit> // 文本编辑类
class my_MainWindow : public QMainWindow
{
Q_OBJECT
public:
my_MainWindow(QWidget *parent = nullptr);
~my_MainWindow();
};
#endif // MY_MAINWINDOW_H
- my_mainwindow.cpp
cpp
#include "my_mainwindow.h"
my_MainWindow::my_MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 调整窗口大小
this->resize(600,400);
// 创建菜单栏 QMenuBar 最多只能有一个
QMenuBar *mbar = menuBar();
// 把菜单栏放到当前窗口中
this->setMenuBar(mbar);
// 往菜单栏中增加菜单
QMenu *file = mbar->addMenu("文件");
// mbar->setStyleSheet("background-color:black");
QMenu *edit = mbar->addMenu("编辑");
// 往 "文件" 菜单中增加菜单项
file->addAction("新建");
// 增加分隔符
file->addSeparator();
// 往菜单中增加菜单项
file->addAction("打开");
// 创建工具栏 QToolBar 可以有多个
QToolBar *tbar = new QToolBar(this);
// 把工具栏放到窗口中
this->addToolBar(Qt::LeftToolBarArea,tbar);
// 后期设置 只允许停靠范围 左边 或 右边 可以继续或
tbar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
// 设置不允许浮动
tbar->setFloatable(false);
// 往工具栏中增加工具项 文本
tbar->addAction("锤子");
// 往工具栏中增加工具项 按钮
QPushButton *btn = new QPushButton("榔头",this);
tbar->addWidget(btn);
// 创建状态栏 QStatusBar 最多只能有一个
QStatusBar *sbar = statusBar();
// 把状态栏放到窗口中
this->setStatusBar(sbar);
// 在状态栏中增加标签
QLabel *lab = new QLabel("标签",this);
// 往状态栏中增加标签组件
// 默认在左边
// sbar->addWidget(lab);
// 默认在右边
sbar->addPermanentWidget(lab);
// 创建浮动窗口 QDockWidget 可以有多个
QDockWidget *dock = new QDockWidget("浮动窗口",this);
// 把浮动窗口放到窗口中
this->addDockWidget(Qt::TopDockWidgetArea, dock);
// 设置浮动窗口的停靠范围
dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
// 中心部件 最多只能有一个
QTextEdit *text = new QTextEdit(this);
// 将中心部件放到窗口中
this->setCentralWidget(text);
}
my_MainWindow::~my_MainWindow()
{
}
- 运行结果
一百一十、ui界面文件
- ui界面文件在项目工程文件的Forms文件夹下,
- 可以通过ui指针访问到ui界面上的所有组件(控件)。
- 创建时需要选中 ui 的界面
ui 操作界面
一百一十一、资源文件的添加
- 添加资源文件后,需要用到文件就可以不再用绝对路径了
- 方便把整个项目打包,这样别人打开
- 把资源文件放入到该项目工程文件中,选中项目中任意一个文件,右击,在explorer中显示,将资源文件复制到该项目下。
- 添加资源文件
- 选中文件夹中的所有文件
- 最后 Ctrl+B 或者左下角的锤子,构建一下
一百一十二、信号与槽
- 信号和槽是qt引以为傲的核心机制之一,可以实现多个组件之间的相互通信
- 信号:信号函数,定义在类体的signals权限下,信号函数不是一个完整的函数,只有声明,没有定义。
- 槽:槽函数,定义在类体的slots权限下,槽函数是一个完整的函数,既有声明,又有定义,也可以当成普通函数调用。
- 任何组件都有系统提供的默认信号函数和槽函数。
112.1 包含信号函数和槽函数的类体定义
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT //有关信号和槽的宏
public:
Widget(QWidget *parent = nullptr);
~Widget();
signals: //表示该权限下都是信号函数
void my_signal(); //自定义一个信号函数
public slots: //表示该权限下是公共的槽函数
void my_slot(); //自定义一个槽函数
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
112.2 信号和槽的连接方式
-
基于ui界面上的连接,在ui界面下面的信号与槽区,进行信号与槽的连接,该连接只适用于系统提供的信号和槽
不需要手动书写信号函数,槽函数,连接函数。
-
基于ui界面上的连接,在组件上,右击-->转到槽,选中要发射的信号,需要程序员在槽函数中写逻辑代码,但也不需要写连接函数。
cpp//按钮2对应的槽函数 void Widget::on_Btn2_clicked() { //让按钮1变色 //ui->Btn1->setStyleSheet("background-color:red"); static int num = 0; if(num%3 == 0) { ui->Btn1->setStyleSheet("background-color:red"); } else if (num%3 == 1) { ui->Btn1->setStyleSheet("background-color:green"); } else if (num%3 == 2) { ui->Btn1->setStyleSheet("background-color:blue"); } ++num; }
-
手动连接信号和槽函数,基于qt4版本,该连接是不友好的连接
cpp[static] QMetaObject::Connection //返回值类型 是一个静态成员函数,实现信号和槽的连接 QObject::connect( //函数名 const QObject *sender, //信号的发送者,是一个组件的指针 const char *signal, //发送具体的信号(信号函数),使用const char* ,而函数名使用函数指针来接收,需要用SIGNAL()转换 const QObject *receiver, //信号的接受者,是一个组件的指针 const char *method, ) //对信号处理的槽,使用const char* ,而函数名使用函数指针来接收,需要用SLOT()转换 举个例子: QLabel *label = new QLabel; QScrollBar *scrollBar = new QScrollBar; QObject::connect(scrollBar, SIGNAL(valueChanged(int)), label, SLOT(setNum(int)));
-
手动连接信号和槽函数,基于qt5版本,该连接是友好的连接
cpp[static] QMetaObject::Connection //返回值类型 是一个静态成员函数,实现信号和槽的连接 QObject::connect( //函数名 const QObject *sender, //信号的发送者,是一个组件的指针 PointerToMemberFunction signal, //信号函数,是一个函数指针,所以放函数名即可 const QObject *receiver, //信号的接受者,是一个组件的指针 PointerToMemberFunction method, ) //槽函数,是一个函数指针,所以放函数名即可 举个例子: QLabel *label = new QLabel; QLineEdit *lineEdit = new QLineEdit; QObject::connect(lineEdit, &QLineEdit::textChanged, label, &QLabel::setText);
-
手动连接信号和功能函数,只要组件发射了信号,就自动调用功能函数的内容。
功能函数可以是 全局函数,也可以是 lambda表达式
cpp[static] QMetaObject::Connection //函数返回值类型 QObject::connect( //函数名 const QObject *sender, //信号的发送者 PointerToMemberFunction signal, //信号函数 Functor functor) //功能函数
1.全局函数举个例子:
cppvoid someFunction(); QPushButton *button = new QPushButton; QObject::connect(button, &QPushButton::clicked, someFunction);
2.lambda表达式
cppQByteArray page = ...; QTcpSocket *socket = new QTcpSocket; socket->connectToHost("qt-project.org", 80); QObject::connect(socket, &QTcpSocket::connected, [=] () { socket->write("GET " + page + "\r\n"); });
112.3 定义语音播报
-
在工程文件中增加这个 :texttospeech
头文件cpp#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include<QPushButton> #include<QTextToSpeech> //语音播报类 QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT //有关信号和槽的宏 public: Widget(QWidget *parent = nullptr); ~Widget(); signals: //表示该权限下都是信号函数 void my_signal(); //自定义一个信号函数 public slots: //表示该权限下是公共的槽函数 void my_slot(); //自定义一个槽函数 void Btn4_slot(); //btn4对应的槽函数声明 private slots: void on_Btn2_clicked(); //系统定义的槽函数声明 private: Ui::Widget *ui; QPushButton *btn3; //定义一个语音播报者 QTextToSpeech *speecher; }; #endif // WIDGET_H
源文件
cpp#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //给语音播报者实例一个空间 speecher = new QTextToSpeech(this); //实例化一个按钮 btn3 = new QPushButton("按钮3",this); btn3->move(ui->Btn2->x(), ui->Btn2->y()+ui->Btn2->height()+10); btn3->resize(ui->Btn2->width(),ui->Btn2->height()); //手动连接信号和系统槽,基于qt4版本 是不友好的连接 //函数原型:[static] QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection) //参数1:是一个组件的指针 信号的发送者 //参数2:信号函数,需要宏函数转换 //参数3:是一个组件的指针 信号的接受者 //参数4:槽函数,需要宏函数转换 //connect(btn3, SIGNAL(clicked()), this, SLOT(close())); //手动连接信号和系统槽,基于qt4版本 是不友好的连接 this->connect(btn3, SIGNAL(clicked()), this,SLOT(my_slot())); //手动连接信号和自定义槽,基于qt5版本 是友好的连接 //函数原型:[static] QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection) //参数1:是一个组件的指针 信号的发送者 connect(ui->Btn4, &QPushButton::clicked, this, &Widget::Btn4_slot); } Widget::~Widget() { delete ui; } //自定义槽函数的实现 void Widget::my_slot() { this->close(); } //按钮4对应的槽函数实现 #include<QTextToSpeech> //语音播报类 void Widget::Btn4_slot() { //this->close(); static int num = 0; if(num%3 == 0) { speecher->say("咳咳咳"); } else if (num%3 == 1) { speecher->say(ui->Btn2->text()); } else if (num%3 == 2) { speecher->say(this->btn3->text()); } ++num; } //按钮2对应的槽函数 void Widget::on_Btn2_clicked() { //让按钮1变色 //ui->Btn1->setStyleSheet("background-color:red"); static int num = 0; if(num%3 == 0) { ui->Btn1->setStyleSheet("background-color:red"); } else if (num%3 == 1) { ui->Btn1->setStyleSheet("background-color:green"); } else if (num%3 == 2) { ui->Btn1->setStyleSheet("background-color:blue"); } ++num; }
112.4 自定义信号
- 自定义信号,写在类体的signals权限下,无返回值类型,只有声明,没有定义
- 自定义信号,需要用emit关键字触发,一旦被触发,就会执行与该信号连接的槽函数
112.5 信号与槽的断开连接
- 断开信号与槽的连接,只需要讲上述的连接函数改成disconnect即可,其函数参数和连接函数一致。
小作业
使用手动连接,将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中,
在自定义的槽函数中调用关闭函数
将登录按钮使用qt5版本的连接到自定义的槽函数中,
在槽函数中判断ui界面上输入的账号是否为"admin",密码是否为"123456",
如果账号密码匹配成功,则输出"登录成功",并关闭该界面,
如果匹配失败,则输出登录失败,并将密码框中的内容清空
我写的
login.h
cpp
#ifndef LOGIN_H
#define LOGIN_H
#include <QWidget>
#include <QPushButton>
#include <QDebug>
#include <QString>
QT_BEGIN_NAMESPACE
namespace Ui { class Login; }
QT_END_NAMESPACE
class Login : public QWidget
{
Q_OBJECT
public:
Login(QWidget *parent = nullptr);
~Login();
signals:
void clicked_cencel_signal();
public slots:
void close_window_slot();
private:
Ui::Login *ui;
};
#endif // LOGIN_H
login.cpp
cpp
#include "login.h"
#include "ui_login.h"
Login::Login(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Login)
{
ui->setupUi(this);
// 上半部分的图画
ui->loginLab->setPixmap(QPixmap(":/pictrue/qq_login.gif"));
// 设置上半部分图画为自适应大小
ui->loginLab->setScaledContents(true);
// 设置窗口左上角的企鹅和QQ
this->setWindowTitle("QQ");
this->setWindowIcon(QIcon(":/pictrue/qie.png"));
// 设置输入框前面的企鹅和密码图片
ui->unameLab->setPixmap(QPixmap(":/pictrue/qie.png"));
ui->passwdLab->setPixmap(QPixmap(":/pictrue/passwd.jpg"));
// 设置密码输入形式
ui->passwdEdit->setEchoMode(QLineEdit::Password);
// 设置头像
ui->touxiang->setPixmap(QPixmap(":/pictrue/touxiang.ico"));
// 设置右下角的二维码
ui->ewm->setPixmap(QPixmap(":/pictrue/eweima.png"));
// 用 QT4 的方式连接自定义的槽函数,用于让 取消按钮 去 关闭窗口
connect(ui->cencelBtn, SIGNAL(clicked()), this, SLOT(close_window_slot()));
// 用 QT5 的方式 让登录按钮 连接自定义的槽函数
connect(ui->loginBtn,&QPushButton::clicked,[&](){
if(ui->unameEdit->text() == "admin" && ui->passwdEdit->text() == "123456"){
qDebug() << "登录成功";
close_window_slot();
}
else
{
ui->passwdEdit->clear();
}
});
}
Login::~Login()
{
delete ui;
}
void Login::close_window_slot()
{
this->close();
}
main.cpp
cpp
#include "login.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Login w;
w.show();
return a.exec();
}