赞
踩
本次实验内容为Qt自定义标题栏,最小化、最大化、关闭窗口,双击最大化,鼠标拖动等界面软件的基本常规操作。
我们在做一个软件界面的时候,有时需要其任务栏显示一些文本、图片甚至一些自定义控件的内容,但是通过Qt自动创建的窗口类仅自带系统风格的标题栏,往往并不能满足我们的自定义设计需求。
在这种情况下,需要用Qt设计自定义标题栏内的相关内容。本篇博客记录本人实现这一功能的前后代码过程,并不一定是标准方式,仅作一个记录,在后面项目用的时候进行查阅。
主要实现的窗口操作为以下5点内容:
(1)在“灰色”区域,即自定义标题栏区域内,最左侧为logo图标,往右为软件名称标题,最右边分别外三个按钮,依次为“最小化”、“最大化”、“关闭”按钮;
(2)标题栏区域(包含logo以及名称标题上)拖动鼠标,实现整个窗口的拖动功能,蓝色区域拖拽鼠标,不会拖动整个窗口;
(3)标题栏区域(包含logo以及名称标题上)双击鼠标左键,实现最大化、还原窗口的操作;
(4)鼠标移动至“最小化”、“最大化”、“关闭”按钮上会改变按钮的背景色;
(5)鼠标单击最小化、最大化、关闭按钮,嫩实现相应的窗口操作功能。
下图为自定义标题栏的软件界面效果。
建立Qt工程文件,自动生成widget.h,widget.cpp以及widget.ui,再新建一个Qt 的Ui界面类,即title类,生成title.h,title.cpp,title.ui三个文件
widget类为整体窗体类,用于最底层展示窗口,title类为自定义标题栏类。
整个工程文件夹下内容如下图所示:
QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 SOURCES += \ main.cpp \ title.cpp \ widget.cpp HEADERS += \ title.h \ widget.h FORMS += \ title.ui \ widget.ui # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target RESOURCES += \ src.qrc
在widget.h文件中将title类的头文件title.h包含进去,并声明一个title类指针。
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include "title.h" QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: Ui::Widget *ui; title *t1; }; #endif // WIDGET_H
在Widget构造函数中,首先建立ui界面,设置窗口的无边框属性,实例化一个title对象,并将该对象放置到窗体的对象树上。
此句为设置无自带标题栏的属性,必须有这句话。
setWindowFlags(Qt::FramelessWindowHint);
新建一个垂直布局
QVBoxLayout* layout = new QVBoxLayout(this);
将自定义标题栏放置入垂直布局中去
layout->addWidget(t1);
#include "widget.h" #include "ui_widget.h" #include <QVBoxLayout> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); setWindowFlags(Qt::FramelessWindowHint); //隐藏标题栏(无边框) t1 = new title(this); t1->setParent(this); //新建一个垂直布局,并将title对象、ui->stackedWidget放置入该垂直布局中去 QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(t1); layout->addWidget(ui->stackedWidget); //设置垂直布局间隙 layout->setSpacing(0); layout->setMargin(0); } Widget::~Widget() { delete ui; }
ui界面中,在Widget中放置一个QStackedWidget用于后续工作,不需要在此处进行布局。
在widget.h文件中将title类的头文件title.h包含进去,并声明一个title类指针。
#ifndef TITLE_H #define TITLE_H #include <QWidget> #include <QMouseEvent> namespace Ui { class title; } class title : public QWidget { Q_OBJECT public: explicit title(QWidget *parent = nullptr); ~title(); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseDoubleClickEvent(QMouseEvent *event); private slots: void onClicked(); private: Ui::title *ui; QPoint m_start; //起始点 QPoint m_end; //结束点 bool m_leftButtonPressed; //鼠标左键按下标记 }; #endif // TITLE_H
在title构造函数中,首先建立ui界面,接着连接鼠标点击title中的三个QPushButton时产生的信号及对应操作的槽函数。
此处将三个按钮的点击信号连接至同一个槽函数,在槽函数中判断点击信号的发送对象,然后作出相应操作。
重写mousePressEvent、mouseMoveEvent、mouseMoveEvent、mouseDoubleClickEvent四个鼠标事件
#include "title.h" #include "ui_title.h" #include <QDebug> title::title(QWidget *parent) : QWidget(parent), ui(new Ui::title) { ui->setupUi(this); connect(ui->pushButton,SIGNAL(clicked(bool)),this, SLOT(onClicked())); connect(ui->pushButton_2,SIGNAL(clicked(bool)),this, SLOT(onClicked())); connect(ui->pushButton_3,SIGNAL(clicked(bool)),this, SLOT(onClicked())); } title::~title() { delete ui; } void title::mousePressEvent(QMouseEvent *event) { //鼠标左键按下事件 if(event->button()==Qt::LeftButton) { //记录鼠标左键状态 m_leftButtonPressed = true; //记录鼠标在屏幕中的位置 m_start = event->globalPos(); // qDebug()<<QString::fromLocal8Bit("左键被按下了"); } } void title::mouseMoveEvent(QMouseEvent *event) { if(m_leftButtonPressed) { //将父窗体移动到父窗体原来的位置加上鼠标移动的位置:event->globalPos()-m_start //this->window()获取 this->window()->move(this->window()->geometry().topLeft()+event->globalPos()-m_start); //将鼠标在屏幕中的位置替换为新的位置 m_start = event->globalPos(); } } void title::mouseReleaseEvent(QMouseEvent *event) { if(event->button()==Qt::LeftButton) { m_leftButtonPressed = false; } } void title::mouseDoubleClickEvent(QMouseEvent *event) { Q_UNUSED(event); ui->pushButton_3->click(); } void title::onClicked() { QPushButton *pButton = qobject_cast<QPushButton *>(sender()); QWidget *pWindow = this->window(); if (pWindow->isTopLevel()) { if(pButton == ui->pushButton) { pWindow->showMinimized(); } else if(pButton == ui->pushButton_2) { pWindow->close(); } else if(pButton == ui->pushButton_3) { pWindow->isMaximized()?pWindow->showNormal():pWindow->showMaximized(); } } }
title.ui界面中,在title中放置两个QLabel三个QPushButton,两个QLabel分别用于展示logo及软件标题名称,三个QPushButton为最小化、最大化以及关闭操作。
在右侧的对象树上,顶层对象上右键改变样式表,添加如下的样式表,直接设置title类中各个子对象的样式。
注意:此处设置标题名称应通过右键设置样式表的方式设置其相关属性,
不能通过右键“改变多文本信息”来设置其属性
,否则标题栏鼠标拖动的效果将会失效
。
QWidget#widget { background-color: rgb(98, 98, 98); } QLabel#label_2 { font: 16pt bold "楷体"; font-weight:900; color:white; } QPushButton { border-style: solid; border-width: 0px; border-radius: 0px; background-color: rgba(223, 223, 223, 0); } QPushButton::focus{outline: none;} QPushButton::hover { border-style: solid; border-width: 0px; border-radius: 0px; background-color: rgba(223, 223, 223, 150); }
直接在QtCreator右下方设置QPushButton类相关属性,这里的pushButton_3比较特殊,它具有两个状态,一是“还原”状态,二是“最大化”状态,在QAbstractButton里有icon的属性,Normal Off状态下选择“最大化.png”,Active On状态下选择“还原.png”,并且需要勾选“checkabel”复选框
当然,这里的相关设置也可以通过代码实现,我个人还是比较习惯于直接在Ui界面内设置了,比较方便。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。