QT学习第六课

目录

1. QMessageBox 消息对话框

2. QWidget类

3. parent参数

4. 堆栈窗口QStackedWidget

5. QMainWindow主窗口类

5.1 QMenuBar 菜单栏

5.2 QToolBar 工具栏

5.3 状态栏QStatusBar

6. 新建一个自定义窗口

7.对象传值

7.1 父对象→子对象

​编辑

7.2 子对象→父对象

8. 事件机制


1. QMessageBox 消息对话框

QMessageBox继承自QDialog,显示一个模态对话框,用于用户前台信息通知或询问用户问题并且接收问题答案。

QMessageBox可以直接使用四种预设的风格格式:

QDialog的Qt源码中的派生类往往都是一些在特定场合下预设好的对话框窗口,这些窗口的使用无需创建对象,直接使用静态成员函数弹窗,使用函数的返回值作为这个窗口的结果。

QMessageBox类的弹窗函数如下:

// 参数1 parent参数
// 参数2 窗口标题
// 参数3 信息内容
// 返回值 用户点击按钮的类型
StandardButton QMessageBox::critical|information|question|warning
(
    QWidget * parent, 
    const QString & title, 
    const QString & text)[static]
// 构造函数
// 参数 parent	
QMessageBox(QWidget * parent = 0)
// 向自定义QMessageBox窗口添加按钮
// 参数1 抽象按钮类,传入派生类
// 参数2 按钮的放置规则
void QMessageBox::addButton(QAbstractButton * button, ButtonRole role)

dialog.h

#ifndef DIALOG_H
#define DIALOG_H
 
#include <QDialog>
#include <QButtonGroup>
#include <QMessageBox>
#include <QPushButton>
#include <QPixmap>
 
namespace Ui {
class Dialog;
}
 
class Dialog : public QDialog
{
    Q_OBJECT
 
public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
 
private:
    Ui::Dialog *ui;
    QButtonGroup *group;
    QMessageBox *box;
    QPushButton* btn1;
    QPushButton* btn2;
    QPushButton* btn3;
 
    // 创建并展示一个自定义的QMessageBox的函数
    void customMessageBox();
 
private slots:
    // 与void buttonClicked(int id)连接
    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->pushButton_Ques,1);
    group->addButton(ui->pushButton_info,2);
    group->addButton(ui->pushButton_warn,3);
    group->addButton(ui->pushButton_crit,4);
    group->addButton(ui->pushButton_custom,5);
 
    connect(group,SIGNAL(buttonClicked(int)),
            this,SLOT(btnsClickedSlot(int)));
}
 
Dialog::~Dialog()
{
    delete ui;
}
// 自定义弹窗
void Dialog::customMessageBox()
{
    // 创建一个QMessageBox对象
    box = new QMessageBox(this);
    // 设置标题
    box->setWindowTitle("肯德基特惠");
    // 图片对象
    QPixmap map(":/new/prefix1/kfc.png");
    // 设置图片
    box->setIconPixmap(map);
    // 设置文本
    box->setText("5.20-5.22肯德基蛋挞20元6个");
    btn1 = new QPushButton("吃",box);
    btn2 = new QPushButton("不吃",box);
    btn3 = new QPushButton("猛吃",box);
    // 把按钮放到QMessageBox的规定位置
    box->addButton(btn1,QMessageBox::YesRole);
    box->addButton(btn2,QMessageBox::NoRole);
    box->addButton(btn3,QMessageBox::DestructiveRole);
 
    // 显示对话框
    box->show();
}
 
void Dialog::btnsClickedSlot(int id)
{
    if(id == 1)
    {
        QMessageBox::StandardButton result =
                QMessageBox::question(this,"问题","你今早吃了吗?");
        if(result == QMessageBox::Yes)
        {
            close();
        }else if (result == QMessageBox::No)
        {
            lower();
        }
    }else if(id == 2)
    {
        QMessageBox::information(this,"信息","今天早上吃的甜沫 油旋");
    }else if(id == 3)
    {
        QMessageBox::warning(this,"警告","甜沫有点不新鲜!");
    }else if(id == 4)
    {
        QMessageBox::critical(this,"错误","食物中毒了");
    }else if(id == 5)
    {
        customMessageBox();
    }else
    {
 
    }
}

2. QWidget类

QWidget类是所有窗口和组件的基类,之前更多是在组件的角度认识他,实际上QWidget身为所有窗口的基类,也具有很多窗口的属性,窗口类的继承结构如下:

新建项目,使自带窗口类继承QWidget:

此时的项目自带的窗口类Widget继承了QWidget,在主函数创建并展示。

QWidget类作为所有窗口的基类,内部也规定了很多窗口特性:

● windowTitle : QString

窗口标题

● windowFlags : Qt::WindowFlags

在使用setWindowFlags设置多个窗口标记时,使用 | 风格(多个窗口状态可能会出现冲突)

// 设置窗口标记
// 参数为窗口标记的枚举
void	setWindowFlags(Qt::WindowFlags type)

// 设置窗口状态
// 参数为窗口状态的枚举
void QWidget::setWindowState(Qt::WindowStates windowState)

窗口状态有时会与窗口标记冲突。

dialog.cpp

#include "widget.h"
#include "ui_widget.h"
 
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    setWindowTitle("我的窗口");
    // 设置最上层无边框
    setWindowFlags(Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
    // 设置为全屏
    setWindowState(Qt::WindowFullScreen);
}
 
Widget::~Widget()
{
    delete ui;
}

3. parent参数

目前对parent参数有以下几点理解:

● parent参数表示子组件位于那个窗口中

● parent参数决定了QWIdget对象是独立窗口还是内嵌窗口

实际上parent参数还表示Qt的内存回收机制,如果a对象作为b对象构造时的parent参数,表示a对象是b对象的父对象(非继承),是一种内存回收的依赖关系。b对象会跟随a对象一并销毁,此时无需控制b对象的销毁过程。(无需手动调用delete)。

如果创建堆内存对象创建时不传递parent参数,表示此对象需要程序员手动delete。

绝大多数下,建议堆内存对象创建时传递parent参数。

dialog.hj

#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 btnYesClicked();
    void btnNoClicked();
};
 
#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(btnYesClicked()));
    connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(btnNoClicked()));
}
 
Dialog::~Dialog()
{
    qDebug() << "析构函数";
    delete ui;
}
 
void Dialog::btnYesClicked()
{
    // 传递Parent参数,在创建一个Dialog对象
    Dialog *d = new Dialog(this);
    d->show();
}
 
void Dialog::btnNoClicked()
{
    // 不传递Parent参数,在创建一个Dialog对象
    Dialog *d = new Dialog();
    d->show();
}

4. 堆栈窗口QStackedWidget

通常作为独立窗口的内嵌窗口,与QListWidget进行联动。

// 添加一个item
void QListWidget::addItem(const QString & label)
// 当前页改变
void	currentRowChanged(int currentRow)[signal]
// 设置当前页
void	QStackedWidget::setCurrentIndex(int index)[slot]

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"
 
Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    // 向QListWidget添加item
    ui->listWidget->addItem("蓝");
    ui->listWidget->addItem("绿");
    ui->listWidget->addItem("红");
    // 把ListWidget和QStackedWidget联动
    connect(ui->listWidget,SIGNAL(currentRowChanged(int)),
            ui->stackedWidget,SLOT(setCurrentIndex(int)));
}
 
Dialog::~Dialog()
{
    delete ui;
}

5. QMainWindow主窗口类

新建项目时选择QMainWindow。

QMainWindow是最适合作为主窗口的类型,因为其包含多个部分:

5.1 QMenuBar 菜单栏

菜单栏的组成如下所示:

菜单栏的构建可以使用Designer,也可以使用C++代码实现,但是不能混用。

相关C++函数:

// 向菜单栏添加一级菜单
// 参数为菜单的文字
// 返回值是添加的菜单对象
QMenu * QMenuBar::addMenu(const QString & title)

// 向菜单中添加动作
// 参数为动作的文字
// 返回值是添加的动作的对象
QAction * QMenu::addAction(const QString & text)
// 向菜单中添加下一级菜单
// 参数为菜单的文字
// 返回值是添加的下一级菜单对象
QMenu *  QMenu:: addMenu(const QString & title)

为了使QAction点击之后有触发效果,需要使用对应的信号连接槽函数,QAction的信号函数如下:

5.2 QToolBar 工具栏

工具栏按钮往往使用菜单栏下的QAction对象,但是需要给QAction设置图标:

可通过下面的函数(C++代码)或Designer拖拽的效果设置工具栏按钮。

// 添加一个已有的QAction对象到工具栏
void QToolBar::addAction(QAction * action)

5.3 状态栏QStatusBar

QStatusBar支持自定义格式,可以添加组件:

void QStatusBar::addWidget(QWidget * widget, int stretch = 0)

普通使用可以通过下面两个槽函数进行信息的显示和消除

// 在状态栏展示信息
// 参数1 展示信息的内容
// 参数2 信息显示的时间(单位是毫秒),默认值0表示一直显示
void QStatusBar::showMessage(const QString & message, int timeout = 0)[slot]
// 清空显示
void QStatusBar::clearMessage()

dialog.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:
    void actionNewTriggledSlot(); // 点击新建项目
    void actionCppTriggledSlot(); // 点击hello.cpp
};
 
#endif // MAINWINDOW_H

dialog.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
//    QMenu * menuFile = ui->menuBar->addMenu("文件");
//    QMenu * menuEdit = ui->menuBar->addMenu("编辑");
//    // 向一级菜单中添加动作
//    QAction * actionNew = menuFile->addAction("新建项目与文件");
//    QAction * actionOpen = menuFile->addAction("打开文件或项目");
//    // 向一级菜单中添加二级菜单
//    QMenu * menuRecent = menuFile->addMenu("最近访问的文件...");
//    // 向二级菜单中添加动作
//    QAction * actionCpp = menuRecent->addAction("dialog.cpp");
//    QAction * actionH = menuRecent->addAction("dialog.h");
 
    connect(ui->action,SIGNAL(triggered(bool)),
            this,SLOT(actionNewTriggledSlot()));
    connect(ui->actionDialog_cpp,SIGNAL(triggered(bool)),
            this,SLOT(actionCppTriggledSlot()));
    ui->mainToolBar->addAction(ui->action_2);
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
 
void MainWindow::actionNewTriggledSlot()
{
    ui->plainTextEdit->appendPlainText("新建了一个文档!");
    ui->statusBar->showMessage("新建了一个文档!",3000);
}
 
void MainWindow::actionCppTriggledSlot()
{
    ui->plainTextEdit->appendPlainText("打开了hello.cpp!");
}

6. 新建一个自定义窗口

自定义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()));
}
 
Dialog::~Dialog()
{
    delete ui;
}
 
void Dialog::btnClickedSlot()
{
    // 创建MyDialog对象并展示
    MyDialog *md = new MyDialog(this);
    md->show();
 
    // 限制按钮只能点一次
    ui->pushButton->setEnabled(false);
}

7.对象传值

7.1 父对象→子对象

此处指的是Qt的Parent参数的依赖关系,并非继承关系!!!后文同。

这种情况最佳解决方案是使用C++的成员函数传参

【例】 转动紫球,绿球跟着转

7.2 子对象→父对象

【例】转动绿球,紫球跟着转

这种情况最佳的解决方案是信号槽传参,子对象发射带参数的信号函数,父对象使用带参数的槽函数接收。

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); //紫球数值改变调用的槽函数
    void valueSlot(int); // 接收MyDialog对象发射的信号
};
 
#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);
    md = new MyDialog(this);
    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
 
    connect(ui->dial,SIGNAL(valueChanged(int)),
            this,SLOT(valueChangedSlot(int)));
 
    connect(md,SIGNAL(valueSignal(int)),this,SLOT(valueSlot(int)));
}
 
Dialog::~Dialog()
{
    delete ui;
}
 
void Dialog::btnClickedSlot()
{
    // 创建MyDialog对象并展示
    md->show();
 
    // 限制按钮只能点一次
    ui->pushButton->setEnabled(false);
}
 
void Dialog::valueChangedSlot(int value)
{
    // 把数值传给子窗口
    md->setGDialValue(value);
}
 
void Dialog::valueSlot(int value)
{
    // 设置紫球数值
    ui->dial->setValue(value);
}

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();
    // 这里用public是因为父子窗口不是继承关系
    void setGDialValue(int);
private:
    Ui::MyDialog *ui;
signals:
    void valueSignal(int); // 发射value值的信号
 
private slots:
    void valueChangedSlot(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::setGDialValue(int value)
{
    ui->dial->setValue(value);
}
 
void MyDialog::valueChangedSlot(int value)
{
    // 发射带参数的自定义信号
    emit valueSignal(value);
}

8. 事件机制

事件是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]

事件函数的基础使用只需要在对应的类中覆盖基类的事件即可。事件函数的参数就是包含了当前事件的数据对象。

【问题】事件函数与信号槽的区别?

● 事件由具体对象进行处理

● 信号由具体对象主动产生

● 改写事件处理函数可能导致程序行为发生改变

● 信号是否存在对应的槽函数不会改变程序行为

// 绘制图片
// 参数1 横轴坐标
// 参数2 纵轴坐标
// 参数3 绘制宽度
// 参数4 绘制高度
// 参数5 绘制内容
void	drawPixmap(int x, int y, int width, int height, const QPixmap & pixmap)

dialog.h

#ifndef DIALOG_H
#define DIALOG_H
 
#include <QDialog>
#include <QDebug>
#include <QPainter> // 画家类
#include <QKeyEvent>
 
namespace Ui {
class Dialog;
}
 
class Dialog : public QDialog
{
    Q_OBJECT
 
public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
 
private:
    Ui::Dialog *ui;
protected:
    void paintEvent(QPaintEvent * event);
    void keyPressEvent(QKeyEvent * event);
 
};
 
#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 *event)
{
    // 创建一个画家对象
    QPainter painter(this);
    QPixmap map(":/new/prefix1/bg.jpg");
 
    // 绘制图片
    // 参数1 横轴坐标
    // 参数2 纵轴坐标
    // 参数3 绘制宽度
    // 参数4 绘制高度
    // 参数5 绘制内容
    painter.drawPixmap(0,0,width(),height(),map);
 
    qDebug() << this->width() << this->height();
    qDebug() << this->x() << this->y();
}
 
void Dialog::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_A) // 如果按键是A
    {
        int value = ui->progressBar->value();
        ui->progressBar->setValue(--value);
    }else if(event->key() == Qt::Key_S) // 如果按键是S
    {
        ui->progressBar->setValue(0);
    }else if(event->key() == Qt::Key_W) // 如果按键是W
    {
        ui->progressBar->setValue(100);
    }else if(event->key() == Qt::Key_D) // 如果按键是D
    {
        int value = ui->progressBar->value();
        ui->progressBar->setValue(++ value);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值