PyQt5 switch between windows - pyqt

I want to create menu based on tiles. Now I need PyQt5 concept how to switch MainWindow to Window1/Window2/... with back option to MainWindow. The only thing I've achieved is opening a new window on top. I'd rather have separate windows, where I could define different functions.
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
from PyQt5.QtCore import pyqtSlot
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.title = "App"
self.top = 100
self.left = 100
self.width = 680
self.height = 500
self.InitUI()
def InitUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.top, self.left, self.width, self.height)
buttonWindow1 = QPushButton('Window1', self)
buttonWindow1.move(100, 100)
buttonWindow1.clicked.connect(self.buttonWindow1_onClick)
buttonWindow2 = QPushButton('Window2', self)
buttonWindow2.move(100, 200)
buttonWindow2.clicked.connect(self.buttonWindow2_onClick)
self.show()
#pyqtSlot()
def buttonWindow1_onClick(self):
self.statusBar().showMessage("Switched to window 1")
#pyqtSlot()
def buttonWindow2_onClick(self):
self.statusBar().showMessage("Switched to window 2")
if __name__ == '__main__':
app=QApplication(sys.argv)
ex=Window()
sys.exit(app.exec_())

Try it:
import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.title = "App"
self.top = 100
self.left = 100
self.width = 680
self.height = 500
self.InitUI()
def InitUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.top, self.left, self.width, self.height)
buttonWindow1 = QPushButton('Window1', self)
buttonWindow1.move(100, 100)
buttonWindow1.clicked.connect(self.buttonWindow1_onClick)
self.lineEdit1 = QLineEdit("Type here what you want to transfer for [Window1].", self)
self.lineEdit1.setGeometry(250, 100, 400, 30)
buttonWindow2 = QPushButton('Window2', self)
buttonWindow2.move(100, 200)
buttonWindow2.clicked.connect(self.buttonWindow2_onClick)
self.lineEdit2 = QLineEdit("Type here what you want to transfer for [Window2].", self)
self.lineEdit2.setGeometry(250, 200, 400, 30)
self.show()
#pyqtSlot()
def buttonWindow1_onClick(self):
self.statusBar().showMessage("Switched to window 1")
self.cams = Window1(self.lineEdit1.text())
self.cams.show()
self.close()
#pyqtSlot()
def buttonWindow2_onClick(self):
self.statusBar().showMessage("Switched to window 2")
self.cams = Window2(self.lineEdit2.text())
self.cams.show()
self.close()
class Window1(QDialog):
def __init__(self, value, parent=None):
super().__init__(parent)
self.setWindowTitle('Window1')
self.setWindowIcon(self.style().standardIcon(QStyle.SP_FileDialogInfoView))
label1 = QLabel(value)
self.button = QPushButton()
self.button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
self.button.setIcon(self.style().standardIcon(QStyle.SP_ArrowLeft))
self.button.setIconSize(QSize(200, 200))
layoutV = QVBoxLayout()
self.pushButton = QPushButton(self)
self.pushButton.setStyleSheet('background-color: rgb(0,0,255); color: #fff')
self.pushButton.setText('Click me!')
self.pushButton.clicked.connect(self.goMainWindow)
layoutV.addWidget(self.pushButton)
layoutH = QHBoxLayout()
layoutH.addWidget(label1)
layoutH.addWidget(self.button)
layoutV.addLayout(layoutH)
self.setLayout(layoutV)
def goMainWindow(self):
self.cams = Window()
self.cams.show()
self.close()
class Window2(QDialog):
def __init__(self, value, parent=None):
super().__init__(parent)
self.setWindowTitle('Window2')
self.setWindowIcon(self.style().standardIcon(QStyle.SP_FileDialogInfoView))
label1 = QLabel(value)
self.button = QPushButton()
self.button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
self.button.setIcon(self.style().standardIcon(QStyle.SP_ArrowLeft))
self.button.setIconSize(QSize(200, 200))
layoutV = QVBoxLayout()
self.pushButton = QPushButton(self)
self.pushButton.setStyleSheet('background-color: rgb(0,0,255); color: #fff')
self.pushButton.setText('Click me!')
self.pushButton.clicked.connect(self.goMainWindow)
layoutV.addWidget(self.pushButton)
layoutH = QHBoxLayout()
layoutH.addWidget(label1)
layoutH.addWidget(self.button)
layoutV.addLayout(layoutH)
self.setLayout(layoutV)
def goMainWindow(self):
self.cams = Window()
self.cams.show()
self.close()
if __name__ == '__main__':
app=QApplication(sys.argv)
ex=Window()
sys.exit(app.exec_())

Try this:
from file2 import Ui_Dialog2 #------>import the class for next window
def buttonWindow1_onClick(self):
self.window=QtWidgets.QMainWindow()
self.ui=Ui_Dialog2() #------------->creating an object
self.ui.setupUi(self.window)
self.window.show()
Here the Ui_Dialog2() represents that your are creating an object for new window (in your case creating object for Window1 for switch MainWindow to Window1 ).So when you click the next button this function is called so an object is created for the next window and the window will be opened.

Related

PyQt5 - How can I delete the default empty field placed around a Tab widget?

I'm writing a GUI with PyQt5 and I realized that the Tab widgets have a default empty field placed around them (see the attached screenshot). How can I delete it?
Here is an example:
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QTabWidget, QVBoxLayout
class App(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'PyQt5 tabs'
self.left = 0
self.top = 0
self.width = 300
self.height = 200
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.table_widget = MyTableWidget(self)
self.setCentralWidget(self.table_widget)
self.setStyleSheet("background-color:red")
self.show()
class MyTableWidget(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
self.tabs = QTabWidget()
self.tab1 = QWidget()
self.tab2 = QWidget()
self.tabs.resize(300,200)
self.tabs.addTab(self.tab1,"Tab 1")
self.tabs.addTab(self.tab2,"Tab 2")
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())

Catch final signal from QTimer object

I have a simple PyQt script. When I click a button, it starts a QTimer object and increments a progress bar. What I want is to change the label of my text when my progress bar reaches 100%. It worked for me once, but I can't get it to work anymore. What am I doing wrong?
Here's the main part of my code.
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QProgressBar demo')
self.timerButton = QPushButton("Start", self)
self.timerButton.clicked.connect(self.timerStart)
self.timerObject = QTimer(self)
#self.timerObject.destroyed.connect(lambda:self.timerButton.setText("Finished") )
self.timerObject.destroyed.connect(lambda:print("Called" ))
self.progressBar = QProgressBar(self)
self.progressBar.setGeometry(10, 20, 290, 25)
self.timerButton.move(110,150)
self.progressBar.move(10,100)
self.increment = 0
self.resize(300, 300)
self.show()
#pyqtSlot()
def headsUp(self):
if(self.increment >= 100):
self.timerObject.stop()
else:
self.increment += 1
self.progressBar.setValue(self.increment)
return
def timerStart(self):
if (self.timerObject.isActive()):
self.timerObject.stop()
self.timerButton.setText("Resume")
else:
self.timerObject.timeout.connect(self.headsUp)
self.timerButton.setText("Pause")
self.timerObject.start(100)
destroyed is only issued when you delete the object, that a QTimer peer does not imply that it is deleted from memory, therefore it does not emit that signal, a possible solution is to create a signal for the QProgressBar when the value takes the maximum value as shown below:
import sys
from PyQt5 import QtCore, QtWidgets
class ProgressBar(QtWidgets.QProgressBar):
finished = QtCore.pyqtSignal()
def __init__(self, *args, **kwargs):
super(ProgressBar, self).__init__(*args, *kwargs)
self.valueChanged.connect(self.on_valueChanged)
#QtCore.pyqtSlot(int)
def on_valueChanged(self, val):
if val == self.maximum():
self.finished.emit()
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QProgressBar demo')
self.timerButton = QtWidgets.QPushButton("Start", self)
self.timerButton.clicked.connect(self.timerStart)
self.timerObject = QtCore.QTimer(self)
self.progressBar = ProgressBar(self)
self.progressBar.finished.connect(lambda: print("Called" ))
self.increment = 0
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.progressBar)
lay.addWidget(self.timerButton)
self.resize(300, 300)
#QtCore.pyqtSlot()
def headsUp(self):
if self.increment >= 100:
self.timerObject.stop()
else:
self.increment += 1
self.progressBar.setValue(self.increment)
#QtCore.pyqtSlot()
def timerStart(self):
if self.timerObject.isActive():
self.timerObject.stop()
self.timerButton.setText("Resume")
else:
self.timerObject.timeout.connect(self.headsUp)
self.timerButton.setText("Pause")
self.timerObject.start(100)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Another best option is to use QTimeLine and its finished signal:
import sys
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QProgressBar demo')
self.timerButton = QtWidgets.QPushButton("Start", self)
self.timerButton.clicked.connect(self.timerStart)
self.timerObject = QtCore.QTimeLine(1000, self)
self.timerObject.setFrameRange(0, 100)
self.progressBar = QtWidgets.QProgressBar(self)
self.timerObject.frameChanged.connect(self.progressBar.setValue)
self.timerObject.finished.connect(lambda: print("Called" ))
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.progressBar)
lay.addWidget(self.timerButton)
self.resize(300, 300)
#QtCore.pyqtSlot()
def timerStart(self):
if self.timerObject.state() == QtCore.QTimeLine.Running:
self.timerObject.stop()
self.timerButton.setText("Resume")
else:
self.timerButton.setText("Pause")
self.timerObject.resume()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
This isn't working because you are connecting to the timers destoryed signal, but the timer is not being destroyed. To use this code as is, call self.timerObject.deleteLater() after you stop the timer.

PyQt change picture with keyboard button

this is my first post here and I haven't seen it anywhere so hopefully it is ok. I am trying to change the displayed image with a keyboard click (think slideshow). This is my code so far:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt
import os
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'Document Analysis'
self.left = 30
self.top = 30
self.width = 640
self.height = 480
self.imagenumber=0
self.initUI()
def keyPressEvent(self, event):
key=event.key()
if key==Qt.Key_Right:
self.imagenumber=self.imagenumber+1
self.showimage(self.imagenumber)
self.show()
else:
super(self).keyPressEvent(event)
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.showimage(0)
self.show()
def showimage(self,imagenumber):
label = QLabel(self)
directory = "C:\\Desktop\\Pictures"
imagelist = os.listdir(directory)
pixmap = QPixmap(directory + '\\' + imagelist[imagenumber])
label.setPixmap(pixmap)
self.resize(pixmap.width() + 500, pixmap.height())
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
It seems to be sort of getting somewhere, the first image displays just fine, and I know imagenumber does change, and when I stopped it from showing at first it resized the window but still didn't show the image. Any suggestions on what I am doing wrong?
This is part of a larger project which is the reason for the extra space on the side of the picture, but help would be appreciated.
You're close. Try the following...
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt
import os
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'Document Analysis'
self.left = 30
self.top = 30
self.width = 640
self.height = 480
self.imagenumber=0
self.initUI()
def keyPressEvent(self, event):
key=event.key()
if key==Qt.Key_Right:
self.imagenumber=self.imagenumber+1
self.showimage(self.imagenumber)
# self.show()
else:
super(self).keyPressEvent(event)
def initUI(self):
layout = QVBoxLayout()
self.setLayout(layout)
self.label = QLabel(self)
layout.addWidget(self.label)
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.showimage(0)
self.show()
def showimage(self,imagenumber):
# label = QLabel(self)
directory = "C:\\Desktop\\Pictures"
imagelist = os.listdir(directory)
pixmap = QPixmap(directory + '\\' + imagelist[imagenumber])
# label.setPixmap(pixmap)
self.label.setPixmap(pixmap)
self.resize(pixmap.width() + 500, pixmap.height())
# self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Mainly, you need a persistent label. You also only need to call show() once.

Video Speed is too first in PyQt5, Opencv

When i run this code the video speed is very fast. Maybe it is happening because of the frame rate(because different frame rate is used for HD and FHD). How can i solve the issue and fixed the frame rate.i use cap.set(15,-.8) to slow down the frame rate but it doesn't work.The video size is 1080p(full HD).
import sys
import cv2
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
import datetime
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'PyQt5 Video'
self.left = 100
self.top = 100
self.width = 640
self.height = 480
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.resize(1800, 1200)
# create a label
# create a label
label = QLabel(self)
label.move(280, 120)
label.resize(640, 480)
label1 = QLabel(self)
label1.move(580, 620)
self.th = Thread(self)
self.th.changePixmap.connect(label.setPixmap)
self.th.changeLabel.connect(label1.setText)
self.th.start()
def closeEvent(self, event):
self.th.stop()
QWidget.closeEvent(self, event)
class Thread(QThread):
changePixmap = pyqtSignal(QPixmap)
changeLabel = pyqtSignal(str)
def __init__(self, parent=None):
QThread.__init__(self, parent=parent)
self.isRunning = True
def run(self):
cap = cv2.VideoCapture('a.mp4')
while self.isRunning:
ret, frame = cap.read()
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
convertToQtFormat = QImage(rgbImage.data, rgbImage.shape[1], rgbImage.shape[0], QImage.Format_RGB888)
convertToQtFormat = QPixmap.fromImage(convertToQtFormat)
p = convertToQtFormat.scaled(640, 400, Qt.KeepAspectRatio)
self.changePixmap.emit(p)
now = datetime.datetime.now()
sec = now.second
self.changeLabel.emit(str(sec))
def stop(self):
self.isRunning = False
self.quit()
self.wait()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())

QWidget cannot display on QMainWindow instance PyQt5

I am learning PyQt5 now and tried to do something little on my own. I have made a very basic custom toolbox, which has just 6 QPushButtons buttons on it, which inherits from QWidget class.
My problem is that I can't display my toolbox on my QMainWidow instance. Let me show you what I did;
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class ToolBox(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
btn = [QPushButton('B', self) for i in range(6)]
for Btn in btn:
Btn.resize(30, 30)
self.resize(60, 90)
k = 0
for i in range(6):
btn[i].move((i%2)*30, k*30)
k += 1 if i % 2 == 1 else 0
self.show()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.resize(300, 200)
self.statusBar().showMessage('Ready!')
exitAction = QAction(QIcon('idea.png'), 'Exit', self)
exitAction.setStatusTip('Exit application')
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(qApp.quit)
menuBar = self.menuBar()
fileMenu = menuBar.addMenu('File')
fileMenu.addAction(exitAction)
t = ToolBox()
t.move(150, 150)
t.show() #With and without this line, it doesn't work.
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
m = MainWindow()
sys.exit(app.exec_())
You just need to position your widget somewhere in the QMainWindow canvas. All you have to do is position it in the MainWindow. Just for an example, I use setCentralWidget() to position your QWidget.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class ToolBox(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
btn = [QPushButton('B', self) for i in range(6)]
for Btn in btn:
Btn.resize(30, 30)
self.resize(60, 90)
k = 0
for i in range(6):
btn[i].move((i%2)*30, k*30)
k += 1 if i % 2 == 1 else 0
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.resize(300, 200)
self.statusBar().showMessage('Ready!')
exitAction = QAction(QIcon('idea.png'), 'Exit', self)
exitAction.setStatusTip('Exit application')
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(qApp.quit)
menuBar = self.menuBar()
fileMenu = menuBar.addMenu('File')
fileMenu.addAction(exitAction)
t = ToolBox()
self.setCentralWidget(t)
if __name__ == '__main__':
app = QApplication(sys.argv)
m = MainWindow()
m.show()
sys.exit(app.exec_())

Resources