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

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