【Qt5】寫一個更容易滑鼠點選並帶遊標的QSlider的子類
阿新 • • 發佈:2019-02-03
2018.02.12更新
優化了遊標的控制元件視窗屬性,遊標不再受任何元件的範圍限制;優化了遊標出現的位置;優化了滑鼠點選得到的值,四捨五入得到。
2018.02.22更新
使用自定義訊號sig_triggeredToValue,控制元件被觸發時發射此訊號,傳遞出滑塊變化後的值,不再使用sliderMoved()訊號。避免了鍵盤控制滑塊移動不能產生sliderMoved()訊號的問題。
2018.04.10更新
重寫了控制元件的setVisible(), setEnable(), setDisable()方法,保證在控制元件不可見或無效狀態下,不顯示遊標。Qt自帶的QSlider控制元件提供了一個滑塊控制,但是滑鼠點選時,只能步進,使用起來很不方便。
另外,沒有能夠方便的區分出使用者觸發和setValue()兩種情況導致的值變化的訊號。
所以本人繼承QSlider,寫了QtSliderEasyClick控制元件。本控制元件可以點哪到哪,同時自定義了訊號sig_triggeredToValue,用於表示滑塊被觸發時導致的值變化,可以區分出使用者觸發導致的值變化,另外還增加了遊標顯示滑鼠位置對應的值,效果如圖(滑鼠位置在遊標68下面,截圖不顯示滑鼠哈):
#include "qtslidereasyclick.h" #include <QCursor> QtSliderEasyClick::QtSliderEasyClick(QWidget *parent) : QSlider(parent), triggered_(false) { // 連線觸發導致的值改變時的相關訊號槽 connect(this, &QtSliderEasyClick::actionTriggered, this, &QtSliderEasyClick::__slot_actionTriggered); connect(this, &QtSliderEasyClick::valueChanged, this, &QtSliderEasyClick::__slot_valueChanged); label_ = new QLabel(this); // 使其顯示的位置不受父控制元件限制,也不回有視窗框架和工作列任務,也不會獲得焦點 label_->setWindowFlags(Qt::FramelessWindowHint|Qt::Tool); label_->setFocusPolicy(Qt::NoFocus); label_->setAttribute(Qt::WA_ShowWithoutActivating,true); // 設定標籤字型大小 QFont font; font.setPointSize(11); label_->setFont(font); // 允許在滑鼠不點選時跟蹤滑鼠位置 setMouseTracking(true); // 保證點選遊標時,不會產生中間值,而是一次性跳躍到點選處 this->setPageStep(0); } QtSliderEasyClick::~QtSliderEasyClick() { } void QtSliderEasyClick::setVisible(bool visible) { QSlider::setVisible(visible); // 保證設定不可見後,label_不可見 if(!visible) { label_->hide(); } } void QtSliderEasyClick::setDisabled(bool disabled) { QSlider::setDisabled(disabled); // 保證設定無效後,label_不可見 if(disabled) { label_->hide(); } } void QtSliderEasyClick::setEnabled(bool enabled) { QSlider::setEnabled(enabled); // 保證設定無效後,label_不可見 if(!enabled) { label_->hide(); } } void QtSliderEasyClick::__slot_actionTriggered(int) { // 滑塊空間被觸發時,觸發狀態為真 triggered_ = true; } void QtSliderEasyClick::__slot_valueChanged(int value) { // 觸發狀態為真時,發射觸發值訊號,並還原觸發狀態 if(triggered_) { sig_triggeredToValue(value); triggered_ = false; } } void QtSliderEasyClick::mousePressEvent(QMouseEvent *ev) { // 注意應先呼叫父類的滑鼠點選處理事件,否則無法拖動 QSlider::mousePressEvent(ev); // 根據滑鼠位置計算值並設定值 int value = __calcuValueFromPos(ev->pos()); setValue(value); } void QtSliderEasyClick::mouseMoveEvent(QMouseEvent *ev) { QSlider::mouseMoveEvent(ev); if(!this->isEnabled()) { return; } int posValue = __calcuValueFromPos(ev->pos()); label_->setText(valueToText(posValue)); label_->adjustSize(); // 獲取算本控制元件在螢幕中的位置 QPoint this_pos = this->mapToGlobal(QPoint(0,0)); // 計算得到標籤位置範圍 int min_pos_x_lable = this_pos.x(); int max_pos_x_lable = this_pos.x() + this->width() - label_->width(); int pos_y_lable = this_pos.y() - label_->height() - 5; // 根據滑鼠位置和標籤範圍,計算新的標籤位置 int pos_x_label = QCursor::pos().x() - (label_->width()>>1); pos_x_label = (pos_x_label<min_pos_x_lable)?min_pos_x_lable:pos_x_label; pos_x_label = (pos_x_label>max_pos_x_lable)?max_pos_x_lable:pos_x_label; // 移動標籤到計算得到的位置 label_->move(pos_x_label, pos_y_lable); } void QtSliderEasyClick::enterEvent(QEvent *ev) { QSlider::enterEvent(ev); if(!this->isEnabled()) { return; } label_->show(); } void QtSliderEasyClick::leaveEvent(QEvent *ev) { QSlider::leaveEvent(ev); label_->hide(); } QString QtSliderEasyClick::valueToText(int value) { return QString::number(value); } int QtSliderEasyClick::__calcuValueFromPos(const QPoint &pos) { // 使用四捨五入 int value = qRound((maximum() - minimum()) * pos.x() / (double)this->width() + minimum()); // 限制返回值在取值範圍內 value = (value > maximum())?maximum():value; return (value<minimum())?minimum():value; }