Qt之模仿QQ主面板界面

Qt之模仿QQ主面板界面

效果图

这里写图片描述

这里写图片描述

这里写图片描述

这里大家值得注意的是,QQ等级设置,已经列表展开搜索时的三角符的旋转效果

这里写图片描述

//QQMainWindow.cpp
#include "qqmainwindow.h"
#include "contactitem.h"
#include "rootcontatitem.h"
#include "skinwindow.h"

#include <QPainter>
#include <QMouseEvent>
#include <QSpacerItem>
#include <QProxyStyle>
#include <QTimer>

class CustomProxyStyle : public QProxyStyle
{
public:
    virtual void drawPrimitive(PrimitiveElement element, const QStyleOption * option,
        QPainter * painter, const QWidget * widget = 0) const
    {
        if (PE_FrameFocusRect == element)
        {
            return;
        }
        else
        {
            QProxyStyle::drawPrimitive(element, option, painter, widget);
        }
    }
};

QQMainWindow::QQMainWindow(QWidget *parent)
    : BasicWindow(parent)
{
    ui.setupUi(this);
    m_styleName = "MainWindow";
    loadStyleSheet("MainWindow");
    initControl();

    QTimer* timer = new QTimer(this);
    timer->setInterval(500);
    connect(timer, &QTimer::timeout, [this](){
        static int level = 0;
        if (level == 99)
        {
            level = 0;
        }
        setLevelPixmap(level);
        level++;
    });
    timer->start();
}

QQMainWindow::~QQMainWindow()
{

}

void QQMainWindow::initControl()
{
    ui.treeWidget->setStyle(new CustomProxyStyle);

    setLevelPixmap(0);
    setUserName(QString::fromLocal8Bit("雨田哥-工作号"));
    setHeadPixmap(":/QQMainWindow/Resources/MainWindow/yutiange.jpg");
    setStatusMenuIcon(":/QQMainWindow/Resources/MainWindow/StatusSucceeded.png");

    QHBoxLayout *flowLayout = new QHBoxLayout();
    flowLayout->setContentsMargins(0, 0, 0, 0);
    flowLayout->setSpacing(2);
    flowLayout->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/app_7.png", "app_7"));
    flowLayout->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/app_2.png", "app_2"));
    flowLayout->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/app_3.png", "app_3"));
    flowLayout->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/app_4.png", "app_4"));
    flowLayout->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/app_5.png", "app_5"));
    flowLayout->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/app_6.png", "app_6"));
    flowLayout->addStretch();
    flowLayout->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/skin.png", "app_skin"));
    ui.appWidget->setLayout(flowLayout);

    ui.bottomLayout_up->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/app_10.png", "app_10"));
    ui.bottomLayout_up->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/app_8.png", "app_8"));
    ui.bottomLayout_up->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/app_11.png", "app_11"));
    ui.bottomLayout_up->addWidget(addOtherAppExtension(":/QQMainWindow/Resources/MainWindow/app/app_9.png", "app_9"));
    ui.bottomLayout_up->addStretch();

    ui.lineEdit->installEventFilter(this);
    ui.searchLineEdit->installEventFilter(this);

    initContactTree();
    initStrangerTree();

    connect(ui.sysmin, SIGNAL(clicked(bool)), this, SLOT(onShowMin(bool)));
    connect(ui.sysclose, SIGNAL(clicked(bool)), this, SLOT(onShowClose(bool)));
}

void QQMainWindow::setHeadPixmap(const QString& headPath)
{
    ui.headLabel->setPixmap(getRoundImage(QPixmap(headPath), QPixmap(":/QQMainWindow/Resources/MainWindow/head_mask.png"), ui.headLabel->size()));
}

void QQMainWindow::setUserName(const QString& username)
{
    ui.nameLabel->adjustSize();
    QString name = ui.nameLabel->fontMetrics().elidedText(username, Qt::ElideRight, ui.nameLabel->width());
    ui.nameLabel->setText(name);
}

void QQMainWindow::setStatusMenuIcon(const QString& statusPath)
{
    QPixmap statusBtnPixmap(ui.statusBtn->size());
    statusBtnPixmap.fill(Qt::transparent);
    QPainter painter(&statusBtnPixmap);
    painter.drawPixmap(4, 4, QPixmap(statusPath));
    painter.drawPixmap(16, 3, QPixmap(":/QQMainWindow/Resources/MainWindow/arrow_normal.gft.png"));
    ui.statusBtn->setIcon(statusBtnPixmap);
    ui.statusBtn->setIconSize(ui.statusBtn->size());
}

void QQMainWindow::setLevelPixmap(int level)
{
    QPixmap levelPixmap(ui.levelBtn->size());
    levelPixmap.fill(Qt::transparent);
    QPainter painter(&levelPixmap);
    painter.drawPixmap(0, 4, QPixmap(":/QQMainWindow/Resources/MainWindow/lv.png"));
    int unitNum = level / 1 % 10;//取个位数字
    int tenNum = level / 10 % 10;//取十位数字
    //十位
    painter.drawPixmap(10, 4, QPixmap(":/QQMainWindow/Resources/MainWindow/levelvalue.png"), tenNum * 6, 0, 6, 7);
    //个位
    painter.drawPixmap(16, 4, QPixmap(":/QQMainWindow/Resources/MainWindow/levelvalue.png"), unitNum * 6, 0, 6, 7);
    ui.levelBtn->setIcon(levelPixmap);
    ui.levelBtn->setIconSize(ui.levelBtn->size());
}

QWidget* QQMainWindow::addOtherAppExtension(const QString& apppath, const QString& appName)
{
    QPushButton* btn = new QPushButton(this);
    btn->setFixedSize(20, 20);
    QPixmap pixmap(btn->size());
    pixmap.fill(Qt::transparent);
    QPainter painter(&pixmap);
    QPixmap appPixmap(apppath);
    painter.drawPixmap((btn->width() - appPixmap.width()) / 2, (btn->height() - appPixmap.height())/2, appPixmap);
    btn->setIcon(pixmap);
    btn->setIconSize(btn->size());
    btn->setProperty("hasborder", true);
    btn->setObjectName(appName);
    connect(btn, &QPushButton::clicked, this, &QQMainWindow::onAppIconCliked);
    return btn;
}

void QQMainWindow::onAppIconCliked()
{
    if (sender()->objectName() == "app_skin")
    {
        SkinWindow* skinWindow = new SkinWindow();
        skinWindow->show();
    }
}

void QQMainWindow::resizeEvent(QResizeEvent *event)
{
    setUserName(QString::fromLocal8Bit("雨田哥-工作号"));
    __super::resizeEvent(event);
}

bool QQMainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (ui.searchLineEdit == obj)
    {
        if (event->type() == QEvent::FocusIn)
        {
            ui.searchWidget->setStyleSheet("QWidget#searchWidget {background-color:rgb(255, 255, 255);}\
                                            QPushButton#searchBtn {border-image:url(:/QQMainWindow/Resources/MainWindow/search/main_search_deldown.png);}\
                                            QPushButton#searchBtn:hover {border-image:url(:/QQMainWindow/Resources/MainWindow/search/main_search_delhighlight.png);}\
                                            QPushButton#searchBtn:pressed{ border-image:url(:/QQMainWindow/Resources/MainWindow/search/main_search_delhighdown.png);}");

        }
        else if (event->type() == QEvent::FocusOut)
        {
            ui.searchWidget->setStyleSheet(QString("QWidget#searchWidget {background-color:rgba(%1,%2,%3,50);}\
                                                    QPushButton#searchBtn {border-image:url(:/QQMainWindow/Resources/MainWindow/search/search_icon.png);}").arg(m_colorBackGround.red()).arg(m_colorBackGround.green()).arg(m_colorBackGround.blue()));
        }
    }
    return __super::eventFilter(obj, event);
}

void QQMainWindow::mousePressEvent(QMouseEvent *event)
{
    if (qApp->widgetAt(event->pos()) != ui.lineEdit && ui.lineEdit->hasFocus())
    {
        ui.lineEdit->clearFocus();
    }
    else if (qApp->widgetAt(event->pos()) != ui.searchLineEdit && ui.searchLineEdit->hasFocus())
    {
        ui.searchLineEdit->clearFocus();
    }
    __super::mousePressEvent(event);
}

void QQMainWindow::initContactTree()
{
    //展开和收缩时信号,以达到变更我三角图片;
    connect(ui.treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(onItemClicked(QTreeWidgetItem *, int)));
    connect(ui.treeWidget, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT(onItemExpanded(QTreeWidgetItem *)));
    connect(ui.treeWidget, SIGNAL(itemCollapsed(QTreeWidgetItem *)), this, SLOT(onItemCollapsed(QTreeWidgetItem *)));
    //分组节点
    QTreeWidgetItem *pRootFriendItem = new QTreeWidgetItem();
    pRootFriendItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
    //设置Data用于区分,Item是分组节点还是子节点,0代表分组节点,1代表子节点
    pRootFriendItem->setData(0, Qt::UserRole, 0);
    RootContatItem *pItemName = new RootContatItem(ui.treeWidget);

    int nMyFriendNum = 6;
    QString qsGroupName = QString::fromLocal8Bit("我的好友 %1/%2").arg(0).arg(nMyFriendNum);
    pItemName->setText(qsGroupName);
    //擦入分组节点
    ui.treeWidget->addTopLevelItem(pRootFriendItem);
    ui.treeWidget->setItemWidget(pRootFriendItem, 0, pItemName);

    for (int nIndex = 0; nIndex < nMyFriendNum; ++nIndex)
    {
        //添加子节点
        addMyFriendInfo(pRootFriendItem);
    }
}

void QQMainWindow::addMyFriendInfo(QTreeWidgetItem* pRootGroupItem)
{
    QTreeWidgetItem *pChild = new QTreeWidgetItem();
    //添加子节点
    pChild->setData(0, Qt::UserRole, 1);
    ContactItem* pContactItem = new ContactItem(ui.treeWidget);
    pContactItem->setHeadPixmap(getRoundImage(QPixmap(":/QQMainWindow/Resources/MainWindow/yutiange.jpg"), QPixmap(":/QQMainWindow/Resources/MainWindow/head_mask.png"), pContactItem->getHeadLabelSize()));
    pContactItem->setUserName(QString::fromLocal8Bit("雨田哥-工作号"));
    pContactItem->setSignName(QString::fromLocal8Bit("欢迎访问雨田哥工作号"));
    pRootGroupItem->addChild(pChild);
    ui.treeWidget->setItemWidget(pChild, 0, pContactItem);
}

void QQMainWindow::initStrangerTree()
{
    //分组节点
    QTreeWidgetItem *pRootFriendItem = new QTreeWidgetItem();
    pRootFriendItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
    //设置Data用于区分,Item是分组节点还是子节点,0代表分组节点,1代表子节点
    pRootFriendItem->setData(0, Qt::UserRole, 0);
    RootContatItem *pItemName = new RootContatItem(ui.treeWidget);

    int nMyFriendNum = 8;
    QString qsGroupName = QString::fromLocal8Bit("陌生人 %1/%2").arg(0).arg(nMyFriendNum);
    pItemName->setText(qsGroupName);
    //擦入分组节点
    ui.treeWidget->addTopLevelItem(pRootFriendItem);
    ui.treeWidget->setItemWidget(pRootFriendItem, 0, pItemName);

    for (int nIndex = 0; nIndex < nMyFriendNum; ++nIndex)
    {
        //添加子节点
        addStarngerInfo(pRootFriendItem);
    }
}

void QQMainWindow::addStarngerInfo(QTreeWidgetItem* pRootGroupItem)
{
    QTreeWidgetItem *pChild = new QTreeWidgetItem();
    //添加子节点
    pChild->setData(0, Qt::UserRole, 1);
    ContactItem* pContactItem = new ContactItem(ui.treeWidget);
    pContactItem->setHeadPixmap(getRoundImage(QPixmap(":/QQMainWindow/Resources/MainWindow/yutiange.jpg"), QPixmap(":/QQMainWindow/Resources/MainWindow/head_mask.png"), pContactItem->getHeadLabelSize()));
    pContactItem->setUserName(QString::fromLocal8Bit("雨田哥-工作号-陌生人"));
    pContactItem->setSignName(QString::fromLocal8Bit("欢迎访问雨田哥工作号-陌生人"));
    pRootGroupItem->addChild(pChild);
    ui.treeWidget->setItemWidget(pChild, 0, pContactItem);
}

void QQMainWindow::onItemClicked(QTreeWidgetItem * item, int column)
{
    bool bIsChild = item->data(0, Qt::UserRole).toBool();
    if (!bIsChild)
    {
        item->setExpanded(!item->isExpanded());
    }
}

void QQMainWindow::onItemExpanded(QTreeWidgetItem * item)
{
    bool bIsChild = item->data(0, Qt::UserRole).toBool();
    if (!bIsChild)
    {
        RootContatItem *prootItem = dynamic_cast<RootContatItem*>(ui.treeWidget->itemWidget(item, 0));
        if (prootItem)
        {
            prootItem->setExpanded(true);
        }
    }
}

void QQMainWindow::onItemCollapsed(QTreeWidgetItem * item)
{
    bool bIsChild = item->data(0, Qt::UserRole).toBool();
    if (!bIsChild)
    {
        RootContatItem *prootItem = dynamic_cast<RootContatItem*>(ui.treeWidget->itemWidget(item, 0));
        if (prootItem)
        {
            prootItem->setExpanded(false);
        }
    }
}
SkinWindow.cpp
#include "skinwindow.h"
#include "qclicklabel.h"
#include "notifymanager.h"

SkinWindow::SkinWindow(QWidget *parent)
    : BasicWindow(parent)
{
    ui.setupUi(this);
    m_styleName = "SkinWindow";
    initControl();
    setAttribute(Qt::WA_DeleteOnClose);
    loadStyleSheet("SkinWindow");
}

SkinWindow::~SkinWindow()
{

}

void SkinWindow::initControl()
{
    QList<QColor> colorLst = { QColor(22, 154, 218), QColor(40, 138, 221), QColor(49, 166, 107), QColor(218, 67, 68),
                               QColor(177, 99, 159), QColor(107, 81, 92), QColor(89, 92, 160), QColor(21, 156, 199) ,
                               QColor(79, 169, 172), QColor(155, 183, 154), QColor(128, 77, 77), QColor(240, 188, 189) };
    for (int row = 0; row < 3; row++)
    {
        for (int column = 0; column < 4; column++)
        {
            QClickLabel* label = new QClickLabel(this);
            label->setCursor(Qt::PointingHandCursor);
            connect(label, &QClickLabel::clicked, [row, column, colorLst, this](){
                NotifyManager::getInstance()->notifyOtherWindowChangeSkin(colorLst.at(4 * row + column));
            });
            label->setFixedSize(84, 84);
            QPalette palette;
            palette.setColor(QPalette::Background, colorLst.at(4 * row + column));
            label->setAutoFillBackground(true);
            label->setPalette(palette);

            ui.gridLayout->addWidget(label, row, column);
        }
    }

    connect(ui.sysmin, SIGNAL(clicked(bool)), this, SLOT(onShowMin(bool)));
    connect(ui.sysclose, SIGNAL(clicked(bool)), this, SLOT(onShowClose(bool)));
}
//父节点Item
#include "rootcontatitem.h"
#include <QPainter>
#include <QPropertyAnimation>
#include <QDebug>

RootContatItem::RootContatItem(QWidget *parent)
    : QLabel(parent)
    , m_rotation(0)
{
    setFixedHeight(32);
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    m_animation = new QPropertyAnimation(this, "rotation");
    m_animation->setDuration(50);
    m_animation->setEasingCurve(QEasingCurve::InQuad);
}

RootContatItem::~RootContatItem()
{

}

void RootContatItem::setExpanded(bool expand)
{
    if (expand)
    {
        m_animation->setEndValue(90);
    }
    else
    {
        m_animation->setEndValue(0);
    }
    m_animation->start();
}

int RootContatItem::rotation()
{
    return m_rotation;
}

void RootContatItem::setRotation(int rotation)
{
    m_rotation = rotation;
    update();
}

void RootContatItem::setText(const QString& title)
{
    m_titleText = title;
    update();
}

void RootContatItem::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    {  
        painter.setRenderHint(QPainter::TextAntialiasing, true);
        QFont font;
        font.setPointSize(10);
        painter.setFont(font);
        painter.drawText(24, 0, width() - 24, height(), Qt::AlignLeft | Qt::AlignVCenter, m_titleText);
    }

    {
        painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
        painter.save();
        //背景图
        QPixmap pixmap(":/QQMainWindow/Resources/MainWindow/arrow.png");
        QPixmap tmpPixmap(pixmap.size());
        tmpPixmap.fill(Qt::transparent);

        QPainter p(&tmpPixmap);
        p.setRenderHint(QPainter::SmoothPixmapTransform, true);
        //旋转m_rotation角度
        p.translate(pixmap.width() / 2, pixmap.height() / 2);
        p.rotate(m_rotation);
        p.drawPixmap(0 - pixmap.width() / 2, 0 - pixmap.height() / 2, pixmap);
        painter.drawPixmap(6, (height() - pixmap.height()) / 2, tmpPixmap);
        painter.restore();
    }

    __super::paintEvent(event);
}

结尾

只为记录,只为分享! 愿所写能对你有所帮助。不忘记点个赞,谢谢~

—————– 需要工程文件的,可以加我QQ —————–

QQ等级设置效果,和好友列表展开和收缩时三角符号旋转动画效果。大家可以值得注意下。

  • 22
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
Qt是一个跨平台的开发框架,可以用于开发各种类型的应用程序,包括模仿CAD界面。开发模仿CAD界面Qt应用程序可以通过以下步骤实现: 1. 设计界面:使用Qt提供的设计工具(如Qt Creator)创建一个新的窗口应用程序,并设计CAD界面的外观。可以使用Qt的UI设计工具,比如布局管理器、窗口、按钮、绘图区域等控件来实现CAD界面的布局和元素。 2. 实现用户交互:根据CAD界面的需求,在Qt中实现与用户的交互。比如,可以使用鼠标和键盘事件来实现CAD界面的用户输入响应,例如绘制、选择、移动和缩放元素等操作。 3. 实现绘图功能:在CAD界面中,绘图是一个重要的功能。使用Qt的绘图API,可以实现CAD界面的绘图功能,包括点、线、多边形等几何元素的绘制,以及颜色、线型和填充等属性的设置。 4. 实现编辑功能:CAD界面通常提供了对绘图元素的编辑功能,如选择、移动、旋转和缩放等操作。使用Qt的事件处理机制,可以实现这些编辑功能的响应和处理。 5. 添加其他功能:根据CAD界面的需求,可以添加其他功能,如图层管理、撤销重做、导入导出等功能。使用Qt提供的功能组件,可以方便地实现这些功能。 6. 进行界面美化:通过使用Qt提供的样式表功能、图标资源和字体设置,可以对CAD界面进行美化,使其更加符合用户的视觉需求。 总之,借助Qt的跨平台特性和丰富的开发组件,可以很方便地开发模仿CAD界面的应用程序。通过合理利用Qt提供的功能和工具,我们可以实现一个功能强大、易于操作的CAD界面应用程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

雨田哥

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

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

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

打赏作者

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

抵扣说明:

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

余额充值