Better way to create a color picker that is more realtime? OpenGL, Shaders?, Different, faster App-Loop...
-
Hello There :)
I created a color manager with color picker functionality. I have an HSV color rectangle with a hue slider that defines the hue of the color rectangle. I then can click/drag over the rectangle to select a color. There's also a dot that's located where the color is i select/drag-select. I do this by generating a qimage. But this is very sluggish. It updates the dot's position and rgb and hsv textboxes I connected to it all felt minute instead of realtime.
The color rectangle i'm speaking of looks like this (external source, not my apps image):
Here are some of the functions to get an idea:
def update_gradient(self): """Regenerate the gradient image.""" self.gradient_image = QImage(self.width(), self.height(), QImage.Format_RGB32) for x in range(self.width()): for y in range(self.height()): saturation = x / self.width() value = 1 - (y / self.height()) color = QColor.fromHsv(self.hue, int(saturation * 255), int(value * 255)) self.gradient_image.setPixel(x, y, color.rgb())
def paintEvent(self, event): """Draw the HSV color picking area with the control dot.""" super().paintEvent(event) # Create a painter object painter = QPainter(self) # Top-left is white (S=0, V=1), top-right is fully saturated color, bottom is black (V=0) for x in range(self.width()): for y in range(self.height()): saturation = x / self.width() # Horizontal axis represents saturation (0 to 1) value = 1 - (y / self.height()) # Vertical axis represents value (1 at top, 0 at bottom) color = QColor.fromHsv(self.hue, int(saturation * 255), int(value * 255)) painter.setPen(color) painter.drawPoint(x, y) # Draw the control dot painter.setPen(QPen(Qt.black, 2)) # Black border painter.setBrush(QColor(255, 255, 255)) # White inner color painter.drawEllipse(self.dot_position, self.dot_radius, self.dot_radius)
def move_dot_to_position(self, position: QPoint): """Update the dot position based on the mouse click or movement.""" # Constrain the dot position within the color rectangle new_x = min(max(position.x(), 0), self.width()) new_y = min(max(position.y(), 0), self.height()) if self.dot_position.x() == new_x and self.dot_position.y() == new_y: return # Skip redundant updates self.dot_position = QPoint(new_x, new_y) self.update() # Trigger a repaint to move the dot # Emit the signal to update color from the new dot position saturation = new_x / self.width() # Horizontal axis represents saturation (0 to 1) value = 1 - (new_y / self.height()) # Vertical axis represents value (1 at top, 0 at bottom) # Use self.color_picker_ui to reference ColorPickerUI's method if self.color_picker_ui: self.color_picker_ui.update_from_color_area(saturation, value)
Is there any way to make these updates between color picker, color picker dot and the connected textboxes (QLineEdits) in realtime? I tried to use a QOpenGLWidget as Color Rectangle, but this doesn't help at all. Is there a better way to do it instead of using a QImage, or is this simply the update rate that PySide6 brings along? Is there maybe a way to add the crucial elements to a faster executing "application-loop" so the color rectangle and the rgb, hsv text boxes would get updated instantly as soon as i use the color rect.? PySide6 itself doesn't have such built in realtime color picker/color area functionlities or does it? I cannot work with shaders on the GPU, can I?
Any tipps and tricks are greatly appreciated :)
All the best,
Oli -
Hi,
Qt has the QColorDialog.
Would that work for you ?
Otherwise, you can build your widget with Qt OpenGL related classes and use shaders if you want.