Qt漂亮界面

要做一个类似下面的qt界面,顶部是导航栏的样子——包含图标和程序名称,右边是界面切换按钮,然后放大、缩小和关闭按钮也在,还能拖动。这样,就更像一个商用的软件了。

在这里插入图片描述
功能规划:
1.去掉菜单栏、工具栏;
2.顶部导航栏包含程序图标、名称、界面切换按钮、放大缩小关闭按钮;
3.顶部导航栏可以拖动;
4.导航栏按钮可以切换界面。

可以参考的相关博客链接

一、去掉菜单栏和工具栏

在UI设计界面,在menuBar和mainToolBar上右键,选择移除菜单栏和移除工具栏。
在这里插入图片描述
把顶部的图标和程序名称、放大缩小关闭按钮都去掉,使用如下语句。

this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);

二、顶部导航栏的设计

主要是用installEventFilter来实现的。参考第6章节。
这个顶部导航栏是通过注册监听事件,让app监控所有的程序事件。如果属性是可移动的,然后记录鼠标的坐标等,来控制窗口的位置和大小。

appinit.h头文件

#ifndef APPINIT_H
#define APPINIT_H

#include <QObject>

class AppInit : public QObject
{
    Q_OBJECT
public:
    static AppInit *Instance();
    explicit AppInit(QObject *parent = 0);    

    void start();

protected:
    bool eventFilter(QObject *obj, QEvent *evt);

private:
    static AppInit *self;

signals:

public slots:
};

#endif // APPINIT_H

appinit.cpp的文件

#include "appinit.h"
#include "qmutex.h"
#include "qapplication.h"
#include "qevent.h"
#include "qwidget.h"

AppInit *AppInit::self = 0;
AppInit *AppInit::Instance()
{
    if (!self) {
        QMutex mutex;
        QMutexLocker locker(&mutex);
        if (!self) {
            self = new AppInit;
        }
    }

    return self;
}

AppInit::AppInit(QObject *parent) : QObject(parent)
{
}

bool AppInit::eventFilter(QObject *obj, QEvent *evt)
{
    QWidget *w = (QWidget *)obj;
    //如果窗口w的属性“canMove"是假的,继续监听
    if (!w->property("canMove").toBool()) {
        return QObject::eventFilter(obj, evt);
    }

    //如果属性是可移动
    static QPoint mousePoint;
    static bool mousePressed = false;

    //获取鼠标事件
    QMouseEvent *event = static_cast<QMouseEvent *>(evt);
    if (event->type() == QEvent::MouseButtonPress) {
        //如果鼠标被按下,且是左键按下
        if (event->button() == Qt::LeftButton) {
            mousePressed = true;
            //记下当前坐标:全局坐标-窗口坐标
            mousePoint = event->globalPos() - w->pos();
            return true;
        }
        //如果鼠标松开
    } else if (event->type() == QEvent::MouseButtonRelease) {
        mousePressed = false;
        return true;
        //如果鼠标在移动
    } else if (event->type() == QEvent::MouseMove) {
        if (mousePressed && (event->buttons() && Qt::LeftButton)) {
            //移动当前窗口到某个位置
            w->move(event->globalPos() - mousePoint);
            return true;
        }
    }

    return QObject::eventFilter(obj, evt);
}

void AppInit::start()
{
    qApp->installEventFilter(this);
}

使用方式:

//函数功能:让自定义的顶部导航栏可以拖动
    AppInit::Instance()->start();

三、阵列按钮的点击事件写法

当我们有一排按钮需要程序来添加点击事件时,如果一个个connect那么代码就太长了,connect需要写,它们的槽函数又要单独写,而这些按钮响应的事件处理又差不多。那么可以用如下的写法,立马让你成为QT中级程序员的感觉。
在这里插入图片描述
使用findChildren函数找到某个widget下所有的按钮,如下面代码所示。

//设置顶部导航按钮
    QList<QToolButton *> tbtns = ui->widgetTop->findChildren<QToolButton *>();
    foreach (QToolButton *btn, tbtns) {
        btn->setIconSize(icoSize);
        btn->setMinimumWidth(icoWidth);
        btn->setCheckable(true);
        connect(btn, SIGNAL(clicked()), this, SLOT(buttonClick()));
    }

首先,findChildren函数找到了widgetTop下的所有QToolButton类型按钮。
然后,给每一个按钮设置图标尺寸,宽度和可选择属性,然后连接connect到buttonClick()槽函数。
槽函数代码如下:

void UIDemo01::buttonClick()
{
    QToolButton *b = (QToolButton *)sender();
    //获取当前点击事件按钮的名称
    QString name = b->text();

    QList<QToolButton *> tbtns = ui->widgetTop->findChildren<QToolButton *>();
    foreach (QToolButton *btn, tbtns) {
        if (btn == b) {
            //如果是当前点击事件的按钮,将其设为选中状态
            btn->setChecked(true);
        } else {
            //如果不是当前点击事件的按钮,将其设为未选中状态
            btn->setChecked(false);
        }
    }

    if (name == "主界面") {
        ui->stackedWidget->setCurrentIndex(0);
    } else if (name == "系统设置") {
        ui->stackedWidget->setCurrentIndex(1);
    } else if (name == "警情查询") {
        ui->stackedWidget->setCurrentIndex(2);
    } else if (name == "调试帮助") {
        ui->stackedWidget->setCurrentIndex(3);
    } else if (name == "用户退出") {
        //退出程序
        exit(0);
    }
}

这个槽函数,首先使用sender()函数获得了发生点击事件的那个QToolButton类型按钮的句柄。
然后,将其设为选中状态,将其他的按钮设为未选中状态;
最后,根据按钮的名称来选择跳转到的主界面。

四、重写缩写界面、放大界面和关闭程序事件

首先,在.h文件中注册这些函数

private slots:
    void on_btnMenu_Min_clicked();
    void on_btnMenu_Max_clicked();
    void on_btnMenu_Close_clicked();

然后,直接重写这些函数即可。

void UIDemo01::on_btnMenu_Min_clicked()
{
    //qt自带函数
    showMinimized();
}

void UIDemo01::on_btnMenu_Max_clicked()
{
    //静态定义变量,只在第一次使用
    static bool max = false;
    //静态定义变量获得尺寸
    static QRect location = this->geometry();

    //记忆放大前的窗口尺寸,方便取消最大化时返回原位置和大小
    if (max) {
        this->setGeometry(location);
    } else {
        //保存当前的窗口尺寸
        location = this->geometry();
        //设置界面可达的最大尺寸
        this->setGeometry(qApp->desktop()->availableGeometry());
    }

    //最大化就不能移动了
    this->setProperty("canMove", max);
    max = !max;
}

void UIDemo01::on_btnMenu_Close_clicked()
{
    //qt自带函数
    close();
}

五、鼠标事件的处理

有时我们需要捕获某个控件上的鼠标事件,比如这个界面在导航栏双击可以最大化和取消最大化。
首先,在.h文件中注册bool eventFilter(QObject *watched, QEvent *event);函数

protected:
    bool eventFilter(QObject *watched, QEvent *event);

然后,给需要捕获鼠标事件的控件添加鼠标事件注册

ui->widgetTitle->installEventFilter(this);//顶部导航栏注册鼠标事件

最后,在鼠标事件中编写处理程序

bool UIDemo01::eventFilter(QObject *watched, QEvent *event)
{
    //如果是鼠标双击事件
    if (event->type() == QEvent::MouseButtonDblClick) {
        //如果发生的控件是 ui->widgetTitle
        if (watched == ui->widgetTitle) {
            //调用发生最大化的函数
            on_btnMenu_Max_clicked();
            return true;
        }
    }

    //我们处理了点击事件,把事件返回到上层,让它们继续处理其他事件
    return QWidget::eventFilter(watched, event);
}

六、installEventFilter的使用

installEventFilter的使用参考
简述:
事件过滤器,可以实现一个QObject监视另一个QObject的所有事件,但是两个QObject必须在同一个线程内

使用:
被监视者(ui->widge)安装事件过滤器

 ui->widget->installEventFilter(this);

在监视者(this)里重新实现eventFilter()函数,此函数返回false时,表示监视者(this)不过滤此事件,事件将会继续发送到被监视者(ui->widge);返回true时表示监视者过滤此事件,事件将不会发送到被监视者

bool CustomerSwitchet::eventFilter(QObject *obj,QEvent *e)
{
    QWidget*wid = qobject_cast<QWidget*>(obj);
    if(wid==ui->widget)
    {
    	//根据事件类型,写处理逻辑
       qDebug()<<"widget";
    }
    return  false;
}
  • 6
    点赞
  • 100
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kissgoodbye2012

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值