环境配置 :MinGW + QT 5.12 |
这里需要说明一下: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);
}
}
环境配置 :MinGW + QT 5.12 |