Python PyQt5 passing class variables without re-opening window [duplicate] - python

I have two windows (App.py and ChildApp.py) and .ui files for both with same name.
App.py:
import sys
from PyQt4 import QtCore, QtGui, uic
from ChildApp import ChildApp
qtCreatorFile = "App.ui" # Enter file here.
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class App(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
self.message = None
self.child_window = ChildApp()
self.pushButton.clicked.connect(self.sendMessage)
def sendMessage(self):
self.message = self.lineEdit.text()
self.child_window.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = App()
window.show()
sys.exit(app.exec_())
ChildApp.py:
import sys
from PyQt4 import QtCore, QtGui, uic
qtCreatorFile = "ChildApp.ui" # Enter file here.
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class ChildApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
self.pushButton.clicked.connect(self.alertmessage)
def alertmessage(self):
message = "test"
self.label.setText("Message : "+message)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = ChildApp()
window.show()
sys.exit(app.exec_())
In Main.py file I have a variable self.message.
When I click on the button "Do something with text", text in the textbox is assigned to self.message and the child window is opened.
Now in the child window, when I click on button "Show message", the method alertmessage() is called, where it sets message = "text".
This variable message must be assigned to value of self.message from MainApp.py.
Please help
Thank you

Call the child that way:
self.child_window = ChildApp(parent=self)
Define the child app this way:
class ChildApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent):
self.parent = parent
you can use the parent variables through self.parent.whatever
It must work, but I wouldn't advise this because you are not supposed to know the fields of the parent form the child.

I don't think you can get local data from the parent. I would do the following:
Use a signal to update the child when the text is changed in the lineEdit:
self.lineEdit.textChanged.connect(self.updateChild)
Add this function in the main window:
def updateChild(self):
self.child_window.setMessage(self.lineEdit.text())
and keep the variable self._message updated in the child window:
def setMessage(self, message):
self._message=message
so that whenever you need this variable, it is up to date

Related

Why can't I connect the clicked event of a QPushButton to a function inside a Python class?

I'm trying to connect the clicked event of a QPushButton inside a class (MyButton) to a function inside the same class (print_hello_world) in PyQt5. I'm expecting to print "Hello World" when the user clicks on the button. Can anyone explain why the following code does not work? (i.e. clicking on the button does not print anything)
import sys
from PyQt5.QtWidgets import *
class MyButton:
def __init__(self, parent):
self.parent = parent
self.push_button = QPushButton('Print', parent)
self.push_button.clicked.connect(self.print_hello_world)
def print_hello_world(self):
print("Hello World")
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
button = MyButton(parent=self)
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())
The above code will work if I add button.push_button.clicked.connect(lambda:button) after I instantiate the MyButton object in the Window class. Can anyone explain to me why the first code does not work and the following code works?
import sys
from PyQt5.QtWidgets import *
class MyButton:
def __init__(self, parent):
self.parent = parent
self.push_button = QPushButton('Print', parent)
self.push_button.clicked.connect(self.print_hello_world)
def print_hello_world(self):
print("Hello World")
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
button = MyButton(parent=self)
button.push_button.clicked.connect(lambda:button)
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())
What is an alternative way to make the first code work by modifying the MyButton class without having to add extra lines of code after instantiating the class?
I am also learning and working on PyQt based software development. I did a few experiments with the code and by calling super initialization, the first code works fine. Here is the modified code:
import sys
from PyQt5.QtWidgets import *
class MyButton(QWidget):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
self.push_button = QPushButton('Print', parent)
self.push_button.clicked.connect(self.print_hello_world)
def print_hello_world(self):
print("Hello World")
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
button = MyButton(parent=self)
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())
'button' is destroyed because of garbage collection inside 'Window's init method, because it is not an instance variable so 'button' goes out of scope when init method finishes.
So this version works as intended:
import sys
from PyQt5.QtWidgets import *
class MyButton:
def __init__(self, parent):
self.parent = parent
self.push_button = QPushButton('Print', parent)
self.push_button.clicked.connect(self.print_hello_world)
def print_hello_world(self):
print("Hello World")
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.button = MyButton(parent=self)
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())

PyQt5 .ui file not loading

So my expected outcome is for the login.ui to show when the login button is clicked. My code reached the def gotologin function and the class LoginScreen , but it doesn't load the ui
import sys
from PyQt5.uic import loadUi
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QDialog, QApplication
class WelcomeScreen(QDialog):
def __init__(self):
super(WelcomeScreen, self).__init__()
loadUi('welcomescreen.ui', self)
self.login.clicked.connect(self.gotologin)
def gotologin(self):
login = LoginScreen()
widget.addWidget(login)
widget.setCurrentIndex(widget.currentIndex()+1)
class LoginScreen(QDialog):
def __init__(self):
super(LoginScreen, self).__init__()
loadUi('login.ui', self)
app = QApplication(sys.argv)
welcome = WelcomeScreen()
widget = QtWidgets.QStackedWidget()
widget.addWidget(welcome)
widget.setFixedHeight(800)
widget.setFixedWidth(1200)
window = WelcomeScreen()
window.show()
try:
sys.exit(app.exec_())
except:
print('Exiting')
Your logic is strange since you are creating 2 WelcomeScreen: One added to the QStackedWidget and the second as a window. Besides that, the QStackedWidget has never been shown. And as the icing on the cake you don't limit the scopes of the variables.
Considering the above, it is better to create a controller that implements the logic of switching widgets and limits scopes.
import sys
from functools import cached_property
from PyQt5.uic import loadUi
from PyQt5.QtWidgets import QApplication, QDialog, QStackedWidget
class WelcomeScreen(QDialog):
def __init__(self):
super(WelcomeScreen, self).__init__()
loadUi("welcomescreen.ui", self)
class LoginScreen(QDialog):
def __init__(self):
super(LoginScreen, self).__init__()
loadUi("login.ui", self)
class Controller:
def __init__(self):
self.stacked_widget.addWidget(self.welcome)
self.stacked_widget.addWidget(self.login)
self.welcome.login.clicked.connect(self.goto_login)
#cached_property
def stacked_widget(self):
return QStackedWidget()
#cached_property
def welcome(self):
return WelcomeScreen()
#cached_property
def login(self):
return LoginScreen()
def goto_login(self):
self.stacked_widget.setCurrentWidget(self.login)
def main(args):
app = QApplication(args)
controller = Controller()
controller.stacked_widget.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main(sys.argv)
And finally, do not silence the exceptions since their reason for being is to indicate that something is wrong. I prefer that when the program fails then it shouts at me that a silent error since the latter is the cause of many bugs.

pyqt5 custom dialog input popup within main window

I need to generate a custom popup input window triggered by clicking a QPushButton in my app (via clicked). It needs to get several inputs from the user of different types and then return them to the calling function inside the main window app. I have found built in functions such as QInputDialog that can do this for single specific inputs, but I can't figure out how to do this in the case of a popup that asks for several inputs of different types at once (preferably in a window designed in Qt Designer). Does anyone know how to do this?
import sys
import os
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5 import uic
path = os.path.dirname(__file__) #uic paths from itself, not the active dir, so path needed
qtCreatorFile = "NAME.ui" #Ui file name, from QtDesigner
Ui_MainWindow, QtBaseClass = uic.loadUiType(path + qtCreatorFile) #process through pyuic
class MyApp(QMainWindow, Ui_MainWindow): #gui class
def __init__(self):
#Set up the gui via Qt
super(MyApp, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.add_button.clicked.connect(self.add_row) #add_button is QPushButton
def add_row(self):
data1, data2, data3 = #popup form to get data (types are not the same)
#do stuff with data
pass
#start app
if __name__ == "__main__":
app = QApplication(sys.argv) #instantiate a QtGui (holder for the app)
window = MyApp()
window.show()
sys.exit(app.exec_())
There is no single solution but I will give you a guide to do what you want.
If you want to get a widget with the behavior of QInputDialog you must first choose the right template, in this case a good option is Dialog with Buttons Bottom or Dialog with Buttons Right, add the components you want, position it, etc.
Then as you show your code you create a class that inherits from QDialog and then create a method where you get the results but to do so do not use show() but exec_()
path = os.path.dirname(__file__)
qtCreatorFile = "some_dialog.ui"
Ui_Dialog, _ = uic.loadUiType(os.path.join(path,qtCreatorFile))
class CustomDialog(QDialog, Ui_Dialog):
def __init__(self):
super(CustomDialog, self).__init__()
self.setupUi(self)
# set initials values to widgets
def getResults(self):
if self.exec_() == QDialog.Accepted:
# get all values
val = self.some_widget.some_function()
val2 = self.some_widget2.some_another_function()
return val1, val2, ...
else:
return None
And then use it in your function:
class MyApp(QMainWindow, Ui_MainWindow): #gui class
def __init__(self):
#Set up the gui via Qt
super(MyApp, self).__init__()
self.setupUi(self)
self.add_button.clicked.connect(self.add_row) #add_button is QPushButton
def add_row(self):
w = CustomDialog()
values = w.getResults()
if values:
data1, data2, data3 = values

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

pyqtSignal() connects bool object instead of str

Let's say I have this snippet of code:
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import pyqtSignal
from ui_helloworld import Ui_MainWindow
from ui_hellodialog import Ui_Hi
from sys import argv
from sys import exit
class MainWindow(QMainWindow):
update = pyqtSignal(str)
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.h = HelloDialog()
self.ui.pushButton.clicked.connect(self.update_label)
self.ui.doIt.clicked.connect(self.h.update_label)
def update_label(self):
self.h.show()
def update_label_hello(self, msg):
self.update.emit(msg)
class HelloDialog(QDialog):
def __init__(self):
super(HelloDialog, self).__init__()
self.ui = Ui_Hi()
self.ui.setupUi(self)
def update_label(self, msg):
print msg
# Crashes the program:
# TypeError: setText(self, str): argument 1 has unexpected type 'bool'
# >> self.ui.label.setText(msg)
self.ui.label.setText("Hello world!")
def main():
app = QApplication(argv)
window = MainWindow()
window.show()
exit(app.exec_())
if __name__=="__main__":
main()
It's fairly simple. It's 2 windows, one is a QMainWindow and the other is a QDialog. The MainWindow has 2 buttons, pushButton and doIt:
pushButton opens the HelloDialog
doIt emit the update signal
The problem is, that the slot in HelloDialog Is receiving a boolean from the update signal in MainWindow, but I declared it as a str object.
Why does the the update_label slot receive a bool and not a str object?
localhost :: Documents/Python/qt ยป python main.py
{ push `doIt` object }
False
The Ui_MainWidow and Ui_Hi classes are pyuic5 generated.
I did not need to connect to self.h.update_label directly. I had to connect to the method inside MainWindow called update_label_hello to doIt, and then connect the pyqtSignal to the slot in HelloDialog
So, the final result is this:
init of MainWindow:
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.h = HelloDialog()
self.ui.pushButton.clicked.connect(self.update_label_)
self.ui.doIt.clicked.connect(self.update_label_hello)
self.update.connect(self.h.update_label)

Categories

Resources