PyQt5 Moveable button causes screen smear - python

User defined button that will hold an image and is moveable causes screen smearing when moved to the left and causes a screen smear to the right of the widget. Any ideas?
Image of smearing to the right of the playing card - vertical grey lines.
As i stated this only happens when moving the button to the left.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from functools import partial
import datetime,psutil,sys
class playingCard(QPushButton):
def __init__(self, Text = '', parent = None):
super(playingCard, self).__init__()
self.ftop = 10
self.fleft = 10
self.fwidth = 87
self.fheight = 124
self.initUI()
def initUI(self):
self.setGeometry(self.fleft, self.ftop, self.fwidth+2, self.fheight+2)
self.setText('')
pixmap = QPixmap('clubs1.png')
pixmap = pixmap.scaled(self.fwidth,self.fheight, Qt.KeepAspectRatio, Qt.FastTransformation)
buttonicon = QIcon(pixmap)
self.setIcon(buttonicon)
self.setIconSize( QSize(self.fwidth,self.fheight))
self.setFixedSize( QSize(self.fwidth+2,self.fheight+2))
def mousePressEvent(self, event):
self.__mousePressPos = None
self.__mouseMovePos = None
if event.button() == Qt.LeftButton:
self.__mousePressPos = event.globalPos()
self.__mouseMovePos = event.globalPos()
super(playingCard, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if event.buttons() == Qt.LeftButton:
# adjust offset from clicked point to origin of widget
currPos = self.mapToGlobal(self.pos())
globalPos = event.globalPos()
diff = globalPos - self.__mouseMovePos
newPos = self.mapFromGlobal(currPos + diff)
self.move(newPos)
self.__mouseMovePos = globalPos
super(playingCard, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if self.__mousePressPos is not None:
moved = event.globalPos() - self.__mousePressPos
if moved.manhattanLength() > 3:
event.ignore()
return
super(playingCard, self).mouseReleaseEvent(event)
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def addAction(self,name,shortcut,status):
self.actions[name] = QAction(name, self)
self.actions[name].setShortcut(shortcut)
self.actions[name].setStatusTip(status)
if name == 'Exit':
self.actions[name].triggered.connect( self.close )
else:
self.actions[name].triggered.connect( partial(self.viewEvent,name) )
def hastab(self,tabname):
return self.tabWidget.findChild(QWidget, tabname) != None
def ontab(self,tabname):
currentIndex = self.tabWidget.currentIndex()
currentTitle = self.tabWidget.tabText(currentIndex)
return tabname == currentTitle
def gettab(self,tabname):
page = self.tabWidget.findChild(QWidget, tabname)
return self.tabWidget.indexOf(page)
def initUI(self):
self.actions = dict() # holds the QActions
self.tabs = dict()
self.tabWidget = QTabWidget()
self.tabWidget.setTabsClosable(True)
self.tabWidget.tabCloseRequested.connect(self.closeTab)
self.setCentralWidget(self.tabWidget)
self.addAction('Exit', 'Ctrl+Q','Exit application')
self.addAction('Game','Ctrl+G','Game')
self.statusBar()
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction( self.actions['Game'] )
fileMenu.addAction( self.actions['Exit'] )
self.setWindowTitle('Main window')
self.showMaximized()
def closeTab (self, currentIndex):
currentQWidget = self.tabWidget.widget(currentIndex)
title=self.tabWidget.tabText(currentIndex)
currentQWidget.deleteLater()
self.tabWidget.removeTab(currentIndex)
del self.tabs[title]
del self.tables[title]
self.timers[title].stop()
del self.timers[title]
def keyPressEvent(self, e):
currentIndex=self.tabWidget.currentIndex()
title = None
if currentIndex != -1:
title=self.tabWidget.tabText(currentIndex)
if e.key() == Qt.Key_F11:
if self.isMaximized():
self.showNormal()
else:
self.showMaximized()
def viewEvent(self, name):
if name in self.tabs:
return
self.tabs[name] = QWidget()
vbox = QVBoxLayout()
vbox.addWidget( playingCard() )
# Add box layout, add table to box layout and add box layout to widget
self.tabs[name].layout = vbox
self.tabs[name].setLayout(self.tabs[name].layout)
self.tabWidget.addTab(self.tabs[name],name)
def closeEvent(self, event):
reply = QMessageBox.question(self, 'Message',
"Are you sure to quit?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

Related

Drag-and-drop from button to button without subclass

I want to move color data from button to button.
Is there any other way to subclass pushbutton with eventfilter?
The event.pos() value was different when eventfilter was installEventFilter on pushbutton.
from PySide2 import QtWidgets, QtCore, QtGui
from functools import partial
class DragTest(QtWidgets.QMainWindow):
def __init__(self):
super(DragTest, self).__init__()
cent = QtWidgets.QWidget()
self.setCentralWidget(cent)
layout = QtWidgets.QHBoxLayout(cent)
self.color1_btn = QtWidgets.QPushButton()
self.color1_btn.clicked.connect(partial(self.color_btn_click, widget=self.color1_btn))
self.color2_btn = QtWidgets.QPushButton()
self.color2_btn.clicked.connect(partial(self.color_btn_click, widget=self.color2_btn))
layout.addWidget(self.color1_btn)
layout.addWidget(self.color2_btn)
self.btn1 = QtWidgets.QPushButton()
self.btn2 = QtWidgets.QPushButton()
layout.addWidget(self.btn1)
layout.addWidget(self.btn2)
def color_btn_click(self, widget):
color = QtWidgets.QColorDialog.getColor()
if color.isValid():
print "red: {0}, green: {1}, blue: {2}".format(*color.getRgb())
widget.setStyleSheet("background-color:rgb({0},{1},{2})".format(*color.getRgb()))
widget.setProperty("color", color.getRgb())
def eventFilter(self, obj, event):
super(DragTest, self).eventFilter(obj, event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = DragTest()
win.show()
sys.exit(app.exec_())
You can set up the drag operation in eventFilter if that's your preference. Make sure acceptDrops is True for the buttons, and then catch the mouse move and drag events in the event filter. QMimeData has a colorData property to store the QColor object.
class DragTest(QtWidgets.QMainWindow):
def __init__(self):
super(DragTest, self).__init__()
cent = QtWidgets.QWidget()
self.setCentralWidget(cent)
layout = QtWidgets.QHBoxLayout(cent)
self.color1_btn = QtWidgets.QPushButton(acceptDrops=True)
self.color1_btn.clicked.connect(partial(self.color_btn_click, widget=self.color1_btn))
self.color2_btn = QtWidgets.QPushButton(acceptDrops=True)
self.color2_btn.clicked.connect(partial(self.color_btn_click, widget=self.color2_btn))
layout.addWidget(self.color1_btn)
layout.addWidget(self.color2_btn)
self.color1_btn.installEventFilter(self)
self.color2_btn.installEventFilter(self)
self.color1_btn.color = self.color2_btn.color = None
self.btn1 = QtWidgets.QPushButton()
self.btn2 = QtWidgets.QPushButton()
layout.addWidget(self.btn1)
layout.addWidget(self.btn2)
def color_btn_click(self, widget):
color = QtWidgets.QColorDialog.getColor()
if color.isValid():
self.set_color(widget, color)
def set_color(self, widget, color):
widget.setStyleSheet("background-color:rgb({0},{1},{2})".format(*color.getRgb()))
widget.color = color
def eventFilter(self, obj, event):
if obj in {self.color1_btn, self.color2_btn}:
if event.type() == QtCore.QEvent.MouseMove and obj.color:
mimedata = QtCore.QMimeData()
mimedata.setColorData(obj.color)
pixmap = QtGui.QPixmap(20, 20)
pixmap.fill(QtCore.Qt.transparent)
painter = QtGui.QPainter(pixmap)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setBrush(obj.color)
painter.setPen(QtGui.QPen(obj.color.darker(150), 2))
painter.drawEllipse(pixmap.rect().center(), 8, 8)
painter.end()
drag = QtGui.QDrag(obj)
drag.setMimeData(mimedata)
drag.setPixmap(pixmap)
drag.setHotSpot(pixmap.rect().center())
drag.exec_(QtCore.Qt.CopyAction)
elif event.type() == QtCore.QEvent.DragEnter:
event.accept() if event.mimeData().hasColor() else event.ignore()
elif event.type() == QtCore.QEvent.Drop:
self.set_color(obj, event.mimeData().colorData())
event.accept()
return super(DragTest, self).eventFilter(obj, event)

Creating right-click menu on splitter handle in PyQt5 python

I have made a splitter. I have been trying to bring a right-click menu when the splitter handle is right-clicked.
Here is the code I have created. Currently, it doesn't recognise the right clicks on the handle of the splitter. (note: this code currently updates count if right-clicked in the first frame of the splitter i,e Top left frame)
from PyQt5.QtWidgets import *
from PyQt5 import QtGui
from PyQt5.QtCore import Qt
# This class is to create the outer window
class OuterLayout(QMainWindow):
def __init__(self):
super().__init__()
self.window()
def window(self):
self.setMinimumSize(1000, 900)
self.showMaximized()
self.setWindowIcon(QtGui.QIcon('Images/Logo_small.png'))
self.setWindowTitle('Splitter')
self.menu_bar()
inner_layout = SplitterLayout()
layout = inner_layout.add_layout()
self.setCentralWidget(layout)
def menu_bar(self):
menu_bar = self.menuBar()
file_menu = menu_bar.addMenu('File')
self.file(file_menu)
edit_menu = menu_bar.addMenu('Edit')
self.edit(edit_menu)
def file(self, file):
new = QAction('New', self)
file.addAction(new)
def edit(self, edit):
pass
# This class creates the splitter window
class SplitterLayout(QWidget):
def __init__(self):
super(QWidget, self).__init__()
self.count = 0
self.splitter_handle_width = 3 # This is to set the width of the handle
# This is a method to add a new splitter window
def add_layout(self):
left = QFrame()
left.setFrameShape(QFrame.StyledPanel)
bottom = QFrame()
bottom.setFrameShape(QFrame.StyledPanel)
splitter1 = QSplitter(Qt.Horizontal)
splitter1.setHandleWidth(self.splitter_handle_width)
lineedit = QLineEdit()
lineedit.setStyleSheet('background-color:green')
splitter1.addWidget(left)
splitter1.addWidget(lineedit)
splitter1.setSizes([200, 200])
print(splitter1.handle(3))
splitter1.mousePressEvent = self.splitter_clicked
splitter2 = QSplitter(Qt.Vertical)
splitter2.setHandleWidth(self.splitter_handle_width)
splitter2.addWidget(splitter1)
splitter2.addWidget(bottom)
return splitter2
def splitter_clicked(self, event):
self.count += 1
print('splitter_double clicked' + str(self.count))
# def mousePressEvent(self, event):
# if event.button == Qt.RightButton:
# print('Right mouse clicked')
#
# elif event.button == Qt.LeftButton:
# print('Left mouse clicked')
def main():
splitter = QApplication([])
outer_layout = OuterLayout()
outer_layout.show()
splitter.exec_()
if __name__ == '__main__':
main()
The trick here is to create a custom QSplitterHandle class and override QSplitterHandle.mousePressEvent and a custom QSplitter class where you override createHandle so that it returns the custom QSplitterHandle instead of the standard one, i.e.
class MySplitter(QSplitter):
def createHandle(self):
return MySplitterHandle(self.orientation(), self)
class MySplitterHandle(QSplitterHandle):
def mousePressEvent(self, event):
if event.button() == Qt.RightButton:
print('Right mouse clicked')
elif event.button() == Qt.LeftButton:
print('Left mouse clicked')
super().mousePressEvent(event)
Finally, to use the custom QSplitter you need to replace all occurrences of QSplitter with MySplitter in SplitterLayout.

screen snipping program leaves left over square after snip

I'm attempting to resolved an issue with a left over square after my snipping program is done snipping. I would like to delete any instance of the square drawing after the initial snip
.
Steps to replicate:
Select "mode" > select "snip" > drag rectangle and take a screen snip
Select "mode" > select "snip" > now observe the previous snip still has the rectangle on the screen (as shown in the picture)
My code:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PIL import ImageGrab
from PyQt5.QtGui import QCursor
from PyQt5.QtWidgets import QApplication
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
self.topMenu()
def initUI(self):
self.setWindowTitle("Lil Snippy")
self.setWindowIcon(QtGui.QIcon("assets/lilSnippyIcon.png"))
self.setGeometry(400, 300, 400, 300)
# QApplication.setOverrideCursor(Qt.WaitCursor)
def topMenu(self):
menubar = self.menuBar()
fileMenu = menubar.addMenu("File")
saveAct = QtWidgets.QAction(QtGui.QIcon("assets/saveIcon.png"), "Save", self)
saveAsAct = QtWidgets.QAction(
QtGui.QIcon("assets/saveAsIcon.png"), "Save As", self
)
modeMenu = menubar.addMenu("Mode")
snipAct = QtWidgets.QAction(QtGui.QIcon("assets/cameraIcon.png"), "Snip", self)
snipAct.setShortcut(QtGui.QKeySequence("F1"))
snipAct.triggered.connect(self.activateSnipping)
videoAct = QtWidgets.QAction(QtGui.QIcon("assets/videoIcon.png"), "Video", self)
videoAct.setShortcut("F2")
soundAct = QtWidgets.QAction(QtGui.QIcon("assets/audioIcon.png"), "Sound", self)
soundAct.setShortcut("F3")
autoAct = QtWidgets.QAction(
QtGui.QIcon("assets/automationIcon.png"), "Automation", self
)
autoAct.setShortcut("F4")
optionsMenu = menubar.addMenu("Options")
helpMenu = menubar.addMenu("Help")
helpAct = QtWidgets.QAction(QtGui.QIcon("assets/helpIcon.png"), "Help", self)
aboutAct = QtWidgets.QAction(QtGui.QIcon("assets/aboutIcon.png"), "About", self)
fileMenu.addAction(saveAct)
fileMenu.addAction(saveAsAct)
modeMenu.addAction(snipAct)
modeMenu.addAction(videoAct)
modeMenu.addAction(soundAct)
modeMenu.addAction(autoAct)
helpMenu.addAction(helpAct)
helpMenu.addAction(aboutAct)
self.snipper = SnippingWidget()
self.snipper.closed.connect(self.on_closed)
def activateSnipping(self):
self.snipper.showFullScreen()
QApplication.setOverrideCursor(QtCore.Qt.CrossCursor)
self.hide()
def on_closed(self):
self.show()
class SnippingWidget(QtWidgets.QMainWindow):
closed = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(SnippingWidget, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
self.setStyleSheet("background:transparent;")
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.outsideSquareColor = "red"
self.squareThickness = 2
self.start_point = QtCore.QPoint()
self.end_point = QtCore.QPoint()
def mousePressEvent(self, event):
self.start_point = event.pos()
self.end_point = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end_point = event.pos()
self.update()
def mouseReleaseEvent(self, QMouseEvent):
r = QtCore.QRect(self.start_point, self.end_point).normalized()
self.hide()
img = ImageGrab.grab(bbox=r.getCoords())
img.save("snips/testImage.png")
QApplication.restoreOverrideCursor()
self.closed.emit()
def paintEvent(self, event):
trans = QtGui.QColor(22, 100, 233)
r = QtCore.QRectF(self.start_point, self.end_point).normalized()
qp = QtGui.QPainter(self)
trans.setAlphaF(0.2)
qp.setBrush(trans)
outer = QtGui.QPainterPath()
outer.addRect(QtCore.QRectF(self.rect()))
inner = QtGui.QPainterPath()
inner.addRect(r)
r_path = outer - inner
qp.drawPath(r_path)
qp.setPen(
QtGui.QPen(QtGui.QColor(self.outsideSquareColor), self.squareThickness)
)
trans.setAlphaF(0)
qp.setBrush(trans)
qp.drawRect(r)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
application = App()
application.show()
sys.exit(app.exec_())
You have to reset self.start_point and self.end_point:
def mouseReleaseEvent(self, QMouseEvent):
r = QtCore.QRect(self.start_point, self.end_point).normalized()
self.hide()
img = ImageGrab.grab(bbox=r.getCoords())
img.save("snips/testImage.png")
QApplication.restoreOverrideCursor()
self.closed.emit()
self.start_point = QtCore.QPoint()
self.end_point = QtCore.QPoint()

Screen Snipping Program - Transparent Snipping Area

I'm in the process of converting my successful screen snipping program from Tkinter to PYQT5. My question is how to create a fully transparent snipping area (a dynamically updating square region would be nice). The outside of the square will be semi-opaque. I've looked all over stack overflow and the internet and could not find an example of this (others are not a fully transparent drawing window). I've attached my code and a picture example of what I am looking for. The "SnippingWidget" is the class that does the snipping logic.
import sys
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, QWidget
from PyQt5.QtGui import QIcon, QKeySequence
from PIL import ImageGrab
class App(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
self.topMenu()
def initUI(self):
self.setWindowTitle('Lil Snippy')
self.setWindowIcon(QIcon('assets/lilSnippyIcon.png'))
self.setGeometry(400, 300, 400, 300)
self.show()
def topMenu(self):
menubar = self.menuBar()
fileMenu = menubar.addMenu('File')
saveAct = QAction(QIcon('assets/saveIcon.png'), 'Save', self)
saveAsAct = QAction(QIcon('assets/saveAsIcon.png'), 'Save As', self)
modeMenu = menubar.addMenu('Mode')
snipAct = QAction(QIcon('assets/cameraIcon.png'), 'Snip', self)
snipAct.setShortcut(QKeySequence('F1'))
snipAct.triggered.connect(self.activateSnipping)
videoAct = QAction(QIcon('assets/videoIcon.png'), 'Video', self)
videoAct.setShortcut('F2')
soundAct = QAction(QIcon('assets/audioIcon.png'), 'Sound', self)
soundAct.setShortcut('F3')
autoAct = QAction(QIcon('assets/automationIcon.png'), 'Automation', self)
autoAct.setShortcut('F4')
helpMenu = menubar.addMenu('Help')
helpAct = QAction(QIcon('assets/helpIcon.png'), 'Help', self)
aboutAct = QAction(QIcon('assets/aboutIcon.png'), 'About', self)
fileMenu.addAction(saveAct)
fileMenu.addAction(saveAsAct)
modeMenu.addAction(snipAct)
modeMenu.addAction(videoAct)
modeMenu.addAction(soundAct)
modeMenu.addAction(autoAct)
helpMenu.addAction(helpAct)
helpMenu.addAction(aboutAct)
def activateSnipping(self):
print("yes")
self.Snipper = SnippingWidget()
application.hide()
class SnippingWidget(QMainWindow):
def __init__(self, parent = None):
super(SnippingWidget, self).__init__(parent)
self.setStyleSheet("background-color: transparent;")
self.setWindowOpacity(.2)
self.showFullScreen()
self.outsideSquareColor = 'red'
self.squareThickness = 4
self.startX = None
self.startY = None
self.endX = None
self.endY = None
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = self.begin
self.startX = event.x()
self.startY = event.y()
self.update()
def mouseReleaseEvent(self, QMouseEvent):
self.destroy()
x1 = min(self.begin.x(), self.end.x())
y1 = min(self.begin.y(), self.end.y())
x2 = max(self.begin.x(), self.end.x())
y2 = max(self.begin.y(), self.end.y())
img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
img.save('snips/testImage.png')
application.show()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.setPen(QtGui.QPen(QtGui.QColor('red'), self.squareThickness))
trans = QtGui.QColor(255,255,255,255)
qp.setBrush(trans)
rect = QtCore.QRectF(self.begin, self.end)
qp.drawRect(rect)
if __name__ == '__main__':
app = QApplication(sys.argv)
application = App()
sys.exit(app.exec_())
You have to use QPainterPath to subtract the rectangle from the window with the selected rectangle:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PIL import ImageGrab
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
self.topMenu()
def initUI(self):
self.setWindowTitle("Lil Snippy")
self.setWindowIcon(QtGui.QIcon("assets/lilSnippyIcon.png"))
self.setGeometry(400, 300, 400, 300)
def topMenu(self):
menubar = self.menuBar()
fileMenu = menubar.addMenu("File")
saveAct = QtWidgets.QAction(QtGui.QIcon("assets/saveIcon.png"), "Save", self)
saveAsAct = QtWidgets.QAction(
QtGui.QIcon("assets/saveAsIcon.png"), "Save As", self
)
modeMenu = menubar.addMenu("Mode")
snipAct = QtWidgets.QAction(QtGui.QIcon("assets/cameraIcon.png"), "Snip", self)
snipAct.setShortcut(QtGui.QKeySequence("F1"))
snipAct.triggered.connect(self.activateSnipping)
videoAct = QtWidgets.QAction(QtGui.QIcon("assets/videoIcon.png"), "Video", self)
videoAct.setShortcut("F2")
soundAct = QtWidgets.QAction(QtGui.QIcon("assets/audioIcon.png"), "Sound", self)
soundAct.setShortcut("F3")
autoAct = QtWidgets.QAction(
QtGui.QIcon("assets/automationIcon.png"), "Automation", self
)
autoAct.setShortcut("F4")
helpMenu = menubar.addMenu("Help")
helpAct = QtWidgets.QAction(QtGui.QIcon("assets/helpIcon.png"), "Help", self)
aboutAct = QtWidgets.QAction(QtGui.QIcon("assets/aboutIcon.png"), "About", self)
fileMenu.addAction(saveAct)
fileMenu.addAction(saveAsAct)
modeMenu.addAction(snipAct)
modeMenu.addAction(videoAct)
modeMenu.addAction(soundAct)
modeMenu.addAction(autoAct)
helpMenu.addAction(helpAct)
helpMenu.addAction(aboutAct)
self.snipper = SnippingWidget()
self.snipper.closed.connect(self.on_closed)
def activateSnipping(self):
self.snipper.showFullScreen()
self.hide()
def on_closed(self):
self.snipper.hide()
self.show()
class SnippingWidget(QtWidgets.QMainWindow):
closed = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(SnippingWidget, self).__init__(parent)
self.setStyleSheet("background-color: transparent;")
self.setWindowOpacity(0.2)
self.outsideSquareColor = "red"
self.squareThickness = 4
self.start_point = QtCore.QPoint()
self.end_point = QtCore.QPoint()
def mousePressEvent(self, event):
self.start_point = event.pos()
self.end_point = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end_point = event.pos()
self.update()
def mouseReleaseEvent(self, QMouseEvent):
r = QtCore.QRect(self.start_point, self.end_point).normalized()
img = ImageGrab.grab(bbox=r.getCoords())
img.save("snips/testImage.png")
self.closed.emit()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.setPen(
QtGui.QPen(QtGui.QColor(self.outsideSquareColor), self.squareThickness)
)
trans = QtGui.QColor(255, 255, 255, 255)
qp.setBrush(trans)
outer = QtGui.QPainterPath()
outer.addRect(QtCore.QRectF(self.rect()))
inner = QtGui.QPainterPath()
inner.addRect(QtCore.QRectF(self.start_point, self.end_point).normalized())
r = outer - inner
qp.drawPath(r)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
application = App()
application.show()
sys.exit(app.exec_())
Update:
class SnippingWidget(QtWidgets.QMainWindow):
closed = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(SnippingWidget, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
self.setStyleSheet("background:transparent;")
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.outsideSquareColor = "red"
self.squareThickness = 4
self.start_point = QtCore.QPoint()
self.end_point = QtCore.QPoint()
def mousePressEvent(self, event):
self.start_point = event.pos()
self.end_point = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end_point = event.pos()
self.update()
def mouseReleaseEvent(self, QMouseEvent):
r = QtCore.QRect(self.start_point, self.end_point).normalized()
img = ImageGrab.grab(bbox=r.getCoords())
img.save("snips/testImage.png")
self.closed.emit()
def paintEvent(self, event):
trans = QtGui.QColor(255, 255, 255)
r = QtCore.QRectF(self.start_point, self.end_point).normalized()
qp = QtGui.QPainter(self)
trans.setAlphaF(0.2)
qp.setBrush(trans)
outer = QtGui.QPainterPath()
outer.addRect(QtCore.QRectF(self.rect()))
inner = QtGui.QPainterPath()
inner.addRect(r)
r_path = outer - inner
qp.drawPath(r_path)
qp.setPen(
QtGui.QPen(QtGui.QColor(self.outsideSquareColor), self.squareThickness)
)
trans.setAlphaF(0)
qp.setBrush(trans)
qp.drawRect(r)

how to save previous rectangles after update()?

user can draw rectangles by this application by giving clicking twice on grey picture. But this application dont saves last rectangles, instead of saving its drawing(updateing) a new rectangle by 2 next points. how i can solve this problem? how can i save previouse rectangles too?
class myQLabel(QLabel):
def __init__(self,parent):
super(myQLabel, self).__init__(parent)
self.x = 0
self.y = 0
self.trafficlines = []
def mousePressEvent(self, QMouseEvent):
#print mode
self.x = QMouseEvent.x()
self.y = QMouseEvent.y()
if self.x != 0 and self.y != 0:
self.trafficlines.append(copy.deepcopy([self.x,self.y]))
print "______"
print self.x
print self.y
print "("+str(mode)+")"
print "______"
def paintEvent(self, QPaintEvent):
super(myQLabel, self).paintEvent(QPaintEvent)
painter = QPainter(self)
if mode == 0:
painter.setPen(QPen(Qt.red,3))
elif mode == 1:
painter.setPen(QPen(Qt.blue,3))
elif mode == 2:
painter.setPen(QPen(Qt.green,3))
elif mode == 3:
painter.setPen(QPen(Qt.magenta,3))
if len(self.trafficlines)%2==1 and len(self.trafficlines)>0:
painter.drawPoint(self.trafficlines[-1][0],self.trafficlines[-1][1])
if len(self.trafficlines)%2==0 and len(self.trafficlines)>0 and mode!=0:
painter.drawLine( self.trafficlines[-2][0],self.trafficlines[-2][1],self.trafficlines[-1][0],self.trafficlines[-1][1] )
if len(self.trafficlines)%2==0 and len(self.trafficlines)>0 and mode==0:
x1=self.trafficlines[-2][0]
y1=self.trafficlines[-2][1]
x2=self.trafficlines[-1][0]
y2=self.trafficlines[-1][1]
painter.drawLine( x1,y1,x1,y2)
painter.drawLine( x1,y2,x2,y2)
painter.drawLine( x2,y2,x2,y1)
painter.drawLine( x2,y1,x1,y1)
self.update()
This is all the code:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys, os
import copy
mode = 5
class Example(QWidget):
def __init__(self,parent):
super(Example, self).__init__()
self.main_image_name="C:\Python27\project\main_image.png"
self.initUI()
def initUI(self):
File_name = QLabel('Setup file name')
File_name_edit = QLineEdit()
QToolTip.setFont(QFont('SansSerif', 10))
#QMainWindow.statusBar().showMessage('Ready')
self.setGeometry(300, 300, 250, 150)
self.resize(640, 360)
#self.setFixedSize(640, 360)
self.center()
self.main_image = myQLabel(self)
self.main_image.setPixmap(QPixmap(self.main_image_name))
btn = QPushButton("Make setup file")
btn.setToolTip('Press <b>Detect</b> button for detecting objects by your settings')
btn.resize(btn.sizeHint())
btn.clicked.connect(QCoreApplication.instance().quit)
btn_browse = QPushButton("Browse")
btn_browse.clicked.connect(self.browse)
btn_set = QPushButton("Set name")
#fullscreen
#self.main_image.setScaledContents(True)
#just centered
self.main_image.setAlignment(Qt.AlignCenter)
#Layout
box_File_name = QHBoxLayout()
box_File_name.addWidget(File_name)
box_File_name.addWidget(File_name_edit)
box_File_name.addWidget(btn_set)
grid = QGridLayout()
grid.setSpacing(10)
grid.addLayout(box_File_name, 1, 0)
#grid.addWidget(File_name_edit, 1, 1)
grid.addWidget(self.main_image, 2, 0)
grid.addWidget(btn_browse, 3 , 0)
grid.addWidget(btn, 4, 0)
box_number = QVBoxLayout()
number_group=QButtonGroup() # Number group
r0=QRadioButton("Traffic Lights")
number_group.addButton(r0)
r1=QRadioButton("Direction")
number_group.addButton(r1)
r2=QRadioButton("Traffic Lines H")
number_group.addButton(r2)
r3=QRadioButton("Traffic Lines V")
number_group.addButton(r3)
box_number.addWidget(r0)
box_number.addWidget(r1)
box_number.addWidget(r2)
box_number.addWidget(r3)
r0.toggled.connect(self.radio0_clicked)
r1.toggled.connect(self.radio1_clicked)
r2.toggled.connect(self.radio2_clicked)
r3.toggled.connect(self.radio3_clicked)
box_road_sign = QHBoxLayout()
road_sign_label = QLabel('Road signs', self)
road_sign = QComboBox()
road_sign.addItem("None")
road_sign.addItem("ex1")
road_sign.addItem("ex2")
road_sign.addItem("ex3")
road_sign.addItem("ex4")
road_sign.addItem("ex5")
box_road_sign.addWidget(road_sign_label)
box_road_sign.addWidget(road_sign)
grid.addLayout(box_road_sign, 1, 1)
grid.addLayout(box_number, 2, 1)
self.setLayout(grid)
self.show()
def browse(self):
w = QWidget()
w.resize(320, 240)
w.setWindowTitle("Select Picture")
filename = QFileDialog.getOpenFileName(w, 'Open File', '/')
self.main_image_name = filename
self.main_image.setPixmap(QPixmap(self.main_image_name))
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def radio0_clicked(self, enabled):
if enabled:
print("0")
global mode
mode=0
def radio1_clicked(self, enabled):
if enabled:
print("1")
global mode
mode=1
def radio2_clicked(self, enabled):
if enabled:
print("2")
global mode
mode=2
def radio3_clicked(self, enabled):
if enabled:
print("3")
global mode
mode=3
class myQLabel(QLabel):
def __init__(self,parent):
super(myQLabel, self).__init__(parent)
self.x = 0
self.y = 0
self.trafficlines = []
def mousePressEvent(self, QMouseEvent):
#print mode
self.x = QMouseEvent.x()
self.y = QMouseEvent.y()
if self.x != 0 and self.y != 0:
self.trafficlines.append(copy.deepcopy([self.x,self.y]))
print "______"
print self.x
print self.y
print "("+str(mode)+")"
print "______"
def paintEvent(self, QPaintEvent):
super(myQLabel, self).paintEvent(QPaintEvent)
painter = QPainter(self)
if mode == 0:
painter.setPen(QPen(Qt.red,3))
elif mode == 1:
painter.setPen(QPen(Qt.blue,3))
elif mode == 2:
painter.setPen(QPen(Qt.green,3))
elif mode == 3:
painter.setPen(QPen(Qt.magenta,3))
if len(self.trafficlines)%2==1 and len(self.trafficlines)>0:
painter.drawPoint(self.trafficlines[-1][0],self.trafficlines[-1][1])
if len(self.trafficlines)%2==0 and len(self.trafficlines)>0 and mode!=0:
painter.drawLine( self.trafficlines[-2][0],self.trafficlines[-2][1],self.trafficlines[-1][0],self.trafficlines[-1][1] )
if len(self.trafficlines)%2==0 and len(self.trafficlines)>0 and mode==0:
x1=self.trafficlines[-2][0]
y1=self.trafficlines[-2][1]
x2=self.trafficlines[-1][0]
y2=self.trafficlines[-1][1]
painter.drawLine( x1,y1,x1,y2)
painter.drawLine( x1,y2,x2,y2)
painter.drawLine( x2,y2,x2,y1)
painter.drawLine( x2,y1,x1,y1)
self.update()
class menubarex(QMainWindow):
def __init__(self, parent=None):
super(menubarex, self).__init__(parent)
self.form_widget = Example(self)
self.setCentralWidget(self.form_widget)
self.initUI()
def initUI(self):
exitAction = QAction(QIcon('exit.png'), '&Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
exitAction.triggered.connect(qApp.quit)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAction)
#self.toolbar = self.addToolBar('Exit')
#self.toolbar.addAction(exitAction)
self.statusBar().showMessage('Ready')
self.setWindowTitle('mi ban')
self.setWindowIcon(QIcon('C:\Python27\project\icon.png'))
def closeEvent(self, event):
reply = QMessageBox.question(self, 'Message',
"Are you sure to quit?", QMessageBox.Yes |
QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
def main():
app = QApplication(sys.argv)
#ex = Example()
menubar = menubarex()
menubar.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
paintEvent() redraws the entire widget, so it does not save memory from the previous drawing, so the rectangles or previous lines are not saved. The solution is to store those states and redraw everything again, for this we can store the mode and points in trafficlines as shown below:
class myQLabel(QLabel):
def __init__(self,parent):
super(myQLabel, self).__init__(parent)
self.trafficlines = []
self.mode = 0
self.start_point = QPoint()
def setMode(self, mode):
self.mode = mode
def mousePressEvent(self, event):
if self.start_point.isNull():
self.start_point = event.pos()
else:
self.trafficlines.append((self.mode,[self.start_point, event.pos()]))
self.start_point = QPoint()
self.update()
def paintEvent(self, event):
super(myQLabel, self).paintEvent(event)
painter = QPainter(self)
colors = [Qt.red, Qt.blue, Qt.green, Qt.magenta]
for mode, points in self.trafficlines:
painter.setPen(QPen(colors[mode],3))
if mode != 0:
painter.drawLine(*points)
else:
rect = QRect(*points)
painter.drawRect(rect)
if not self.start_point.isNull():
painter.setPen(QPen(colors[self.mode],3))
painter.drawPoint(self.start_point)
Note: do not use global variables, they are difficult to debug, in addition to unnecessary many times.
Also I take the liberty to improve your code by making it more readable with fewer lines. The complete code is in the following part:
import sys
import os
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Example(QWidget):
def __init__(self,parent):
super(Example, self).__init__()
self.main_image_name="C:\Python27\project\main_image.png"
self.initUI()
def initUI(self):
File_name = QLabel('Setup file name')
File_name_edit = QLineEdit()
self.resize(640, 360)
self.center()
self.main_image = myQLabel(self)
self.main_image.setPixmap(QPixmap(self.main_image_name))
btn = QPushButton("Make setup file")
btn.setToolTip('Press <b>Detect</b> button for detecting objects by your settings')
btn.resize(btn.sizeHint())
btn.clicked.connect(QCoreApplication.instance().quit)
btn_browse = QPushButton("Browse")
btn_browse.clicked.connect(self.browse)
btn_set = QPushButton("Set name")
self.main_image.setAlignment(Qt.AlignCenter)
#Layout
box_File_name = QHBoxLayout()
box_File_name.addWidget(File_name)
box_File_name.addWidget(File_name_edit)
box_File_name.addWidget(btn_set)
grid = QGridLayout(self)
grid.setSpacing(10)
grid.addLayout(box_File_name, 1, 0)
#grid.addWidget(File_name_edit, 1, 1)
grid.addWidget(self.main_image, 2, 0)
grid.addWidget(btn_browse, 3 , 0)
grid.addWidget(btn, 4, 0)
box_number = QVBoxLayout()
number_group = QButtonGroup(self) # Number group
for i, text in enumerate(["Traffic Lights", "Direction", "Traffic Lines H", "Traffic Lines V"]):
rb = QRadioButton(text)
box_number.addWidget(rb)
number_group.addButton(rb, i)
number_group.buttonClicked[int].connect(self.main_image.setMode)
number_group.button(0).setChecked(True)
box_road_sign = QHBoxLayout()
road_sign_label = QLabel('Road signs', self)
road_sign = QComboBox()
road_sign.addItems(["None", "ex1", "ex2","ex3", "ex4", "ex5"])
box_road_sign.addWidget(road_sign_label)
box_road_sign.addWidget(road_sign)
grid.addLayout(box_road_sign, 1, 1)
grid.addLayout(box_number, 2, 1)
def browse(self):
filename = QFileDialog.getOpenFileName(self, 'Open File', '/')
self.main_image_name = filename
self.main_image.setPixmap(QPixmap(self.main_image_name))
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
class myQLabel(QLabel):
def __init__(self,parent):
super(myQLabel, self).__init__(parent)
self.trafficlines = []
self.mode = 0
self.start_point = QPoint()
def setMode(self, mode):
self.mode = mode
def mousePressEvent(self, event):
if self.start_point.isNull():
self.start_point = event.pos()
else:
self.trafficlines.append((self.mode,[self.start_point, event.pos()]))
self.start_point = QPoint()
self.update()
def paintEvent(self, event):
super(myQLabel, self).paintEvent(event)
painter = QPainter(self)
colors = [Qt.red, Qt.blue, Qt.green, Qt.magenta]
for mode, points in self.trafficlines:
painter.setPen(QPen(colors[mode],3))
if mode != 0:
painter.drawLine(*points)
else:
rect = QRect(*points)
painter.drawRect(rect)
if not self.start_point.isNull():
painter.setPen(QPen(colors[self.mode],3))
painter.drawPoint(self.start_point)
class menubarex(QMainWindow):
def __init__(self, parent=None):
super(menubarex, self).__init__(parent)
self.form_widget = Example(self)
self.setCentralWidget(self.form_widget)
self.initUI()
def initUI(self):
exitAction = QAction(QIcon('exit.png'), '&Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
exitAction.triggered.connect(qApp.quit)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAction)
self.statusBar().showMessage('Ready')
self.setWindowTitle('mi ban')
self.setWindowIcon(QIcon('C:\Python27\project\icon.png'))
def closeEvent(self, event):
reply = QMessageBox.question(self, 'Message',
"Are you sure to quit?", QMessageBox.Yes |
QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
def main():
app = QApplication(sys.argv)
#ex = Example()
menubar = menubarex()
menubar.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Categories

Resources