小编给大家分享一下Qt中如何实现自选股列表拖拽、右键常用菜单功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
效果展示
如下效果图所示,是自选股使用上的一个展示效果,具有如下功能
1.搜索编辑框,支持股票代码和股票名称搜索
2.搜索预览框支持鼠标hover,并且可以使用键盘上下键进行当前项切换,单机时支持切换自选股
3.自选股列表,支持拖拽,拖拽时会有拖拽项映像,并示意将要拖拽到哪个位置
4.支持右键菜单,可以对某一项进行移动,删除等操作

如果觉着demo比较丑的话,可以看财联社-产品展示这篇文章中的效果图
自选股列表
接下来就是我们这篇文章的重头戏了,也是比较复杂的一个内容。
自选股列表我选择的是使用QListWidget来实现,然后每一个item上在放一个Widget即可,Widget就是我们定制窗体内容,这里我们主要讲解几个比较重要的核心内容
1、列表初始化
初始化StockList,实际上自选股列表应该从服务器拉取,我们这里作为demo测试,因此就自己模拟了5条数据进行插入。
//已选个股列表
d_ptr->m_pStockList = new StockList;
connect(d_ptr->m_pStockList, &StockList::RowClicked, this, [this](const QString & symbol){
emit RowClicked(symbol);
});
//测试数据 正常情况下 应该是列表自己拉取
OptionalMarketItem item;
for (int i = 1; i <= 5; ++i)
{
item.wstrSymbol = QString("0h000%1").arg(i).toStdWString();
item.wstrName = QString("%1%1%1").arg(i).toStdWString();
item.wstrIndustryName = QString("pingyin%1").arg(i).toStdWString();
d_ptr->m_pStockList->AddItem(item);
}
2、添加Item
往StockList中添加item项时,我们首先需要构造一个标准的QListWidgetItem结构,然后把我们自己定制的ListItem放到这个标准item结构上。
QListWidgetItem * StockList::AddItem(const OptionalMarketItem & data)
{
ListItem * itemWidget = new ListItem;
itemWidget->SetData(data);
QListWidgetItem * item = new QListWidgetItem;
addItem(item);
item->setSizeHint(QSize(0, 50));
setItemWidget(item, itemWidget);
return item;
}
ListItem就是一个普通的QWidget,上边排列了一些QLabel,用于显示我们的股票数据。
ListItem界面构造就不过多解释了,唯一需要说明的就是,我们股票数据发送变化时,界面上会有红绿色框的动画提示,这里需要调用两行代码来实现重新获取控件qss代码,并刷洗界面。
this->style()->unpolish(this);
this->style()->polish(this);
3、右键菜单
本篇文章和上一篇文章的右键菜单实现方式一样,都是参考我很早以前写的Qt之自定义QLineEdit右键菜单这篇文章,实现默认的contextMenuEvent函数即可。
右键菜单已经说的很多了,这里就一笔带过了,需要的同学可以自己快速的瞅一眼,应该比较容易理解。
void StockList::contextMenuEvent(QContextMenuEvent * event)
{
if (d_ptr->m_AllowMenu == false)
{
return;
}
if (d_ptr->m_ContextMenu == nullptr)
{
d_ptr->m_ContextMenu = new QMenu(this);
d_ptr->m_ContextMenu->setObjectName(QStringLiteral("StockListMenu"));
d_ptr->m_ContextMenu->setFixedWidth(100);
QAction * delAct = new QAction(QStringLiteral("删除自选股"), d_ptr->m_ContextMenu);
QAction * topAct = new QAction(QStringLiteral("置顶"), d_ptr->m_ContextMenu);
QAction * bottomAct = new QAction(QStringLiteral("置底"), d_ptr->m_ContextMenu);
QAction * upAct = new QAction(QStringLiteral("上移一位"), d_ptr->m_ContextMenu);
QAction * downAct = new QAction(QStringLiteral("下移一位"), d_ptr->m_ContextMenu);
connect(delAct, &QAction::triggered, this, &StockList::DeleteSotck);
connect(topAct, &QAction::triggered, this, &StockList::TopSotck);
connect(bottomAct, &QAction::triggered, this, &StockList::BottomSotck);
connect(upAct, &QAction::triggered, this, &StockList::UpSotck);
connect(downAct, &QAction::triggered, this, &StockList::DownSotck);
d_ptr->m_ContextMenu->addAction(delAct);
d_ptr->m_ContextMenu->addAction(topAct);
d_ptr->m_ContextMenu->addAction(bottomAct);
d_ptr->m_ContextMenu->addAction(upAct);
d_ptr->m_ContextMenu->addAction(downAct);
}
d_ptr->m_ContextMenu->exec(mapToGlobal(event->pos()));
QListWidget::contextMenuEvent(event);
}
以上5个菜单,虽然看起来功能相差很多,但是其实处理逻辑基本都是一样的,先是一个内容结构排序,然后进行刷新数据到界面上。
为了节省篇幅,我这里就只介绍置顶一只股票的操作
置顶的逻辑看起来是这样的
1.移除当前项
2.并且把当前项item插入到新位置
3.构造一个新的Widget,设置给item
4.把新位置的item设置为当前选中项
5.上传最新列表到数据中心,或者服务器
void StockList::TopSotck()
{
QListWidgetItem * item = currentItem();
if (item == nullptr)
{
return;
}
if (row(item) == 0)
{
return;
}
ListItem * itemWidget = ItemWidget(item);
QListWidgetItem * newItem = takeItem(row(item));
insertItem(0, newItem);
ListItem * topWidget = new ListItem;
topWidget->SetData(itemWidget->GetData());
setItemWidget(newItem, topWidget);
if (itemWidget)
{
itemWidget->close();
itemWidget = nullptr;
}
setCurrentItem(newItem);
StorageData();
}
4、拖拽Item
拖拽Item应该算是一个比较难一点儿功能,好在Qt已经为我们实现了一套QDrag事件的回调方法,也比较好使,如下图所示,重写如下4个方法,基本的拖拽事件就能完成了。
但是这里我么有选择默认的这个回调函数来实现这个功能,其中最大的原因就是,他们的可定制性太局限了。
我这里采取的是自己模拟鼠标拖拽功能,同过重写如下几个函数来达到我的目的
virtual void mousePressEvent(QMouseEvent * event) override;
virtual void mouseMoveEvent(QMouseEvent * event) override;
virtual void mouseReleaseEvent(QMouseEvent * event) override;
virtual void enterEvent(QEvent * event) override;
virtual void leaveEvent(QEvent * event) override;
1.鼠标按下时,主要是记录了一些内容状态,方便在鼠标移动时去做判断,并决定是否启用鼠标拖拽功能
2.鼠标移动就比较复杂了,进行了各种对比,还需要移动被拖拽项的映像位置,移动那一根水平线的位置
3.鼠标释放时,调整整个列表的内容
4.鼠标进入窗体时,显示水平标识线
5.鼠标离开窗体时,隐藏水平标识线
上边只是粗略的描述了这几个函数的功能, 因为函数实现体都比较长,因此这里我也是选择几个关键点来做以说明。
a、move函数
产生拖拽时,移动鼠标,我们需要处理很多事件,比如
1、初始化水平表示线和拖拽项映像
if (d_ptr->m_ShotLine == nullptr)
{
InitShotLine();
}
if (d_ptr->m_ShotPicture == nullptr)
{
InitShotLabel();
}
2、拖拽时修改鼠标状态
根据拖拽启动后,鼠标是否还在当前拖拽项上,设置鼠标的状态。
if (ListItem * newWidget = ItemWidget(d_ptr->dragItem))
{
d_ptr->m_ShotPicture->move(QCursor::pos() - d_ptr->dragItemPos);
d_ptr->m_DragRect = visualItemRect(d_ptr->dragItem);
if (d_ptr->m_DragRect.contains(event->pos()) || event->pos().isNull())
{
if ((event->pos() - d_ptr->startPos).manhattanLength() > 5)
{
setCursor(Qt::ForbiddenCursor);
}
}
else
{
setCursor(Qt::ArrowCursor);
}
if (d_ptr->m_ShotPicture->isHidden())
{
d_ptr->m_ShotPicture->show();
}
}
b、release函数
鼠标释放时,把拖拽项移动到新的位置
if (ListItem * oldWidget = ItemWidget(d_ptr->dragItem))
{
QListWidgetItem * newItem = new QListWidgetItem;
ListItem * itemWidget = new ListItem;
itemWidget->SetData(oldWidget->GetData());
insertItem(insertPos, newItem);
newItem->setSizeHint(QSize(0, 50));
setItemWidget(newItem, itemWidget);
setCurrentItem(newItem);
oldWidget->deleteLater();
}
5、刷新数据
全量刷新数据。在原来的列表上刷新数据
当原始列表行数不够时,构造新的行
当原始列表函数多时,移除末尾多的行
void StockList::Update_p(OptionalMarketItemVector data)
{
d_ptr->m_bOnceLoad = true;
disconnect(this, &QListWidget::currentItemChanged, this, &StockList::CurrentItemChanged);
int i = 0;
for (auto iter = data.begin(); iter != data.end(); ++iter, ++i)
{
bool success = false;
if (QListWidgetItem * item = this->item(i))
{
if (ListItem * itemWidget = ItemWidget(item))
{
itemWidget->SetData(*iter);
success = true;
}
}
if (!success)
{
AddItem(*iter);
}
}
if (i < this->count())
{
QListWidgetItem * item = nullptr;
while (item = this->item(i))
{
if (ListItem * itemWidget = ItemWidget(item))
{
itemWidget->close();
itemWidget = nullptr;
}
item = takeItem(i);
delete item;
}
}
if (d_ptr->m_LeftPress == false)
{
RecoveryCurrentItem();
}
connect(this, &QListWidget::currentItemChanged, this, &StockList::CurrentItemChanged);
}
以上是“Qt中如何实现自选股列表拖拽、右键常用菜单功能”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注天达云行业资讯频道!