PyQt5 Media Player Corrupts video - python

I tried making a PyQt5 custom media player that opens plays one specific video and print the coordinates of the mouse when left clicking.
class Window(QWidget):
def init(self):
super().init()
user32 = ctypes.windll.user32
user32.SetProcessDPIAware()
self.setWindowTitle("Media Player")
self.setGeometry(350, 100, 700, 500)
self.setWindowIcon(QIcon('eye_icon.png'))
p = self.palette()
p.setColor(QPalette.Window, Qt.black)
self.setPalette(p)
self.init_ui()
def init_ui(self):
# Create a Media Player Object
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.mediaPlayer.mediaStatusChanged.connect(self.statusChanged)
# Create a Video Widget Object
self.videowidget = QVideoWidget()
# Create Play Button
self.playBtn = QPushButton()
self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
self.playBtn.clicked.connect(self.play_video)
# Create Hbox Layout
hboxLayout = QHBoxLayout()
hboxLayout.setContentsMargins(0, 0, 0, 0)
# Set Widgets to the Hbox layout
hboxLayout.addWidget(self.playBtn)
# Create Vbox Layout
vboxLayout = QVBoxLayout()
vboxLayout.addWidget(self.videowidget)
vboxLayout.addLayout(hboxLayout)
self.setLayout(vboxLayout)
self.mediaPlayer.setVideoOutput(self.videowidget)
# Media Player Signals
self.mediaPlayer.stateChanged.connect(self.mediastate_changed)
self.hidden = True
def mousePressEvent(self, event):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
if event.button() == Qt.LeftButton:
x, y = pyautogui.position()
a = (x, y)
print(a)
def statusChanged(self, status):
if status == QMediaPlayer.EndOfMedia:
if self.filename.endswith('.mp4') or self.filename.endswith('.flv') or self.filename.endswith('.mov') \
or self.filename.endswith('.wmv') or self.filename.endswith('.avi') or self.filename.endswith(
'.mkv'):
print("End of video")
else:
self.playBtn.setEnabled(False)
def hide_unhide(self):
if self.hidden:
self.playBtn.show()
self.hidden = False
else:
self.playBtn.hide()
self.hidden = True
def play_video(self):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
self.mediaPlayer.pause()
else:
self.filename = 'Black_Video_3.mp4'
global filepath
filepath = self.filename
self.playBtn.hide()
if self.filename != '':
self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(self.filename)))
self.mediaPlayer.play()
self.playBtn.setEnabled(False)
def mediastate_changed(self, state):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
self.playBtn.setIcon(
self.style().standardIcon(QStyle.SP_MediaPause)
)
else:
self.playBtn.setIcon(
self.style().standardIcon(QStyle.SP_MediaPlay)
)
def set_position(self, position):
self.mediaPlayer.setPosition(position)
def handle_errors(self):
self.playBtn.setEnabled(False)
self.label.setText("Error:" + self.mediaPlayer.errorString())
def statusChanged(self, status):
if status == QMediaPlayer.EndOfMedia:
if self.filename.endswith('.mp4') or self.filename.endswith('.flv') or self.filename.endswith('.mov') \
or self.filename.endswith('.wmv') or self.filename.endswith('.avi') or self.filename.endswith(
'.mkv'):
print("Bye")
sys.exit()
else:
self.playBtn.setEnabled(False)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.showMaximized()
app.exec_()
Problem is that the video on the left down side of the screen looks like the frame is broken kind of like a puzzle. Like the image is moving a little up and down at that side of the screen and it is really annoying. This happens especially in Full Screen. Any ideas what I am doing wrong?

Related

Transparent widget problem over a vlc video on

I am trying to display transparent label over video output using PyQt and vlc library. Although I can put my label on video, the part under the label is not visible as if there is no video underneath. By the way, target platform is Windows. Also, I think the problem is setting media player to video frame window id. However, if I remove the line 'self.mediaplayer.set_hwnd(int(self.videoframe.winId()))', the video would be displayed in it's own window not my player window.
My attempt looks like this:
.
My code is attached below:
import platform
import sys
import vlc
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
class Player(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Media Player")
# Create a basic vlc instance
self.instance = vlc.Instance()
self.media = None
# Create an empty vlc media player
self.mediaplayer = self.instance.media_player_new()
self.widget = QtWidgets.QWidget(self)
self.setCentralWidget(self.widget)
self.lbl = QtWidgets.QLabel()
font = QFont('Helvetica', 16, QFont.Bold)
self.lbl.setFont(font)
self.lbl.setText("This is my\ntransparent\nlabel.")
self.lbl.setAlignment(Qt.AlignCenter)
self.lbl.setFixedSize(200,200)
self.videoframe = QtWidgets.QFrame(frameShape=QtWidgets.QFrame.Box, frameShadow=QtWidgets.QFrame.Raised)
self.videoframe.setFixedSize(600,600)
self.mediaplayer.set_hwnd(int(self.videoframe.winId()))
fileName = "C:\\Users\\...\\test.mp4" #dir of the video
self.media = self.instance.media_new(fileName)
# Put the media in the media player
self.mediaplayer.set_media(self.media)
# Parse the metadata of the file
self.media.parse()
self.vboxlayout = QtWidgets.QGridLayout()
self.vboxlayout.addWidget(self.videoframe,0,0)
self.vboxlayout.addWidget(self.lbl,0,0)
self.widget.setLayout(self.vboxlayout)
self.mediaplayer.play()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
player = Player()
player.show()
sys.exit(app.exec_())
I just had the same problem and my solution is: JUST FOUR THICK LABELS THAT DRAW A SQUARE.
here is my code:
class MouseTracker(QtCore.QObject):
positionChanged = QtCore.pyqtSignal(QtCore.QEvent)
def __init__(self, widget):
super().__init__(widget)
self._widget = widget
self.widget.setMouseTracking(True)
self.widget.installEventFilter(self)
#property
def widget(self):
return self._widget
def eventFilter(self, o, e):
if e.type() == QtCore.QEvent.MouseButtonPress:
# print("pressed")
self.positionChanged.emit(e)
elif e.type() == QtCore.QEvent.MouseButtonRelease:
# print("release")
self.positionChanged.emit(e)
if o is self.widget and e.type() == QtCore.QEvent.MouseMove:
self.positionChanged.emit(e)
return super().eventFilter(o, e)
then the mainclass...
class MainWindow(QMainWindow):
def __init__(self, master=None):
QMainWindow.__init__(self, master)
self.setWindowTitle("Media Player")
# creating a basic vlc instance
self.instance = vlc.Instance()
# creating an empty vlc media player
self.mediaplayer = self.instance.media_player_new()
self.initUI()
self.isPaused = False
def initUI(self):
self.x0 = None
self.y0 = None
self.x1 = None
self.y1 = None
# Set up the user interface, signals & slots
self.statusBar().showMessage("Ready")
self.resize(640, 480)
self.widget = QWidget(self)
self.setCentralWidget(self.widget)
# In this widget, the video will be drawn
if sys.platform == "darwin": # for MacOS
from PyQt5.QtWidgets import QMacCocoaViewContainer
self.video_label = QMacCocoaViewContainer(0)
else:
self.video_label = QLabel()
tracker = MouseTracker(self.video_label)
tracker.positionChanged.connect(self.on_positionChanged)
self.positionslider = QSlider(Qt.Horizontal, self)
self.positionslider.setToolTip("Position")
self.positionslider.setMaximum(1000)
self.positionslider.sliderMoved.connect(self.setPosition)
#########Buttons#################
self.height_of_BTNS = 30
self.playbutton = QPushButton("Play")
self.playbutton.clicked.connect(self.PlayPause)
self.stopbutton = QPushButton("Stop")
self.stopbutton.clicked.connect(self.Stop)
self.volumeslider = QSlider(Qt.Horizontal, self)
self.volumeslider.setMaximum(100)
self.volumeslider.setValue(self.mediaplayer.audio_get_volume())
self.volumeslider.setToolTip("Volume")
self.volumeslider.valueChanged.connect(self.setVolume)
#################################
self.marker_label_top = QLabel(self)
self.marker_label_top.hide()
self.marker_label_top.raise_()
#################################
self.marker_label_btm = QLabel(self)
self.marker_label_btm.hide()
self.marker_label_btm.raise_()
#################################
self.marker_label_r = QLabel(self)
self.marker_label_r.hide()
self.marker_label_r.raise_()
#################################
self.marker_label_l = QLabel(self)
self.marker_label_l.hide()
self.marker_label_l.raise_()
self.hbuttonbox = QHBoxLayout()
self.hbuttonbox.addWidget(self.playbutton)
self.hbuttonbox.addWidget(self.stopbutton)
self.hbuttonbox.addWidget(self.volumeslider)
self.hbuttonbox.addStretch(1)
self.vboxlayout = QVBoxLayout()
self.vboxlayout.addWidget(self.video_label)
self.vboxlayout.addWidget(self.positionslider)
self.vboxlayout.addLayout(self.hbuttonbox)
self.widget.setLayout(self.vboxlayout)
##############################
self.label_position = QtWidgets.QLabel(self.video_label, alignment=QtCore.Qt.AlignCenter)
self.label_position.setStyleSheet('background-color: white; border: 1px solid black')
##############################
open = QAction("&Open", self)
open.triggered.connect(self.OpenFile)
exit = QAction("&Exit", self)
exit.triggered.connect(sys.exit)
menubar = self.menuBar()
filemenu = menubar.addMenu("&File")
filemenu.addAction(open)
filemenu.addSeparator()
filemenu.addAction(exit)
self.timer = QTimer(self)
self.timer.setInterval(200)
self.timer.timeout.connect(self.updateUI)
self.timer_1 = QTimer(self)
self.timer_1.setInterval(10000)
self.timer_1.timeout.connect(self.updateUI_info)
# Below functions must be FALSE in order to work mousetracker
self.mediaplayer.video_set_mouse_input(False)
self.mediaplayer.video_set_key_input(False)
self.show()
then the function that draw the square when the mouse button released. It actually draw 4 thick labels above the video_label. IMPORTANT TO SET FALSE the self.mediaplayer.video_set_mouse_input(False) and self.mediaplayer.video_set_key_input(False)
#QtCore.pyqtSlot(QtCore.QEvent)
def on_positionChanged(self, e):
if e.type() == QtCore.QEvent.MouseButtonPress:
self.statusBar().showMessage("Ready")
self.marker_label_top.hide()
self.marker_label_r.hide()
self.marker_label_l.hide()
self.marker_label_btm.hide()
print("Mouse press")
self.x0 = e.x()
self.y0 = e.y()
elif e.type() == QtCore.QEvent.MouseButtonRelease and self.x0 is not None and self.y0 is not None:
self.x1 = e.x()
self.y1 = e.y()
print("Mouse release")
if abs(self.x0 - self.x1) > 30 and abs(self.y0 - self.y1) > 30:
marker_width = self.x1 - self.x0
marker_height = self.y1 - self.y0
self.marker_label_top.setStyleSheet("border: 2px solid black;")
self.marker_label_top.resize(marker_width, 2)
self.marker_label_top.move(self.x0, self.y0)
self.marker_label_top.show()
self.marker_label_l.setStyleSheet("border: 2px solid black;")
self.marker_label_l.resize(2, marker_height)
self.marker_label_l.move(self.x0, self.y0)
self.marker_label_l.show()
self.marker_label_r.setStyleSheet("border: 2px solid black;")
self.marker_label_r.resize(2, marker_height)
self.marker_label_r.move(self.x1, self.y0)
self.marker_label_r.show()
self.marker_label_btm.setStyleSheet("border: 2px solid black;")
self.marker_label_btm.resize(marker_width, 2)
self.marker_label_btm.move(self.x0, self.y1)
self.marker_label_btm.show()
print(f"Values UI MOUSE TRACKER X: {self.x0} ,Y: {self.y0}, X1: {self.x1}, Y1: {self.y1}")
else:
self.statusBar().showMessage("Make it bigger")
# self.worker1.reset_values()
self.x0 = None
self.y0 = None
self.x1 = None
self.y1 = None
self.label_position.move(e.x(), e.y())
self.label_position.setText("(%d, %d)" % (e.x(), e.y()))
self.label_position.adjustSize()
self.label_position.show()
and the rest of the code
def PlayPause(self):
# Toggle play/pause status
if self.mediaplayer.is_playing():
self.mediaplayer.pause()
self.playbutton.setText("Play")
self.isPaused = True
else:
if self.mediaplayer.play() == -1:
self.OpenFile()
return
self.mediaplayer.play()
self.playbutton.setText("Pause")
self.timer.start()
self.timer_1.start()
self.isPaused = False
def Stop(self):
self.mediaplayer.stop()
self.playbutton.setText("Play")
def OpenFile(self, filename=None):
if filename == False:
filename = QFileDialog.getOpenFileName(self, "Open File", os.path.expanduser('~'))[0]
if not filename:
return
# # create the media
if sys.version < '3':
filename = vlc.unicode(filename)
self.media = self.instance.media_new(filename)
# put the media in the media player
self.mediaplayer.set_media(self.media)
# parse the metadata of the file
self.media.parse()
if sys.platform.startswith('linux'): # for Linux using the X Server
self.mediaplayer.set_xwindow(self.video_label.winId())
elif sys.platform == "win32": # for Windows
self.mediaplayer.set_hwnd(self.video_label.winId())
print(self.video_label.winId())
elif sys.platform == "darwin": # for MacOS
self.mediaplayer.set_nsobject(int(self.video_label.winId()))
self.PlayPause()
def setVolume(self, Volume):
self.mediaplayer.audio_set_volume(Volume)
def setPosition(self, position):
# setting the position to where the slider was dragged
self.mediaplayer.set_position(position / 1000.0)
def updateUI(self):
# updates the user interface
# setting the slider to the desired position
self.positionslider.setValue(int(self.mediaplayer.get_position() * 1000))
# self.mediaplayer.video_take_snapshot(num=0, psz_filepath='a.png', i_width=1920, i_height=1080)
if not self.mediaplayer.is_playing():
# no need to call this function if nothing is played
self.timer.stop()
if not self.isPaused:
# after the video finished, the play button stills shows
# "Pause", not the desired behavior of a media player
# this will fix it
self.Stop()
def updateUI_info(self):
fps = self.mediaplayer.get_fps()
sec = self.mediaplayer.get_time() / 1000
frame_no = int(round(sec * fps))
print(
f" Frame number Now: {frame_no} \n Frame Rate per Second: {fps} \n Current position in seconds {self.mediaplayer.get_time() / 1000} \n -------------------")
if __name__ == "__main__":
App = QApplication(sys.argv)
Root = MainWindow()
if sys.argv[1:]:
Root.OpenFile(sys.argv[1])
sys.exit(App.exec_())
enjoy :)

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.

PyQt5 Moveable button causes screen smear

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_())

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