PyQt - how to rerender window - python

I am new to PyQt and Qt at all and I have a problem with window rendering or updating or how to call it. Problem is that when I call QWidget.show(), none of added components after are displayed. Here is a simple code, where in init(), there is called self.show(). First QLabel item is displayed and the second one is not. What am I doing wrong?
Code:
from PyQt6.QtWidgets import QApplication, QWidget, QLabel
import sys
class MyGui(QWidget):
box = {}
def __init__(self) -> None:
super().__init__()
self.setFixedSize(200, 400)
self.setStyleSheet("background-color:#000000")
self.box["top"] = QLabel(self)
self.box["top"].setFixedSize(200, 200)
self.box["top"].setStyleSheet("background-color:red")
self.box["top"].move(0,0)
self.show()
self.box["botom"] = QLabel(self)
self.box["botom"].setFixedSize(200, 200)
self.box["botom"].setStyleSheet("background-color:green")
self.box["botom"].move(0,200)
if __name__ == "__main__":
app = QApplication(sys.argv)
my_app = MyGui()
my_app.show()
try:
sys.exit(app.exec())
except SystemExit:
print("Closing window..")
Screenshots of GUI window:
With self.show()
Without self.show()

Related

Timers cannot be stopped from another thread - Remove Focus

import sys
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit
class Worker(QThread):
def __init__(self, textBox):
super().__init__()
self.textBox = textBox
def run(self):
while True:
if self.textBox.text() == "close":
app.quit()
break
if self.textBox.text() == "removeFocus":
self.textBox.clearFocus()
class window(QWidget):
def __init__(self):
super().__init__()
vBox = QVBoxLayout()
self.setLayout(vBox)
self.resize(600, 400)
textBox = QLineEdit()
vBox.addWidget(textBox)
worker = Worker(textBox)
worker.start()
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = window()
sys.exit(app.exec())
When I type "close" in the textBox it works very fine but when I type "removeFocus", it still works but I get this error:
QObject::killTimer: Timers cannot be stopped from another thread
Why am I getting such an error even though the program is running?
(Since the process I want to do is very simple, I don't think I can go into much detail. I've just started learning Python. This is the first time I use this site. I'm sorry if I made a mistake while creating a post. Thank you)
In Qt you must not access or modify the GUI information from another thread (see this for more information) since it does not guarantee that it works (the GUI elements are not thread-safe), in your case luckily you have no problems but It is dangerous to use your approach in real.
In your case it is also unnecessary to use threads since it is enough to use the textChanged signal from QLineEdit.
import sys
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit
class Window(QWidget):
def __init__(self):
super().__init__()
vBox = QVBoxLayout(self)
self.resize(600, 400)
self.textBox = QLineEdit()
vBox.addWidget(self.textBox)
self.textBox.textChanged.connect(self.on_text_changed)
#pyqtSlot(str)
def on_text_changed(self, text):
if text == "close":
QApplication.quit()
elif text == "removeFocus":
self.textBox.clearFocus()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())

PyQt: how to load multiple .ui Files from Qt Designer

I want to add startup window that when I click button, it will open another window and close current window. For each window, it has seperated UI which created from Qt Designer in .ui form.
I load both .ui file via uic.loadUiType(). The first window(first UI) can normally show its UI but when I click button to go to another window, another UI (second UI) doesn't work. It likes open blank window.
Another problem is if I load first UI and then change to second UI (delete that Class and change to another Class, also delete uic.loadUiType()), the second UI still doesn't work (show blank window)
Please help... I research before create this question but can't find the answer.
Here's my code. How can I fix it?
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QIcon
from PyQt5 import uic
#load both ui file
uifile_1 = 'UI/openPage.ui'
form_1, base_1 = uic.loadUiType(uifile_1)
uifile_2 = 'UI/mainPage.ui'
form_2, base_2 = uic.loadUiType(uifile_2)
class Example(base_1, form_1):
def __init__(self):
super(base_1,self).__init__()
self.setupUi(self)
self.startButton.clicked.connect(self.change)
def change(self):
self.main = MainPage()
self.main.show()
class MainPage(base_2, form_2):
def __int__(self):
super(base_2, self).__init__()
self.setupUi(self)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
First you have an error, you must change __int__ to __init__. To close the window call the close() method.
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QIcon
from PyQt5 import uic
#load both ui file
uifile_1 = 'UI/openPage.ui'
form_1, base_1 = uic.loadUiType(uifile_1)
uifile_2 = 'UI/mainPage.ui'
form_2, base_2 = uic.loadUiType(uifile_2)
class Example(base_1, form_1):
def __init__(self):
super(base_1,self).__init__()
self.setupUi(self)
self.startButton.clicked.connect(self.change)
def change(self):
self.main = MainPage()
self.main.show()
self.close()
class MainPage(base_2, form_2):
def __init__(self):
super(base_2, self).__init__()
self.setupUi(self)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())

PyQt5 QFileDialog stops application from closing

I am trying to write a PyQt5 application that does the following:
Creates and opens a Main Window. The MainWindow has a function that opens a QFileDialog window.
Function to open QFileDialog can be triggered in two ways (1) from a file menu option called 'Open' (2) automatically, after the Main window is shown.
My problem is that I haven't found a way to get the QfileDialog to automatically open (2) that doesn't cause the application to hang when the main window is closed. Basic example of code can be found below:
import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QWidget,
QHBoxLayout, QCalendarWidget, QScrollArea, QFileDialog, QAction, QFrame)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.openAction = QAction(QIcon('/usr/share/icons/breeze/places/64/folder-open.svg'), 'Open', self)
self.openAction.triggered.connect(self.openDialog)
self.menubar = QMenuBar(self)
fileMenu = self.menubar.addMenu('&File')
fileMenu.addAction(self.openAction)
self.event_widgets = EventWidgets(self)
self.setMenuBar(self.menubar)
self.setCentralWidget(self.event_widgets)
def openDialog(self):
ics_path = QFileDialog.getOpenFileName(self, 'Open file', '/home/michael/')
class EventWidgets(QWidget):
def __init__(self, parent):
super(EventWidgets, self).__init__(parent)
self.initUI()
def initUI(self):
self.calendar = QCalendarWidget(self)
self.frame = QFrame()
self.scrollArea = QScrollArea()
self.scrollArea.setWidget(self.frame)
horizontal_box = QHBoxLayout()
horizontal_box.addWidget(self.calendar)
horizontal_box.addWidget(self.scrollArea)
self.setLayout(horizontal_box)
if __name__ == '__main__':
app = QApplication(sys.argv)
app_window = MainWindow()
app_window.showMaximized()
app_window.openDialog()
sys.exit(app.exec_())
Code has been tested on KDE Neon and Arch Linux, both have same issue.
I can get round this issue by handling the close event of the Main Window manually - i.e. adding this function to MainWindow:
def closeEvent(self, event):
sys.exit()
But I am not sure a) why this is necessary b) if it is best practice.
I tried your code on macOS Sierra and it works as it's supposed to. However I would propose a different approach to solve your problem.
What you could do is to implement the showEvent() function in your MainWindow class, which is executed whenever a widget is displayed (either using .show() or .showMaximized()) and trigger your custom slot to open the QFileDialog. When doing this you could make use of a single shot timer to trigger the slot with some minimal delay: the reason behind this is that if you simply open the dialog from within the showEvent(), you will see the dialog window but not the MainWindow below it (because the QFileDialog is blocking the UI until the user perform some action). The single shot timer adds some delay to the opening of the QFileDialog, and allows the MainWindow to be rendered behind the modal dialog. Here is a possible solution (not that I made some minor changes to your code, which you should be able to easily pick up):
import sys
from PyQt5 import QtCore
from PyQt5 import QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.openAction = QtWidgets.QAction('Open', self)
self.openAction.triggered.connect(self.openDialog)
menuBar = self.menuBar()
fileMenu = menuBar.addMenu('&File')
fileMenu.addAction(self.openAction)
self.event_widgets = EventWidgets(self)
self.setCentralWidget(self.event_widgets)
def showEvent(self, showEvent):
QtCore.QTimer.singleShot(50, self.openDialog)
#QtCore.pyqtSlot()
def openDialog(self):
ics_path = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', '/Users/daniele/')
class EventWidgets(QtWidgets.QWidget):
def __init__(self, parent):
super(EventWidgets, self).__init__(parent)
self.calendar = QtWidgets.QCalendarWidget(self)
self.frame = QtWidgets.QFrame()
self.scrollArea = QtWidgets.QScrollArea()
self.scrollArea.setWidget(self.frame)
horizontal_box = QtWidgets.QHBoxLayout()
horizontal_box.addWidget(self.calendar)
horizontal_box.addWidget(self.scrollArea)
self.setLayout(horizontal_box)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app_window = MainWindow()
app_window.showMaximized()
sys.exit(app.exec_())

PyQt5 show a file content in message window

I have a file info.txt, and I want to show content when I click on Info.
import sys
from PyQt5.QtWidgets import QMainWindow, QTextEdit, QAction, QApplication, QMessageBox
from PyQt5.QtGui import QIcon
file=open("info.txt","r")
data=file.read()
class Example(QMainWindow):
def showdialog(self):
msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText(data)
msg.setWindowTitle("Info")
msg.show()
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
textEdit = QTextEdit()
self.setCentralWidget(textEdit)
sourceAction = QAction(QIcon('info.png'), 'More informations', self)
sourceAction.setShortcut('Ctrl+I')
sourceAction.setStatusTip('More info')
self.statusBar()
sourceAction.triggered.connect(self.showdialog)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&About')
fileMenu.addAction(sourceAction)
sourceAction.triggered.connect(self.showdialog)
toolbar = self.addToolBar('Exit')
toolbar.addAction(sourceAction)
self.setGeometry(300, 300, 350, 250)
self.setWindowTitle('Summoner info')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
file.close()
The message box doesn't show the content of the file info.txt and almost instantly disappear.
You're defining showdialog as a method of your class Example.
This
sourceAction.triggered.connect(showdialog)
however, looks for showdialog in the local and global namespace - where it isn't defined.
Instead, connect the signal to the the method:
sourceAction.triggered.connect(self.showdialog)
Plus, you'll also have to take at least self as a parameter in your method. I've also added an msg.show() call - your messagebox will otherwise not become visible.
def showdialog(self):
msg = QMessageBox(self) # use self as parent here
# and/or keep a reference to the messagebox
self.messageBox = msg
# etc...
# actually show the message box:
msg.show()
EDIT: Added self as parent for the messagebox - so it's not recycled.

how to check if PyQt window exists

I have an application in development using PyQt4.
This app will popup a window on particular events in the application.
I want to know if the popup window which was popped up exists on the next event i wan to display the message on the same window rather tan creating another window.
For example you can consider a messaging application. where when we get a message the window will popup. and if we receive the message again from same user the message will be appended to that window itself.
My scenario is also the same.
Anyone have any idea on this...?
All you have to do is keep a reference to the popup window and then reset the text as necessary.
Here's a simple demo:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.button = QtGui.QPushButton('ShowTime!', self)
self.button.clicked.connect(self.handleButton)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.button)
self._dialog = None
def handleButton(self):
if self._dialog is None:
self._dialog = QtGui.QMessageBox(self)
self._dialog.setWindowTitle('Messages')
self._dialog.setModal(False)
pos = self.pos()
pos.setX(pos.x() + self.width() + 10)
self._dialog.move(pos)
self._dialog.setText(
'The time is: %s' % QtCore.QTime.currentTime().toString())
self._dialog.show()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

Categories

Resources