告別Qt Slider!用純C++打造更輕量的TpSlider組件

組件運行效果展示

TpSlider

組件概述

TpSlider組件簡介

TpSlider是PiXSingleGUI庫中的可拖動滑塊組件,支持水平和垂直兩種方向的滑動操作。TpSlider.h:13-17該組件提供了完整的用戶交互功能,包括鼠標拖拽、數值范圍設置和實時反饋機制。

核心特性

  • 雙向支持:支持水平(Horizon)和垂直(Vertical)兩種滑動方向
  • 精確控制:提供數值范圍設置和當前值獲取功能TpSlider.h:24-37
  • 事件驅動:基于信號槽機制的松耦合通信TpSlider.h:40-48
  • 高性能渲染:優化的繪制流程,適用于嵌入式環境

核心架構設計

繼承關系與基類依賴

TpSlider繼承自tpChildWidget基類,這種設計遵循了PiXSingleGUI庫的統一架構模式。TpSlider.h:10基類提供了以下核心能力:

  • 事件處理框架:統一的鼠標、鍵盤事件分發機制
  • 渲染管理:標準化的繪制接口和更新調度
  • 內存管理:自動的生命周期管理和資源釋放

數據結構設計

組件采用PIMPL(PointertoImplementation)設計模式,將所有實現細節封裝在TpSliderData結構中:TpSlider.cpp:7-25

struct TpSliderData
{int32_t maxValue = 100;int32_t minValue = 0;double value = 0;TpSlider::SliderDirect direct = TpSlider::Horizon;// 頂點矩形區域bool isPressVertex = false;ItpRect vertexRect;ItpPoint pressPoint;// 一個間隔值對應的像素double valuePx = 0;// 是否正在拖拽調整進度,拖拽過程不響應setValue事件bool isDrag = false;
};

數據結構的關鍵設計:

  • 數值管理:minValuemaxValuevalue三元組管理滑塊狀態
  • 交互狀態:isPressVertexisDrag標志位控制拖拽邏輯
  • 性能優化:valuePx預計算像素比例,vertexRect緩存頂點區域

功能實現詳解

數值范圍管理

滑塊的數值管理通過setRange()setValue()方法實現:TpSlider.cpp:48-68

void TpSlider::setRange(const int32_t &min, const int32_t &max)
{TpSliderData *sliderData = static_cast<TpSliderData *>(data_);sliderData->minValue = min;sliderData->maxValue = max;if (sliderData->maxValue < sliderData->minValue)sliderData->maxValue = sliderData->minValue + 1;if (sliderData->value < sliderData->minValue)sliderData->value = sliderData->minValue;else if (sliderData->value > sliderData->maxValue)sliderData->value = sliderData->maxValue;else{}rangeChanged.emit(sliderData->minValue, sliderData->maxValue);update();
}

邊界處理邏輯:

  • 自動修正無效范圍(最大值小于最小值)
  • 當前值超出范圍時自動調整到邊界值
  • 范圍變化時觸發rangeChanged信號通知

鼠標事件處理機制

按下事件處理

鼠標按下事件的核心是區域檢測和狀態初始化:TpSlider.cpp:104-129

bool TpSlider::onMousePressEvent(TpMouseEvent *event)
{TpSliderData *sliderData = static_cast<TpSliderData *>(data_);sliderData->isPressVertex = false;sliderData->isDrag = false;if (event->button() != BUTTON_LEFT)return true;ItpPoint mousePoint = event->pos();if (sliderData->vertexRect.contains(mousePoint)){if (sliderData->direct == TpSlider::Horizon)sliderData->valuePx = 1.0 * (sliderData->maxValue - sliderData->minValue) / width();elsesliderData->valuePx = 1.0 * (sliderData->maxValue - sliderData->minValue) / height();sliderData->pressPoint = mousePoint;sliderData->isPressVertex = true;sliderData->isDrag = true;}return true;
}

關鍵算法:

  • 只響應左鍵點擊且點擊在頂點區域內
  • 根據滑塊方向預計算像素-數值轉換比例
  • 設置拖拽狀態標志,防止外部setValue干擾

移動事件處理

拖拽過程中的數值計算是組件的核心算法:TpSlider.cpp:131-183

bool TpSlider::onMouseMoveEvent(TpMouseEvent *event)
{TpSliderData *sliderData = static_cast<TpSliderData *>(data_);if (sliderData->isPressVertex){ItpPoint curMotionPoint = event->pos();int32_t offsetPx = 0;if (sliderData->direct == TpSlider::Horizon){offsetPx = curMotionPoint.x - sliderData->pressPoint.x;}else{offsetPx = sliderData->pressPoint.y - curMotionPoint.y;}// std::cout << " offsetPx  " << offsetPx << std::endl;if (std::abs(offsetPx) >= sliderData->valuePx){int32_t oldValue = sliderData->value;sliderData->value += (offsetPx * sliderData->valuePx);if (sliderData->value > sliderData->maxValue){sliderData->value = sliderData->maxValue;}else if (sliderData->value < sliderData->minValue){sliderData->value = sliderData->minValue;}else{}// std::cout << " sliderData->value  " << sliderData->value << std::endl;int32_t newValue = sliderData->value;if (newValue != oldValue){valueChanged.emit(newValue);}}sliderData->pressPoint = curMotionPoint;update();}return true;
}

算法特點:

  • 方向適配:水平方向計算X軸偏移,垂直方向計算Y軸偏移(注意Y軸反向)
  • 增量更新:基于像素偏移量計算數值變化
  • 防抖處理:只有數值真正改變時才觸發valueChanged信號

信號槽通信機制

組件提供兩個核心信號用于外部通信:TpSlider.h:41-48

public 
signals:
/// @brief 值變化信號
/// @param int 當前值
declare_signal(valueChanged, int32_t);/// @brief 范圍變化信號
/// @param int 當前最小值
/// @param int 當前最大值
declare_signal(rangeChanged, int32_t, int32_t);

PiXSingleGUI的信號槽系統基于模板實現,提供類型安全的事件通信:TpSignalSlot.h:91-130

渲染系統實現

繪制流程

滑塊的繪制分為三個層次:背景軌道、進度填充和拖拽頂點。TpSlider.cpp:192-228

TpSliderData *sliderData = static_cast<TpSliderData *>(data_);// tpChildWidget::onPaintEvent(event);
TpShared<TpCssData> curCssData = currentStatusCss();TpCanvas *painter = event->canvas();// 整體高度、寬度;分成4份。進度條1份,頂點2份,淺色頂點4份
uint32_t bgWidth = width();
uint32_t bgHeight = height();
uint32_t bgX = 0;
uint32_t bgY = 0;// 不能用父類繪制,繪制背景色
ItpRect rect = event->rect();
if (objectType() == TP_FLOAT_OBJECT)
{if ((curCssData->backgroundColor() & 0xff) != 0xff){painter->erase();}
}if (sliderData->direct == TpSlider::Horizon)
{bgHeight = height() / 4.0;bgY = (height() - bgHeight) / 2.0;painter->roundedBox(0, bgY, rect.w, bgY + bgHeight, roundCorners(), curCssData->backgroundColor());
}
else
{bgWidth = width() / 4.0;bgX = (width() - bgWidth) / 2.0;painter->roundedBox(bgX, 0, bgX + bgWidth, rect.h, roundCorners(), curCssData->backgroundColor());
}

方向適配渲染

水平方向渲染:TpSlider.cpp:240-272

if (sliderData->direct == TpSlider::Horizon)
{circleRadius = height() / 4.0 * 2.0 / 2.0;valueWidth = valuePercent * width();if (valueWidth != 0)painter->roundedBox(0, bgY, valueWidth, bgY + bgHeight, roundCorners(), curCssData->subColor());int32_t circleX = valueWidth;if (circleX == 0){circleX = circleRadius;}else if (circleX == width()){circleX = width() - circleRadius;}else{}// 繪制淡色圓形頂點painter->filledCircle(circleX, height() / 2.0, height() / 2.0, lightSubColor);// 繪制圓形頂點painter->filledCircle(circleX, height() / 2.0, circleRadius, subColor);// 記錄頂點區域sliderData->vertexRect.x = circleX - circleRadius;sliderData->vertexRect.y = height() / 2.0 - circleRadius;sliderData->vertexRect.w = circleRadius * 2;sliderData->vertexRect.h = circleRadius * 2;
}
  • 軌道高度為組件高度的1/4
  • 頂點位置根據數值百分比計算
  • 邊界處理確保頂點不超出范圍

垂直方向渲染:TpSlider.cpp:274-307

else
{circleRadius = width() / 4.0 * 2.0 / 2.0;valueWidth = valuePercent * height();if (valueWidth != 0)painter->roundedBox(bgX, height() - valueWidth, bgX + bgWidth, height(), roundCorners(), subColor);int32_t circleY = height() - valueWidth;if (circleY == 0){circleY = circleRadius;}else if (circleY == height()){circleY = height() - circleRadius;}else{}// 繪制淡色圓形頂點painter->filledCircle(width() / 2.0, circleY, width() / 2.0, lightSubColor);// 繪制圓形頂點painter->filledCircle(width() / 2.0, circleY, circleRadius, subColor);// 記錄頂點區域sliderData->vertexRect.x = width() / 2.0 - circleRadius;sliderData->vertexRect.y = circleY - circleRadius;sliderData->vertexRect.w = circleRadius * 2;sliderData->vertexRect.h = circleRadius * 2;
}
  • 軌道寬度為組件寬度的1/4
  • 從底部向上填充(符合用戶直覺)
  • Y坐標計算考慮垂直方向特殊性

樣式系統集成

TpSlider組件集成了PiXSingleGUI的樣式系統,支持通過CSS配置外觀:TpSlider.cpp:197

// tpChildWidget::onPaintEvent(event);
TpShared<TpCssData> curCssData = currentStatusCss();

可配置的樣式屬性:

  • backgroundColor:軌道背景色
  • subColor:進度填充色和頂點顏色
  • roundCorners:圓角半徑設置

使用示例程序

#include "TpApp.h"
#include "TpFixScreen.h"
#include "TpLabel.h"
#include "TpSlider.h"
#include "TpFont.h"int32_t main(int32_t argc, char *argv[])
{TpApp app(argc, argv);TpFixScreen *vScreen = new TpFixScreen();vScreen->setBackGroundColor(_RGBA(128, 128, 128, 255));vScreen->setVisible(true); // vScreen setvisible will be update displayapp.bindVScreen(vScreen);TpLabel *valueText = new TpLabel(vScreen);valueText->setText(TpString::number(50));valueText->setAlign(tinyPiX::AlignCenter);valueText->font()->setFontColor(_RGB(255, 255, 255),_RGB(255, 255, 255));valueText->font()->setFontSize(128);valueText->setWidth(600);valueText->setHeight(400);valueText->move(20, 150);TpSlider *slider = new TpSlider(vScreen);slider->setValue(50);slider->setSize(500, 10);slider->move(20, 20);TpSlider *vSlider = new TpSlider(vScreen);vSlider->setDirection(TpSlider::Vertical);vSlider->setValue(50);vSlider->setSize(10, 500);vSlider->move(650, 20);connect(slider, valueChanged, [=](int32_t value){ valueText->setText(TpString::number(value));vSlider->setValue(value); });connect(vSlider, valueChanged, [=](int32_t value){ valueText->setText(TpString::number(value));slider->setValue(value); });vScreen->update();return app.run();
}

TinyPiXOS開發者聯盟

源碼級支持 + 真實項目:TinyPiXOS開發者聯盟招募中?,國產自主輕量級嵌入式設備桌面操作系統交流社群。
獲取開發資料
官網網站
B 站視頻

感謝支持和關注,如果對項目感興趣,請點贊、收藏和轉發!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/98203.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/98203.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/98203.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

sensitive-word 敏感詞性能提升14倍優化全過程 v0.28.0

背景 有一天&#xff0c;群里收到小伙伴提的一個問題&#xff0c;為什么程序 sensitive-word 第一次執行這么慢? sensitive-word-131 初步驗證 自己本地用 v0.27.1 驗證了一下&#xff0c;確實很奇怪&#xff0c;第一次明顯很慢。 為了排除一些干擾項&#xff0c;我們把一些…

4.6 多個光源

1.Include Files 2.The Second Light 3.Point Light1.Include Files 為了在著色器中實現多光源支持, 我們需要添加更多通道; 這些通道會包含幾乎相同的代碼, 為了避免代碼重復, 我們將著色器代碼移到一個包含文件中; 與光照著色器相同的文件夾中創建一個后綴為.cginc的文件, 將…

ANSYS HFSS的簡單認識

HFSS&#xff08;High Frequency Structure Simulator&#xff09;是ANSYS公司開發的一款用于高頻電磁場仿真的行業標準軟件。它通過“計算”電磁波在各種結構中的行為&#xff0c;來幫助工程師設計天線、濾波器、微波電路、高速電子封裝等。我用一個簡單易懂的比喻來幫你理解整…

Codeforces Round 1046 (Div. 2) vp補題

只是簽了三道題就燃盡了… 原題連接 A //不可能連續進三球 得分值差最多的只有00X00X00X00 bool jud(int a,int b){if(a!0&&b!0&&max(a,b)-2*(min(a,b)1)>1)return 0;if(a0||b0){if(abs(a-b)>3)return 0;}return 1; } void solve() {int a,b,c,d;cin…

水泵運行組態監控系統御控物聯網解決方案

一、方案背景與需求分析隨著工業4.0和智慧城市建設的推進&#xff0c;傳統水泵監控方式存在數據孤島、響應滯后、運維成本高等問題。本方案通過物聯網&#xff08;IoT&#xff09;技術構建水泵運行組態監控系統&#xff0c;實現設備狀態實時感知、故障預警、遠程調控及能效優化…

海爾電視刷機

硬盤格式化只有ntfs和exfat怎么辦&#xff0c;沒有fat32 這臺型號le32c31 連有線幾天后突然卡系統啟動中 電視系統崩潰了怎么辦&#xff1f;一直顯示啟動中&#xff01;三分鐘解決問題&#xff0c;只要五元搞定&#xff01;_嗶哩嗶哩_bilibili format H: /fs:FAT32 慢 disk…

Science Advances副主編:如何提高論文投稿接收率?

國際著名綜合性學術期刊《Science Advances》每年可接到約20000份投稿&#xff0c;有高達90%的拒稿率&#xff0c;大部分稿件甚至沒有進入評審階段&#xff0c;作為該期刊的副主編之一&#xff0c;杜克大學的Warren Warren教授撰寫了文章&#xff0c;給投稿人提出幾點建議以提高…

少兒配音教育:廣州聲與色在線科技有限公司打造趣味課程,助力青少年語言能力提升

針對青少年語言表達能力培養需求&#xff0c;廣州聲與色在線科技有限公司推出 “少兒配音趣味課程”&#xff0c;通過動畫、童話等青少年喜愛的形式&#xff0c;融合發聲訓練與興趣培養&#xff0c;成為少兒素質教育的新選擇。課程設計貼合 8-15 歲青少年認知特點&#xff1a;分…

【架構藝術】變更風險防控架構嵌入決策降噪模塊的方法

在先前的文章中&#xff0c;我們聊到了一個變更觀測任務可以通過什么樣的方式對不同的變更防控能力做統一調度&#xff0c;達到優越的變更風險攔截效果。但是在實戰當中&#xff0c;變更觀測任務集成了很多能力&#xff0c;即便風險攔截率很高&#xff0c;但不同能力效果也有差…

LeetCode算法日記 - Day 33: 最長公共前綴、最長回文子串

目錄 1. 最長公共前綴 1.1 題目解析 1.2 解法 1.3 代碼實現 2. 最長回文子串 2.1 題目解析 2.2 解法 2.3 代碼實現 1. 最長公共前綴 14. 最長公共前綴 - 力扣&#xff08;LeetCode&#xff09; 編寫一個函數來查找字符串數組中的最長公共前綴。 如果不存在公共前綴&…

Python畢業設計推薦:基于Django的飲食計劃推薦與交流分享平臺 飲食健康系統 健康食譜計劃系統

精彩專欄推薦訂閱&#xff1a;在 下方專欄&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主頁&#xff1a;計算機畢設木哥&#x1f525; &#x1f496; 文章目錄 一、項目介紹二…

物聯網雙軸傾角傳感器廠家全面解析

內容概要本文旨在全面解析物聯網雙軸傾角傳感器廠家的核心競爭力&#xff0c;為進口設備代理商及工業物聯網項目提供實用選型指南。我們將深入探討行業領先制造商的研發實力和生產標準&#xff0c;重點分析產品特性如低功耗設計優勢、0.2高精度測量特性&#xff0c;以及CAN/電流…

Docker學習筆記-網絡類型

Docker 網絡類型1、Docker四種網絡模式 &#xff08;1&#xff09;docker四種網絡模式如下&#xff1a; Bridge contauner 橋接式網絡模式Host(open) container 開放式網絡模式Container(join) container 聯合掛載式網絡模式&#xff0c;是host網絡模式的延伸None(Close)…

SDRAM詳細分析-08 數據手冊解讀

大家好,這里是大話硬件。 前面我們梳理了很多關于內存的內容,不知道有沒有人好奇,為什么要花這么大的精力做這些內容? 在4月份的時候,三星宣布將在2025年逐步停產DDR4內存顆粒,隨后海力士和鎂光也跟著一起,都宣布逐步停產DDR4顆粒。這三家半導體廠商在內存方面頂了半邊…

Windows 環境下部署 MinIO 集群

文章目錄介紹軟件特點下載多機分布式集群部署1.前提準備2. 新建minio工作目錄3. 編寫運行命令4. 啟動、測試5. nginx配置介紹 MinIO 是一款高性能、開源、云原生的分布式對象存儲系統&#xff0c;專為私有云、公有云和邊緣計算場景設計&#xff0c;完全兼容 Amazon S3 API&…

鴻蒙libxm2交叉編譯

一開始先使用了lycium,但是沒有編譯通過 改為使用源碼自帶的配置文件編譯 我使用的源碼是libxml2-2.9.10.tar.gz 解壓后進行下面的配置: root@ubuntu:/home/lw/libxml2-2.9.10# export OHOS_SDK=/home/lw/ohos-sdk/linuxroot@ubuntu:/home/lw/libxml2-2.9.10# export AS=…

MCAP :機器人數據容器的全面實踐指南

Outline: MCAP 已形成完整工具鏈生態&#xff1a; Foxglove Studio&#xff1a;可視化分析工具mcap-cli&#xff1a;跨平臺命令行工具AWS RoboMaker&#xff1a;原生云存儲支持 隨著 IEEE 正在制定的 P3196 機器人數據標準&#xff0c;MCAP 正在演進為行業基礎架構的重要組成…

【Bluedroid】A2dp Source播放流程源碼分析(7):藍牙音頻流啟動流程深度解析(btif_av_stream_start)

本文深入分析Android Bluetooth協議棧中A2DP音頻流啟動的完整流程,從應用層調用btif_av_stream_start()開始,穿越BTIF、BTA、AVDTP多層架構,最終通過L2CAP發送AVDTP啟動命令。揭示狀態機驅動、異步消息傳遞、流控制等核心機制。并通過代碼與日志結合的方式,揭示藍牙音頻流從…

Miniconda安裝與VSCode搭建遠程Python、Jupyter開發環境

前言 數據科學和機器學習工作流程中&#xff0c;當本地計算機無法滿足計算任務的需求時&#xff0c;往往需要一個更強大計算能力的遠程環境。另一方面&#xff0c;VSCode由于其輕便和易用性&#xff0c;以及豐富的插件生態系統&#xff0c;一直是遠程開發的首選編輯器。本文介紹…

vue3前端開發的基礎教程——快速上手

【前言】這里使用的技術棧&#xff1a;fastapivue3pycharm一、創建vue3項目在項目的文件夾使用下面命令創建vue3前端框架代碼npm create vitelatest frontend選擇框中選擇&#xff1a; Framework: VueVariant: JavaScript 或 TypeScript cd frontend npm install啟動本地開發np…