热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Qt股票组件之自选股列表拖拽、右键常用菜单功能的实现

这篇文章主要介绍了Qt股票组件之自选股列表拖拽、右键常用菜单功能的实现方法,本文通过实例文字相结合的形式给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

一、开头嘴一嘴

本文带领大家来看看自选股列表的实现。

如果有需要的朋友可以加我好友,有偿提供源码、或者也可以进一步提供功能定制

封装的控件,或者demo都是没有样式的,所以看着会比较丑一些,不过加样式也是分分钟。。。这里咱可以先看功能,需要即可定制

本篇文章的自选股和大多数炒股软件一样,每一条自选都是支持拖拽的,拖拽时鼠标会跟随一个拖拽映像,并且鼠标移动时,会有拖拽提示,告知我们鼠标释放时拖拽项将会被插入到哪个位置。除过拖拽之外,自选股列表还支持右键菜单,都是一样常用的操作。

右键菜单包括置顶、置低、删除、下移一项、上移一项等

本篇文章中不包括的功能也可以提供定制,需求合理即可。

下面来具体说一说这个功能的实现思路,会公开大多数核心代码,有需要的同学可以根据思路自行完善整个代码。

二、效果展示

如下效果图所示,是自选股使用上的一个展示效果,具有如下功能

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 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股票组件之自选股列表拖拽、右键常用菜单功能的实现 ,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!


推荐阅读
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 在Kubernetes上部署JupyterHub的步骤和实验依赖
    本文介绍了在Kubernetes上部署JupyterHub的步骤和实验所需的依赖,包括安装Docker和K8s,使用kubeadm进行安装,以及更新下载的镜像等。 ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 学习笔记(34):第三阶段4.2.6:SpringCloud Config配置中心的应用与原理第三阶段4.2.6SpringCloud Config配置中心的应用与原理
    立即学习:https:edu.csdn.netcourseplay29983432482?utm_sourceblogtoedu配置中心得核心逻辑springcloudconfi ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 20211101CleverTap参与度和分析工具功能平台学习/实践
    1.应用场景主要用于学习CleverTap的使用,该平台主要用于客户保留与参与平台.为客户提供价值.这里接触到的原因,是目前公司用到该平台的服务~2.学习操作 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
author-avatar
手机用户2602922981
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有