How can I open and close a new window from main window in PyQt? - pyqt5

I searched in Google usually many posts are talking about how to open a new window and not indicating how to close the window. I found several posts in this website but most of them are using dialog window which is not considered in my software.
I make a UI, which contains a spin box and a button, to demonstrate my problem. I can type in a number equal or less than 5 in spin box. When I click the button, a number of new windows will show up and how many windows will show up is depending on the number in the spin box. If I change to the number in spin box then click the button, the original windows will be closed and new windows will be shown.
Fox example, first I type in "2" in spin box then click the button. Then 2 new windows will show up. If I change the number in spin box to 3 then click the button, the original 2 windows will be closed and 3 new windows will show up.
Here is my main program code:
from PyQt5.QtWidgets import QApplication, QMainWindow
from uitest_review import Ui_MainWindow # import the UI module
# set up a class for main window
class window(QMainWindow):
def __init__(self, parent=None):
super(window, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.Open.clicked.connect(self.openwindow)
def openwindow(self):
windownum = self.ui.windownum.value()
print("open window num:", windownum)
opennewwindow = newwindow(self)
opennewwindow.show()
class newwindow(QMainWindow):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
if __name__ == "__main__":
app = QApplication([])
gui = window()
gui.show()
app.exec_()
Here is my UI code:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(816, 577)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 796, 537))
self.scrollAreaWidgetContents.setObjectName(\
"scrollAreaWidgetContents")
self.verticalLayout = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
spacerItem = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
self.verticalLayout.addItem(spacerItem)
self.windownum = QtWidgets.QSpinBox(self.scrollAreaWidgetContents)
self.windownum.setMaximum(5)
self.windownum.setObjectName("windownum")
self.verticalLayout.addWidget(self.windownum)
self.groupBox = QtWidgets.QGroupBox(self.scrollAreaWidgetContents)
self.groupBox.setTitle("")
self.groupBox.setObjectName("groupBox")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.groupBox)
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
self.Open = QtWidgets.QPushButton(self.groupBox)
font = QtGui.QFont()
font.setPointSize(14)
font.setBold(True)
font.setWeight(75)
self.Open.setFont(font)
self.Open.setObjectName("Open")
self.horizontalLayout.addWidget(self.Open)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem2)
self.verticalLayout.addWidget(self.groupBox)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.gridLayout.addWidget(self.scrollArea, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.Open.setText(_translate("MainWindow", "Open"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
I create a new class (newwindow) in my main program and I can call this class to show a new window. But I cannot figure out how to detect how many windows is opened and how to close them. Does anyone can help me? Thank you so much.

I figured out by myself.
class window(QMainWindow):
def __init__(self, parent=None):
super(window, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.Open.clicked.connect(self.openwindow)
self.openedwin = []
def openwindow(self):
windownum = self.ui.windownum.value()
if windownum != 0:
if self.openedwin != []:
for window in self.openedwin:
window.close()
for repeat in range(windownum):
opennewwindow = newwindow(self)
# print("opennewwindow:", opennewwindow)
self.openedwin.append(opennewwindow)
opennewwindow.show()
# print("self.openedwin:", self.openedwin)
class newwindow(QMainWindow):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
if __name__ == "__main__":
app = QApplication([])
gui = window()
gui.show()
app.exec_()
I add a list self.openedwin = [] to save all window objects. I can use "window object".close() command to close the window before opening new one.

Related

PyQt application not functioning properly when being used with threads [duplicate]

This question already has answers here:
In PyQt, what is the best way to share data between the main window and a thread
(1 answer)
Example of the right way to use QThread in PyQt?
(3 answers)
Background thread with QThread in PyQt
(7 answers)
Closed 4 months ago.
I have created a UI which contains a text edit control. Below is its code:
home.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
self.textEdit.setGeometry(QtCore.QRect(130, 140, 301, 241))
self.textEdit.setObjectName("textEdit")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Below is the main.py:
import sys
import time
from home import Ui_MainWindow
from PyQt5.QtWidgets import QApplication, QMainWindow
from threading import Thread
class UI(QMainWindow, Ui_MainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.textEdit.append("Application starting")
Thread(target=self.startProc).start()
def startProc(self):
i = 0
while True:
i = i + 1
self.ui.textEdit.append("Current value: {}".format(i))
time.sleep(1)
if i == 5:
break
app = QApplication(sys.argv)
main_window = UI()
main_window.show()
sys.exit(app.exec_())
So in above code, I am creating a thread (startProc) which runs for 5sec and then break. This code is working fine in Windows 10 and executes normally but when running it in Ubuntu 18.04, it runs fine and as soon as the thread stops, the whole app crashes with below errors:
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
Is there any specific reason that its working fine on Windows but not in Ubuntu? How can I resolve this issue?

PyQt5) When I try to open Second window, it is closed without any error messages

I'm trying to open second window on main window.
I made 2 classes for each windows, and run the code. when I click the button on main window, the main window is closed and second windows show. but after 1 seconds the second window is closed and the process ends.
Really I don't know why it does...
from PyQt5 import QtWidgets
import sys
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(400, 300)
# Button
self.button = QtWidgets.QPushButton(self)
self.button.setGeometry(0, 0, 400, 300)
self.button.setText('Open Sub Window')
self.button.setStyleSheet('font-size:40px')
self.button.clicked.connect(self.sub_show)
def sub_show(self):
self.hide()
self.sub_window = SubWindow()
self.sub_window.exec()
self.show()
class SubWindow(QtWidgets.QWidget):
def __init__(self):
super(SubWindow, self).__init__()
self.resize(400, 300)
self.button2 = QtWidgets.QPushButton(self)
self.button2.setGeometry(0, 0, 400, 300)
self.button2.setText('Back to Main window')
self.button2.setStyleSheet('font-size:40px')
self.button2.clicked.connect(self.home)
self.show()
def home(self):
self.close()
if __name__ == "__main__" :
app = QtWidgets.QApplication([])
mw = MainWindow()
mw.show()
sys.exit(app.exec())
You are calling show a few to many times. Also QWidget doesn't have an exec method. You will also want the first window to reappear when you close the second I assume.
I made some changes in the example below. Give it a try:
from PyQt5 import QtWidgets
import sys
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(400, 300)
self.button = QtWidgets.QPushButton(self)
self.button.setGeometry(0, 0, 400, 300)
self.button.setText('Open Sub Window')
self.button.setStyleSheet('font-size:40px')
self.button.clicked.connect(self.sub_show)
def sub_show(self):
self.hide()
self.sub_window = SubWindow()
# connect signal to show again when button2 is pressed
self.sub_window.button2.clicked.connect(self.show)
self.sub_window.show()
class SubWindow(QtWidgets.QWidget):
def __init__(self):
super(SubWindow, self).__init__()
self.resize(400, 300)
self.button2 = QtWidgets.QPushButton(self)
self.button2.setGeometry(0, 0, 400, 300)
self.button2.setText('Back to Main window')
self.button2.setStyleSheet('font-size:40px')
self.button2.clicked.connect(self.close)
if __name__ == "__main__" :
app = QtWidgets.QApplication([])
mw = MainWindow()
mw.show()
sys.exit(app.exec())

PYQT5 webcam is not opening on the label

I am trying to set my webcam to a label and open it on pageload. However code does not throw any error also it does not getting bind to the label as well. Can anyone tell me how to fix this?
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'camera.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow,qApp
import sys
import cv2
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget)
self.gridLayoutWidget.setGeometry(QtCore.QRect(169, 59, 471, 251))
self.gridLayoutWidget.setObjectName("gridLayoutWidget")
self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.label = QtWidgets.QLabel(self.gridLayoutWidget)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.capture = cv2.cv2.VideoCapture(0)
timer = QtCore.QTimer()
timer.setInterval(int(1000/30))
timer.timeout.connect(self.get_frame)
timer.start()
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def get_frame(self):
frame = self.capture.read()
image = QtGui.QImage(frame, *frame.shape[1::-1], QtGui.QImage.Format_RGB888).rgbSwapped()
pixmap = QtGui.QPixmap.fromImage(image)
self.label.setPixmap(pixmap)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
The problem is that timer is a local variable that will be destroyed so the get_frame method will not be invoked, the solution is to make it a member of the class so you must change timer to self.timer. Also the read() method returns a tuple, no the frame so you should change it to:
def get_frame(self):
ret, frame = self.capture.read()
if ret:
image = QtGui.QImage(
frame, *frame.shape[1::-1], QtGui.QImage.Format_RGB888
).rgbSwapped()
pixmap = QtGui.QPixmap.fromImage(image)
self.label.setPixmap(pixmap)

The QTableWidget always scrolls to setColumn/RowCount automatically

I am currently trying to add a file (that changes periodically) to a QTable widget. However, the row and column also changes permanently.
To delete old information:
self.tableWidget.setRowCount(0)
self.tableWidget.setColumnCount(0)
Change to new list length:
self.tableWidget.setRowCount(len(someList))
self.tableWidget.setColumnCount(4)
After that the scroll position is at the top. Although I also did the following:
self.tableWidget.setAutoScroll(False)
pos = self.tableWidget.verticalScrollBar().value()
#Change the column row size
#check max>=pos
self.tableWidget.verticalScrollBar().setValue(pos)
Everything is ignored and it scrolls up anyway.
My code example:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer
import sys
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(618, 510)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents_2 = QtWidgets.QWidget()
self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 594, 440))
self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2")
self.gridLayout_2 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2)
self.gridLayout_2.setObjectName("gridLayout_2")
self.tableWidget = QtWidgets.QTableWidget(self.scrollAreaWidgetContents_2)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(4)
self.tableWidget.setRowCount(20)
self.gridLayout_2.addWidget(self.tableWidget, 0, 0, 1, 1)
self.scrollArea.setWidget(self.scrollAreaWidgetContents_2)
self.gridLayout.addWidget(self.scrollArea, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 618, 25))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.qTimer = QTimer()
self.qTimer.setInterval(1000)
self.qTimer.timeout.connect(self.getData)
self.qTimer.start()
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
def getData(self):
self.tableWidget.setRowCount(0)
self.tableWidget.setColumnCount(0)
self.tableWidget.setColumnCount(4)
self.tableWidget.setRowCount(20)
#Problem: Scrolls to top
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Changing the layout of an item model requires a certain amount of time to the view that is showing it.
In order to ensure that the scroll bar is updated, you can ask Qt to "process" its current event queue:
def getData(self):
pos = self.tableWidget.verticalScrollBar().value()
self.tableWidget.setRowCount(0)
self.tableWidget.setColumnCount(0)
self.tableWidget.setColumnCount(4)
self.tableWidget.setRowCount(20)
QtWidgets.QApplication.processEvents()
self.tableWidget.verticalScrollBar().setValue(pos)
On the other hand, to minimize unnecessary requests on the table and avoid flickering, you should set the row count to the new amount instead of resetting it everytime. In this way you don't need to move the scroll bar everytime, as it will always try to keep its previous position, even if the new row count is less than before.
Note: you should not modify (nor try to mimic) the files generated by pyuic, as those files have to be imported in your main script(s) instead. Read more about using Designer.

pyqt5 videowidget not showing in layout

I am writing a program with pyqt5 where pressing a button first cycles through some pictures then cycles through some videos.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
import glob
import argparse
import sys
class MainWindow(QMainWindow):
def __init__(self,args):
super(MainWindow, self).__init__()
self.setWindowTitle('Navon test')
self.setWindowFlags(Qt.FramelessWindowHint)
# exit option for the menu bar File menu
self.exit = QAction('Exit', self)
self.exit.setShortcut('Ctrl+q')
# message for the status bar if mouse is over Exit
self.exit.setStatusTip('Exit program')
# newer connect style (PySide/PyQT 4.5 and higher)
self.exit.triggered.connect(app.quit)
self.setWindowIcon(QIcon('icon.ico'))
self.centralwidget = CentralWidget(args)
self.setCentralWidget(self.centralwidget)
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
QCoreApplication.instance().quit()
self.centralwidget.startvid()
class CentralWidget(QWidget):
def __init__(self,args):
super(CentralWidget, self).__init__()
self.layout = QVBoxLayout()
self.layout.setAlignment(Qt.AlignCenter)
self.setLayout(self.layout)
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.vw = QVideoWidget()
self.player.setVideoOutput(self.vw)
def startvid(self):
self.layout.addWidget(self.vw)
url= QUrl.fromLocalFile(glob.glob("videos/*")[0])
content= QMediaContent(url)
self.player.setMedia(content)
self.player.setVideoOutput(self.vw)
self.player.play()
if __name__== "__main__":
parser = argparse.ArgumentParser()
#~ parser.add_argument("-nb","--nobox",action="store_true", help="do not wait for the box connection")
args = parser.parse_args()
app = QApplication(sys.argv)
mainwindow = MainWindow(args)
#~ mainwindow.showFullScreen()
mainwindow.show()
sys.exit(app.exec_())
I tried to paste the minimal code. The thing is, I press the button nothing shows, although I used examples like this one PyQt5 - Can't play video using QVideoWidget to test if playing the video is ok, and these work. It's as if it is not adding the widget to the layout or something. Any idea what might be wrong?
I had to use QGraphicsView to achieve what I wanted, here is a fix:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
import glob
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle('Navon test')
self.setWindowFlags(Qt.FramelessWindowHint)
# exit option for the menu bar File menu
self.exit = QAction('Exit', self)
self.exit.setShortcut('Ctrl+q')
# message for the status bar if mouse is over Exit
self.exit.setStatusTip('Exit program')
# newer connect style (PySide/PyQT 4.5 and higher)
self.exit.triggered.connect(app.quit)
self.setWindowIcon(QIcon('icon.ico'))
self.centralwidget = VideoPlayer()
self.setCentralWidget(self.centralwidget)
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
self.centralwidget.phaseQuit(2)
self.centralwidget.play()
class VideoPlayer(QWidget):
def __init__(self, parent=None):
super(VideoPlayer, self).__init__(parent)
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.videoItem = QGraphicsVideoItem()
self.videoItem.setSize(QSizeF(640, 480))
scene = QGraphicsScene(self)
graphicsView = QGraphicsView(scene)
scene.addItem(self.videoItem)
layout = QVBoxLayout()
layout.addWidget(graphicsView)
self.setLayout(layout)
self.mediaPlayer.setVideoOutput(self.videoItem)
self.counter = 0
def play(self):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
pass
else:
self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(glob.glob("videos/*")[self.counter])))
self.mediaPlayer.play()
self.counter += 1
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
player = MainWindow()
player.show()
sys.exit(app.exec_())