Qt股票組件之自選股列表拖拽、右鍵常用菜單功能的實(shí)現(xiàn)
一、開頭嘴一嘴
本文帶領(lǐng)大家來看看自選股列表的實(shí)現(xiàn)。
如果有需要的朋友可以加我好友,有償提供源碼、或者也可以進(jìn)一步提供功能定制
封裝的控件,或者demo都是沒有樣式的,所以看著會(huì)比較丑一些,不過加樣式也是分分鐘。。。這里咱可以先看功能,需要即可定制
本篇文章的自選股和大多數(shù)炒股軟件一樣,每一條自選都是支持拖拽的,拖拽時(shí)鼠標(biāo)會(huì)跟隨一個(gè)拖拽映像,并且鼠標(biāo)移動(dòng)時(shí),會(huì)有拖拽提示,告知我們鼠標(biāo)釋放時(shí)拖拽項(xiàng)將會(huì)被插入到哪個(gè)位置。除過拖拽之外,自選股列表還支持右鍵菜單,都是一樣常用的操作。
右鍵菜單包括置頂、置低、刪除、下移一項(xiàng)、上移一項(xiàng)等
本篇文章中不包括的功能也可以提供定制,需求合理即可。
下面來具體說一說這個(gè)功能的實(shí)現(xiàn)思路,會(huì)公開大多數(shù)核心代碼,有需要的同學(xué)可以根據(jù)思路自行完善整個(gè)代碼。
二、效果展示
如下效果圖所示,是自選股使用上的一個(gè)展示效果,具有如下功能
1.搜索編輯框,支持股票代碼和股票名稱搜索
2.搜索預(yù)覽框支持鼠標(biāo)hover,并且可以使用鍵盤上下鍵進(jìn)行當(dāng)前項(xiàng)切換,單機(jī)時(shí)支持切換自選股
3.自選股列表,支持拖拽,拖拽時(shí)會(huì)有拖拽項(xiàng)映像,并示意將要拖拽到哪個(gè)位置
4.支持右鍵菜單,可以對(duì)某一項(xiàng)進(jìn)行移動(dòng),刪除等操作
如果覺著demo比較丑的話,可以看財(cái)聯(lián)社-產(chǎn)品展示這篇文章中的效果圖
三、自選股列表
接下來就是我們這篇文章的重頭戲了,也是比較復(fù)雜的一個(gè)內(nèi)容。
自選股列表我選擇的是使用QListWidget來實(shí)現(xiàn),然后每一個(gè)item上在放一個(gè)Widget即可,Widget就是我們定制窗體內(nèi)容,這里我們主要講解幾個(gè)比較重要的核心內(nèi)容
1、列表初始化
初始化StockList,實(shí)際上自選股列表應(yīng)該從服務(wù)器拉取,我們這里作為demo測(cè)試,因此就自己模擬了5條數(shù)據(jù)進(jìn)行插入。
//已選個(gè)股列表 d_ptr->m_pStockList = new StockList; connect(d_ptr->m_pStockList, &StockList::RowClicked, this, [this](const QString & symbol){ emit RowClicked(symbol); }); //測(cè)試數(shù)據(jù) 正常情況下 應(yīng)該是列表自己拉取 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項(xiàng)時(shí),我們首先需要構(gòu)造一個(gè)標(biāo)準(zhǔn)的QListWidgetItem結(jié)構(gòu),然后把我們自己定制的ListItem放到這個(gè)標(biāo)準(zhǔn)item結(jié)構(gòu)上。
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就是一個(gè)普通的QWidget,上邊排列了一些QLabel,用于顯示我們的股票數(shù)據(jù)。
ListItem界面構(gòu)造就不過多解釋了,唯一需要說明的就是,我們股票數(shù)據(jù)發(fā)送變化時(shí),界面上會(huì)有紅綠色框的動(dòng)畫提示,這里需要調(diào)用兩行代碼來實(shí)現(xiàn)重新獲取控件qss代碼,并刷洗界面。
this->style()->unpolish(this); this->style()->polish(this);
3、右鍵菜單
本篇文章和上一篇文章的右鍵菜單實(shí)現(xiàn)方式一樣,都是參考我很早以前寫的Qt之自定義QLineEdit右鍵菜單這篇文章,實(shí)現(xiàn)默認(rèn)的contextMenuEvent函數(shù)即可。
右鍵菜單已經(jīng)說的很多了,這里就一筆帶過了,需要的同學(xué)可以自己快速的瞅一眼,應(yīng)該比較容易理解。
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個(gè)菜單,雖然看起來功能相差很多,但是其實(shí)處理邏輯基本都是一樣的,先是一個(gè)內(nèi)容結(jié)構(gòu)排序,然后進(jìn)行刷新數(shù)據(jù)到界面上。
為了節(jié)省篇幅,我這里就只介紹置頂一只股票的操作
置頂?shù)倪壿嬁雌饋硎沁@樣的
1.移除當(dāng)前項(xiàng)
2.并且把當(dāng)前項(xiàng)item插入到新位置
3.構(gòu)造一個(gè)新的Widget,設(shè)置給item
4.把新位置的item設(shè)置為當(dāng)前選中項(xiàng)
5.上傳最新列表到數(shù)據(jù)中心,或者服務(wù)器
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應(yīng)該算是一個(gè)比較難一點(diǎn)兒功能,好在Qt已經(jīng)為我們實(shí)現(xiàn)了一套QDrag事件的回調(diào)方法,也比較好使,如下圖所示,重寫如下4個(gè)方法,基本的拖拽事件就能完成了。
但是這里我么有選擇默認(rèn)的這個(gè)回調(diào)函數(shù)來實(shí)現(xiàn)這個(gè)功能,其中最大的原因就是,他們的可定制性太局限了。
我這里采取的是自己模擬鼠標(biāo)拖拽功能,同過重寫如下幾個(gè)函數(shù)來達(dá)到我的目的
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.鼠標(biāo)按下時(shí),主要是記錄了一些內(nèi)容狀態(tài),方便在鼠標(biāo)移動(dòng)時(shí)去做判斷,并決定是否啟用鼠標(biāo)拖拽功能
2.鼠標(biāo)移動(dòng)就比較復(fù)雜了,進(jìn)行了各種對(duì)比,還需要移動(dòng)被拖拽項(xiàng)的映像位置,移動(dòng)那一根水平線的位置
3.鼠標(biāo)釋放時(shí),調(diào)整整個(gè)列表的內(nèi)容
4.鼠標(biāo)進(jìn)入窗體時(shí),顯示水平標(biāo)識(shí)線
5.鼠標(biāo)離開窗體時(shí),隱藏水平標(biāo)識(shí)線
上邊只是粗略的描述了這幾個(gè)函數(shù)的功能, 因?yàn)楹瘮?shù)實(shí)現(xiàn)體都比較長(zhǎng),因此這里我也是選擇幾個(gè)關(guān)鍵點(diǎn)來做以說明。
a、move函數(shù)
產(chǎn)生拖拽時(shí),移動(dòng)鼠標(biāo),我們需要處理很多事件,比如
1、初始化水平表示線和拖拽項(xiàng)映像
if (d_ptr->m_ShotLine == nullptr) { InitShotLine(); } if (d_ptr->m_ShotPicture == nullptr) { InitShotLabel(); }
2、拖拽時(shí)修改鼠標(biāo)狀態(tài)
根據(jù)拖拽啟動(dòng)后,鼠標(biāo)是否還在當(dāng)前拖拽項(xiàng)上,設(shè)置鼠標(biāo)的狀態(tài)。
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函數(shù)
鼠標(biāo)釋放時(shí),把拖拽項(xiàng)移動(dòng)到新的位置
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、刷新數(shù)據(jù)
全量刷新數(shù)據(jù)。在原來的列表上刷新數(shù)據(jù)
當(dāng)原始列表行數(shù)不夠時(shí),構(gòu)造新的行
當(dāng)原始列表函數(shù)多時(shí),移除末尾多的行
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); }
總結(jié)
以上所述是小編給大家介紹的Qt股票組件之自選股列表拖拽、右鍵常用菜單功能的實(shí)現(xiàn) ,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
visual studio 2019工具里添加開發(fā)中命令提示符的方法
這篇文章主要介紹了visual studio 2019工具里添加開發(fā)中命令提示符的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03C++11 std::function和std::bind 的使用示例詳解
C++11中的std::function和std::bind是函數(shù)對(duì)象的重要組成部分,它們可以用于將函數(shù)和參數(shù)綁定在一起,形成一個(gè)可調(diào)用的對(duì)象,這篇文章主要介紹了C++11 std::function和std::bind 的使用示例詳解,需要的朋友可以參考下2023-03-03C++小練習(xí)之高性能實(shí)現(xiàn)字符串分割
字符串分割是日常工作中比較常見的基礎(chǔ)函數(shù),通常大家會(huì)使用現(xiàn)成的基礎(chǔ)庫(kù),基礎(chǔ)庫(kù)的性能是否是最佳的,本文主要和大家探討一下如何最大限度的提升字符串分割的性能,希望對(duì)大家有所幫助2023-10-10Qt中Tab與Tree組件實(shí)現(xiàn)分頁(yè)菜單
本文主要介紹tabWidget選擇夾組件與TreeWidget樹形選擇組件的常用方法及靈活運(yùn)用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12C++實(shí)現(xiàn)宿舍管理查詢系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)宿舍管理查詢系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03