How to inherit attributes of instance from PyQt5 code - python

I am trying to create a GUI using PyQt5. I have an external script with functions, to change values on the screen. However I cannot access the attributes of the Qt object externally.
In my external script I have tried:
Main.MainWindow.label_55...
Main.ui.label_55...
And multiple other variations
*Main is the name of the PyQT5.py file
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_())
Error:
AttributeError: module 'Main' has no attribute 'MainWindow'

From your question I suppose by "accessing externally" you mean "by importing". If you import a module with an "import protection" statement like
if __name__ == "__main__":
the code inside this block does not run. It only runs when you execute the module directly, not via an import. That's why the other module does not see MainWindow.
If that's your main app window you should probably make imports the other way round. The main app imports other modules and calls them, eventually passing the main window or other objects as parameters.

Related

Increase start up time of pyqt5 application with custom modules

I have a pyqt5 application. In the program you can open various other windows from the MainWindow. The different windows are stored in a separate module and are imported into the main file, which represents the MainWindow. Furthermore I use several custom widgets, which are also stored in a separate module and imported into the main file.
The program runs smoothly, but it takes a few seconds for the program to start. Exactly I can not say what causes the delay at startup. However, it seems to be due to my custom modules.
Is there a possibility to speed up the loading of the modules or to load the modules after the MainWindow is open?
The main file looks something like his:
#other imports
...
#import custom modules
from MyWidgets import MyTreeView
from MyWindows import MySecondWindow
basedir = Path(__file__).parent.absolute()
class App(QMainWindow):
def __init__(self):
super(App, self).__init__()
uic.loadUi(os.path.join(basedir, "gui", "MainWindow.ui"), self)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = App()
window.showMaximized()
window.show()
sys.exit(app.exec_())

PyQT with QT Creator

I am trying to develop a small gui using PySide and the QT Creator.
As the base implementation, I have choosen a QMainWindow.
The problem is that adding any elements to that MainWindow inside the Editor results in an empty window when I run the code.
The initially generated python code looks like this:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.load_ui()
def load_ui(self):
loader = QUiLoader()
path = os.path.join(os.path.dirname(__file__), "form.ui")
ui_file = QFile(path)
ui_file.open(QFile.ReadOnly)
loader.load(ui_file, self)
ui_file.close()
if __name__ == "__main__":
app = QApplication([])
widget = MainWindow()
widget.show()
sys.exit(app.exec_())
I know that loader.load(ui_file, self) returns a widget. My solution was:
def load_ui(self):
loader = QUiLoader()
path = os.path.join(os.path.dirname(__file__), "form.ui")
ui_file = QFile(path)
ui_file.open(QFile.ReadOnly)
self.window = loader.load(ui_file, self)
self.window.show()
ui_file.close()
if __name__ == "__main__":
app = QApplication([])
widget = MainWindow()
#widget.show() <<<<<<--- removing this
sys.exit(app.exec_())
This works for me but this clearly cannot be the way this is supposed to work.
I am confused on why QT Creator gives me this non-working templaet.
Furthermore I am curious on how custom functions should be implemented.
When clicking on the clicked() slot for a button, it tells me
No ui_form.h found! (translated)
I ended up writing the functions into my MainWindow class like this:
self.window.menuopen_button.clicked.connect(lambda x: self.menu_animation(x))
self.window.minimise_button.clicked.connect(lambda x: self.menu_buttons('minimise'))
Your initial code only loads the UI file into the QUiLoader object - you don't do anything else with it. When you call widget.show(), you're calling the QMainWindow's show method which is a default window (and, hence, empty) since you haven't added the loaded widget to it.
Your solution similarly loads the UI but displays it via the widget object's show method. However, you're not amending it to your main window, so you're basically tossing your main window and just using the widget.
There are a couple ways to correctly accomplish what you want:
One way would be to, as #musicamante suggested, add the loaded UI widget to your MainWindow object (and by the way, this is supported by PySide2: https://doc.qt.io/archives/qtforpython-5.12/PySide2/QtUiTools/QUiLoader.html - the example in the detailed description shows exactly how to do this).
Or the other way, which I prefer, would be to use the uic utility, PySide2-uic, in the build process to generate a UI Python class based on the UI file.
The Qt documentation has tutorials showing both methods. The linked documentation shows PySide6 as support for PySide2 has been discontinued with the release of Qt6. The API for PySide2, PySide6, and PyQt5 are all very similar, so if you're migrating from either PySide2 or PyQt then the change should be relatively painless. I recommend using PySide6 as this is the Python binding officially supported by Qt.

How to run a pyqt5 application properly?

I can't get the GUI for my application to run in the manner that I need it to. My question is, given the below criteria, how do I go about setting up and running the GUI properly. The lack of good documentation that I have found is insanely frustrating (maybe I'm looking in the wrong places?).
I have a main window in a file called MainCustomerWindow.py containing a class by the same name. This is where all the code from the qt designer is. I have another class file called GUIController. The GUIController class does just that, controls the multiple GUI windows. It is in this GUIController class that I am trying to instantiate and run the MainCustomerWindow. Here is the code I have been trying.
def setup_window(self):
APP = QtWidgets.QApplication(sys.argv)
Window = MainCustomerWindow()
Window.setupUi(QtWidgets.QMainWindow)
Window.show()
sys.exit(APP.exec_())
Just as a side note, I come from JavaFX and Swing, and don't fully understand the workflow for pyqt5. So if someone could add an explanation for that as well it would be greatly appreciated.
The class generated by Qt Designer is not a widget, it is a class used to fill an existing widget, so you must create an object in the window, assuming you have used the "Main Window" template, then the widget must be QMainWindow (if it is another maybe you should use QDialog or QWidget), then you have to create another class that belongs to the design, and using the method setupUi() you must pass the widget to fill it:
def setup_window(self):
app = QtWidgets.QApplication(sys.argv)
# create window
window = QtWidgets.QMainWindow()
ui = MainCustomerWindow()
# fill window
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
Although a better option is to create a new class and have it inherit from both:
class MainWindow(QtWidgets.QMainWindow, MainCustomerWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
If you want to get detailed information I recommend you read the following:
http://pyqt.sourceforge.net/Docs/PyQt5/designer.html
You can try taking the code you have there and adding it to the main statement at the end of your app's script. You can also have this statement instantiate your class where the init method contains the setupui() call. For example:
if __name__ == '__main__':
app = QWidgets.QApplication(sys.argv)
window = QMainWindow()
main_window = MainCustomerWindow()
window.show()
sys.exit(app.exec())
This code first sets up the PyQt app as an instance of QApplication. Next it instantiates an instance of QMainWindow so that PyQt knows what to display as the main app starts. In my experience, I've put setupui() in the init method of the app class. In your case, in the init method of MainCustomerWindow Finally, window.show() tells PyQt to begin rendering the main window.

PyQt runs button functions on startup

I created a UI using Qt Designer for a python application.
The main function of my application runs when a button is clicked, like this:
self.button.clicked.connect(get_data(arg1, arg2, arg3))
To create the UI when the program begins, here is my main method:
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QDialog()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
However, the function "get_data" runs immediately upon start-up, despite the button not even rendering on my screen.
How can I stop the function from running immediately upon start-up?
It's because you are trying to connect the clicked event to the result of the function get_data. What you want to do is connect it to the actual function, like this:
self.button.clicked.connect(get_data)
You need to find another way to pass args into get_data. A lambda would work, but I'd use other methods (ie making a class)

Passing string from one py to gui

Can someone tell me how do this?
I got main.py and gui.py (made in pyqt4).
The main.py runs some code, whatever, print "hello world" and I want to pass this string to gui.py in listWidget.addItem().
So in main.py I did:
from gui import Ui_Form
send_str = "hello all"
ui.listWidget.addItem(send_str)
and I get the error:
NameError: global name 'ui' is not defined.
which points to gui.py as in gui.py is
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
Form = QtGui.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
If i put both code in one py, all if working.
How to separate these two, since i want my main.py to execute in endless loop, and from time to time i want to open gui and check whats new value main.py going to send to window?
First problem is that ui variable is local to the if name == "main"
Second problem is the if itself because that branch will not be activated when you import a module, that is similar to the main() in c
3rd problem: the gui in QT has to run in the main thread. This means that your algorithm needs to run in another thread (there is an alternative with timers but it is ugly and harder to implement)
See a tutorial on QT threads and use the signal-slot mechanism to comunitate between gui thread and algorithm thread.

Categories