环境配置 :MinGW + QT 5.12

效果图(左边是拖拽即选中,右边是拖拽不影响选中):


这种自定义拖拽样式的灵感来自于Chrome浏览器的书签栏。文章中所使用的自定义QListWidget来自于:自定义QListWidget实现item被hover时改变图标样式(模仿网易云音乐选项列表)(方法二)中的TestListWidget类的拓展(在之前的基础上加入了拖拽的代码)。本文中拖拽的特点是:拖拽不影响选中。


实现方法:

  • 拖拽功能实现:继承QListWidget(重写drag事件)
  • item在release时被选中:继承QListWidget(重写mousePressEvent和mouseReleaseEvent)
  • item在被hover时改变图标样式:继承QListWigetItem + 继承QStyledItemDelegate
  • 绘制dropIndicator:继承QListWidget(使用update()进行控制) + 继承QStyledItemDelegate (使用画笔进行绘制)

拖拽时缩略图thumbnail类:

  • Qt绘制形状不规则窗口(一)

推荐其它关于拖拽的文章:

  • 拖拽之路(原生之初一):自定义QListWidget实现美观的拖拽样式
  • 拖拽之路(原生之初二):自定义QListView实现美观的拖拽样式
  • 拖拽之路(一):自定义QListWidget实现美观的拖拽样式(拖拽即选中)
  • 拖拽之路(二):自定义QListWidget实现美观的拖拽样式(拖拽不影响选中)
  • 拖拽之路(三):自定义QListView实现美观的拖拽样式(拖拽即选中)
  • 拖拽之路(四):自定义QListView实现美观的拖拽样式(拖拽不影响选中)
  • 拖拽之路(五):自定义QListWidget实现美观的拖拽样式(拖拽不影响选中 + doAutoScroll)

这里需要说明一下:QListWidget是鼠标press时item就会被选中,自定义的TestListWidget类重写了mousePressEvent和mouseReleaseEvent使得item在鼠标release时才会被选中。至于为什么这样做,是因为Chrome浏览器的书签栏以及网易云音乐的选项列表都是在鼠标release时才会触发选中…
正是由于item在鼠标release时才会被选中,所以才会出现 拖拽即选中 和 拖拽不影响选中 两种情况,而QListWidget是鼠标press时item就会被选中,所以只能是 拖拽即选中(拖拽的条件是press,导致item在触发拖拽时就被选中)。


(0)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);
}

(1)TestListWidget类继承自QListWidget

  • TestListWidget.h文件:
class TestListWidget : public QListWidget
{Q_OBJECTpublic:explicit TestListWidget(QWidget *parent = nullptr);bool isDraging() const {return IsDraging;}int offset() const {return 19;}int highlightedRow() const {return theHighlightedRow;}int dragRow() const {return theDragRow;}int selectedRow() const {return theSelectedRow;}static QString myMimeType() { return QStringLiteral("TestListWidget/text-icon-icon_hover"); }protected:void mousePressEvent(QMouseEvent *event) override;void mouseReleaseEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;void dragEnterEvent(QDragEnterEvent *event) override;void dragLeaveEvent(QDragLeaveEvent *event) override;void dragMoveEvent(QDragMoveEvent *event) override;void dropEvent(QDropEvent *event) override;private:QPoint startPos;bool IsDraging = false;QRect oldHighlightedRect;QRect theHighlightedRect;int theHighlightedRow = -1;int theDragRow = -1;int theSelectedRow = -1;int theInsertRow = -1;const QRect targetRect(const QPoint &position) const;
};
  • TestListWidget.c文件:
TestListWidget::TestListWidget(QWidget *parent) :QListWidget(parent)
{//setMouseTracking(true);  //注释与否没有影响//setDragEnabled(true);  //注释与否没有影响setAcceptDrops(true);//setDropIndicatorShown(false);  //注释与否没有影响//setDefaultDropAction(Qt::MoveAction);  //注释与否没有影响
}//拖拽起点
void TestListWidget::mousePressEvent(QMouseEvent *event)
{if(event->buttons() & Qt::LeftButton){startPos = event->pos();}
}void TestListWidget::mouseReleaseEvent(QMouseEvent *event)
{if((event->pos() - startPos).manhattanLength() > 5) return;TestListWidgetItem *item = static_cast<TestListWidgetItem *>(itemAt(event->pos()));setCurrentItem(item);
}void TestListWidget::mouseMoveEvent(QMouseEvent *event)
{if(event->buttons() & Qt::LeftButton){//[1]超过规定距离才会触发拖拽,防止手滑...if((event->pos() - startPos).manhattanLength() < QApplication::startDragDistance()) return;
//[1]TestListWidgetItem *theDragItem = static_cast<TestListWidgetItem *>(itemAt(startPos));//setCurrentItem(theDragItem);  //拖拽即选中theDragRow = row(theDragItem);theSelectedRow = row(currentItem());//[2]这部分是把拖拽的数据放在QMimeData容器中(参考Qt例程puzzle,使用QByteArray和QDataStream感觉很方便)QString text = theDragItem->text();QIcon icon = theDragItem->Img;QIcon icon_hover = theDragItem->Img_hover;QByteArray itemData;QDataStream dataStream(&itemData, QIODevice::WriteOnly);dataStream << text << icon << icon_hover;QMimeData *mimeData = new QMimeData;mimeData->setData(myMimeType(), itemData);
//[2]//[3]设置拖拽时的缩略图,thumbnail类(找机会我会写一篇单独的文章介绍)是继承自QWidget的类椭圆形半透明窗口,使用grab()将QWidget变成QPixmap。thumbnail *DragImage = new thumbnail(this);DragImage->setupthumbnail(icon_hover, text);//DragImage->setIconSize(18);  //default:20QPixmap pixmap = DragImage->grab();QDrag *drag = new QDrag(this);drag->setMimeData(mimeData);//设置缩略图drag->setPixmap(pixmap);//设置鼠标在缩略图上的位置drag->setHotSpot(QPoint(pixmap.width()/2, pixmap.height()/2));
//[3]//拖拽开始!if(drag->exec(Qt::MoveAction) == Qt::MoveAction){if(theSelectedRow != theDragRow) delete takeItem(row(theDragItem));}}
}void TestListWidget::dragEnterEvent(QDragEnterEvent *event)
{TestListWidget *source = qobject_cast<TestListWidget *>(event->source());if (source && source == this) {//IsDraging(标志位)判断是否正在拖拽IsDraging = true;event->setDropAction(Qt::MoveAction);event->accept();}
}//当拖拽离开QListWidget时,需要update以保证DropIndicator消失
void TestListWidget::dragLeaveEvent(QDragLeaveEvent *event)
{theHighlightedRow = -2;if(!theHighlightedRect.contains(QRect(0, 40 * theDragRow, width(), 40))){update(theHighlightedRect);}//IsDraging(标志位)判断是否正在拖拽IsDraging = false;theInsertRow = -1;event->accept();
}//拖拽移动时刷新以更新DropIndicator
void TestListWidget::dragMoveEvent(QDragMoveEvent *event)
{TestListWidget *source = qobject_cast<TestListWidget *>(event->source());if (source && source == this) {oldHighlightedRect = theHighlightedRect;theHighlightedRect = targetRect(event->pos());//offset() = 19(这个数值是我调用父类的dropEvent(event)一次一次试出来的,我觉得公式应该是19 = 40 / 2 - 1, 其中40是item行高)if(event-o>pos().y() >= offset()){theHighlightedRow = row(itemAt(event->pos() - QPoint(0, offset())));if(oldHighlightedRect != theHighlightedRect){update(oldHighlightedRect);  //刷新旧区域使DropIndicator消失update(theHighlightedRect);  //刷新新区域使DropIndicator显示}elseupdate(theHighlightedRect);theInsertRow = row(itemAt(event->pos() - QPoint(0, offset()))) + 1;}else{theHighlightedRow = -1;update(QRect(0, 0, width(), 80));  //仅刷新第一行theInsertRow = 0;}event->setDropAction(Qt::MoveAction);event->accept();}
}void TestListWidget::dropEvent(QDropEvent *event)
{TestListWidget *source = qobject_cast<TestListWidget *>(event->source());if (source && source == this){IsDraging = false;  //拖拽完成theHighlightedRow = -2;update(theHighlightedRect);  //拖拽完成,刷新以使DropIndicator消失//这种情况下,拖拽后的顺序和之前的顺序相同,所以无需触发拖拽if(theInsertRow == theDragRow || theInsertRow == theDragRow + 1) return;//如果拖拽行即选中行,则可以直接调用父类dropEvent(event)if(theSelectedRow == theDragRow){QListWidget::dropEvent(event);return;}//如果拖拽行非选中行,则需要手动插入QString text;QIcon icon, icon_hover;QByteArray itemData = event->mimeData()->data(myMimeType());QDataStream dataStream(&itemData, QIODevice::ReadOnly);dataStream >> text >> icon >> icon_hover;TestListWidgetItem *theInsertItem = new TestListWidgetItem(/*this*/);  //注意这里不能指定parenttheInsertItem->setUpIcon(icon, icon_hover);theInsertItem->setText(text);insertItem(theInsertRow, theInsertItem);event->setDropAction(Qt::MoveAction);event->accept();}
}const QRect TestListWidget::targetRect(const QPoint &position) const
{//40是item的行高if(position.y() >= offset())return QRect(0, (position.y() - offset()) / 40 * 40, width(), 2 * 40);elsereturn QRect(0, 0, width(), 40);
}

(2)TestItemDelegate类继承自QStyledItemDelegate,主要是为了绘制dropIndicator。图示为dropIndicator组成:

  • TestItemDelegate.h文件:
#define POLYGON 4   //等腰三角形直角边长
#define WIDTH 1     //分隔符粗细的一半class TestItemDelegate : public QStyledItemDelegate
{Q_OBJECTpublic:TestItemDelegate(QObject *parent = nullptr);protected:void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
  • TestItemDelegate.c文件:
void TestItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{TestListWidget *dragWidget = qobject_cast<TestListWidget *>(option.styleObject);bool isDraging = dragWidget->isDraging();QRect rect = option.rect;painter->setRenderHint(QPainter::Antialiasing, true);painter->setPen(Qt::NoPen);if(option.state & (QStyle::State_MouseOver | QStyle::State_Selected)){TestListWidgetItem *item = static_cast<TestListWidgetItem *>(dragWidget->item(index.row()));item->setIcon(item->Img_hover);if(option.state & QStyle::State_MouseOver){}if(option.state & QStyle::State_Selected){painter->setBrush(QColor(180, 0, 0));painter->drawRect(rect.topLeft().x(), rect.topLeft().y(), 4, rect.height());painter->setBrush(QColor(230, 231, 234));painter->drawRect(rect.topLeft().x() + 4, rect.topLeft().y(), rect.width() - 4, rect.height());}}else{TestListWidgetItem *item = static_cast<TestListWidgetItem *>(dragWidget->item(index.row()));item->setIcon(item->Img);}//begin dragif(isDraging){int theDragRow = dragWidget->dragRow();int theSelectedRow = dragWidget->selectedRow();int UpRow = dragWidget->highlightedRow();int DownRow = UpRow + 1;int rowCount = dragWidget->count() - 1;//只绘制空隙,而不绘制DropIndicator(这种情况是当拖拽行非选中行时,需要在选中行上面或者下面绘制空隙用来显示DropIndicator)if(index.row() == theSelectedRow && theDragRow != theSelectedRow){if(index.row() == UpRow && index.row() != theDragRow - 1){int offset = 3;  //这个值可以自己定,设为3感觉更美观QPolygon trianglePolygon_bottomLeft;trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - (offset + WIDTH) + 1);trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - (offset + WIDTH + POLYGON) + 1);trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x() + POLYGON, rect.bottomLeft().y() - (offset + WIDTH) + 1);QPolygon trianglePolygon_bottomRight;trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() + 1, rect.bottomRight().y() - (offset + WIDTH) + 1);trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() + 1, rect.bottomRight().y() - (offset + WIDTH + POLYGON) + 1);trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() - POLYGON + 1, rect.bottomRight().y() - (offset + WIDTH) + 1);painter->setBrush(QColor(245, 245, 247));painter->drawPolygon(trianglePolygon_bottomLeft);painter->drawPolygon(trianglePolygon_bottomRight);painter->drawRect(rect.bottomLeft().x(), rect.bottomLeft().y() - (offset + WIDTH) + 1, rect.width(), offset + WIDTH);painter->drawRect(rect.bottomLeft().x(), rect.bottomLeft().y() - (offset + WIDTH) + 1, rect.width(), offset + WIDTH);}else if(index.row() == DownRow && index.row() != theDragRow + 1){int offset = 3;QPolygon trianglePolygon_topLeft;trianglePolygon_topLeft << QPoint(rect.topLeft().x(), rect.topLeft().y() + offset + WIDTH);trianglePolygon_topLeft << QPoint(rect.topLeft().x(), rect.topLeft().y() + offset + WIDTH + POLYGON);trianglePolygon_topLeft << QPoint(rect.topLeft().x() + POLYGON, rect.topLeft().y() + offset + WIDTH);QPolygon trianglePolygon_topRight;trianglePolygon_topRight << QPoint(rect.topRight().x() + 1, rect.topRight().y() + offset + WIDTH);trianglePolygon_topRight << QPoint(rect.topRight().x() + 1, rect.topRight().y() + offset + WIDTH + POLYGON);trianglePolygon_topRight << QPoint(rect.topRight().x() - POLYGON + 1, rect.topRight().y() + offset + WIDTH);painter->setBrush(QColor(245, 245, 247));painter->drawPolygon(trianglePolygon_topLeft);painter->drawPolygon(trianglePolygon_topRight);painter->drawRect(rect.topLeft().x(), rect.topLeft().y(), rect.width(), offset + WIDTH);}}//绘制DropIndicatorif(index.row() == UpRow && index.row() != theDragRow - 1 && index.row() != theDragRow){painter->setBrush(QColor(66, 133, 244));if(UpRow == rowCount){//到达尾部,三角形向上移动一个WIDTH的距离,以使分隔符宽度*2QPolygon trianglePolygon_bottomLeft;trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - (POLYGON + WIDTH) + 1 - WIDTH);trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - WIDTH + 1 - WIDTH);trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x() + POLYGON, rect.bottomLeft().y() - WIDTH + 1 - WIDTH);QPolygon trianglePolygon_bottomRight;trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() + 1, rect.bottomRight().y() - (POLYGON + WIDTH) + 1 - WIDTH);trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() + 1, rect.bottomRight().y() - WIDTH + 1 - WIDTH);trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() - POLYGON + 1, rect.bottomRight().y() - WIDTH + 1 - WIDTH);painter->drawRect(rect.bottomLeft().x(), rect.bottomLeft().y() - 2 * WIDTH + 1, rect.width(), 2 * WIDTH);  //rectpainter->drawPolygon(trianglePolygon_bottomLeft);painter->drawPolygon(trianglePolygon_bottomRight);}else {//正常情况,组成上半部分(+1是根据实际情况修正)QPolygon trianglePolygon_bottomLeft;trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - (POLYGON + WIDTH) + 1);trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - WIDTH + 1);trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x() + POLYGON, rect.bottomLeft().y() - WIDTH + 1);QPolygon trianglePolygon_bottomRight;trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() + 1, rect.bottomRight().y() - (POLYGON + WIDTH) + 1);trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() + 1, rect.bottomRight().y() - WIDTH + 1);trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() - POLYGON + 1, rect.bottomRight().y() - WIDTH + 1);painter->drawRect(rect.bottomLeft().x(), rect.bottomLeft().y() - WIDTH + 1, rect.width(), WIDTH);  //rectpainter->drawPolygon(trianglePolygon_bottomLeft);painter->drawPolygon(trianglePolygon_bottomRight);}}else if(index.row() == DownRow && index.row() != theDragRow + 1 && index.row() != theDragRow){painter->setBrush(QColor(66, 133, 244));if(DownRow == 0){//到达头部,三角形向下移动一个WIDTH的距离,以使分隔符宽度*2QPolygon trianglePolygon_topLeft;trianglePolygon_topLeft << QPoint(rect.topLeft().x(), rect.topLeft().y() + (POLYGON + WIDTH) + WIDTH);trianglePolygon_topLeft << QPoint(rect.topLeft().x(), rect.topLeft().y() + WIDTH + WIDTH);trianglePolygon_topLeft << QPoint(rect.topLeft().x() + POLYGON, rect.topLeft().y() + WIDTH + WIDTH);QPolygon trianglePolygon_topRight;trianglePolygon_topRight << QPoint(rect.topRight().x() + 1, rect.topRight().y() + (POLYGON + WIDTH) + WIDTH);trianglePolygon_topRight << QPoint(rect.topRight().x() + 1, rect.topRight().y() + WIDTH + WIDTH);trianglePolygon_topRight << QPoint(rect.topRight().x() - POLYGON + 1, rect.topRight().y() + WIDTH + WIDTH);painter->drawRect(rect.topLeft().x(), rect.topLeft().y(), rect.width(), 2 * WIDTH);  //rectpainter->drawPolygon(trianglePolygon_topLeft);painter->drawPolygon(trianglePolygon_topRight);}else{//正常情况,组成下半部分(+1是根据实际情况修正)QPolygon trianglePolygon_topLeft;trianglePolygon_topLeft << QPoint(rect.topLeft().x(), rect.topLeft().y() + (POLYGON + WIDTH));trianglePolygon_topLeft << QPoint(rect.topLeft().x(), rect.topLeft().y() + WIDTH);trianglePolygon_topLeft << QPoint(rect.topLeft().x() + POLYGON, rect.topLeft().y() + WIDTH);QPolygon trianglePolygon_topRight;trianglePolygon_topRight << QPoint(rect.topRight().x() + 1, rect.topRight().y() + (POLYGON + WIDTH));trianglePolygon_topRight << QPoint(rect.topRight().x() + 1, rect.topRight().y() + WIDTH);trianglePolygon_topRight << QPoint(rect.topRight().x() - POLYGON + 1, rect.topRight().y() + WIDTH);painter->drawRect(rect.topLeft().x(), rect.topLeft().y(), rect.width(), WIDTH);  //rectpainter->drawPolygon(trianglePolygon_topLeft);painter->drawPolygon(trianglePolygon_topRight);}}//用于高亮拖拽行if(index.row() == theDragRow && theDragRow != theSelectedRow){painter->setBrush(QColor(180, 0, 0));painter->drawRect(rect.topLeft().x(), rect.topLeft().y(), 4, rect.height());painter->setBrush(QColor(230, 231, 234));painter->drawRect(rect.topLeft().x() + 4, rect.topLeft().y(), rect.width() - 4, rect.height());//opt.state is used to hightlight the fontQStyleOptionViewItem opt(option);opt.state |= QStyle::State_Selected;QStyledItemDelegate::paint(painter, opt, index);return;}QStyledItemDelegate::paint(painter, option, index);return;}
//end dragQStyledItemDelegate::paint(painter, option, index);
}

(3)使用TestListWidgetItem和TestItemDelegate

  • 主窗口.h文件:
class test : public QWidget
{Q_OBJECT
public:explicit test(QWidget *parent = nullptr);private:void initUi();
};
  • 主窗口.c文件:
test::test(QWidget *parent) : QWidget(parent)
{initUi();
}void test::initUi()
{setFixedSize(250, 600);TestListWidget *listwidget = new TestListWidget(this);listwidget->setIconSize(QSize(25, 25));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); padding-left:14px;}""QListWidget::Item:selected{color:rgba(40, 40, 200, 255); padding-left:15px;}");TestItemDelegate *delegate = new TestItemDelegate();listwidget->setItemDelegate(delegate);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);
}

如果想要接触更多关于拖拽的代码,在Qt例程中搜索“drag”。推荐看一下例程puzzle的两种实现方法(一种是继承QListWidget,另一种是QListView + 继承QAbstractListModel)。

环境配置 :MinGW + QT 5.12

拖拽之路(二):自定义QListWidget实现美观的拖拽样式(拖拽不影响选中)相关推荐

  1. 拖拽之路(五):自定义QListWidget实现美观的拖拽样式(拖拽不影响选中 + doAutoScroll)

    环境配置 :MinGW + QT 5.12 效果图: 这种自定义拖拽样式的灵感来自于Chrome浏览器的书签栏.文章中所使用的自定义QListWidget来自于:自定义QListWidget实现ite ...

  2. 拖拽之路(原生之初一):自定义QListWidget实现美观的拖拽样式

    环境配置 :MinGW + QT 5.12 效果图(左边是QListWidget传统拖拽样式,右边是自定义拖拽样式): 这种自定义拖拽样式的灵感来自于Chrome浏览器的书签栏.这篇文章命名为 &qu ...

  3. 拖拽之路(一):自定义QListWidget实现美观的拖拽样式(拖拽即选中)

    环境配置 :MinGW + QT 5.12 效果图(左边是QListWidget传统拖拽样式,右边是自定义拖拽样式): 这种自定义拖拽样式的灵感来自于Chrome浏览器的书签栏.文章中所使用的自定义Q ...

  4. 拖拽之路(四):自定义QListView实现美观的拖拽样式(拖拽不影响选中)

    环境配置 :MinGW + QT 5.12 效果图(左边是QListView拖拽即选中样式,右边是拖拽不影响选中样式): 这种自定义拖拽样式的灵感来自于Chrome浏览器的书签栏.本文中拖拽的特点是: ...

  5. Vue 实现拖拽模块(二)自定义拖拽组件位置

    上文介绍了 拖拽添加组件 的简单实现,本文将继续给大家分享如何自定义拖拽组件位置的简单实现,文中通过示例代码介绍,感兴趣的小伙伴们可以了解一下 本文主要介绍了 Vue自定义拖拽组件位置的简单实现,具体 ...

  6. vue拖拽效果(适用范围自定义表单,电子合同签章等)

    vue拖拽效果实现 实现原因 之前项目需求做一个自定义拖拽控件,进行自定义表单生成以及电子合同签字盖章,总结一下思路. 实现思路 首先需要可以拖拽的控件, 鼠标长按拖拽到拖拽存放区后,松开鼠标拖拽存放 ...

  7. js 拖拽生成html,js拖拽插件 js 拖拽控件生成自定义表单 怎么实现

    想请教一个js的问题,拖拽控件 js 拖拽控件生成自定义表单 怎么实现 说说步骤吧 监听mousedown事件 - 获取鼠标点击元素,判断是否可拖拽 - 设置flag做标记 - 建一个tempDOM, ...

  8. Android仿QQ消息拖拽效果(二)

    前言 本文参考辉哥贝塞尔曲线 - QQ消息汽包拖拽,前面我们使用二阶贝塞尔曲线绘制了拖拽圆点效果Android仿QQ消息拖拽效果(一)(二阶贝塞尔曲线使用),这里我们在此基础之上实现仿QQ消息拖拽爆炸 ...

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

    环境配置 :MinGW + QT 5.12 效果图: 这里需要说明一下:QListWidget是鼠标press时item就会被选中,自定义的TestListWidget类重写了mousePressEv ...

最新文章

  1. php 多人游戏_「谁会是下一个王者农药」云服务器如何搭建游戏服务器?
  2. 【计算机视觉】EmguCV学习笔记(1)Hello World
  3. python画圆形螺旋线_这个Python项目,一秒生成可爱像素风图片
  4. 收藏:Sql类型与.Net(C#)类型对应关系
  5. C++利用线性探查实现存储机制hash table的算法(附完整源码)
  6. C#开发的高性能EXCEL导入、导出工具DataPie(支持MSSQL、ORACLE、ACCESS,附源码下载地址)...
  7. 软件配置管理(二)配置管理角色与过程
  8. mysql 获取年预提,【判断题】正确核算待摊费用和预提费用,有助于划分本期费用与非本期费用的界限。...
  9. C/C++获取当前路径、获取任意pid完整路径(readlink()函数)
  10. 管理软件开发历程之一Coolite配置
  11. javaweb——总结
  12. 《深度学习》李宏毅 -- task6卷积神经网络
  13. 39. PHP 错误与异常处理(3)
  14. sql2008计算机环境,win2008r2下安装sql2008r2初版
  15. Log4j不同级别输出到不同文件的几种方式
  16. 步进电机驱动器电压是多少?
  17. 存算一体——后摩尔时代的AI芯片架构
  18. 用python制作动态二维码印刷价格_用一行Python代码制作动态二维码
  19. python虚拟机:pvm
  20. 怎么批量修改文件夹里照片的名字

热门文章

  1. 计算机组成原理课件ppt6,唐朔飞 计算机组成原理课件6.ppt
  2. hadoopsdk使用_Hadoop的一些基本操作
  3. cdh中hue集成hbase_HBase版本 | Cloudera Enterprise 6.2.0发布
  4. sql server 替换有反斜杠的字符串_字符串提取,到底谁是你的菜?
  5. Hakase and Nano 博弈
  6. 4000元性价比主机
  7. 轻量化网络:SqueezeNet
  8. 【五级流水线CPU】—— 5. 转移指令(14条)
  9. (编译适用于ARM的linux内核并进行QEMU仿真)Compile Linux kernel 3.2 for ARM and emulate with QEMU
  10. CSS知识点补充收集