Как реализовать слайдер с круглой полой ручкой в qt

#c #qt #qslider

Вопрос:

есть ли способ реализовать ползунок с круглой полой ручкой в QT?

изображение

Комментарии:

1. В чем проблема с тем, чтобы ручка была просто такой полой?

2. @hyde привет, если он прямо настроен на полый, вы увидите канавку ниже.

3. Итак, вы хотите, чтобы полая часть «просвечивала» канавку. Если это сложное требование, вам, возможно , придется реализовать свой собственный рисунок, сублиссировав QAbstractScrollbar или просто QScrollBar (или, если это пользовательский интерфейс QML, просто создайте пользовательский компонент полосы прокрутки в QML, не очень сложно и хорошее упражнение в QML).

4. @Parisa.H.R QSlider принадлежит QtWidgets

5. @Parisa.H.R Я хочу реализовать это на c .

Ответ №1:

Ознакомившись с документацией QStyle , я решил использовать QStyle для перерисовки QSlider , чтобы добиться желаемого эффекта. Вот код реализации.

 # coding:utf-8
from PyQt5.QtCore import QSize, Qt, pyqtSignal, QPoint, QRectF
from PyQt5.QtGui import QColor, QMouseEvent, QPainter, QPainterPath
from PyQt5.QtWidgets import (QProxyStyle, QSlider, QStyle, QStyleOptionSlider,
                             QWidget)

class HollowHandleStyle(QProxyStyle):
    """ 滑块中空样式 """

    def __init__(self, config: dict = None):
        """
        Parameters
        ----------
        config: dict
            样式配置
        """
        super().__init__()
        self.config = {
            "groove.height": 3,
            "sub-page.color": QColor(255, 255, 255),
            "add-page.color": QColor(255, 255, 255, 64),
            "handle.color": QColor(255, 255, 255),
            "handle.ring-width": 4,
            "handle.hollow-radius": 6,
            "handle.margin": 4
        }
        config = config if config else {}
        self.config.update(config)

        # 计算 handle 的大小
        w = self.config["handle.margin"] self.config["handle.ring-width"]   
            self.config["handle.hollow-radius"]
        self.config["handle.size"] = QSize(2*w, 2*w)

    def subControlRect(self, cc: QStyle.ComplexControl, opt: QStyleOptionSlider, sc: QStyle.SubControl, widget: QWidget):
        """ 返回子控件所占的矩形区域 """
        if cc != self.CC_Slider or opt.orientation != Qt.Horizontal or sc == self.SC_SliderTickmarks:
            return super().subControlRect(cc, opt, sc, widget)

        rect = opt.rect

        if sc == self.SC_SliderGroove:
            h = self.config["groove.height"]
            grooveRect = QRectF(0, (rect.height()-h)//2, rect.width(), h)
            return grooveRect.toRect()

        elif sc == self.SC_SliderHandle:
            size = self.config["handle.size"]
            x = self.sliderPositionFromValue(
                opt.minimum, opt.maximum, opt.sliderPosition, rect.width())
            # 解决滑块跑出滑动条的情况
            x *= (rect.width()-size.width())/rect.width()
            sliderRect = QRectF(x, 0, size.width(), size.height())
            return sliderRect.toRect()

    def drawComplexControl(self, cc: QStyle.ComplexControl, opt: QStyleOptionSlider, painter: QPainter, widget: QWidget):
        """ 绘制子控件 """
        if cc != self.CC_Slider or opt.orientation != Qt.Horizontal:
            return super().drawComplexControl(cc, opt, painter, widget)

        grooveRect = self.subControlRect(cc, opt, self.SC_SliderGroove, widget)
        handleRect = self.subControlRect(cc, opt, self.SC_SliderHandle, widget)
        painter.setRenderHints(QPainter.Antialiasing)
        painter.setPen(Qt.NoPen)

        # 绘制滑槽
        painter.save()
        painter.translate(grooveRect.topLeft())

        # 绘制划过的部分
        w = handleRect.x()-grooveRect.x()
        h = self.config['groove.height']
        painter.setBrush(self.config["sub-page.color"])
        painter.drawRect(0, 0, w, h)

        # 绘制未划过的部分
        x = w self.config['handle.size'].width()
        painter.setBrush(self.config["add-page.color"])
        painter.drawRect(x, 0, grooveRect.width()-w, h)
        painter.restore()

        # 绘制滑块
        ringWidth = self.config["handle.ring-width"]
        hollowRadius = self.config["handle.hollow-radius"]
        radius = ringWidth   hollowRadius

        path = QPainterPath()
        path.moveTo(0, 0)
        center = handleRect.center()   QPoint(1, 1)
        path.addEllipse(center, radius, radius)
        path.addEllipse(center, hollowRadius, hollowRadius)

        handleColor = self.config["handle.color"]  # type:QColor
        handleColor.setAlpha(255 if opt.activeSubControls !=
                             self.SC_SliderHandle else 153)
        painter.setBrush(handleColor)
        painter.drawPath(path)

        # 滑块按下
        if widget.isSliderDown():
            handleColor.setAlpha(255)
            painter.setBrush(handleColor)
            painter.drawEllipse(handleRect)

 

Вот пример того, как использовать HollowHandleStyle :

 # coding:utf-8
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QApplication, QWidget, QSlider


class Demo(QWidget):

    def __init__(self):
        super().__init__()
        self.resize(300, 200)
        self.setStyleSheet("Demo{background: rgb(34, 180, 127)}")
        style = {
            "sub-page.color": QColor(70, 23, 180),
            "handle.ring-width": 4,
            "handle.hollow-radius": 6,
            "handle.margin": 4
        }
        self.slider = QSlider(Qt.Horizontal, self)
        self.slider.setStyle(HollowHandleStyle(style))
        self.slider.resize(200, 28)
        self.slider.move(50, 100)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Demo()
    w.show()
    sys.exit(app.exec_())

 

На следующем рисунке показан конечный эффект:

ползунок

Ответ №2:

вы можете сделать фон Генделя прозрачным и установить для него границу по таблице стилей, но таким образом вы увидите линию слайдера, если вы выберете цвет фона слайдера таким же, как и его бэкэнд, вы можете исправить его с помощью таблицы стилей, иначе вам следует написать его краской и создать свой собственный слайдер.

 QSlider::groove:horizontal {
    border-radius: 1px;
    height: 2px;
    margin: 20px;
    background-color: rgb(52, 59, 72);
}
QSlider::groove:horizontal:hover {
    background-color: rgb(55, 62, 76);
}
QSlider::handle:horizontal {
    background-color: transparent;
    border: 4px solid black;
    height: 22px;
    width: 22px;
    margin: -14px 0;
    border-radius: 14px;
    padding: -14px 0px;
}
 

введите описание изображения здесь

введите описание изображения здесь

код пользовательского интерфейса :

 <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>561</width>
    <height>238</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <property name="styleSheet">
   <string notr="true">background-color: rgb(255, 255, 255);</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QSlider" name="horizontalSlider">
      <property name="minimumSize">
       <size>
        <width>0</width>
        <height>70</height>
       </size>
      </property>
      <property name="styleSheet">
       <string notr="true">QSlider::groove:horizontal {
    border-radius: 1px;
    height: 2px;
    margin: 20px;
    background-color: rgb(52, 59, 72);
}
QSlider::groove:horizontal:hover {
    background-color: rgb(55, 62, 76);
}
QSlider::handle:horizontal {
    background-color: white;
    border: 4px solid black;
    height: 22px;
    width: 22px;
    margin: -14px 0;
    border-radius: 14px;
    padding: -14px 0px;
}

</string>
      </property>
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>561</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>