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 :)
Related
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?
Here is the code for a camera surveillance system. In the configuration_page.py file I'm getting the size of the window as 100x30 despite using self.showMaximized() and resizeEvent(). The widgets present in it are also showing the size as 640x480. I'm particularly interested in retrieving the size of a widget named self.mid_frame in CameraDisplay class present in config.py file.
Earlier I was facing the same issue in dashboard.py file but I found a workaround by explicitly passing width and height in that case. But this time I'm stuck because I need to get the size of the widget named self.mid_frame. I don't understand why even resizeEvent is showing the wrong size.
main.py
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import Qt, QRect
from threading import Thread, RLock, Lock
from collections import deque
from datetime import datetime
import time
import sys
import cv2
import imutils
from dashboard import *
from configuration_page import *
from global_widgets import *
class CameraWidget(QtGui.QWidget):
"""Independent camera feed
Uses threading to grab IP camera frames in the background
#param width - Width of the video frame
#param height - Height of the video frame
#param stream_link - IP/RTSP/Webcam link
#param aspect_ratio - Whether to maintain frame aspect ratio or force into fraame
"""
def __init__(self, stream_link=0, stacked_widget=None, width=0, height=0, btn_text=None, idx=None, aspect_ratio=False, parent=None, deque_size=1):
super(CameraWidget, self).__init__(parent)
# Initialize deque used to store frames read from the stream
self.deque = deque(maxlen=deque_size)
self.maintain_aspect_ratio = aspect_ratio
self.camera_stream_link = stream_link
self.stacked_widget = stacked_widget
self.idx = idx
# Flag to check if camera is valid/working
self.online = False
self.capture = None
self.video_frame = QtGui.QLabel()
self.video_frame_1 = QtGui.QLabel()
self.load_network_stream()
# Start background frame grabbing
self.get_frame_thread = Thread(target=self.get_frame, args=())
self.get_frame_thread.daemon = True
self.get_frame_thread.start()
# Periodically set video frame to display
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.set_frame)
self.timer.start(.5)
print('Started camera: {}'.format(self.camera_stream_link))
def load_network_stream(self):
"""Verifies stream link and open new stream if valid"""
def load_network_stream_thread():
if self.verify_network_stream(self.camera_stream_link):
self.capture = cv2.VideoCapture(self.camera_stream_link)
self.online = True
self.load_stream_thread = Thread(target=load_network_stream_thread, args=())
self.load_stream_thread.daemon = True
self.load_stream_thread.start()
def verify_network_stream(self, link):
"""Attempts to receive a frame from given link"""
cap = cv2.VideoCapture(link)
if not cap.isOpened():
return False
cap.release()
return True
def get_frame(self):
"""Reads frame, resizes, and converts image to pixmap"""
while True:
try:
if self.capture.isOpened() and self.online:
# Read next frame from stream and insert into deque
status, frame = self.capture.read()
if status:
self.deque.append(frame)
else:
self.capture.release()
self.online = False
else:
# Attempt to reconnect
print('attempting to reconnect', self.camera_stream_link)
self.load_network_stream()
self.spin(2)
self.spin(.001)
except AttributeError:
pass
def spin(self, seconds):
"""Pause for set amount of seconds, replaces time.sleep so program doesnt stall"""
time_end = time.time() + seconds
while time.time() < time_end:
QtGui.QApplication.processEvents()
def set_frame(self):
"""Sets pixmap image to video frame"""
if not self.online:
self.spin(1)
return
if self.deque and self.online:
# Grab latest frame
frame = self.deque[-1]
frame_1 = self.deque[-1]
# Display frames on dashboard and configuration pages
# Frame for dashboard
# Keep frame aspect ratio
if self.maintain_aspect_ratio:
self.frame = imutils.resize(frame, width=self.screen_width)
# Force resize
else:
self.frame = cv2.resize(frame, (self.screen_width, self.screen_height))
self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
h, w, ch = self.frame.shape
bytesPerLine = ch * w
# Frame for configuration page-----------------------------------------------------------------------------------------
# print('2: ', self.screen_width_1, self.screen_height_1)
self.frame_1 = cv2.resize(frame_1, (self.screen_width_1, self.screen_height_1))
self.frame_1 = cv2.cvtColor(self.frame_1, cv2.COLOR_BGR2RGB)
h_1, w_1, ch_1 = self.frame_1.shape
bytesPerLine_1 = ch_1 * w_1
# Convert to pixmap and set to video frame
self.img = QtGui.QImage(self.frame, w, h, bytesPerLine, QtGui.QImage.Format_RGB888)
self.pix = QtGui.QPixmap.fromImage(self.img)
self.video_frame.setPixmap(self.pix)
self.img_1 = QtGui.QImage(self.frame_1, w_1, h_1, bytesPerLine_1, QtGui.QImage.Format_RGB888)
self.pix_1 = QtGui.QPixmap.fromImage(self.img_1)
self.video_frame_1.setPixmap(self.pix_1)
def set_frame_params(self, width, height, btn_text=None, idx=0):
self.screen_width = width
self.screen_height = height
self.btn_text = btn_text
self.idx = idx
def set_frame_params_1(self, width, height):
self.screen_width_1 = width
self.screen_height_1 = height
def get_video_display_frame(self):
self.video_display_frame = QtGui.QFrame()
self.video_layout = QtGui.QVBoxLayout()
self.video_btn = QtGui.QPushButton(self.btn_text)
self.video_btn.setStyleSheet("background-color: rgb(128, 159, 255);")
self.video_btn.clicked.connect(self.on_clicked)
# self.video_frame = QtGui.QLabel()
self.video_frame.setScaledContents(True)
self.video_layout.addWidget(self.video_btn)
self.video_layout.addWidget(self.video_frame)
self.video_layout.setContentsMargins(0,0,0,0)
self.video_layout.setSpacing(0)
self.video_display_frame.setLayout(self.video_layout)
return self.video_display_frame
def get_video_frame(self):
self.video_frame_1.setScaledContents(True)
return self.video_frame_1
#QtCore.pyqtSlot()
def on_clicked(self):
GlobalObject().dispatchEvent("hello", args=(self.idx,))
self.stacked_widget.setCurrentIndex(1)
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.stacked_widget = QtGui.QStackedWidget()
layout = QtGui.QVBoxLayout()
layout.setContentsMargins(0,0,0,0)
layout.addWidget(self.stacked_widget)
widget = QtGui.QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.cam1 = CameraWidget(camera1, self.stacked_widget, idx=1)
widget_1 = DashBoard(self.cam1, self.stacked_widget)
widget_2 = ZoneConfig(self.cam1, self.stacked_widget)
self.stacked_widget.addWidget(widget_1)
self.stacked_widget.addWidget(widget_2)
self.showMaximized()
camera1 = '../streams/Fog.avi'
if __name__ == '__main__':
app = QtGui.QApplication([])
app.setStyle(QtGui.QStyleFactory.create("plastique"))
# app.setStyle(QtGui.QStyleFactory.create("Cleanlooks"))
window = Window()
window.show()
sys.exit(app.exec_())
dashboard.py
from PyQt4 import QtGui, QtCore
from global_widgets import *
class DashBoard(QtGui.QWidget):
def __init__(self, cam1, stacked_widget, parent=None):
super(DashBoard, self).__init__(parent)
self.showMaximized()
self.screen_width = self.width()
self.screen_height = self.height()
self.stacked_widget = stacked_widget
# Layouts and frames
layout = QtGui.QVBoxLayout()
top_frame = QtGui.QFrame()
top_frame.setStyleSheet("background-color: rgb(208, 208, 225)")
mid_frame = QtGui.QFrame()
mid_frame.setStyleSheet("background-color: rgb(153, 187, 255)")
layout.addWidget(top_frame, 1)
layout.addWidget(QHLine())
layout.addWidget(mid_frame, 20)
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
self.setLayout(layout)
# Top frame
label = QtGui.QLabel('Dashboard')
label.setFont(QtGui.QFont('Times New Roman', 20))
top_layout = QtGui.QHBoxLayout()
top_layout.addWidget(label, alignment=QtCore.Qt.AlignCenter)
top_layout.setContentsMargins(5,5,5,5)
top_frame.setLayout(top_layout)
# Middle frame
self.mid_layout = QtGui.QStackedLayout()
# Create camera widgets
print('Creating Camera Widgets...')
cam_widget = Cam1(cam1, self.screen_width, self.screen_height, self)
self.mid_layout.addWidget(cam_widget)
self.mid_layout.setCurrentWidget(cam_widget)
mid_frame.setLayout(self.mid_layout)
class Cam1(QtGui.QWidget):
def __init__(self, cam1, screen_width, screen_height, parent=None):
super(Cam1, self).__init__(parent)
cam1.set_frame_params(screen_width, screen_height, 'VIDS 01', 1)
# Add widgets to layout
print('Adding widgets to layout...')
layout = QtGui.QGridLayout()
layout.addWidget(cam1.get_video_display_frame(),0,0,1,1)
layout.setContentsMargins(5,5,5,5)
self.setLayout(layout)
configuration_page.py
from PyQt4 import QtGui, QtCore
from global_widgets import *
from ui_main import *
class ZoneConfig(QtGui.QWidget):
def __init__(self, cam1, stacked_widget, parent=None):
super(ZoneConfig, self).__init__(parent)
GlobalObject().addEventListener("hello", self.set_cam)
self.layout = QtGui.QVBoxLayout()
self.frame = QtGui.QFrame()
self.frame_layout = QtGui.QStackedLayout()
# self.setLayout(self.frame_layout)
self.screen_width = self.width()
self.screen_height = self.height()
cam_widget_1 = CameraDisplay(cam1, 1, self.frame_layout, stacked_widget, self)
self.frame_layout.addWidget(cam_widget_1)
self.frame.setLayout(self.frame_layout)
self.layout.addWidget(self.frame)
self.layout.setContentsMargins(0,0,0,0)
self.setLayout(self.layout)
#QtCore.pyqtSlot()
def set_cam(self, index):
if index == 1:
self.frame_layout.setCurrentIndex(0)
class CameraDisplay(QtGui.QWidget):
def __init__(self, cam, idx, frame_layout, stacked_widget, parent=None):
super(CameraDisplay, self).__init__(parent)
self.showMaximized()
self.screen_width = self.width()
self.screen_height = self.height()
self.frame_layout = frame_layout
self.stacked_widget = stacked_widget
print('size: ', self.screen_width, self.screen_height)
# Layouts and frames
layout = QtGui.QVBoxLayout()
top_frame = QtGui.QFrame()
top_frame.setStyleSheet("background-color: rgb(208, 208, 225)")
self.mid_frame = QtGui.QFrame() ## Size of this frame is needed
self.mid_frame.setStyleSheet("background-color: rgb(153, 187, 255)")
btm_frame = QtGui.QFrame()
btm_frame.setStyleSheet("background-color: rgb(208, 208, 225)")
# Top frame
label = QtGui.QLabel('Configuration')
label.setFont(QtGui.QFont('Times New Roman', 20))
top_layout = QtGui.QHBoxLayout()
top_layout.addWidget(label, alignment=QtCore.Qt.AlignCenter)
top_layout.setContentsMargins(5,5,5,5)
top_frame.setLayout(top_layout)
# Middle frame
mid_layout = QtGui.QHBoxLayout()
# Create camera widgets
print('Creating Camera Widgets...')
mid_layout = QtGui.QHBoxLayout()
self.video_frame = cam.get_video_frame()
mid_layout.addWidget(self.video_frame)
mid_layout.setContentsMargins(5,5,5,5)
self.mid_frame.setLayout(mid_layout)
# Bottom frame
btn = QtGui.QPushButton('Dashboard')
btn.clicked.connect(self.goMainWindow)
btm_layout = QtGui.QHBoxLayout()
btm_layout.addStretch()
btm_layout.addWidget(btn)
btm_layout.setContentsMargins(5,5,5,5)
btm_frame.setLayout(btm_layout)
layout.addWidget(top_frame, 1)
layout.addWidget(QHLine())
layout.addWidget(self.mid_frame, 50)
layout.addWidget(QHLine())
layout.addWidget(btm_frame, 1)
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
self.setLayout(layout)
# self.showMaximized()
cam.set_frame_params_1(self.mid_frame.width(), self.mid_frame.height()-10) ## here I want the size
def resizeEvent(self, event):
QtGui.QWidget.resizeEvent(self, event)
def goMainWindow(self):
self.stacked_widget.setCurrentIndex(0)
I think the problem is only in configuration_page.py file but I'm pasting entire code in case anyone wants to go throught the entire logic.
Add the following to your code.
def event(self, e):
if e.type() in (QEvent.Show, QEvent.Resize):
widget_w = self.mid_frame.frameGeometry().width()
widget_h = self.mid_frame.frameGeometry().height()
screen_w = self.width()
screen_h = self.height()
# For "debugging" purposes:
print("Widget - width: %s height: %s" % (widget_w, widget_h)
print("screen - width: %s height: %s" % (screen_w, screen_h)
return ((widget_w, widget_h), (screen_w, screen_h))
#return {"widget": {"width": widget_w, "height": widget_h}, "screen": {"width": screen_w, "height": screen_h}}
Trying to remove a qwidget and replace it with another qwidget and then reload the layout the qwidget is a part of
I've already tried the update and removeWidget method, though i could've used it improperly
from PyQt5.Qt import *
import sys
validUser = False
app = None
class App(QMainWindow):
def __init__(self):
super().__init__()
screen = app.primaryScreen().size()
self.title = 'Restaurant Application'
width = screen.width()
height = screen.height()
self.left = 0
self.top = 0
self.width = width
self.height = height
self.setMouseTracking(True)
self.table_widget = MyTableWidget(self)
self.setCentralWidget(self.table_widget)
self.initUI()
self.show()
def initUI(self):
# window
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
# statusbar
self.statusBar().showMessage('Welcome to el restaurante')
def mousePressEvent(self, event):
print('Mouse coords: ( %d : %d )' % (event.x(), event.y()))
class MyTableWidget(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
# Initialize tab screen
self.tabs = QTabWidget()
self.login = QWidget()
self.menu = QWidget()
self.checkOut = QWidget()
self.tabs.resize(500, 200)
# Add tabs
self.tabs.addTab(self.login, "Login")
self.tabs.addTab(self.menu, "Menu")
self.tabs.addTab(self.checkOut, "Check out")
# Create login tab
self.login.layout = QVBoxLayout(self)
self.menu.layout = QVBoxLayout(self)
# login text
self.loginPrompt = QLabel("Please provide a valid login")
self.loginPrompt.setFixedSize(315,30)
self.loginPromptFont = QFont("Times", 27, QFont.Bold)
self.loginPrompt.setFont(self.loginPromptFont)
self.login.layout.addWidget(self.loginPrompt)
self.login.setLayout(self.login.layout)
# Create textbox
self.loginTextbox = QLineEdit(self)
self.loginTextbox.returnPressed.connect(self.on_click_login)
self.loginTextbox.setFixedSize(170,20)
# Create a button in the window
self.loginButton = QPushButton('Login button', self)
self.loginButton.clicked.connect(self.on_click_login)
self.loginButton.setFixedSize(100,40)
self.login.layout.addWidget(self.loginTextbox,alignment=Qt.AlignCenter)
self.login.layout.addWidget(self.loginButton,alignment=Qt.AlignCenter)
#widget code i use to decide which widget to add
self.menuInvalidUserLogin = QLabel("Please login in to view")
self.menuValidUserLogin = QLabel("Here's the menu")
if(validUser):
self.menu.layout.addWidget(self.menuValidUserLogin)
else:
self.menu.layout.addWidget(self.menuInvalidUserLogin)
self.menu.setLayout(self.menu.layout)
# Add tabs to widget
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
def on_click_login(self):
global validUser
global app
textboxValue = self.loginTextbox.text()
if(textboxValue.lower() == 'pass'):
validUser=True
#the solutions i have been trying
self.menu.layout.removeWidget(self.menuInvalidUserLogin)
self.layout.removeWidget(self.menuInvalidUserLogin)
self.menu.layout.update()
QMessageBox.question(self, 'Response', "Login successful: Welcome", QMessageBox.Ok,QMessageBox.Ok)
else:
validUser=False
QMessageBox.question(self, 'Response', "Login unsuccessful: EXPLAIN YOURSELF", QMessageBox.Ok,QMessageBox.Ok)
self.loginTextbox.setText("")
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
expected results should be that the old widget is removed, new widget is added and then the layout those widgets are a part of is refreshed
Is this what you were expecting?
Also, is there a specific reason why you are using global variables in your class? It is bad practice, you should make them class members.
from PyQt5 import QtWidgets, QtCore, QtGui
import sys
class App(QtWidgets.QMainWindow):
def __init__(self):
super(App,self).__init__()
app = QtWidgets.QApplication.instance()
screen = app.primaryScreen().size()
self.title = 'Restaurant Application'
width = screen.width()
height = screen.height()
self.left = 0
self.top = 0
self.width = width
self.height = height
self.setMouseTracking(True)
self.table_widget = MyTableWidget(self)
self.setCentralWidget(self.table_widget)
self.initUI()
self.show()
def initUI(self):
# window
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
# statusbar
self.statusBar().showMessage('Welcome to el restaurante')
def mousePressEvent(self, event):
print('Mouse coords: ( %d : %d )' % (event.x(), event.y()))
class MyTableWidget(QtWidgets.QWidget):
def __init__(self, parent):
super(MyTableWidget, self).__init__(parent)
self.layout = QtWidgets.QVBoxLayout()
self.validUser = False
# Initialize tab screen
self.tabs = QtWidgets.QTabWidget()
self.login = QtWidgets.QWidget()
self.menu = QtWidgets.QWidget()
self.checkOut = QtWidgets.QWidget()
self.tabs.resize(500, 200)
# Add tabs
self.tabs.addTab(self.login, "Login")
self.tabs.addTab(self.menu, "Menu")
self.tabs.addTab(self.checkOut, "Check out")
# Create login tab
self.login.layout = QtWidgets.QVBoxLayout()
self.menu.layout = QtWidgets.QVBoxLayout()
# login text
self.loginPrompt = QtWidgets.QLabel("Please provide a valid login")
self.loginPrompt.setFixedSize(315,30)
self.loginPromptFont = QtGui.QFont("Times", 27, QtGui.QFont.Bold)
self.loginPrompt.setFont(self.loginPromptFont)
self.login.layout.addWidget(self.loginPrompt)
self.login.setLayout(self.login.layout)
# Create textbox
self.loginTextbox = QtWidgets.QLineEdit()
self.loginTextbox.returnPressed.connect(self.on_click_login)
self.loginTextbox.setFixedSize(170,20)
# Create a button in the window
self.loginButton = QtWidgets.QPushButton('Login button')
self.loginButton.clicked.connect(self.on_click_login)
self.loginButton.setFixedSize(100,40)
self.login.layout.addWidget(self.loginTextbox,alignment=QtCore.Qt.AlignCenter)
self.login.layout.addWidget(self.loginButton,alignment=QtCore.Qt.AlignCenter)
#widget code i use to decide which widget to add
self.menuInvalidUserLogin = QtWidgets.QLabel("Please login in to view")
self.menuValidUserLogin = QtWidgets.QLabel("Here's the menu")
if(self.validUser):
self.menu.layout.addWidget(self.menuValidUserLogin)
else:
self.menu.layout.addWidget(self.menuInvalidUserLogin)
self.menu.setLayout(self.menu.layout)
# Add tabs to widget
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
def on_click_login(self):
textboxValue = self.loginTextbox.text()
if(textboxValue.lower() == 'pass'):
self.validUser=True
for i in reversed(range(self.menu.layout.count())):
widgetToRemove = self.menu.layout.itemAt(i).widget()
self.menu.layout.removeWidget(widgetToRemove)
widgetToRemove.deleteLater()
self.menu.layout.addWidget(self.menuValidUserLogin)
QtWidgets.QMessageBox.question(self, 'Response', "Login successful: Welcome", QtWidgets.QMessageBox.Ok,QtWidgets.QMessageBox.Ok)
self.tabs.setCurrentIndex(1)
else:
self.validUser=False
QtWidgets.QMessageBox.question(self, 'Response', "Login unsuccessful: EXPLAIN YOURSELF", QtWidgets.QMessageBox.Ok,QtWidgets.QMessageBox.Ok)
self.loginTextbox.setText("")
def main():
app = QtWidgets.QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
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_())
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()