【问题标题】:Only Color Gradient from Qt5 ColorDialog仅来自 Qt5 ColorDialog 的颜色渐变
【发布时间】:2020-01-21 20:41:02
【问题描述】:

我想问是否可以只使用 QColorDialog 的颜色渐变(红色包围)部分。

我在不同的 Linux 机器(ubuntu + raspian)上使用 PyQt5 和 Python3。

【问题讨论】:

    标签: python python-3.x pyqt pyqt5 qcolordialog


    【解决方案1】:

    只需要隐藏除QColorPickerQColorLuminancePicker之外的所有元素。

    import sys
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class ColorDialog(QtWidgets.QColorDialog):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setOptions(self.options() | QtWidgets.QColorDialog.DontUseNativeDialog)
    
            for children in self.findChildren(QtWidgets.QWidget):
                classname = children.metaObject().className()
                if classname not in ("QColorPicker", "QColorLuminancePicker"):
                    children.hide()
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
    
        colordialog = ColorDialog()
        label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
    
        def onCurrentColorChanged(color):
            label.setStyleSheet("background-color: {}".format(color.name()))
    
        colordialog.currentColorChanged.connect(onCurrentColorChanged)
        onCurrentColorChanged(colordialog.currentColor())
    
        w = QtWidgets.QWidget()
        lay = QtWidgets.QVBoxLayout(w)
        lay.addWidget(colordialog, alignment=QtCore.Qt.AlignCenter)
        lay.addWidget(label)
        w.show()
    
        sys.exit(app.exec_())
    

    【讨论】:

      【解决方案2】:

      solution proposed by eyllanesc 一如既往地完美(而且聪明)。

      尽管如此,几个月前我不得不实现自己的颜色选择器小部件,它仅从代码创建“彩虹色”小部件,我想分享部分代码,因为我相信它可能会引起一些兴趣,尤其是关于“彩虹”的创建和颜色检测。
      我已经对其进行了编辑,使其成为一个基本的可用“颜色选择器”小部件。

      from PyQt5 import QtCore, QtGui, QtWidgets
      
      # a helper function that ensures that a value is between the given range
      sanitize = lambda m, value, M: min(max(m, value), M)
      
      class RgbPicker(QtWidgets.QLabel):
          colorGrads = QtGui.QLinearGradient(0, 0, 1, 0)
          colorGrads.setCoordinateMode(colorGrads.ObjectBoundingMode)
          xRatio = 1. / 6
          # the basic "rainbow" gradient
          colorGrads.setColorAt(0, QtCore.Qt.red)
          colorGrads.setColorAt(1, QtCore.Qt.red)
          colorGrads.setColorAt(xRatio, QtCore.Qt.magenta)
          colorGrads.setColorAt(xRatio * 2, QtCore.Qt.blue)
          colorGrads.setColorAt(xRatio * 3, QtCore.Qt.cyan)
          colorGrads.setColorAt(xRatio * 4, QtCore.Qt.green)
          colorGrads.setColorAt(xRatio * 5, QtCore.Qt.yellow)
      
          # the superimposed white component
          maskGrad = QtGui.QLinearGradient(0, 0, 0, 1)
          maskGrad.setCoordinateMode(maskGrad.ObjectBoundingMode)
          maskGrad.setColorAt(0, QtCore.Qt.transparent)
          maskGrad.setColorAt(1, QtCore.Qt.white)
      
          # the pseudo arrow cursor
          cursorPath = QtGui.QPainterPath()
          cursorPath.moveTo(-10, 0)
          cursorPath.lineTo(-4, 0)
          cursorPath.moveTo(0, -10)
          cursorPath.lineTo(0, -4)
          cursorPath.moveTo(4, 0)
          cursorPath.lineTo(10, 0)
          cursorPath.moveTo(0, 4)
          cursorPath.lineTo(0, 10)
          cursorPen = QtGui.QPen(QtCore.Qt.black, 3)
      
          colorChanged = QtCore.pyqtSignal(QtGui.QColor)
      
          def __init__(self, color=None):
              QtWidgets.QLabel.__init__(self)
              self.setFocusPolicy(QtCore.Qt.StrongFocus)
              self.setFixedSize(220, 200)
              # create a pixmap that shows the "rainbow" and draw its contents
              pixmap = QtGui.QPixmap(self.size())
              qp = QtGui.QPainter(pixmap)
              qp.fillRect(pixmap.rect(), self.colorGrads)
              qp.fillRect(pixmap.rect(), self.maskGrad)
              qp.end()
              self.setPixmap(pixmap)
              self.image = pixmap.toImage()
      
              # a multiplier, used when an arrow key is kept pressed
              self.keyTimer = QtCore.QTimer()
              self.keyTimer.setInterval(1000)
              self.keyTimer.timeout.connect(lambda: setattr(self, 'keyMulti', self.keyMulti + 1))
      
              self._cursorPos = QtCore.QPoint()
              self._color = color
      
              self.setColor(color)
      
          @property
          def color(self):
              return self._color
      
          @property
          def cursorPos(self):
              return self._cursorPos
      
          @cursorPos.setter
          def cursorPos(self, pos):
              self._cursorPos = pos
              self.update()
      
          def sanitizePos(self, pos):
              # sanitize the position within the color rainbow margins
              return QtCore.QPoint(sanitize(0, pos.x(), self.width() - 1), sanitize(0, pos.y(), self.height() - 1))
      
          def setColor(self, color):
              h, s, v, a = color.getHsv()
              # compute the coordinates based on hsv components
              x = (360 - h) * (self.width() - 1) / 360.
              y = (255 - s) * (self.height() - 1) / 255.
              self.cursorPos = QtCore.QPoint(x, y)
      
          def translateColorCursor(self, pos):
              # return the color of the given pixel
              return QtGui.QColor(self.image.pixel(pos))
      
          def mousePressEvent(self, event):
              pos = self.sanitizePos(event.pos())
              self._color = self.translateColorCursor(pos)
              self.colorChanged.emit(QtGui.QColor(self._color))
              self.cursorPos = pos
      
          def mouseMoveEvent(self, event):
              pos = self.sanitizePos(event.pos())
              self._color = self.translateColorCursor(pos)
              self.colorChanged.emit(QtGui.QColor(self._color))
              self.cursorPos = pos
      
          def keyPressEvent(self, event):
              deltaX = deltaY = 0
              # emulation of the Qt internal color picker keyboard navigation
              if event.modifiers() & QtCore.Qt.KeypadModifier:
                  if event.key() in (QtCore.Qt.Key_7, QtCore.Qt.Key_Home):
                      deltaX = deltaY = -1
                  elif event.key() in (QtCore.Qt.Key_8, QtCore.Qt.Key_Up):
                      deltaY = -1
                  elif event.key() in (QtCore.Qt.Key_9, QtCore.Qt.Key_PageUp):
                      deltaX = 1
                      deltaY = -1
                  elif event.key() in (QtCore.Qt.Key_4, QtCore.Qt.Key_Left):
                      deltaX = -1
                  elif event.key() in (QtCore.Qt.Key_6, QtCore.Qt.Key_Right):
                      deltaX = 1
                  elif event.key() in (QtCore.Qt.Key_1, QtCore.Qt.Key_End):
                      deltaX = -1
                      deltaY = 1
                  elif event.key() in (QtCore.Qt.Key_2, QtCore.Qt.Key_Down):
                      deltaY = 1
                  elif event.key() in (QtCore.Qt.Key_3, QtCore.Qt.Key_PageDown):
                      deltaX = deltaY = 1
              elif event.key() == QtCore.Qt.Key_Left:
                  deltaX = -1
              elif event.key() == QtCore.Qt.Key_Right:
                  deltaX = 1
              elif event.key() == QtCore.Qt.Key_Up:
                  deltaY = -1
              elif event.key() == QtCore.Qt.Key_Down:
                  deltaY = 1
              elif event.key() == QtCore.Qt.Key_Home:
                  if event.modifiers() == QtCore.Qt.ShiftModifier:
                      deltaY = -1000
                  elif event.modifiers() == QtCore.Qt.ControlModifier:
                      deltaX = deltaY = -1000
                  else:
                      deltaX = -1000
              elif event.key() == QtCore.Qt.Key_End:
                  if event.modifiers() == QtCore.Qt.ShiftModifier:
                      deltaY = 1000
                  elif event.modifiers() == QtCore.Qt.ControlModifier:
                      deltaX = deltaY = 1000
                  else:
                      deltaX = 1000
              elif event.key() == QtCore.Qt.Key_PageUp and not event.modifiers() & QtCore.Qt.KeypadModifier:
                  deltaY = -10
              elif event.key() == QtCore.Qt.Key_PageDown and not event.modifiers() & QtCore.Qt.KeypadModifier:
                  deltaY = +10
              else:
                  return QtWidgets.QWidget.keyPressEvent(self, event)
              if not event.isAutoRepeat():
                  self.keyTimer.start()
                  self.keyMulti = 1
              if deltaX or deltaY:
                  multi = self.keyMulti
                  if event.modifiers() & QtCore.Qt.ShiftModifier:
                      multi *= 10
                  deltaX *= multi
                  deltaY *= multi
              pos = self.sanitizePos(QtCore.QPoint(self.cursorPos.x() + deltaX, self.cursorPos.y() + deltaY))
              self._color = self.translateColorCursor(pos)
              self.colorChanged.emit(QtGui.QColor(self._color))
              self.cursorPos = pos
      
          def keyReleaseEvent(self, event):
              if not event.isAutoRepeat():
                  self.keyTimer.stop()
              QtWidgets.QWidget.keyReleaseEvent(self, event)
      
          def paintEvent(self, event):
              QtWidgets.QLabel.paintEvent(self, event)
              qp = QtGui.QPainter(self)
              qp.setPen(self.cursorPen)
              # translate to the crosshair position and paint it
              qp.translate(self.cursorPos)
              qp.drawPath(self.cursorPath)
      
      
      class BlackPicker(QtWidgets.QWidget):
          # the "black" selector, which has a gradient based on the current selected
          # color of the RgbPicker (selected color -> black)
      
          _rect = QtCore.QRect(0, 8, 16, 200)
      
          grad = QtGui.QLinearGradient(0, 0, 0, 1)
          grad.setCoordinateMode(grad.ObjectBoundingMode)
          grad.setColorAt(1, QtCore.Qt.black)
      
          arrow = QtGui.QPainterPath()
          arrow.lineTo(4, -4)
          arrow.lineTo(4, 4)
          arrow.closeSubpath()
          _color = QtGui.QColor()
          _black = -1
      
          blackChanged = QtCore.pyqtSignal(float)
      
          def __init__(self, color):
              QtWidgets.QWidget.__init__(self)
              self.color = QtGui.QColor(color)
              self.setFixedSize(22, 216)
      
          @property
          def black(self):
              return self._black
      
          @black.setter
          def black(self, black):
              if black == self._black:
                  return
              self._black = black
              self.update()
              self.blackChanged.emit(black)
      
          @property
          def color(self):
              return self._color
      
          @color.setter
          def color(self, color):
              if color == self._color:
                  return
              self._color = QtGui.QColor(color)
              self.grad.setColorAt(0, color)
              self.black = color.getCmykF()[3]
      
          def setWhiteColor(self, color):
              self.grad.setColorAt(0, color)
              self.update()
      
          def setColor(self, color):
              self.color = color
      
          def mousePressEvent(self, event):
              self.black = sanitize(0, event.pos().y() - self._rect.top(), 
                  self._rect.height()) / 200.
      
          def mouseMoveEvent(self, event):
              self.black = sanitize(0, event.pos().y() - self._rect.top(), 
                  self._rect.height()) / 200.
      
          def wheelEvent(self, event):
              if event.pixelDelta().y() < 0:
                  delta = .01
              else:
                  delta = -.01
              self.black = sanitize(0, self.black + delta, 1)
      
          def paintEvent(self, event):
              qp = QtGui.QPainter(self)
              qp.setRenderHints(qp.Antialiasing)
              qp.fillRect(self._rect, self.grad)
              qp.translate(self._rect.right() + 2, self._rect.top() + self.black * self._rect.height())
              qp.setBrush(QtCore.Qt.black)
              qp.translate(.5, .5)
              qp.drawPath(self.arrow)
      
      
      class ColorPicker(QtWidgets.QWidget):
          colorChanged = QtCore.pyqtSignal(QtGui.QColor)
      
          def __init__(self, color=None, parent=None):
              super().__init__(parent)
              layout = QtWidgets.QGridLayout(self)
      
              if not (isinstance(color, QtGui.QColor) and color.isValid()):
                  if isinstance(color, QtCore.Qt.GlobalColor):
                      color = QtGui.QColor(color)
                  else:
                      color = self.palette().color(QtGui.QPalette.WindowText)
      
              self.rgbPicker = RgbPicker(color)
              layout.addWidget(self.rgbPicker, 0, 0)
      
              self.blackPicker = BlackPicker(color)
              layout.addWidget(self.blackPicker, 0, 1)
      
              self.colorWidget = QtWidgets.QWidget()
              layout.addWidget(self.colorWidget, 1, 0, 1, 2)
              self.colorWidget.setMinimumHeight(16)
              self.colorWidget.setAutoFillBackground(True)
      
              self.colorLabel = QtWidgets.QLabel()
              layout.addWidget(self.colorLabel)
      
              self.rgbPicker.colorChanged.connect(self.updateColor)
              self.rgbPicker.colorChanged.connect(self.blackPicker.setWhiteColor)
              self.blackPicker.blackChanged.connect(self.updateColor)
      
              self.updateColor()
      
          def updateColor(self):
              color = self.rgbPicker.color
              c, m, y, _, _ = color.getCmykF()
              color.setCmykF(c, m, y, self.blackPicker.black)
              palette = self.colorWidget.palette()
              palette.setColor(palette.Window, color)
              self.colorWidget.setPalette(palette)
              r, g, b = color.getRgb()[:-1]
              hexColor = '{:02X}{:02X}{:02X}'.format(r, g, b)
              self.colorLabel.setText('R:{:03} G:{:03} B:{:03} - #{}'.format(
                  r, g, b, hexColor))
              self.colorChanged.emit(color)
      
      
      if __name__ == '__main__':
          import sys
          app = QtWidgets.QApplication(sys.argv)
          picker = ColorPicker(QtGui.QColor(QtCore.Qt.white))
          picker.show()
          sys.exit(app.exec())
      

      【讨论】:

        【解决方案3】:

        您可以查看 PyQt 的此圆形颜色选择器设计

        PyQt Circular ColorPicker

        It looks like this and can be easily modified

        【讨论】:

        • 我检查了你的设计,我喜欢它,但在tangente = x / y 行中我发现了异常ZeroDivisionError
        • 其实是这样想的: if y == 0 and x 0: angle = 90 else: tangente = x / y current_angle = math .degrees(math.atan(tangente)) 所以 y 永远不会得到 0,我不确定你是怎么得到错误的
        • 奇怪的是你不相信我。请告诉我们如果y = 0x = 0,会发生什么?
        • 其实我从来没想过中心坐标。谢谢!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-26
        • 2011-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多