zoukankan      html  css  js  c++  java
  • 自定义QListWidget实现item被hover时改变图标样式(模仿网易云音乐选项列表)(方法一)

    本文转载自https://blog.csdn.net/weixin_43742643/article/details/100187743

    前半部分copy了博主的博文,后面是自己的实践和疑惑。

    效果图:

     

    这里需要说明一下:QListWidget是鼠标press时item就会被选中,自定义的TestListWidget类重写了mousePressEvent和mouseReleaseEvent使得item在鼠标release时才会被选中。至于为什么这样做,是因为Chrome浏览器的书签栏以及网易云音乐的选项列表都是在鼠标release时才会触发选中…

    本文中实现方法:

    • item被hover时改变图标样式:继承QListWidgetItem + 继承QListWidget
    • item在鼠标release时选中:继承QListWidget

    另一种实现方法:自定义QListWidget实现item被hover时改变图标样式(模仿网易云音乐选项列表)(方法二)

    (1)TestListWidgetItem类继承自QListWidgetItem

    • TestListWidgetItem.h文件:
    class TestListWidgetItem : public QListWidgetItem
    {
        //Q_OBJECT  //由于QListWidgetItem没有QObject属性,所以Q_OBJECT需要注释掉
    public:
        explicit TestListWidgetItem(QListWidget *view = nullptr);
        void setUpIcon(const QIcon &icon, const QIcon &icon_hover);
    
        QIcon Img;
        QIcon Img_hover;
    };
    • TestListWidgetItem.c文件:
    TestListWidgetItem::TestListWidgetItem(QListWidget *view) :
        QListWidgetItem(view)
    {
    }
    
    void TestListWidgetItem::setUpIcon(const QIcon &icon, const QIcon &icon_hover)
    {
        Img = icon;
        Img_hover = icon_hover;
        setIcon(Img);
    }

    2)TestListWidget类继承自QListWidget

    • TestListWidget.h文件:
    class TestListWidget : public QListWidget
    {
        Q_OBJECT
    public:
        explicit TestListWidget(QWidget *parent = nullptr);
    
    protected:
        void mousePressEvent(QMouseEvent *event) override;
        void mouseReleaseEvent(QMouseEvent *event) override;
        void mouseMoveEvent(QMouseEvent *event) override;
        void leaveEvent(QEvent *event) override;
    
    private:
        QPoint startPos;
        TestListWidgetItem *theHighlightItem = nullptr;
        TestListWidgetItem *oldHighlightItem = nullptr;
        TestListWidgetItem *theSelectedItem = nullptr;
        TestListWidgetItem *oldSelectedItem = nullptr;
    
    private slots:
        void updateSelectedIcon();
    };
    • TestListWidget.c文件:
    TestListWidget::TestListWidget(QWidget *parent) :
        QListWidget(parent)
    {
        //mouseMoveEvent(QMouseEvent *event)需要该属性
        setMouseTracking(true);
        //当前被选中项发生变化时,触发item图标的更新
        connect(this, &TestListWidget::itemSelectionChanged, this, &TestListWidget::updateSelectedIcon);
    }
    
    //处理鼠标hover时,item的图标需要变成hover状态
    void TestListWidget::mouseMoveEvent(QMouseEvent *event)
    {
        oldHighlightItem = theHighlightItem;
        theHighlightItem = static_cast<TestListWidgetItem *>(itemAt(event->pos()));
    
        //旧的hover的item图标回复原状(条件是该item没有被选中)
        //新的hover的iten图标变成hover状态(条件是该item没有被选中)
        if(oldHighlightItem != theHighlightItem){
            if(oldHighlightItem && !oldHighlightItem->isSelected()) oldHighlightItem->setIcon(oldHighlightItem->Img);
            if(theHighlightItem && !theHighlightItem->isSelected()) theHighlightItem->setIcon(theHighlightItem->Img_hover);
        }
    }
    
    //鼠标按下时,startPos记录单击位置
    void TestListWidget::mousePressEvent(QMouseEvent *event)
    {
        if(event->buttons() & Qt::LeftButton){
            startPos = event->pos();
        }
    }
    
    //释放鼠标时,item才会被选中
    void TestListWidget::mouseReleaseEvent(QMouseEvent *event)
    {
        //如果鼠标释放位置和单击位置相距超过5像素,则不会触发item选中
        if((event->pos() - startPos).manhattanLength() > 5) return;
    
        TestListWidgetItem *item = static_cast<TestListWidgetItem *>(itemAt(event->pos()));
        setCurrentItem(item);
    }
    
    //处理鼠标离开后,hover图标回复正常状态
    void TestListWidget::leaveEvent(QEvent *event)
    {
        Q_UNUSED(event);
        oldHighlightItem = theHighlightItem;
        if(oldHighlightItem && !oldHighlightItem->isSelected()) oldHighlightItem->setIcon(oldHighlightItem->Img);
        oldHighlightItem = theHighlightItem = nullptr;
    }
    
    //响应itemSelectionChanged()信号,处理item被选中后,图标变成并保持hover状态
    void TestListWidget::updateSelectedIcon()
    {
        oldSelectedItem = theSelectedItem;
        theSelectedItem = static_cast<TestListWidgetItem *>(currentItem());
    
        //之前被选中的item图标回复原样
        //新被选中的item图标变成hover状态
        if(oldSelectedItem != theSelectedItem){
            if(oldSelectedItem) oldSelectedItem->setIcon(oldSelectedItem->Img);
            if(theSelectedItem) theSelectedItem->setIcon(theSelectedItem->Img_hover);
        }
    }

    (3)使用TestListWidget和TestListWidgetItem

    void test::initUi()
    {
        TestListWidget *listwidget = new TestListWidget(this);
        listwidget->setIconSize(QSize(25, 25));  //设置item图标大小
        listwidget->setFocusPolicy(Qt::NoFocus);  //这样可禁用tab键和上下方向键并且除去复选框
        listwidget->setFixedHeight(320);
        listwidget->setFont(QFont("宋体", 10, QFont::DemiBold));
        listwidget->setStyleSheet(
                    //"*{outline:0px;}"  //除去复选框
                    "QListWidget{background:rgb(245, 245, 247); border:0px; margin:0px 0px 0px 0px;}"
                    "QListWidget::Item{height:40px; border:0px; padding-left:14px; color:rgba(200, 40, 40, 255);}"
                    "QListWidget::Item:hover{color:rgba(40, 40, 200, 255);}"
                    "QListWidget::Item:selected{background:rgb(230, 231, 234); color:rgba(40, 40, 200, 255); border-left:4px solid rgb(180, 0, 0);}"
                    //"QListWidget::Item:selected:active{background:rgb(230, 231, 234); color:rgba(40, 40, 200, 255); border-left:4px solid rgb(180, 0, 0);}");
    
        TestListWidgetItem *item1 = new TestListWidgetItem(listwidget);
        item1->setUpIcon(QIcon(":/listBar_Icon/1.png"), QIcon(":/listBar_Icon/1_hover.png"));
        item1->setText("发现音乐");
    
        TestListWidgetItem *item2 = new TestListWidgetItem(listwidget);
        item2->setUpIcon(QIcon(":/listBar_Icon/2.png"), QIcon(":/listBar_Icon/2_hover.png"));
        item2->setText("私人FM");
    
        TestListWidgetItem *item3 = new TestListWidgetItem(listwidget);
        item3->setUpIcon(QIcon(":/listBar_Icon/3.png"), QIcon(":/listBar_Icon/3_hover.png"));
        item3->setText("朋友");
    
        TestListWidgetItem *item4 = new TestListWidgetItem(listwidget);
        item4->setUpIcon(QIcon(":/listBar_Icon/4.png"), QIcon(":/listBar_Icon/4_hover.png"));
        item4->setText("MV");
    
        TestListWidgetItem *item5 = new TestListWidgetItem(listwidget);
        item5->setUpIcon(QIcon(":/listBar_Icon/5.png"), QIcon(":/listBar_Icon/5_hover.png"));
        item5->setText("本地音乐");
    
        TestListWidgetItem *item6 = new TestListWidgetItem(listwidget);
        item6->setUpIcon(QIcon(":/listBar_Icon/6.png"), QIcon(":/listBar_Icon/6_hover.png"));
        item6->setText("下载管理");
    
        TestListWidgetItem *item7 = new TestListWidgetItem(listwidget);
        item7->setUpIcon(QIcon(":/listBar_Icon/7.png"), QIcon(":/listBar_Icon/7_hover.png"));
        item7->setText("我的音乐云盘");
    
        TestListWidgetItem *item8 = new TestListWidgetItem(listwidget);
        item8->setUpIcon(QIcon(":/listBar_Icon/8.png"), QIcon(":/listBar_Icon/8_hover.png"));
        item8->setText("我的收藏");
    
        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->setSpacing(0);
        layout->addWidget(listwidget);
        layout->setContentsMargins(0, 0, 0, 0);
        setLayout(layout);
    }

    (4)继承QListWidget时其实也可以不需要重写leaveEvent(QEvent *event)和mouseMoveEvent(QMouseEvent *event)这两个函数,只需要重写event(QEvent *event)。

    • TestListWidget.h文件:
    class TestListWidget : public QListWidget
    {
        Q_OBJECT
    public:
        explicit TestListWidget(QWidget *parent = nullptr);
    
    protected:
        void mousePressEvent(QMouseEvent *event) override;
        void mouseReleaseEvent(QMouseEvent *event) override;
        bool event(QEvent *event) override;
    
    private:
        QPoint startPos;
        TestListWidgetItem *theHighlightItem = nullptr;
        TestListWidgetItem *oldHighlightItem = nullptr;
        TestListWidgetItem *theSelectedItem = nullptr;
        TestListWidgetItem *oldSelectedItem = nullptr;
    
    private slots:
        void updateSelectedIcon();
    };
    • TestListWidget.c文件:
    TestListWidget::TestListWidget(QWidget *parent) :
        QListWidget(parent)
    {
        //不重写mouseMoveEvent(QMouseEvent *event)的话,该属性可以不用设置
        //setMouseTracking(true);
        //当前被选中项发生变化时,触发item图标的更新
        connect(this, &TestListWidget::itemSelectionChanged, this, &TestListWidget::updateSelectedIcon);
    }
    
    //鼠标按下时,startPos记录单击位置
    void TestListWidget::mousePressEvent(QMouseEvent *event)
    {
        if(event->buttons() & Qt::LeftButton){
            startPos = event->pos();
        }
    }
    
    //释放鼠标时,item才会被选中
    void TestListWidget::mouseReleaseEvent(QMouseEvent *event)
    {
        //如果鼠标释放位置和单击位置相距超过5像素,则不会触发item选中
        if((event->pos() - startPos).manhattanLength() > 5) return;
        //由于TestListWidgetItem没有QObject属性,所以这里使用static_cast而非qobject_cast
        TestListWidgetItem *item = static_cast<TestListWidgetItem *>(itemAt(event->pos()));
        setCurrentItem(item);
    }
    
    bool TestListWidget::event(QEvent *event)
    {
        switch (event->type()) {
        //处理鼠标hover时,item的图标需要变成hover状态
        case QEvent::HoverMove:
            oldHighlightItem = theHighlightItem;
            //由于TestListWidgetItem没有QObject属性,所以这里使用static_cast而非qobject_cast
            theHighlightItem = static_cast<TestListWidgetItem *>(itemAt(mapFromGlobal(QCursor::pos())));
    
            //旧的hover的item图标回复原状(条件是该item没有被选中)
            //新的hover的iten图标变成hover状态(条件是该item没有被选中)
            if(oldHighlightItem != theHighlightItem){
                if(oldHighlightItem && !oldHighlightItem->isSelected()) oldHighlightItem->setIcon(oldHighlightItem->Img);
                if(theHighlightItem && !theHighlightItem->isSelected()) theHighlightItem->setIcon(theHighlightItem->Img_hover);
            }
            break;
        //处理鼠标离开后,hover图标回复正常状态
        case QEvent::HoverLeave:
            oldHighlightItem = theHighlightItem;
            if(oldHighlightItem && !oldHighlightItem->isSelected()) oldHighlightItem->setIcon(oldHighlightItem->Img);
            oldHighlightItem = theHighlightItem = nullptr;
            break;
        default:
            break;
        }
        return QListWidget::event(event);
    }
    
    //响应itemSelectionChanged()信号,处理item被选中后,图标变成并保持hover状态
    void TestListWidget::updateSelectedIcon()
    {
        oldSelectedItem = theSelectedItem;
        //由于TestListWidgetItem没有QObject属性,所以这里使用static_cast而非qobject_cast
        theSelectedItem = static_cast<TestListWidgetItem *>(currentItem());
    
        //之前被选中的item图标回复原样
        //新被选中的item图标变成hover状态
        if(oldSelectedItem != theSelectedItem){
            if(oldSelectedItem) oldSelectedItem->setIcon(oldSelectedItem->Img);
            if(theSelectedItem) theSelectedItem->setIcon(theSelectedItem->Img_hover);
        }
    }

    这一部分是自己稍加改进的代码,运行无误。还是用的重写事件的方法。

    #include "testlistwidgetitem.h"
    #include <QApplication>
    #include "testlistwidgetitem.h"
    #include "testlistwidget.h"
    #include <QVBoxLayout>
    #include  <QHBoxLayout>
    #include <QWidget>
    #include<QListWidget>
    #include <QMainWindow>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        TestListWidget *listwidget = new TestListWidget();
        listwidget->setIconSize(QSize(25, 25));  //设置item图标大小
        listwidget->setFocusPolicy(Qt::NoFocus);  //这样可禁用tab键和上下方向键并且除去复选框
        listwidget->setFixedHeight(320);
        listwidget->setFont(QFont("宋体", 10, QFont::DemiBold));
        listwidget->setStyleSheet(
            "*{outline:0px;}"  //除去复选框
            "QListWidget{background:rgb(245, 245, 247); border:0px; margin:0px 0px 0px 0px;}"
            "QListWidget::Item{height:40px; border:0px; padding-left:14px; color:rgba(200, 40, 40, 255);}"
            "QListWidget::Item:hover{color:rgba(40, 40, 200, 255);}"
            "QListWidget::Item:selected{background:rgb(230, 231, 234); color:rgba(40, 40, 200, 255); border-left:4px solid rgb(180, 0, 0);}"
            "QListWidget::Item:selected:active{background:rgb(230, 231, 234); color:rgba(40, 40, 200, 255); border-left:4px solid rgb(180, 0, 0);}");
    
        TestListWidgetItem *item1 = new TestListWidgetItem(listwidget);
        item1->setUpIcon(QIcon(":/normal.jpg"), QIcon(":/pressed.jpg"));
        item1->setText("数据查询");
    
        TestListWidgetItem *item2 = new TestListWidgetItem(listwidget);
        item2->setUpIcon(QIcon(":/normal1.jpg"), QIcon(":/pressed1.jpg"));
        item2->setText("曲线查询");
    
        QVBoxLayout *layout = new QVBoxLayout();
        //QHBoxLayout *layout = new QHBoxLayout();
        layout->setSpacing(0);
        layout->addWidget(listwidget);
        layout->setContentsMargins(0, 0, 0, 0);
        //listwidget->setLayout(layout);  //不注掉这一句的话不显示窗体,很奇怪
        listwidget->show();
    
        return a.exec();
    }

  • 相关阅读:
    python3 sorted()函数解析
    MySql 关键字
    python的 a,b=b,a+b 和 a=b b=a+b 的区别
    python3 all() 函数用于检查实参
    Python3 urllib模块
    Python3 shutil模块
    Python3 sys模块
    Python 异常处理和断言
    Python3 os模块
    Pytho3 file open方法
  • 原文地址:https://www.cnblogs.com/sggggr/p/12674744.html
Copyright © 2011-2022 走看看