
Here’s an update of the color picker I did last year.
The color picker has now been updated to use PyQt5 and PySide2 for use in Python 3. That’s the biggest update to it (I think). I’ve also increased the area where the mouse can adjust the value – that arc along the left of the color wheel – so it’s easier to grab.

The pick button has also been reworked. As before, the pick button will take a screenshot of your desktop and display it, then clicking anywhere on that will select the color the mouse was at. For one, taking a screenshot works differently in PyQt5/PySide2 so that part had to be rewritten. But the other part is that pixels are so tiny! So as seen above, there is now a magnifier with the pick button!
When the pick button displays the screenshot, it uses a QGraphicsView and QGraphicsScene. The scene holds both the screenshot and the magnifier. The magnifier is a subclass of a QGraphicsPixmapItem, which also holds the screenshot. This subclass constantly moves with the mouse, takes its position, grabs a small section of the screenshot at that position and displays it at a much larger size. It looks like this:
class magnifier(QGraphicsPixmapItem):
"zoomed in view around mouse\nfrom Orthallelous"
# could use QGraphicsPixmapItem's built-in scale function
# but then wouldn't be able to have the fancy grid
# and that's what matters!
def __init__(self, parent=None):
super(magnifier, self).__init__(parent)
self.setFlags(QGraphicsItem.ItemIsMovable)
self.setAcceptHoverEvents(True)#setAcceptsHoverEvents(True)
self.zoom = self.width = self.height = 10
self.size = QSize(self.width, self.height)
# +zw, zh so the mouse isn't sitting on the grid itself
zw = 0 if self.width % 2 else self.zoom
zh = 0 if self.height % 2 else self.zoom
self.offset = QPoint((self.width * self.zoom + zw) // 2,
(self.height * self.zoom + zh) // 2)
self.background = None
self.setPos(QCursor().pos() - self.offset)
def drawGrid(self, image):
"draws a grid on image"
img = QPixmap(image.width() + 1, image.height() + 1)
p = QPainter(img); p.drawPixmap(1, 1, image)
# the +1 is for the grid around the image; otherwise grid is cut off
w, h, z = img.width(), img.height(), self.zoom
for i in range(max(self.width, self.height) + 1):
p.drawLine(QPoint(0, i * z), QPoint(w, i * z)) # horiztonal lines
p.drawLine(QPoint(i * z, 0), QPoint(i * z, h)) # vertical lines
return img
def setBackground(self, img):
self.background = img; self._readjust()
def setSize(self, w, h):
self.width = w; self.height = h; self._readjust()
def setZoom(self, z):
self.zoom = z; self._readjust()
def _readjust(self):
"re-set some things"
w, h, z = self.width, self.height, self.zoom
zw = 0 if w % 2 else z; zh = 0 if h % 2 else z
self.size = QSize(w, h)
self.offset = QPoint((w * z + zw) // 2, (h * z + zh) // 2)
pos = QCursor().pos() - self.offset
self.setPos(pos); self._setView(pos)
def _setView(self, pos):
"grab viewpoint around pos, set as image"
if self.background is None: return
topLeft = pos - QPoint(self.width // 2, self.height // 2)
try: topLeft = topLeft.toPoint()
except: pass # ugh
rect = QRect(topLeft, self.size)
img = self.background.copy(rect) # crop small section
w, h, z = img.width(), img.height(), self.zoom # scale small section
img = img.scaled(w * z, h * z, Qt.KeepAspectRatio)
self.setPixmap(self.drawGrid(img))
def hoverMoveEvent(self, event):
pos = event.scenePos()
self.setPos(pos - self.offset)
self._setView(pos)
Note that this graphics item tracks the mouse and moves itself, not by the graphics scene. So if you move the mouse too fast, it may get outside of the item’s tracking ability and so the magnifier may stop moving. Just put the mouse back on it for it to start following again.
As for the rest of the color picker code, you may view it here. I’ve also placed an MIT license on the color picker, so enjoy. If you’re wondering about just the magnifier code above, uh… public domain!
Then after I updated this, I made this thing which may or may not appear in the next month’s post!

Leave a comment