首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QDial每转一次

QDial每转一次
EN

Stack Overflow用户
提问于 2021-05-06 11:13:54
回答 1查看 186关注 0票数 1

我正在尝试使用PyQt5,Python3.7.3,使用一个Raspberry pi4B和一个5英寸的触摸屏来开发一个应用程序。问题是我需要做一个QDial,但是如果它从最小范围到最大范围,我想要它进行不止一次的革命。例如,如果Q拨号的范围从0到500,我希望它每转100点,所以你必须做一个完整的旋转5次,从最小值到最大值。

这就是我尝试过的:

代码语言:javascript
复制
from PyQt5.QtWidgets import *
import sys

class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        layout = QGridLayout()
        self.setLayout(layout)
        self.dial = QDial()
        self.dial.setMinimum(0)
        self.dial.setMaximum(100)
        self.dial.setValue(40)
        self.dial.valueChanged.connect(self.sliderMoved)
        self.dial.setWrapping(True)
        self.text=QLabel()
        layout.addWidget(self.dial)
        layout.addWidget(self.text)
        self.isHigher=False

    def sliderMoved(self):
        print("Dial value = %i" % (self.dial.value()))
        self.text.setText(str(self.dial.value()))
        if(self.dial.value()==100 and self.isHigher==False):
            self.higher_range()
            self.isHigher=True
        if(self.dial.value()==100 and self.isHigher==True):
            self.lower_range()
            self.isHigher=False



    def higher_range(self):
        self.dial.setRange(100,200)
        self.dial.setValue(105)

    def lower_range(self):
        self.dial.setRange(0,100)
        self.dial.setValue(95)



        

app = QApplication(sys.argv)
screen = Window()
screen.show()
sys.exit(app.exec_())

`

但这是行不通的,它一直从95变到105,反之亦然。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-06 20:30:15

QDial是一个相当奇特的控件。虽然它仍然被支持,但是它的实现很糟糕,我相信这是一个选择:由于它的性质,增加更多的特性真的很困难。我有相当多的经验,我知道这不是一个容易处理的因素。

它的一个问题是它代表了一个一维范围,但是,从视觉和UI的角度来说,它是一个二维对象。

您想要达到的目标是可能的,但是要考虑到UI元素应该始终以一种清晰的方式显示其状态,并具有相应的适当行为;这是UI能够告诉用户状态的唯一方法。物理拨号没有这个问题:你也有一个触觉反应,告诉你什么时候齿轮到达它的末端。

根据我的经验,我可以告诉您,您应该尽可能地避免它:它似乎是一个很好的、直观的小部件,但实际上很难得到对用户来说真正直观的适当结果。在某些情况下,使用它是有意义的(在我的例子中,表示电子乐器的物理旋钮)。我建议您在斜形和UX方面做一些研究。

也就是说,这是一个可能的原始实现。我已经覆盖了一些方面(最重要的是,valueChanged信号,用于命名一致性),但是对于适当的实现,您应该做更多的工作(和测试)。

诀窍是根据“转数”来设定范围:如果最大转速为500,选择5转,则刻度盘的实际最大值为100。然后,每当值发生变化时,我们检查以前的值是低于还是高于实际范围的最小/最大值,并相应地更改革命计数。

两个重要的注意事项:

  • 由于QDial继承自QAbstractSlider,它有一个范围(最小,最大+ 1),并且由于除法可以有一些休息,“最后”革命将有一个不同的范围;
  • 我没有实施车轮事件,因为这需要进一步的检查和选择适当的行为取决于“先前”的价值和革命;
代码语言:javascript
复制
class SpecialDial(QDial):
    _cycleValueChange = pyqtSignal(int)
    def __init__(self, minimum=0, maximum=100, cycleCount=2):
        super().__init__()
        assert cycleCount > 1, 'cycles must be 2 or more'
        self.setWrapping(True)
        self.cycle = 0
        self.cycleCount = cycleCount
        self._minimum = minimum
        self._maximum = maximum
        self._normalMaximum = (maximum - minimum) // cycleCount
        self._lastMaximum = self._normalMaximum + (maximum - minimum) % self._normalMaximum
        self._previousValue = super().value()
        self._valueChanged = self.valueChanged
        self.valueChanged = self._cycleValueChange
        self._valueChanged.connect(self.adjustValueChanged)

        self.setRange(0, self._normalMaximum)

    def value(self):
        return super().value() + self._normalMaximum * self.cycle

    def minimum(self):
        return self._minimum

    def maximum(self):
        return self._maximum()

    def dialMinimum(self):
        return super().minimum()

    def dialMaximum(self):
        return super().maximum()

    def adjustValueChanged(self, value):
        if value < self._previousValue:
            if (value < self.dialMaximum() * .3 and self._previousValue > self.dialMaximum() * .6 and 
                self.cycle + 1 < self.cycleCount):
                    self.cycle += 1
                    if self.cycle == self.cycleCount - 1:
                        self.setMaximum(self._lastMaximum)
        elif (value > self.dialMaximum() * .6 and self._previousValue < self.dialMaximum() * .3 and
            self.cycle > 0):
                self.cycle -= 1
                if self.cycle == 0:
                    self.setMaximum(self._normalMaximum)
        new = self.value()
        if self._previousValue != new:
            self._previousValue = value
            self.valueChanged.emit(self.value())

    def setValue(self, value):
        value = max(self._minimum, min(self._maximum, value))
        if value == self.value():
            return
        block = self.blockSignals(True)
        self.cycle, value = divmod(value, self._normalMaximum)
        if self.dialMaximum() == self._normalMaximum and self.cycle == self.cycleCount - 1:
            self.setMaximum(self._lastMaximum)
        elif self.dialMaximum() == self._lastMaximum and self.cycle < self.cycleCount - 1:
            self.setMaximum(self._normalMaximum)
        super().setValue(value)
        self.blockSignals(block)
        self._previousValue = self.value()
        self.valueChanged.emit(self._previousValue)

    def keyPressEvent(self, event):
        key = event.key()
        if key in (Qt.Key_Right, Qt.Key_Up):
            step = self.singleStep()
        elif key in (Qt.Key_Left, Qt.Key_Down):
            step = -self.singleStep()
        elif key == Qt.Key_PageUp:
            step = self.pageStep()
        elif key == Qt.Key_PageDown:
            step = -self.pageStep()
        elif key in (Qt.Key_Home, Qt.Key_End):
            if key == Qt.Key_Home or self.invertedControls():
                if super().value() > 0:
                    self.cycle = 0
                    block = self.blockSignals(True)
                    super().setValue(0)
                    self.blockSignals(block)
                    self.valueChanged.emit(self.value())
            else:
                if self.cycle != self.cycleCount - 1:
                    self.setMaximum(self._lastMaximum)
                    self.cycle = self.cycleCount - 1
                if super().value() != self._lastMaximum:
                    block = self.blockSignals(True)
                    super().setValue(self._lastMaximum)
                    self.blockSignals(block)
                    self.valueChanged.emit(self.value())
            return
        else:
            super().keyPressEvent(event)
            return
        if self.invertedControls():
            step *= -1

        current = self.value()
        new = max(self._minimum, min(self._maximum, current + step))
        if current != new:
            super().setValue(super().value() + (new - current))


class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        layout = QGridLayout()
        self.setLayout(layout)
        self.dial = SpecialDial()
        self.dial.valueChanged.connect(self.sliderMoved)
        self.text=QLabel()
        layout.addWidget(self.dial)
        layout.addWidget(self.text)

    def sliderMoved(self):
        self.text.setText(str(self.dial.value()))

我强烈建议你慢慢来:

  • 考虑到这确实是你想要的,因为,正如所说的,这种控制从UX的角度来说是非常棘手的;
  • 仔细阅读代码并理解其逻辑;
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67416992

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档