Qt之模仿QQ登录界面

简述

模仿QQ登录界面。

主要涉及布局管理器、输入控件以及QSS样式的使用。

只实现了基本的外观,并不涉及到内部功能实现。

整个界面分为两大部分,上面的欢迎界面(upPanel)和下面的信息输入界面(downPanel)。每一个部分都用一个单独的类来实现。这两个类都继承自QWidget。

效果

核心代码

核心代码主要涉及以下几个方面的内容

  • 实现无边框窗体
  • 实现窗口的拖动
  • 实现QQ工具栏
  • 实现主功能区

无边框窗体

windows默认的工具栏和QQ不一样,为了方便我们实现自己的工具栏,我们要将它隐藏起来。

setWindowFlags(Qt::FramelessWindowHint);

窗口的拖动

默认情况下只有工具栏所在的矩形长条区域可以拖动控件,但是由于我们将该长条隐藏了,所以需要自己实现窗口拖动效果,主要依据的是重写鼠标事件函数。

.h文件要添加的内容

public:   //设置鼠标按下可移动窗口的区域,在子窗口中必须设置该区域
    void setAreaMovable(const QRect rt);
protected:
    void mousePressEvent(QMouseEvent *);
    void mouseMoveEvent(QMouseEvent *);
    void mouseReleaseEvent(QMouseEvent *);
private:
    Ui::Widget *ui;
    QRect m_areaMovable;//可移动窗口的区域,鼠标只有在该区域按下才能移动窗口
    bool m_bPressed;//鼠标按下标志(不分左右键)
    QPoint m_ptPress;//鼠标按下的初始位置

.cpp文件要添加的内容

void Widget::mousePressEvent(QMouseEvent *e)
{
  //鼠标左键
  if(e->button() == Qt::LeftButton)
  {
  m_ptPress = e->pos();
  qDebug() << pos() << e->pos() << m_ptPress;
  m_bPressed = m_areaMovable.contains(m_ptPress);
  }
}
void Widget::mouseMoveEvent(QMouseEvent *e)
{
  if(m_bPressed)
  {
  qDebug() << pos() << e->pos() << m_ptPress;
  move(pos() + e->pos() - m_ptPress);
  }
}

void Widget::mouseReleaseEvent(QMouseEvent *)
{
  m_bPressed = false;
}

//设置鼠标按下的区域
void Widget::setAreaMovable(const QRect rt)
{
  if(m_areaMovable != rt)
  {
  m_areaMovable = rt;
  }
}

并在主窗口构造函数中加入下面的语句

    m_areaMovable = geometry();
    m_bPressed = false;

注意:这里设置的可拖动区域为全局,如果想要实现仅某个区域可拖动,需要调用setAreaMovable来设定可拖动区域。

实现QQ工具栏

前面我们已经把默认的工具栏给隐藏了,下面需要自己实现工具栏,实现该工具栏的关键点在于如何通过Qt的布局管理器将两个按钮放到右上角。代码如下:

.h文件

#ifndef UPPANEL_H
#define UPPANEL_H

#include <QWidget>
#include <QLabel>
class QToolButton;
class QSpacerItem;

class UpPanel : public QWidget
{
    Q_OBJECT
public:
    explicit UpPanel(QWidget *parent = nullptr);

    void loadStyleSheet(const QString &styleSheetFile);
    virtual void paintEvent(QPaintEvent *event);

    QToolButton *toolBtnClose;
    QToolButton *toolBtnSmall;
    QSpacerItem *verticalSpacer;
    QSpacerItem *horizontalSpacer;

signals:

public slots:
};

#endif // UPPANEL_H

.cpp文件

#include "uppanel.h"

#include <QFile>
#include <QMessageBox>
#include <QPainter>
#include <QStyleOption>
#include <QSpacerItem>
#include <QToolButton>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QMovie>
#include <QLabel>
UpPanel::UpPanel(QWidget *parent) : QWidget(parent)
{
    this->loadStyleSheet(":/up_panel.qss");
    this->setContentsMargins(0, 0, 0, 0);

    toolBtnClose = new QToolButton;
    toolBtnClose->setObjectName(QString::fromUtf8("toolBtnClose"));
    toolBtnSmall = new QToolButton;
    toolBtnSmall->setObjectName(QString::fromUtf8("toolBtnSmall"));

    horizontalSpacer = new QSpacerItem(619, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
    verticalSpacer = new QSpacerItem(20, 241, QSizePolicy::Minimum, QSizePolicy::Expanding);

    QHBoxLayout *toolBtnLayout = new QHBoxLayout;
    toolBtnLayout->addWidget(toolBtnSmall);
    toolBtnLayout->addWidget(toolBtnClose);

    QGridLayout *gridLayout = new QGridLayout;
    gridLayout->setSpacing(6);
    gridLayout->setContentsMargins(0, 0, 0, 0);
    gridLayout->setObjectName(QString::fromUtf8("gridLayout"));

    gridLayout->addItem(horizontalSpacer, 0, 0, 1, 1);
    gridLayout->addLayout(toolBtnLayout, 0, 1, 1, 1);
    gridLayout->addItem(verticalSpacer, 1, 1, 1, 1);

    setLayout(gridLayout);


}


void UpPanel::loadStyleSheet(const QString &styleSheetFile)
{

    QFile file(styleSheetFile);
    file.open(QFile::ReadOnly);
    if (file.isOpen())
    {
        QString styleSheet = this->styleSheet();
        styleSheet += QLatin1String(file.readAll());//读取样式表文件
        this->setStyleSheet(styleSheet);//把文件内容传参
        file.close();
    }
    else
    {
        QMessageBox::information(this,"tip","cannot find qss file");
    }
}

void UpPanel::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QStyleOption styleOpt;
    styleOpt.init(this);
    QPainter painter(this);
    style()->drawPrimitive(QStyle::PE_Widget, &styleOpt, &painter, this);
}

窗口缩放
窗口缩放使用setWindowState来设置窗口状态。

void Widget::windowHide()
{
    this->setWindowState(Qt::WindowMinimized);
}

实现主功能区

主功能区也就是信息输入区(downPanel),如下图所示:

通过观察,我们列出需要的控件如下

    QLabel *qqHeadLabel;
    QLabel *registerLabel;
    QLabel *retrievePasswordLabel;
    QLabel *addFriendsLabel;
    QLabel *QRCodeLabel;

    QComboBox *inputCountComboBox;
    QLineEdit *passwordLineEdit;
    QCheckBox *rememberPasswordBox;
    QCheckBox *autoLoginBox;
    QPushButton *logInPushButton;

    QSpacerItem *verticalSpacer_0;
    QSpacerItem *verticalSpacer_1;
    QSpacerItem *horizontalSpacer_0;
    QSpacerItem *horizontalSpacer_1;
    QSpacerItem *horizontalSpacer_2;

控件设置以及布局如下

    this->loadStyleSheet(":/down_panel.qss");
    this->setObjectName("downPanel");

    qqHeadLabel = new QLabel;
    qqHeadLabel->setObjectName("qqHeadLabel");
    registerLabel = new QLabel;
    registerLabel->setObjectName("registerLabel");
    registerLabel->setText("注册账号");
    retrievePasswordLabel = new QLabel;
    retrievePasswordLabel->setObjectName("retrievePasswordLabel");
    retrievePasswordLabel->setText("找回密码");
    addFriendsLabel = new QLabel;
    addFriendsLabel->setObjectName("addFriendsLabel");
    QRCodeLabel = new QLabel;
    QRCodeLabel->setObjectName("QRCodeLabel");


    inputCountComboBox = new QComboBox;
    inputCountComboBox->setObjectName("inputCountComboBox");
    inputCountComboBox->setEditable(true);
    inputCountComboBox->addItem("1040283480");
    inputCountComboBox->addItem("2839319053");
    passwordLineEdit = new QLineEdit;
    passwordLineEdit->setObjectName("passwordLineEdit");
    passwordLineEdit->setEchoMode(QLineEdit::Password);
    passwordLineEdit->setPlaceholderText("密码");
    passwordLineEdit->addAction(QIcon(":/picture/keyboard.png"), QLineEdit::TrailingPosition);
    rememberPasswordBox = new QCheckBox;
    rememberPasswordBox->setObjectName("rememberPasswordBox");
    rememberPasswordBox->setText("记住密码");
    autoLoginBox = new QCheckBox;
    autoLoginBox->setObjectName("autoLoginBox");
    autoLoginBox->setText("自动登录");
    logInPushButton = new QPushButton;
    logInPushButton->setObjectName("logInPushButton");
    logInPushButton->setText("登录");

    QGridLayout *gridLayout_0 = new QGridLayout;
    gridLayout_0->addWidget(qqHeadLabel, 0, 0, 3, 1);
    gridLayout_0->addWidget(inputCountComboBox, 0, 1, 1, 2);
    gridLayout_0->addWidget(passwordLineEdit, 1, 1, 1, 2);
    gridLayout_0->addWidget(rememberPasswordBox, 2, 1, 1, 1);
    gridLayout_0->addWidget(autoLoginBox, 2, 2, 1, 1);
    gridLayout_0->addWidget(logInPushButton, 3, 1, 1, 2);
    gridLayout_0->addWidget(registerLabel, 0, 3, 1, 1);
    gridLayout_0->addWidget(retrievePasswordLabel, 1, 3, 1, 1);

    QHBoxLayout *horizontalLayout = new QHBoxLayout;
    horizontalLayout->addWidget(addFriendsLabel);
    horizontalSpacer_0 =  new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
    horizontalLayout->addItem(horizontalSpacer_0);
    horizontalLayout->addWidget(QRCodeLabel);

    QGridLayout *gridLayout_1 = new QGridLayout;
    horizontalSpacer_1 = new QSpacerItem(189, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
    horizontalSpacer_2 = new QSpacerItem(189, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
    verticalSpacer_0 = new QSpacerItem(20, 31, QSizePolicy::Minimum, QSizePolicy::Expanding);
    verticalSpacer_1 = new QSpacerItem(20, 32, QSizePolicy::Minimum, QSizePolicy::Expanding);

    gridLayout_1->addItem(horizontalSpacer_1, 1, 0, 1, 1);
    gridLayout_1->addItem(horizontalSpacer_2, 1, 2, 1, 1);
    gridLayout_1->addItem(verticalSpacer_0, 0, 1, 1, 1);
    gridLayout_1->addItem(verticalSpacer_0, 2, 1, 1, 1);
    gridLayout_1->addLayout(gridLayout_0, 1, 1, 1, 1);
    gridLayout_1->addLayout(horizontalLayout, 3, 0, 1, 3);

    this->setLayout(gridLayout_1);

QSS样式

downPanel

QWidget#downPanel{

        background-color: rgb(236, 236, 236);
}

QLabel#qqHeadLabel {
        min-width:90px;
        max-width:90px;
        min-height:90px;
        max-height:90px;
        border-radius:45px;

        border-image: url(:/picture/qqhead.png);
}

QLabel#addFriendsLabel {
        min-width:20px;
        max-width:20px;
        min-height:20px;
        max-height:20px;

        border-image: url(:/picture/add_friends.png);
}

QLabel#QRCodeLabel {
        min-width:20px;
        max-width:20px;
        min-height:20px;
        max-height:20px;

        border-image: url(:/picture/QRode.png);
}

QLabel#registerLabel {
        color:rgb(0, 170, 255);
}

QLabel#retrievePasswordLabel {

        color: rgb(0, 170, 255);
}

QCheckBox {

        color: rgb(100, 100, 100);
}

QPushButton {
        min-height:25px;
        max-height:25px;
        border-radius:3px;
        background-color: rgb(0, 155, 232);
        color:white;
}


QPushButton:hover {
        min-height:25px;
        max-height:25px;
        border-radius:3px;
        background-color: rgb(0, 155, 150);
        color:white;
}


upPanel

QWidget {
        image: url(:/picture/qq.png);
        border-image: url(:/picture/title_background.gif)
}

QToolButton#toolBtnClose {
        background:transparent;
        border-image: url(:/picture/close.png);
        image:none;
        min-width:30px;
        max-width:30px;
        min-height:30px;
        max-height:30px
}
QToolButton#toolBtnSmall {
        background:transparent;
        border-image: url(:/picture/mini.png);
        image:none;
        min-width:30px;
        max-width:30px;
        min-height:30px;
        max-height:30px
}


QToolButton#toolBtnClose:hover {

        background-color: rgba(0, 85, 255, 0.5);
}

QToolButton#toolBtnSmall:hover {
        background-color: rgba(0, 85, 255, 0.5);
}

QSS使用注意事项

  • 如果一个类继承自QWidget,那么必须重新实现paintEvent,QSS样式才会有效果。
  • 如果想要使用具体类选择器(#),那么必须通过setObjectName为具体的类设置objectname。
  • 进行样式设计时请遵循方盒模型(Box Model)
  • 掌握控件大小的设定方法(min-width;max-width;min-height;max-height)

引用


[1] Qt助手

[2] https://www.cnblogs.com/xiongxuanwen/p/5384103.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章