PyQt 创建色环

PyQt creating color circle

我想给那里的小部件占位符添加一个色圈:

我已经尝试过这个库: https://gist.github.com/tobi08151405/7b0a8151c9df1a41a87c1559dac1243a

但如果 window 不是样方,色环就不起作用。 我已经尝试过其他解决方案,但没有获取颜色值的方法。 How to create a "Color Circle" in PyQt?

您能否推荐/告诉我一种创建自己的方法,以便我可以将它们添加到那里? 谢谢!

小部件假定其形状始终为正方形;该代码为此提供了自定义 AspectLayout,但这不是必需的。

这个问题是因为当形状不是正方形时颜色的计算是错误的,因为当一个维度比另一个维度大得多时坐标没有正确映射。例如,如果小部件的宽度比高度高得多,则 x 坐标会“偏移”,因为圆(现在是一个实际的椭圆)居中显示,但颜色函数使用 minimum尺寸。

解决方案是创建一个始终显示在中心的内部 QRect,并将其用于绘制 计算:

class ColorCircle(QWidget):
    # ...
    def resizeEvent(self, ev: QResizeEvent) -> None:
        size = min(self.width(), self.height())
        self.radius = size / 2
        self.square = QRect(0, 0, size, size)
        self.square.moveCenter(self.rect().center())

    def paintEvent(self, ev: QPaintEvent) -> None:
        # ...
        p.setPen(Qt.transparent)
        p.setBrush(hsv_grad)
        p.drawEllipse(self.square)
        p.setBrush(val_grad)
        p.drawEllipse(self.square)
        # ...

    def map_color(self, x: int, y: int) -> QColor:
        x -= self.square.x()
        y -= self.square.y()
        # ...

请注意,该代码使用了 numpy,但它用于那些显然不需要 numpy 性能的应用程序并不真正需要这样一个 巨大 库的函数。

例如,line_circle_inter使用复杂的方法来计算“光标”(小圆圈)的位置,但这完全没有必要,因为色相和饱和度值已经提供了“可用”坐标: 色相表示圆圈中的角度(从12小时位置开始,逆时针方向),而饱和度是与圆心的距离。
QLineF提供了一个方便的函数,fromPolar(),它returns给定长度和角度的线:长度将是半径乘以饱和度,角度是色相乘以360(加上90° ,因为角度总是从 3 点开始);然后我们可以在圆心平移那条线,光标将定位在线段的第二个点:

    def paintEvent(self, event):
        # ...
        p.setPen(Qt.black)
        p.setBrush(self.selected_color)
        line = QLineF.fromPolar(self.radius * self.s, 360 * self.h + 90)
        line.translate(self.square.center())
        p.drawEllipse(line.p2(), 10, 10)

地图颜色功能可以使用相同的逻辑,但相反:我们从中心到鼠标光标位置构造一条线,然后饱和度是长度除以半径(将值消毒为1.0,因为这是最大可能值),而色调是线角(如上负 90°)除以 360,并针对正 0.0-1.0 范围进行消毒。

    def map_color(self, x: int, y: int) -> QColor:
        line = QLineF(QPointF(self.rect().center()), QPointF(x, y))
        s = min(1.0, line.length() / self.radius)
        h = (line.angle() - 90) / 360 % 1.
        return h, s, self.v