您现在的位置是:首页 >技术教程 >(6)——多窗口编程网站首页技术教程
(6)——多窗口编程
目录
1. QMessageBox 消息对话框**
QMessageBox继承自QDialog,是一种用于通知用户或询问用户一个问题的对话框窗口,这种窗口是模态的,会抢占窗口焦点,必须优先处理。
Qt内置的Dialog的派生类通常使用静态成员函数弹出:
// 参数1:父窗口
// 参数2:标题,相当于windowTitle属性
// 参数3:显示的信息
// 返回值:点击的按键类型
StandardButton QMessageBox::四种弹窗类型(QWidget * parent,
const QString & title,
const QString & text) [static]
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QButtonGroup>
#include <QtWidgets> //包含所有组件和窗口的头文件
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QButtonGroup *group;
private slots:
void btnsClickedSlot(int); //按钮点击的槽函数
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
group = new QButtonGroup(this);
group->addButton(ui->pushButtonQ,1);
group->addButton(ui->pushButtonI,2);
group->addButton(ui->pushButtonW,3);
group->addButton(ui->pushButtonC,4);
connect(group,SIGNAL(buttonClicked(int)),this,SLOT(btnsClickedSlot(int)));
}
void Dialog::btnsClickedSlot(int id){
if(id == 1){
QMessageBox::question(this,"question","你今晚吃饭吗?");
}else if(id == 2){
QMessageBox::information(this,"information","你今晚要吃饭!");
}else if(id == 3){
QMessageBox::warning(this,"warning","一顿不吃饿得慌!");
}else if(id == 4){
QMessageBox::critical(this,"critical","顿顿不吃要完蛋!");
}
}
Dialog::~Dialog()
{
delete group;
delete ui;
}
ui:
运行结果:
在question中加问题
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QButtonGroup>
#include <QtWidgets> //包含所有组件和窗口的头文件
#include <QDebug>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QButtonGroup *group;
private slots:
void btnsClickedSlot(int); //按钮点击的槽函数
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
group = new QButtonGroup(this);
group->addButton(ui->pushButtonQ,1);
group->addButton(ui->pushButtonI,2);
group->addButton(ui->pushButtonW,3);
group->addButton(ui->pushButtonC,4);
connect(group,SIGNAL(buttonClicked(int)),this,SLOT(btnsClickedSlot(int)));
}
void Dialog::btnsClickedSlot(int id){
if(id == 1){
QMessageBox::StandardButton result = QMessageBox::question(this,"question","你今晚吃饭吗?");
if(result == QMessageBox::Yes)
qDebug()<<"吃了!";
else if(result == QMessageBox::No)
qDebug()<<"没吃!";
}else if(id == 2){
QMessageBox::information(this,"information","你今晚要吃饭!");
}else if(id == 3){
QMessageBox::warning(this,"warning","一顿不吃饿得慌!");
}else if(id == 4){
QMessageBox::critical(this,"critical","顿顿不吃要完蛋!");
}
}
Dialog::~Dialog()
{
delete group;
delete ui;
}
2. 窗口类继承关系**
窗口类的继承关系如下所示。
QWidget类作为窗口和组件的基类,其内部定义了窗口和组件的基本功能,本节展示一部分作为窗口类的基类所拥有的API:
// 设置窗口状态
// 参数为窗口状态值
void QWidget::setWindowState(Qt::WindowStates windowState)
// 设置窗口标记
// 参数为窗口标记值,多个值之间可以使用|分割,以实际效果为准
void setWindowFlags(Qt::WindowFlags type)
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
// 设置全屏显示
// setWindowState(Qt::WindowFullScreen);
// 设置欢迎页效果
setWindowFlags(Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
}
Dialog::~Dialog()
{
delete ui;
}
QWidget类本身作为所有窗口和组件的基类,QWidget既可以作为窗口对象进行创建,又可以作为组件对象进行创建。
QWidget的构造函数的parent参数传递了一个窗口对象时,此时QWidget会成为这个窗口对象内部的组件。如果不传递此参数,QWidget对象会成为一个独立窗口。
3. QMainWindow 主窗口类**
QMainWindow是最合适做主窗口的类型,因为它包含多个组成部分。
3.1 QMenuBar 菜单栏
菜单栏的组成部分如下所示。
QAction支持信号槽的连接,其信号函数如下。
除了在Designer中添加菜单栏和配置QAction的内容,也可以在C++代码中添加。
3.2 QToolBar 工具栏
当使用Action编辑器设置了QAction的图标后,可以直接拖拽到QToolBar变为工具栏按钮。
工具栏所有的操作也都可以在C++代码中找到对应API。
3.3 QWidget 中心组件
见本章第2节中QWidget作为组件使用时的说明。
3.4 QStatusBar 状态栏
状态栏主要用于显示软件的相关辅助信息,可以使用预设的样式(比较简单),也可以自定义样式。本次以预设的样式为例进行讲解。
主要的函数如下所示。
// 显示信息
// 参数1:信息内容
// 参数2:显示时长,单位毫秒,如果为0(默认值)表示持续显示
void QStatusBar::showMessage(const QString & message, int timeout = 0) [slot]
// 清空信息
void QStatusBar::clearMessage() [slot]
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
private slots:
// QAction点击后触发的槽函数
void triggeredSlot();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 连接信号槽
connect(ui->actionOpen,SIGNAL(triggered()),
this,SLOT(triggeredSlot()));
// 设置状态栏内容
ui->statusBar->showMessage("哈哈哈哈",3000);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::triggeredSlot()
{
// 设置一点显示效果
ui->plainTextEdit->setPlainText("这是随便设置的内容");
}
ui界面:
运行结果:
4. parent参数**
几乎所有的Qt类的构造函数都有一个parent参数,实际上parent参数是Qt的一种内存管理策略。parent参数会作为新创建对象的父对象存在,当父对象销毁时,会一并销毁子对象。
建议在绝大多数情况下,传递parent参数,防止内存泄漏。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QDebug>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
private slots:
//两个按钮点击的槽函数
void btn1ClickedSlot();
void btn2ClickedSlot();
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
connect(ui->pushButton_1,SIGNAL(clicked()),this,SLOT(btn1ClickedSlot()));
connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(btn2ClickedSlot()));
}
Dialog::~Dialog()
{
qDebug()<<"析构函数";
delete ui;
}
void Dialog::btn1ClickedSlot()
{
Dialog* d = new Dialog(this);
d->show();
}
void Dialog::btn2ClickedSlot()
{
Dialog* d = new Dialog;
d->show();
}
哪个最后关,哪个调出析构函数
5. 自定义窗口类**
截止到当前,Qt项目中从来没有完整地创建过一个自定义的窗口类,要么使用的是项目创建后自带的窗口类,要么使用Qt内置的窗口类QMessageBox。
在项目中创建一个Qt的自定义窗口类的操作步骤如下所示。
1. 在Qt Creator中选中项目名称,鼠标右键,点击“添加新文件”。
2. 在弹出的窗口中,按照下图所示进行操作。
3. 在弹出的窗口中选择窗口的模板样式后,点击“下一步”。
4. 在弹出的窗口中给类命名后,点击下一步。
5. 在项目管理界面点击“完成”。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
// 头文件
#include "mydialog.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
private slots:
void btnClickedSlot(); // 单击按钮的槽函数
};
#endif // DIALOG_H
Dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
// 连接信号槽
connect(ui->pushButton,SIGNAL(clicked()),
this,SLOT(btnClickedSlot()));
}
void Dialog::btnClickedSlot()
{
// 创建并启动MyDialog窗口
MyDialog* md = new MyDialog(this);
md->show();
// 屏蔽按钮
ui->pushButton->setEnabled(false);
}
Dialog::~Dialog()
{
delete ui;
}
6. 跨界面参数传递**
6.1 主窗口→子窗口
这种情况可以使用子窗口的构造函数/成员函数传参。
【例子】转动主窗口的QDial,使子窗口的QDial跟着一起转动。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
// 头文件
#include "mydialog.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
MyDialog* md;
private slots:
void btnClickedSlot(); // 单击按钮的槽函数
void valueChangedSlot(int); // QDial数值变化的槽函数
};
#endif // DIALOG_H
dialoh.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
// 连接信号槽
connect(ui->pushButton,SIGNAL(clicked()),
this,SLOT(btnClickedSlot()));
}
void Dialog::btnClickedSlot()
{
// 创建并启动MyDialog窗口
// 参数1:当前主窗口的QDial数值
md = new MyDialog(ui->dial->value(),this);
// 建立QDial的信号槽
connect(ui->dial,SIGNAL(valueChanged(int)),
this,SLOT(valueChangedSlot(int)));
md->show();
// 屏蔽按钮
ui->pushButton->setEnabled(false);
}
void Dialog::valueChangedSlot(int value)
{
// 给子窗口设定参数值
md->setDialValue(value);
}
Dialog::~Dialog()
{
delete ui;
}
mydialog.h
#ifndef MYDIALOG_H
#define MYDIALOG_H
#include <QDialog>
namespace Ui {
class MyDialog;
}
class MyDialog : public QDialog
{
Q_OBJECT
public:
// 增加参数位
explicit MyDialog(int,QWidget *parent = 0);
~MyDialog();
// 增加成员函数
void setDialValue(int);
private:
Ui::MyDialog *ui;
};
#endif // MYDIALOG_H
mydialog.cpp
#include "mydialog.h"
#include "ui_mydialog.h"
MyDialog::MyDialog(int value,QWidget *parent) :
QDialog(parent),
ui(new Ui::MyDialog)
{
ui->setupUi(this);
// 设置QDial的初始值
ui->dial->setValue(value);
}
MyDialog::~MyDialog()
{
delete ui;
}
void MyDialog::setDialValue(int value)
{
// 设置QDial的变化值
ui->dial->setValue(value);
}
6.2 子窗口→主窗口
这种情况可以使用信号槽传参,子窗口发射带参数自定义信号给主窗口的槽函数接收。
【例子】转动子窗口的QDial,使主窗口的QDial跟着一起转动。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
// 头文件
#include "mydialog.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
private slots:
void btnClickedSlot(); // 单击按钮的槽函数
// 与子窗口中的自定义信号连接
void valueSlot(int);
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
// 连接信号槽
connect(ui->pushButton,SIGNAL(clicked()),
this,SLOT(btnClickedSlot()));
}
void Dialog::btnClickedSlot()
{
// 创建并启动MyDialog窗口
MyDialog* md = new MyDialog(this);
// 建立两个窗口对象之间的信号槽
connect(md,SIGNAL(valueSignal(int)),
this,SLOT(valueSlot(int)));
md->show();
// 屏蔽按钮
ui->pushButton->setEnabled(false);
}
void Dialog::valueSlot(int value)
{
// 更新到组件上
ui->dial->setValue(value);
}
Dialog::~Dialog()
{
delete ui;
}
mydialog.h
#ifndef MYDIALOG_H
#define MYDIALOG_H
#include <QDialog>
namespace Ui {
class MyDialog;
}
class MyDialog : public QDialog
{
Q_OBJECT
public:
explicit MyDialog(QWidget *parent = 0);
~MyDialog();
private:
Ui::MyDialog *ui;
private slots:
// QDial转动的槽函数
void valueChangedSlot(int);
signals:
// 带参数的自定义信号
void valueSignal(int);
};
#endif // MYDIALOG_H
mydialog.cpp
#include "mydialog.h"
#include "ui_mydialog.h"
MyDialog::MyDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::MyDialog)
{
ui->setupUi(this);
connect(ui->dial,SIGNAL(valueChanged(int)),
this,SLOT(valueChangedSlot(int)));
}
MyDialog::~MyDialog()
{
delete ui;
}
void MyDialog::valueChangedSlot(int value)
{
// 发送到主窗口!
emit valueSignal(value);
}
7. 事件函数**
事件函数的使用依托于Qt的事件机制,一个来自于外部事件的传递机制模型如下所示。
信号槽虽然好用,但是无法包含所有的情况,事件函数可以起到对信号槽无法覆盖的一些时机进行补充。事件函数的使用无需连接。
常用的事件函数如下所示。
// 绘制事件
void QWidget::paintEvent(QPaintEvent * event) [virtual protected]
// 大小改变事件
void QWidget::resizeEvent(QResizeEvent * event) [virtual protected]
// 鼠标按压事件
void QWidget::mousePressEvent(QMouseEvent * event) [virtual protected]
// 鼠标释放事件
void QWidget::mouseReleaseEvent(QMouseEvent * event) [virtual protected]
// 鼠标双击事件
void QWidget::mouseDoubleClickEvent(QMouseEvent * event) [virtual protected]
// 鼠标移动事件
void QWidget::mouseMoveEvent(QMouseEvent * event) [virtual protected]
// 移动事件
void QWidget::moveEvent(QMoveEvent * event) [virtual protected]
// 按键按压事件
void QWidget::keyPressEvent(QKeyEvent * event) [virtual protected]
// 按键释放事件
void QWidget::keyReleaseEvent(QKeyEvent * event) [virtual protected]
// 获取焦点事件
void QWidget::focusInEvent(QFocusEvent * event) [virtual protected]
// 失去焦点事件
void QWidget::focusOutEvent(QFocusEvent * event) [virtual protected]
// 关闭事件
void QWidget::closeEvent(QCloseEvent * event) [virtual protected]
// 进入事件
void QWidget::enterEvent(QEvent * event) [virtual protected]
void QWidget::leaveEvent(QEvent * event) [virtual protected]
QPaintDevice类表示可绘制设备,其派生类均可以被QPainter类绘制。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QDebug>
#include <QPixmap> // 图片类
#include <QPainter> // 画家类
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
protected:
// 声明事件函数
void paintEvent(QPaintEvent * event);
private:
Ui::Dialog *ui;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
// 定义事件函数
void Dialog::paintEvent(QPaintEvent *)
{
// 输出窗口宽高
qDebug() << this->width() << this->height();
// 创建画家类对象
QPainter painter(this);
QPixmap pic(":/new/prefix1/ikun.jpg");
// 绘制图片函数
// void QPainter::drawPixmap(int x, int y, int width, int height, const QPixmap & pixmap)
// 参数1:横坐标
// 参数2:纵坐标
// 参数3:宽度
// 参数4:高度
// 参数5:图片内容
painter.drawPixmap(0,0,width(),height(),pic);
}
运行结果:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QDebug>
#include <QPixmap> // 图片类
#include <QPainter> // 画家类
#include <QKeyEvent> // 键盘事件参数
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
protected:
// 声明事件函数
void paintEvent(QPaintEvent * event);
void keyPressEvent(QKeyEvent * event);
private:
Ui::Dialog *ui;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
// 定义事件函数
void Dialog::paintEvent(QPaintEvent *)
{
// 输出窗口宽高
qDebug() << this->width() << this->height();
// 创建画家类对象
QPainter painter(this);
QPixmap pic(":/new/prefix1/ikun.jpg");
// 绘制图片函数
// void QPainter::drawPixmap(int x, int y, int width, int height, const QPixmap & pixmap)
// 参数1:横坐标
// 参数2:纵坐标
// 参数3:宽度
// 参数4:高度
// 参数5:图片内容
painter.drawPixmap(0,0,width(),height(),pic);
}
// 所有的事件函数的参数都包含了当前类型事件的参数信息
void Dialog::keyPressEvent(QKeyEvent *event)
{
// 判断按键按哪个
if(event->key() == Qt::Key_A) // 获得按键码之后进行比对
{
// 获得当前进度条的值
int value = ui->progressBar->value();
// 减小进度条的值
ui->progressBar->setValue(--value);
}else if(event->key() == Qt::Key_D)
{
// 获得当前进度条的值
int value = ui->progressBar->value();
// 减小进度条的值
ui->progressBar->setValue(++value);
}
}
运行结果: