文章目录
前言:
在Qt这一强大的跨平台C++图形用户界面应用程序开发框架中,
QWidget
扮演着至关重要的角色。作为所有用户界面对象的基类,QWidget
不仅提供了窗口系统的基本功能,还是构建复杂GUI应用程序的基石。本文将深入探讨QWidget
的基本概念,并重点介绍其常用的特性。
一、QWidget
1、定义与概念
QWidget
是Qt中所有用户界面对象的基类,包括窗口、对话框、按钮、文本框等。它封装了窗口系统的很多特性,如大小、位置、显示状态等,并提供了一系列用于这些特性的方法和信号槽。通过继承QWidget
,开发者可以创建自定义的用户界面元素。
2、继承体系
QWidget
继承自QObject
和QPaintDevice
。这意味着它不仅具有Qt对象系统的基本特性(如信号槽机制、属性系统、事件处理等),还能够进行绘图操作。同时,QWidget
还是许多其他Qt控件(如QPushButton
、QLabel
、QMainWindow
等)的基类。
3、常用特性
3.1、事件处理
QWidget
支持事件处理机制,允许开发者对用户的操作(如鼠标点击、键盘输入)或其他系统事件(如窗口大小改变)进行响应。通过重写事件处理函数(如mousePressEvent
、keyPressEvent
等),可以实现复杂的交互逻辑。下面是QWidget
提供的事件处理器,如下:
// Event handlers
// 鼠标事件
virtual void mousePressEvent(QMouseEvent *event);
virtual void mouseReleaseEvent(QMouseEvent *event);
virtual void mouseDoubleClickEvent(QMouseEvent *event);
virtual void mouseMoveEvent(QMouseEvent *event);
virtual void wheelEvent(QWheelEvent *event);
// 键盘事件
virtual void keyPressEvent(QKeyEvent *event);
virtual void keyReleaseEvent(QKeyEvent *event);
// 焦点事件
virtual void focusInEvent(QFocusEvent *event);
virtual void focusOutEvent(QFocusEvent *event);
virtual void enterEvent(QEvent *event);
virtual void leaveEvent(QEvent *event);
// 绘制事件
virtual void paintEvent(QPaintEvent *event);
// 窗体关闭事件
virtual void closeEvent(QCloseEvent *event);
3.2、布局管理
为了确保界面元素在不同分辨率和窗口大小下都能保持良好的布局,Qt提供了多种布局管理器(如
QVBoxLayout
、QHBoxLayout
、QGridLayout
等)。这些布局管理器可以与QWidget
结合使用,实现自动的布局调整。下面是QWidget
提供的与布局管理相关的成员函数,如下:
QLayout *layout() const;
void setLayout(QLayout *);
3.3、子控件与父子关系
QWidget
支持子控件的概念,即一个QWidget
可以包含其他QWidget
作为其子控件。这种父子关系不仅简化了界面元素的组织方式,还便于事件处理和布局管理。
void setParent(QWidget *parent);
void setParent(QWidget *parent, Qt::WindowFlags f);
static QWidget *find(WId);
3.4、右键菜单
QWidget
提供相关的接口可以设置自定义右键菜单,如下:
void QWidget::setContextMenuPolicy(Qt::ContextMenuPolicy policy)
枚举值 | 作用 |
---|---|
Qt::NoContextMenu | 本对象不显示右键菜单,由父对象决定 |
Qt::PreventContextMenu | 不显示右键菜单,与NoContentMenu不同,不向上层传递右键菜单的命令 |
Qt::DefaultContextMenu | 调用QWidget::contextMenuEvent(), 子类如果自定义菜单项需要重写这个虚函数 。(注意:该值是默认的属性值) |
Qt::ActionsContextMenu | 将本QWidget的所有QAction作为右键显示的菜单,这些QAction是通过QWidget::addActions方法添加的 |
Qt::CustomContextMenu | 发送信号QWidget::customContextMenuRequested(), 通过发信号的形式 |
下面通过一个示例介绍常用的几种策略的用法,如下:
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QAction>
#define ACTION_MAX_SIZE 5
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
m_pMenu = nullptr;
m_pCustomMenu = nullptr;
ui->comboBox->addItem("Qt::DefaultContextMenu");
ui->comboBox->addItem("Qt::ActionsContextMenu");
ui->comboBox->addItem("Qt::CustomContextMenu");
// 方法一:给Widget添加右键菜单,如果右键菜单策略设置的是Qt::ActionsContextMenu,右键时会显示Widget所有的Actions
QList<QAction*> actionList;
for (int i = 0; i < ACTION_MAX_SIZE; i ++)
{
QAction *pAction = new QAction(this);
pAction->setText("ActionsContextMenu Action " + QString::number(i));
connect(pAction, SIGNAL(triggered(bool)), this, SLOT(OnAction()));
actionList.append(pAction);
}
// 调用QWidget::addActions方法添加QAction,当策略采用的是Qt::ActionsContextMenu,会显示添加的菜单
addActions(actionList);
connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnCurrentIndexChange(int)));
// 方法二:通过连接QWidget::customContextMenuRequested信号,实现右键菜单功能,当策略采用的是Qt::CustomContextMenu,会显示槽函数里面的菜单
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(OnShowMenu(const QPoint &)));
}
Widget::~Widget()
{
delete ui;
if (m_pMenu)
{
delete m_pMenu;
}
}
// 方法三:如果右键菜单策略选择的是Qt::DefaultContextMenu(默认的策略),QWidget的派生类通过实现虚函数contextMenuEvent
// 来弹出右键菜单
void Widget::contextMenuEvent(QContextMenuEvent *event)
{
if (m_pMenu == nullptr)
{
m_pMenu = new QMenu(this);
m_pMenu->setParent(this);
QList<QAction*> actionList;
for (int i = 0; i < ACTION_MAX_SIZE; i ++)
{
QAction *pAction = new QAction(this);
pAction->setText("DefaultContextMenu Action " + QString::number(i));
connect(pAction, SIGNAL(triggered(bool)), this, SLOT(OnAction()));
actionList.append(pAction);
}
m_pMenu->addActions(actionList);
}
m_pMenu->move(event->globalX() ,event->globalY());
m_pMenu->show();
}
void Widget::OnAction()
{
QObject *pObj = sender();
QAction *pAction = dynamic_cast<QAction*>(pObj);
qDebug() << "Clieck " << pAction->text();
}
void Widget::OnCurrentIndexChange(int index)
{
switch(index)
{
case 0:
setContextMenuPolicy(Qt::DefaultContextMenu);
ui->label->setText("MenuPolicy Qt::DefaultContextMenu");
break;
case 1:
setContextMenuPolicy(Qt::ActionsContextMenu);
ui->label->setText("Qt::ActionsContextMenu");
break;
case 2:
setContextMenuPolicy(Qt::CustomContextMenu);
ui->label->setText("Qt::CustomContextMenu");
break;
}
}
void Widget::OnShowMenu(const QPoint &pos)
{
if (m_pCustomMenu == nullptr)
{
m_pCustomMenu = new QMenu(this);
m_pCustomMenu->setParent(this);
QList<QAction*> actionList;
for (int i = 0; i < ACTION_MAX_SIZE; i ++)
{
QAction *pAction = new QAction(this);
pAction->setText("CustomContextMenu Action " + QString::number(i));
connect(pAction, SIGNAL(triggered(bool)), this, SLOT(OnAction()));
actionList.append(pAction);
}
m_pCustomMenu->addActions(actionList);
}
m_pCustomMenu->move(pos);
m_pCustomMenu->show();
}
运行结果
3.5、设置/修改属性
QWidget::setAttribute()
是 Qt 框架中QWidget
类的一个成员函数,它用于设置或修改窗口部件(widget)的某些属性。这些属性可以控制窗口部件的行为、外观或其他特性。通过setAttribute()
方法,开发者可以启用或禁用特定的窗口部件功能,而无需直接修改窗口部件的样式表(QSS)或重写其绘制逻辑。函数原型如下:
void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on = true);
attribute
:要设置的属性,它是一个Qt::WidgetAttribute
枚举值。on
:一个布尔值,指定是否启用该属性。默认为true
,表示启用该属性;如果设置为false
,则表示禁用该属性。
常用的
Qt::WidgetAttribute
枚举值
Qt::WA_DeleteOnClose
:如果设置了此属性,当窗口部件被关闭时(例如,通过调用close()
方法),它将被自动删除。这对于临时窗口部件特别有用,可以避免内存泄漏。Qt::WA_TranslucentBackground
:如果设置了此属性,并且窗口部件没有设置背景刷(background brush),则窗口部件将具有透明背景。注意,这通常与特定类型的窗口(如顶层窗口)一起使用,并且可能受到平台限制。Qt::WA_StaticContents
:如果设置了此属性,则窗口部件的内容被认为是静态的,并且不会随着窗口部件的滚动而更新。这可以用于优化某些类型的窗口部件的绘制性能。Qt::WA_NoSystemBackground
:如果设置了此属性,则窗口部件将不会绘制系统背景。这通常与自定义绘制逻辑一起使用,以完全控制窗口部件的外观。Qt::WA_PaintOnScreen
:如果设置了此属性,则窗口部件的内容将直接在屏幕上绘制,而不是在窗口部件自己的缓冲区中绘制。这可以提高某些类型的窗口部件的绘制性能,但也可能导致绘制问题。
3.6、控制窗口显示
在Qt中,要判断一个
QWidget
(或任何QWidget
的派生类)是否正在显示,可以通过检查其isVisible()
方法的返回值来实现。isVisible()
方法会返回一个布尔值,如果窗口是可见的(即已经通过调用show()
、showFullScreen()
、showMaximized()
或showMinimized()
等方法显示,并且没有被最小化或隐藏),则返回true
;否则返回false
。QWidget
常用的控制显示的方法,如下:
bool QWidget::isVisible() const;
void QWidget::show();
void QWidget::hide();
bool QWidget::close();
void QWidget::showMinimized();
void QWidget::showMaximized();
问题:QWidget::hide()
与QWidget::close()
方法之间有啥区别?
QWidget
提供了close()
和hide()
两个重要的成员方法,用于控制窗口部件的显示状态,但它们在功能和行为上存在一些关键的区别。
close()
方法
- 功能:
close()
方法用于尝试关闭窗口部件并释放相关资源。当调用此方法时,窗口部件会先发送一个QCloseEvent
事件。如果窗口部件或其事件处理函数(如重写的closeEvent()
)接受了这个关闭事件,窗口部件将被隐藏。如果设置了Qt::WA_DeleteOnClose
标志,则窗口部件在关闭时还会被删除。 - 信号与槽:
close()
方法会触发与关闭相关的信号和槽机制,允许开发者在窗口关闭前执行清理操作,如保存数据、释放资源等。 - 程序退出:对于主窗口(即没有父窗口的窗口),如果它设置了Qt::WA_QuitOnClose属性,并且它是最后一个带有此属性的可见窗口,那么当它被关闭时,整个Qt应用程序可能会退出。
hide()
方法
- 功能:
hide()
方法仅用于隐藏窗口部件,使其不再在屏幕上显示。与close()
不同,hide()
不会发送QCloseEvent
事件,也不会触发与关闭相关的信号和槽。 - 资源状态:
hide()
方法只是改变了窗口部件的可见性状态,而不会改变其在内存中的状态(除非开发者在隐藏后手动删除了它)。因此,即使窗口部件被隐藏,它仍然存在于内存中,并且可以通过调用show()
方法重新显示。 - 程序退出:
hide()
方法不会导致Qt应用程序退出,无论是对主窗口还是其他窗口部件调用。
4、注意事项
QWidget
使用过程,应该注意下面这些问题,如下:
- 内存管理:在Qt中,
QWidget
及其子类对象的生命周期通常与父对象相关联。当父对象被销毁时,其所有子对象也会被自动销毁。因此,在创建QWidget
对象时,需要注意其父子关系的设置,以避免内存泄漏。 - 事件处理:虽然Qt的事件处理机制非常强大和灵活,但在重写事件处理函数时仍需谨慎。错误的事件处理逻辑可能导致界面响应缓慢、卡顿甚至崩溃。
- 布局管理:合理使用布局管理器可以极大地简化界面布局的工作,并提升用户体验。然而,在复杂的应用程序中,布局管理也可能变得相当复杂和耗时。因此,在设计界面布局时,需要仔细考虑和规划。
5、总结
QWidget
是Qt框架中不可或缺的一部分,它为开发者提供了构建复杂GUI的强大工具和灵活机制。通过深入理解和掌握QWidget
及其相关类,开发者可以创建出功能丰富、界面美观的桌面应用程序。