Read or pass data outside class of mouse event - python

I have a widget that uses rubberband to select region on an image, it can be editable on any aspect. I need to add functions that once the rubberband is placed it can be resizable or editable again so my idea is to save the region points(x,y,w,h) after the mouse release event.
But the problem now is how can I pass the data read in mouse release event outside my rubberband class.
Here is my code of drag and edit of rubberband.
class rubberBandWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.tweaking = False
self.tweakingpart = ""
def mousePressEvent(self, event):
pt = self.mapFromGlobal(event.globalPos())
rg = self.rubberBand.geometry()
if rg.isValid():
tl, tr, bl, br = rg.topLeft(), rg.topRight(), rg.bottomLeft(), rg.bottomRight()
off, offx, offy = QPoint(3, 3), QPoint(4, -3), QPoint(-3, 4)
if QRect(tl - off, tl + off).contains(pt):
self.tweakingpart = "topLeft";
self.setCursor(Qt.SizeFDiagCursor)
elif QRect(tr - off, tr + off).contains(pt):
self.tweakingpart = "topRight";
self.setCursor(Qt.SizeBDiagCursor)
elif QRect(bl - off, bl + off).contains(pt):
self.tweakingpart = "bottomLeft";
self.setCursor(Qt.SizeBDiagCursor)
elif QRect(br - off, br + off).contains(pt):
self.tweakingpart = "bottomRight";
self.setCursor(Qt.SizeFDiagCursor)
elif QRect(tl + offx, tr - offx).contains(pt):
self.tweakingpart = "top";
self.setCursor(Qt.SizeVerCursor)
elif QRect(bl + offx, br - offx).contains(pt):
self.tweakingpart = "bottom"
self.setCursor(Qt.SizeVerCursor)
elif QRect(tl + offy, bl - offy).contains(pt):
self.tweakingpart = "left";
self.setCursor(Qt.SizeHorCursor)
elif QRect(tr + offy, br - offy).contains(pt):
self.tweakingpart = "right";
self.setCursor(Qt.SizeHorCursor)
if self.tweakingpart != "":
self.tweaking = True
return
self.origin = pt
self.rubberBand.setGeometry(QRect(self.origin, QtCore.QSize()))
self.rubberBand.show()
def mouseMoveEvent(self, event):
pt = self.mapFromGlobal(event.globalPos())
if self.tweaking:
rg = self.rubberBand.geometry()
if self.tweakingpart == "topLeft":
rg.setTopLeft(pt)
elif self.tweakingpart == "topRight":
rg.setTopRight(pt)
elif self.tweakingpart == "bottomLeft":
rg.setBottomLeft(pt)
elif self.tweakingpart == "bottomRight":
rg.setBottomRight(pt)
elif self.tweakingpart == "top":
rg.setTop(pt.y())
elif self.tweakingpart == "bottom":
rg.setBottom(pt.y())
elif self.tweakingpart == "left":
rg.setLeft(pt.x())
elif self.tweakingpart == "right":
rg.setRight(pt.x())
self.rubberBand.setGeometry(rg)
else:
self.rubberBand.setGeometry(QRect(self.origin, pt).normalized())
And here is my code on release event and the data of (x, y, w, h) that need to be pass or read outside the class.
def mouseReleaseEvent(self, event):
self.tweaking = False
self.tweakingpart = ""
self.unsetCursor()
if self.rubberBand.width() != 0 and self.rubberBand.height() != 0:
print(self.rubberBand.x(), self.rubberBand.y(), self.rubberBand.width(), self.rubberBand.height())
I need the data every mouse release and save it. So once the user need to resize and edit again, my idea is to set the geometry of rubberband and re run the class so it can be editable again.

If you want to expose the data outside the class you should use signals as I show below:
import sys
from PyQt4 import QtCore, QtGui
class rubberBandWidget(QtGui.QWidget):
rectChanged = QtCore.pyqtSignal(QtCore.QRect) # create signal
...
def mouseReleaseEvent(self, event):
self.tweaking = False
self.tweakingpart = ""
self.unsetCursor()
if not self.rubberBand.geometry().isNull():
self.rectChanged.emit(self.rubberBand.geometry()) # emit signal
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
w = rubberBandWidget()
def on_rectChanged(rect):
# receiver
print(rect.x(), rect.y(), rect.width(), rect.height())
w.rectChanged.connect(on_rectChanged) # connect signal
w.show()
sys.exit(app.exec_())
On the other hand I see that your code is very coupled because if you want to use the same functionality in another widget you will have to copy all the code and that is not desirable, so I take the time to create a custom QRubberband that has that functionality, In the next part I show an example.
import sys
from PyQt4 import QtCore, QtGui
class RubberBand(QtGui.QRubberBand):
rectChanged = QtCore.pyqtSignal(QtCore.QRect)
TopLeft, TopRight, BottomLeft, BottomRight, Top, Bottom, Left, Right, NonePos = range(9)
def __init__(self, parent=None):
super(RubberBand, self).__init__(QtGui.QRubberBand.Rectangle, parent)
self._widget = None
self.setWidget(parent)
self.tweakingpart = RubberBand.NonePos
self.cursors = [QtCore.Qt.SizeFDiagCursor,
QtCore.Qt.SizeBDiagCursor,
QtCore.Qt.SizeBDiagCursor,
QtCore.Qt.SizeFDiagCursor,
QtCore.Qt.SizeVerCursor,
QtCore.Qt.SizeVerCursor,
QtCore.Qt.SizeHorCursor,
QtCore.Qt.SizeHorCursor]
def setWidget(self, widget):
if widget is None:
return
if self._widget is not None:
self._widget.removeEventFilter(self)
self._widget = widget
self._widget.installEventFilter(self)
self.setParent(widget)
def eventFilter(self, obj, event):
if self._widget is obj:
if event.type() == QtCore.QEvent.MouseButtonPress:
self.handleMousePressEvent(event.pos())
return True
elif event.type() == QtCore.QEvent.MouseMove:
self.handleMouseMoveEvent(event.pos())
return True
elif event.type() == QtCore.QEvent.MouseButtonRelease:
self.handleMouseReleaseEvent(event.pos())
return True
return super(RubberBand, self).eventFilter(obj, event)
def handleMousePressEvent(self, pt):
rg = self.geometry()
if not rg.isValid():
return
off, offx, offy = QtCore.QPoint(3, 3), QtCore.QPoint(4, -3), QtCore.QPoint(-3, 4)
rect = QtCore.QRect(-off, off)
tl, tr, bl, br = rg.topLeft(), rg.topRight(), rg.bottomLeft(), rg.bottomRight()
for i, coord in enumerate([tl, tr, bl, br]):
rect.moveCenter(coord)
if rect.contains(pt):
self.tweakingpart = i
if QtCore.QRect(tl + offx, tr - offx).contains(pt):
self.tweakingpart = RubberBand.Top
elif QtCore.QRect(bl + offx, br - offx).contains(pt):
self.tweakingpart = RubberBand.Bottom
elif QtCore.QRect(tl + offy, bl - offy).contains(pt):
self.tweakingpart = RubberBand.Left
elif QtCore.QRect(tr + offy, br - offy).contains(pt):
self.tweakingpart = RubberBand.Right
if 0 <= self.tweakingpart < RubberBand.NonePos:
self._widget.setCursor(self.cursors[self.tweakingpart])
return
self.setGeometry(QtCore.QRect(pt, QtCore.QSize()))
self.show()
def handleMouseMoveEvent(self, pt):
rg = self.geometry()
if 0 <= self.tweakingpart < RubberBand.NonePos:
if self.tweakingpart == RubberBand.TopLeft:
rg.setTopLeft(pt)
elif self.tweakingpart == RubberBand.TopRight:
rg.setTopRight(pt)
elif self.tweakingpart == RubberBand.BottomLeft:
rg.setBottomLeft(pt)
elif self.tweakingpart == RubberBand.BottomRight:
rg.setBottomRight(pt)
elif self.tweakingpart == RubberBand.Top:
rg.setTop(pt.y())
elif self.tweakingpart == RubberBand.Bottom:
rg.setBottom(pt.y())
elif self.tweakingpart == RubberBand.Left:
rg.setLeft(pt.x())
elif self.tweakingpart == RubberBand.Right:
rg.setRight(pt.x())
else:
rg = QtCore.QRect(rg.topLeft(), pt).normalized()
self.setGeometry(rg)
def handleMouseReleaseEvent(self, pt):
self.tweakingpart = RubberBand.NonePos
self._widget.unsetCursor()
if not self.geometry().isNull():
self.rectChanged.emit(self.geometry())
class TestWidget(QtGui.QWidget):
pass
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
w = TestWidget()
rubberBand = RubberBand(w)
def on_rectChanged(rect):
print(rect.x(), rect.y(), rect.width(), rect.height())
rubberBand.rectChanged.connect(on_rectChanged)
w.show()
sys.exit(app.exec_())

Related

QGraphicsItem Rotation handle

I'm new to PyQt5. I'm trying to implement item control like this
there you can rotate item by dragging the rotation handle. What a have for now:
import math
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from math import sqrt, acos
class QDMRotationHandle(QGraphicsPixmapItem):
def __init__(self, item):
super().__init__(item)
self.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable)
self.setPixmap(QPixmap('rotation_handle.png').scaledToWidth(20))
self.setTransformOriginPoint(10, 10)
self.item = item
self.item.boundingRect().moveCenter(QPointF(50, 50))
self.hypot = self.parentItem().boundingRect().height()
self.setPos(self.item.transformOriginPoint().x()-10, self.item.transformOriginPoint().y() - self.hypot)
def getSecVector(self, sx, sy, ex, ey):
return {"x": ex - sx, "y": 0}
def getVector(self, sx, sy, ex, ey):
if ex == sx or ey == sy:
return 0
return {"x": ex - sx, "y": ey - sy}
def getVectorAngleCos(self, ax, ay, bx, by):
ma = sqrt(ax * ax + ay * ay)
mb = sqrt(bx * bx + by * by)
sc = ax * bx + ay * by
res = sc / ma / mb
return res
def mouseMoveEvent(self, event):
pos = self.mapToParent(event.pos())
# parent_pos = self.mapToScene(self.parent.transformOriginPoint())
parent_pos = self.parentItem().pos()
parent_center_pos = self.item.boundingRect().center()
parent_pos_x = parent_pos.x() + self.item.transformOriginPoint().x()
parent_pos_y = parent_pos.y() + self.item.transformOriginPoint().y()
print("mouse: ", pos.x(), pos.y())
print("handle: ", self.pos().x(), self.pos().y())
print("item: ", parent_pos.x(), parent_pos.y())
#print(parent_center_pos.x(), parent_center_pos.y())
vecA = self.getVector(parent_pos_x, parent_pos_y, pos.x(), pos.y())
vecB = self.getSecVector(parent_pos_x, parent_pos_y, pos.x(), parent_pos_y)
#
vect.setLine(parent_pos_x, parent_pos_y, pos.x(), pos.y())
if pos.x() > parent_pos_x:
#
secVect.setLine(parent_pos_x, parent_pos_y, pos.x(), parent_pos_y)
vecB = self.getSecVector(parent_pos_x, parent_pos_y, pos.x(), parent_pos_y)
elif pos.x() < parent_pos_x:
#
secVect.setLine(parent_pos_x, parent_pos_y, pos.x(), parent_pos_y)
vecB = self.getSecVector(parent_pos_x, parent_pos_y, pos.x(), -parent_pos_y)
if vecA != 0:
cos = self.getVectorAngleCos(vecA["x"], vecA["y"], vecB["x"], vecB["y"])
cos = abs(cos)
if cos > 1:
cos = 1
sin = abs(sqrt(1 - cos ** 2))
lc = self.hypot * cos
ld = self.hypot * sin
#self.ell = scene.addRect(parent_pos_x, parent_pos_y, 5, 5)
if pos.x() < parent_pos_x and pos.y() < parent_pos_y:
print(parent_pos_x, parent_pos_y )
#self.ell.setPos(parent_pos.x(), parent_pos.y())
self.setPos(parent_pos_x - lc, parent_pos_y - ld)
elif pos.x() > parent_pos_x and pos.y() < parent_pos_y:
#self.ell.setPos(parent_pos_x, parent_pos_y)
self.setPos(parent_pos_x + lc, parent_pos_y - ld)
elif pos.x() > parent_pos_x and pos.y() > parent_pos_y:
#self.ell.setPos(parent_pos_x, parent_pos_y)
self.setPos(parent_pos_x + lc, parent_pos_y + ld)
elif pos.x() < parent_pos_x and pos.y() > parent_pos_y:
#self.ell.setPos(parent_pos_x, parent_pos_y)
self.setPos(parent_pos_x - lc, parent_pos_y + ld)
else:
if pos.x() == parent_pos_x and pos.y() < parent_pos_y:
self.setPos(parent_pos_x, parent_pos_y - self.hypot)
elif pos.x() == parent_pos_x and pos.y() > parent_pos_y:
self.setPos(parent_pos_x, parent_pos_y + self.hypot)
elif pos.y() == parent_pos_x and pos.x() > parent_pos_y:
self.setPos(parent_pos_x + self.hypot, parent_pos_y)
elif pos.y() == parent_pos_x and pos.x() < parent_pos_y:
self.setPos(parent_pos_x - self.hypot, parent_pos_y)
item_position = self.item.transformOriginPoint()
handle_pos = self.pos()
#print(item_position.y())
angle = math.atan2(item_position.y() - handle_pos.y(),
item_position.x() - handle_pos.x()) / math.pi * 180 - 90
self.item.setRotation(angle)
self.setRotation(angle)
class QDMBoundingRect(QGraphicsRectItem):
def __init__(self, item, handle):
super().__init__()
self.item = item
self.handle = handle
item.setParentItem(self)
handle.setParentItem(self)
self.setRect(0, 0, item.boundingRect().height(), item.boundingRect().width())
self.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable)
app = QtWidgets.QApplication([])
scene = QtWidgets.QGraphicsScene()
item = scene.addRect(0, 0, 100, 100)
item.setTransformOriginPoint(50, 50)
handle_item = QDMRotationHandle(item)
#handle_item.setParentItem(item)
# handle_item.setOffset(10, 10)
#handle_item.setPos(40, -40)
scene.addItem(handle_item)
vect = scene.addLine(0, 0, 100, 100)
secVect = scene.addLine(50, 50, 100, 100)
secVect.setPen(QPen(Qt.green))
boundingRect = QDMBoundingRect(item, handle_item)
scene.addItem(boundingRect)
view = QtWidgets.QGraphicsView(scene)
view.setFixedSize(500, 500)
view.show()
app.exec_()
It works fine when item is in the initial position, but if you move it, the rotation stops working as it should. It seems like i do something wrong with coordinates, but i cant understand what. Please help...
Your object structure is a bit disorganized and unnecessarily convoluted.
For instance:
you're adding handle_item to the scene, but since you've made it a child of item, you shall not try to add it to the scene again;
the ItemIsMovable is useless if you don't call the default implementation in mouseMoveEvent, but for your purpose you actually don't need to make it movable at all;
the whole computation is unnecessarily complex (and prone to bugs, since you're both setting the object position and rotation);
using a pixmap for the handle seems quite unnecessary, use Qt primitives if you can, to avoid graphical artifacts and unnecessary transform computations;
What you could do, instead, is to use a single "bounding rect item", and add controls as its children. Then, by filtering mouse events of those children, you can then alter the rotation based on the scene position of those events.
In the following example, I took care of the above, considering:
control/handle items should always be positioned at 0, 0, so that the computation required for getting/setting their position is much easier;
since items (including vector items) are actually children of the QDMBoundingRect, you don't need to compute coordinates for each point of the vectors: the rotation of the parent will be applied to them automatically;
the secVect (still a child item) is simplified by just setting its x offset using the mapped scene positions of center and handle;
Also, by calling setFiltersChildEvents(True) the sceneEventFilter() receives any scene event from its children, allowing us to track mouse events; we return True for all the events that we handle so that they are not propagated to the parent, and also because move events can only received if mouse press events are accepted (the default implementation ignores them, unless the item is movable).
class QDMBoundingRect(QGraphicsRectItem):
_startPos = QPointF()
def __init__(self, item):
super().__init__()
self.setRect(item.boundingRect())
self.setFlags(self.ItemIsMovable)
self.setFiltersChildEvents(True)
self.item = item
self.center = QGraphicsEllipseItem(-5, -5, 10, 10, self)
self.handle = QGraphicsRectItem(-10, -10, 20, 20, self)
self.vect = QGraphicsLineItem(self)
self.secVect = QGraphicsLineItem(self)
self.secVect.setPen(Qt.green)
self.secVect.setFlags(self.ItemIgnoresTransformations)
self.setCenter(item.transformOriginPoint())
def setCenter(self, center):
self.center.setPos(center)
self.handle.setPos(center.x(), -40)
self.vect.setLine(QLineF(center, self.handle.pos()))
self.secVect.setPos(center)
self.setTransformOriginPoint(center)
def sceneEventFilter(self, item, event):
if item == self.handle:
if (event.type() == event.GraphicsSceneMousePress
and event.button() == Qt.LeftButton):
self._startPos = event.pos()
return True
elif (event.type() == event.GraphicsSceneMouseMove
and self._startPos is not None):
centerPos = self.center.scenePos()
line = QLineF(centerPos, event.scenePos())
self.setRotation(90 - line.angle())
diff = self.handle.scenePos() - centerPos
self.secVect.setLine(0, 0, diff.x(), 0)
return True
if (event.type() == event.GraphicsSceneMouseRelease
and self._startPos is not None):
self._startPos = None
return True
return super().sceneEventFilter(item, event)
app = QApplication([])
scene = QGraphicsScene()
item = scene.addRect(0, 0, 100, 100)
item.setPen(Qt.red)
item.setTransformOriginPoint(50, 50)
boundingRect = QDMBoundingRect(item)
scene.addItem(boundingRect)
view = QGraphicsView(scene)
view.setFixedSize(500, 500)
view.show()
app.exec_()
With the above code you can also implement the movement of the "center" handle, allowing to rotate around a different position:
def sceneEventFilter(self, item, event):
if item == self.handle:
# ... as above
elif item == self.center:
if (event.type() == event.GraphicsSceneMousePress
and event.button() == Qt.LeftButton):
self._startPos = event.pos()
return True
elif (event.type() == event.GraphicsSceneMouseMove
and self._startPos is not None):
newPos = self.mapFromScene(
event.scenePos() - self._startPos)
self.setCenter(newPos)
return True
if (event.type() == event.GraphicsSceneMouseRelease
and self._startPos is not None):
self._startPos = None
return True
return super().sceneEventFilter(item, event)

Time lag during a chess game in pyqt5 python

I've been designing a GUI-based chess game in PyQt5 (Python) . Since it is incomplete , there are some issues . But the biggest issue is , that after every move , the time lag in the GUI increases . After a particular time (say , move 8) , the GUI would almost stop working . Please help . The code is given below :
import PyQt5
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import uic
import chess
import sys
import tabulate
class Chess_App(QtWidgets.QMainWindow):
def __init__(self):
super(Chess_App, self).__init__()
uic.loadUi("CHESS.ui", self)
self.move_name = ""
self.move = ""
self.board_rows = [8,7,6,5,4,3,2,1]
self.board_columns = 'a b c d e f g h'.split(" ")
# variable_needed = f"{self.board_columns[7-(n//8)]}{self.board_rows[n%8]}"
font = QtGui.QFont()
font.setPointSize(1)
self.win = None
self.draw = None
self.valid_move = True
self.Chess_Board = {n:QtWidgets.QPushButton(self) for n in range(64)}
for i in range(64):
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : lightgreen ; color : lightgreen}")
self.Chess_Board[i].setFont(font)
self.Chess_Board[i].setObjectName(f"{self.board_columns[i%8]}{self.board_rows[i//8]}")
self.lineEdit_2.setDisabled(True)
for i in range(64):
if (i // 8) % 2 == 0:
if i % 2 == 0:
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : white}")
if (i // 8) % 2 == 1:
if i % 2 == 1:
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : white}")
self.Chess_Board[i].setGeometry(60+((i%8)*50),140+((i//8)*50),50,50)
self.Chess_Board[i].clicked.connect(self.initiate_move)
self.lineEdit.isReadOnly()
self.pushButton_A.clicked.connect(self.play_move)
self.pushButton_B.clicked.connect(self.resignation)
self.pushButton_C.clicked.connect(self.draw_game)
self.pushButton_D.clicked.connect(self.save_game)
self.pushButton_E.clicked.connect(self.reset_game)
self.board = chess.Board()
self.chessboard()
self.show_board()
self.show()
def chessboard(self):
self.pgn = self.board.epd()
self.final_list = []
self.printable_list = []
pieces = self.pgn.split(" ", 1)[0]
rows = pieces.split("/")
for row in rows:
self.initial_list = []
for chessmen in row:
if chessmen.isdigit():
for i in range(0, int(chessmen)):
self.initial_list.append(".")
else:
self.initial_list.append(chessmen)
self.final_list.append(self.initial_list)
def initiate_move(self):
for i in range(64):
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : lightgreen ; color : lightgreen}")
if (i // 8) % 2 == 0:
if i % 2 == 0:
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : white}")
if (i // 8) % 2 == 1:
if i % 2 == 1:
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : white}")
self.value = self.sender()
self.move = self.value.text().upper()
if self.move == "":
pass
elif len(self.move) == 1:
if self.move == "P":
pass
else:
self.move_name += self.move
self.value.setStyleSheet("QPushButton {background-color : cyan}")
for i in range(64):
self.Chess_Board[i].clicked.connect(self.play_move)
def play_move(self):
self.textBrowser.setText("")
self.valid_move = True
self.button = self.sender()
if len(self.button.text()) == 1:
self.move_name += f"x{self.button.objectName()}"
if self.button.text() == "":
self.move_name += self.button.objectName()
# if self.lineEdit.isEnabled():
# self.move = self.lineEdit.text()
# elif self.lineEdit_2.isEnabled():
# self.move = self.lineEdit_2.text()
try:
self.board.push_san(self.move_name)
except Exception as ex:
self.textBrowser.setText(f"{ex}")
self.valid_move = False
if self.valid_move == True:
if self.lineEdit.isEnabled():
self.lineEdit.setDisabled(True)
self.lineEdit_2.setDisabled(False)
else:
self.lineEdit.setDisabled(False)
self.lineEdit_2.setDisabled(True)
elif self.valid_move == False:
self.move_name = ""
if self.board.is_checkmate():
self.textBrowser.setText("Checkmate !")
self.win = True
self.end_the_game()
if self.board.is_variant_draw():
self.textBrowser.setText("Draw !")
self.draw = True
self.end_the_game()
if self.board.is_stalemate():
self.textBrowser.setText("Stalemate !")
self.draw = True
self.end_the_game()
if self.board.is_fifty_moves():
self.textBrowser.setText("Draw by fifty-move rule !")
self.draw = True
self.end_the_game()
if self.board.is_repetition():
self.textBrowser.setText("Draw by three-fold repitition !")
self.draw = True
self.end_the_game()
self.chessboard()
self.show_board()
for i in range(64):
self.Chess_Board[i].clicked.connect(self.initiate_move)
self.move = ""
self.move_name = ""
def show_board(self):
for x in range(8):
for y in range(8):
if self.final_list[x][y].isupper():
self.Chess_Board[x*8+y].setText(f"{self.final_list[x][y]}".upper())
self.Chess_Board[x*8+y].setIcon(QtGui.QIcon(f"{self.final_list[x][y]}#.png"))
self.Chess_Board[x*8+y].setIconSize(QtCore.QSize(40,40))
elif self.final_list[x][y].islower():
self.Chess_Board[x*8+y].setText(f"{self.final_list[x][y]}".lower())
self.Chess_Board[x*8+y].setIcon(QtGui.QIcon(f"{self.final_list[x][y]}&.png"))
self.Chess_Board[x*8+y].setIconSize(QtCore.QSize(40,40))
elif self.final_list[x][y] == ".":
self.Chess_Board[x*8+y].setIcon(QtGui.QIcon())
self.Chess_Board[x*8+y].setText("")
def reset_game(self):
self.board.reset()
self.lineEdit.setText("")
self.lineEdit_2.setText("")
self.lineEdit.setDisabled(False)
self.lineEdit_2.setDisabled(True)
self.textBrowser.setText("")
self.chessboard()
self.show_board()
self.end_the_game()
def draw_game(self):
self.draw = True
self.end_the_game()
self.textBrowser.setText("It's a draw .")
def resignation(self):
if self.lineEdit.text() == self.lineEdit_2.text() == "":
self.textBrowser.setText("Match Aborted")
else:
if self.move == self.lineEdit.text():
self.win = True
self.end_the_game()
who_resigned = "Black"
elif self.move == self.lineEdit_2.text():
self.win = False
self.end_the_game()
who_resigned = "White"
self.textBrowser.setText(f"{who_resigned} resigned")
def save_game(self):
self.chesstable = tabulate.tabulate(self.final_list, tablefmt="grid", stralign="left")
with open("chess_save_list.txt","a") as writer:
writer.write(self.chesstable)
def end_the_game(self):
if self.win != self.draw:
self.pushButton_A.setDisabled(True)
self.pushButton_B.setDisabled(True)
self.pushButton_C.setDisabled(True)
self.win, self.draw = None, None
elif self.win == self.draw:
self.pushButton_A.setDisabled(False)
self.pushButton_B.setDisabled(False)
self.pushButton_C.setDisabled(False)
app = QtWidgets.QApplication(sys.argv)
window = Chess_App()
app.exec_()
The link to get the .ui link for the code : https://github.com/Vishal01-VKP/Python-Projects/blob/master/GUIs/Games/Chess%20-%20By%20VK/CHESS.ui
Thank you .
It is lagging over time because after each and every move you are connecting the clicked signal again for all 64 buttons in play_move and initiate_move.. connected signal's slot function will be executed in event loop, causing the lag in game
if you are connecting the signal again doesn't mean it will disconnect previous signal but rather add other signals, so after one or two moves each move will cause the 64 signals to connect again, after 5 to 6 moves it will have more than 5000 slots connected to each signal..
If the signal is connected to slot, it will remain connected until it is destroyed or explicitly disconnected..
So Modify your code accordingly so signals doesn't have to be connected again or Disconnect the signals before connecting them again(It could work but not recommended)

Event Filter keeps getting triggered randomly

I've use an event filter to copy and paste items to my table widget. The copy and paste function works fine.
The problem I'm having currently is that the event filter keeps getting triggered by functions not connected to it in any way. This ends up throwing up errors.
The event filter block is:
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.KeyPress and
event.matches(QtGui.QKeySequence.Copy)):
self.copySelection()
return True
return super(MatplotlibWidget, self).eventFilter(source, event)
def copySelection(self):
if self.tabWidget.currentIndex() == 0:
self.rand_table_widget = self.tableWidget
elif self.tabWidget.currentIndex() == 1:
self.rand_table_widget = self.tableWidget_2
elif self.tabWidget.currentIndex() == 2:
self.rand_table_widget = self.tableWidget_3
elif self.tabWidget.currentIndex() == 3:
self.rand_table_widget = self.tableWidget_4
self.copied_cells = self.rand_table_widget.selectedIndexes()
if self.copied_cells:
rows = sorted(index.row() for index in self.copied_cells)
columns = sorted(index.column() for index in self.copied_cells)
rowcount = rows[-1] - rows[0] + 1
colcount = columns[-1] - columns[0] + 1
table = [[''] * colcount for _ in range(rowcount)]
for index in self.copied_cells:
row = index.row() - rows[0]
column = index.column() - columns[0]
table[row][column] = index.data()
stream = io.StringIO()
csv.writer(stream).writerows(table)
QtWidgets.qApp.clipboard().setText(stream.getvalue())
def keyPressEvent(self, event):
if self.tabWidget.currentIndex() == 0:
self.rand_table_widget = self.tableWidget
elif self.tabWidget.currentIndex() == 1:
self.rand_table_widget = self.tableWidget_2
elif self.tabWidget.currentIndex() == 2:
self.rand_table_widget = self.tableWidget_3
elif self.tabWidget.currentIndex() == 3:
self.rand_table_widget = self.tableWidget_4
super().keyPressEvent(event)
if event.key() == Qt.Key_C and (event.modifiers() & Qt.ControlModifier):
self.copied_cells = sorted(self.rand_table_widget.selectedIndexes())
elif event.key() == Qt.Key_V and (event.modifiers() & Qt.ControlModifier):
r = self.rand_table_widget.currentRow() - self.copied_cells[0].row()
c = self.rand_table_widget.currentColumn() - self.copied_cells[0].column()
for cell in self.copied_cells:
self.rand_table_widget.setItem(cell.row() + r, cell.column() + c, QTableWidgetItem(cell.data()))
self.tableWidget.installEventFilter(self)
self.tableWidget_2.installEventFilter(self)
self.tableWidget_3.installEventFilter(self)
self.tableWidget_4.installEventFilter(self)
self.tableWidget_6.installEventFilter(self)
The error I'm getting is:
line 297, in eventFilter
return super(MatplotlibWidget, self).eventFilter(source, event)
TypeError: super(type, obj): obj must be an instance or subtype of type
What is the problem?
Instead of return super(MatplotlibWidget, self).eventFilter(source, event) you can try shorter version return super().eventFilter(source, event) or just return False (bad practice, though).
I recommend to move eventFilter away from widget to separate class, so it can be reusable and to satisfy "single responsibility" principle.

How to Erase/remove particular portion of QGraphicPathItem?

I am adding QgraphicsPathItem to scene and want to erase particular portion of the Qgraphicspathitem. I am using QgraphicsrectItem as Eraser here.Both the items are colliding, but the QgraphicsPathItem is not getting erased.It remains the same in the scene.I am subtracting the two paths and adding it to the QGraphicspathItem
class GraphicsSceneClass(QGraphicsScene):
def __init__(self):
super().__init__()
self.setItemIndexMethod(QGraphicsScene.NoIndex)
self.setBackgroundBrush(QBrush(Qt.black))
self.setSceneRect(0,0,1000,1000)
self.horizontal=QHBoxLayout()
self.widget=QWidget()
self.drawrect=False
self.gridOn = 0
self.selectionMode = 1
self.targetForLine = QRect()
self.drawEnd = True
self.resizemode=0
self.eraser_item = None
self.erasing=False
self.rect=QGraphicsRectItem()
def mousePressEvent(self,event):
try:
sampleTransform = QTransform()
self.objectAtMouse = self.itemAt(event.scenePos(), sampleTransform)
if self.selectionMode == 2:
if self.drawEnd == True:
self.drawEnd = False
elif self.drawEnd == False:
self.drawEnd = True
self.drawLineObj = None
if self.drawEnd == False:
self.lineInsertPoint = self.TargPosForLine(event.scenePos(), "ForLine")
tempPainterPath = QPainterPath()
self.drawLineObj = QGraphicsPathItem()
self.drawLineObj.setPos(self.lineInsertPoint.x(), self.lineInsertPoint.y())
self.drawLineObj.setPen(QPen(Qt.NoPen))
self.drawLineObj.setBrush(QBrush(QColor(Qt.gray)))
self.drawLineObj.setPath(tempPainterPath)
self.addItem(self.drawLineObj)
self.drawLineObj.setFlag(QGraphicsItem.ItemIsSelectable)
if event.buttons() == Qt.RightButton and self.resizemode == 1:
self.erasing = True
self.rect.setRect(event.scenePos().x()-5, event.scenePos().y()-5, 10, 10)
print(event.pos().x(),event.pos().y())
self.addItem(self.rect)
self.rect.setPen(QColor(Qt.red))
except Exception as e:
print("Error in mousepress",e)
def mouseMoveEvent(self,event):
try:
if self.selectionMode == 2 and self.drawEnd == False and self.erasing == False:
f1 = QPainterPath()
gridPos = self.TargPosForLine(event.scenePos(), "ForLine")
f1.moveTo(0, 0)
f1.lineTo(0, 6)
f1.lineTo((gridPos.x() - self.lineInsertPoint.x()), 6)
f1.lineTo((gridPos.x() - self.lineInsertPoint.x()), 0)
f1.closeSubpath()
self.drawLineObj.setPath(f1)
self.drawLineObj.setPos(self.lineInsertPoint.x(), self.lineInsertPoint.y() + 5)
self.drawLineObj.setBrush(QBrush(QColor(Qt.gray)))
pen = QPen(QColor(Qt.gray))
pen.setWidth(0)
self.drawLineObj.setPen(pen)
self.drawLineObj._property = []
self.drawLineObj._angle = 0
if self.selectionMode == 2 and self.drawEnd == True:
self.targetForLine = self.TargPosForLine(event.scenePos(), "ForRect")
self.update()
if event.buttons() & Qt.RightButton and self.erasing:
print(event.scenePos().x(),event.scenePos().y())
self.rect.setRect(event.scenePos().x() - 5, event.scenePos().y() - 5,
10, 10)
for item in self.collidingItems(self.rect):
new = item.path()-(self.rect.shape())
item.setPath(new)
print('collided')
else:
self.targetForLine = QRect()
except Exception as e:
print("Error in mousemove",e)
def mouseReleaseEvent(self, event):
if self.drawrect==True or self.tLext==2 or self.tRext==2 or self.BLext==2 or self.BRext==2:
self.drawrect=False
self.tLext=0
self.tRext=0
self.BLext=0
self.BRext=0
QApplication.changeOverrideCursor(Qt.ArrowCursor)
QApplication.setOverrideCursor(Qt.ArrowCursor)
mainWindow.pointer.setChecked(False)
if self.rect != None:
self.removeItem(self.rect)
def TargPosForLine(self, position, mode):
try:
clicked_column = int((position.y() // 16)) * 16
clicked_row = int((position.x() // 16)) * 16
if clicked_column < 0:
clicked_column = 0
if clicked_row < 0:
clicked_row = 0
if (mode == "ForRect"):
return QRect(clicked_row, clicked_column, 16, 16)
elif (mode == "ForLine"):
return QPointF(clicked_row, clicked_column)
except Exception as e:
print("Error in TargPosForLine", e)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.scene = GraphicsSceneClass()
self.view=QGraphicsView(self.scene)
self.view.setMouseTracking(True)
self.view.setAcceptDrops(True)
self.view.setRenderHint(QPainter.HighQualityAntialiasing)
self.linePointerButton = QToolButton()
self.linePointerButton.setCheckable(True)
self.linePointerButton.setText("Drawline")
self.linePointerButton.setToolTip("Draw Track")
self.linePointerButton.clicked.connect(self.setPointerMode)
self.resizebutton = QToolButton()
self.resizebutton.setText("Resize")
self.resizebutton.setCheckable(True)
self.resizebutton.clicked.connect(self.resizepath)
self.widg=QWidget()
self.horizontal=QHBoxLayout()
self.horizontal.addWidget(self.view)
self.widg.setLayout(self.horizontal)
self.setCentralWidget(self.widg)
self.tool=self.addToolBar("Tool")
self.tool.addWidget(self.linePointerButton)
self.tool.addWidget(self.resizebutton)
def keyPressEvent(self, event):
try:
key = event.key()
if key == Qt.Key_Escape:
but = self.linePointerButton
self.scene.selectionMode = 1
but.setChecked(True)
except Exception:
print("Keypress is not working")
def setPointerMode(self):
try:
self.scene.selectionMode =2
except Exception:
print("Not able to change the selectionmode")
def resizepath(self):
self.scene.resizemode=1
self.scene.selectionMode = 1
self.linePointerButton.setChecked(False)
if __name__=="__main__":
import sys
app=QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
The path and the item and the shape from self.rect don't share the same coordinates system. So, when you want to remove the eraser from the line, the rect, you have to use a common coordinates system (for example, the one of you scene):
for item in self.collidingItems(self.rect):
new = item.mapToScene(item.path())-self.rect.mapToScene(self.rect.shape()) # translate the paths to the scene coords system
item.setPath(item.mapFromScene(new)) # translate the path from the scene coords system

Only Color Gradient from Qt5 ColorDialog

I wanted to ask if it is possible to use only the Color Gradient(red surrounded) part of the QColorDialog.
I am using PyQt5 and Python3 on different Linux machines (ubuntu + raspian).
It is only necessary to hide all the elements except the QColorPicker and QColorLuminancePicker.
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_())
The solution proposed by eyllanesc is perfect (and smart) as always.
Nonetheless, some months ago I had to implement my own color picker widget, which creates the "color rainbow" widget only from code, and I'd like to share part of that code as I believe it could be of some interest, especially regarding the creation of the "rainbow" and the color detection.
I've edited it down to make it a basic usable "color picker" widget.
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())
You can check out this Circular Color Picker design for PyQt
PyQt Circular ColorPicker
It looks like this and can be easily modified

Categories