原文連接:Qt之股票組件-自選股--列表能夠拖拽、右鍵經常使用菜單服務器
上一篇文章Qt之股票組件-股票檢索--支持搜索結果預覽、鼠標、鍵盤操做講述了股票檢索功能,這篇文章咱們來看看自選股列表的實現。ide
若是有須要的朋友能夠加我好友,有償提供源碼、或者也能夠進一步提供功能定製函數
封裝的控件,或者demo都是沒有樣式的,因此看着會比較醜一些,不過加樣式也是分分鐘。。。這裏咱能夠先看功能,須要便可定製工具
本篇文章的自選股和大多數炒股軟件同樣,每一條自選都是支持拖拽的,拖拽時鼠標會跟隨一個拖拽映像,而且鼠標移動時,會有拖拽提示,告知咱們鼠標釋放時拖拽項將會被插入到哪一個位置。除過拖拽以外,自選股列表還支持右鍵菜單,都是同樣經常使用的操做。組件化
右鍵菜單包括置頂、置低、刪除、下移一項、上移一項等佈局
本篇文章中不包括的功能也能夠提供定製,需求合理便可。測試
下面來具體說一說這個功能的實現思路,會公開大多數核心代碼,有須要的同窗能夠根據思路自行完善整個代碼。動畫
以下效果圖所示,是自選股使用上的一個展現效果,具備以下功能this
若是覺着demo比較醜的話,能夠看財聯社-產品展現這篇文章中的效果圖
接下來就是咱們這篇文章的重頭戲了,也是比較複雜的一個內容。
自選股列表我選擇的是使用QListWidget來實現,而後每個item上在放一個Widget便可,Widget就是咱們定製窗體內容,
這裏咱們主要講解幾個比較重要的核心內容
初始化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); }
往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);
本篇文章和上一篇文章的右鍵菜單實現方式同樣,都是參考我很早之前寫的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個菜單,雖然看起來功能相差不少,可是其實處理邏輯基本都是同樣的,先是一個內容結構排序,而後進行刷新數據到界面上。
爲了節省篇幅,我這裏就只介紹置頂一隻股票的操做
置頂的邏輯看起來是這樣的
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(); }
拖拽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;
上邊只是粗略的描述了這幾個函數的功能, 由於函數實現體都比較長,所以這裏我也是選擇幾個關鍵點來作以說明。
a、move函數
產生拖拽時,移動鼠標,咱們須要處理不少事件,好比
一、初始化水平表示線和拖拽項映像
if (d_ptr->m_ShotLine == nullptr) { InitShotLine(); } if (d_ptr->m_ShotPicture == nullptr) { InitShotLabel(); }
二、拖拽時修改鼠標狀態
根據拖拽啓動後,鼠標是否還在當前拖拽項上,設置鼠標的狀態。
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(); }
全量刷新數據。在原來的列表上刷新數據
當原始列表行數不夠時,構造新的行
當原始列表函數多時,移除末尾多的行
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之股票組件-股票檢索--支持搜索結果預覽、鼠標、鍵盤操做
高仿富途牛牛-組件化(六)-炒雞牛逼的佈局記憶功能(序列化和反序列化)
很重要--轉載聲明