Accessing object attributes in pyqt window in separate module - python

I have a main window created in one python module. This module also contains a class definition used to create an object called my_settings.
I also have a separate module which creates a another window (which should be in a different module for various reasons). This window allows various inputs such as opening a file and storing some settings once buttons are clicked blaa blaa.
What I want to do is then amend the attributes of my_setttings. A simplified version of the code is:
MAIN MODULE
class MainWindow(QMainWindow):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
QMainWindow.__init__(self)
uic.loadUi(self.some_directory + "arc_custom_main.ui", self)
self.some_button.clicked.connect(self.open_some_widget)
def open_some_widget(self):
widget = widget_in_other_module(self)
widget_in_other_module.exec_()
app = QApplication(sys.argv)
my_settings=settings()
_mainWindow = MainWindow()
_mainWindow.show()
SEPERATE MODULE
class widget_in_other_module(QDialog):
def __init__(self, parent):
my_settings.temppath = my_settings.OutputDir
QDialog.__init__(self)
self.parent = parent
my_settings.some_attribute= foo
uic.loadUi("some.ui", self)
self.pushButtonOpenMain.clicked.connect(self.openMain)
def openMain(self):
my_settings.some_other_attibute=bar
The problem I have is that I can't find a way to be able to access my_settings in the openMain method of widget_in_other_module. I'm a bit of a newbe to qt and can't for the life of me work out where I should pass my_settings. For various reasons I need all the functionality of widget_in_other_module to be outside of the main module (mostly to do with readability and future planed changes to the main module). I've tried as much as I can think of e.g. including it as a parameter in the line self.pushButtonOpenMain.clicked.connect(self.openMain,my_settings) but this doesn't seem to be allowed. Am I missing something basic here?

Instantiate settings variable in separate module and import this varable where you need it. It could be object of a class or just dictionary.
storage.py
class Settings:
def __init__(self):
print("Settings")
my_settings = Settings()
MainWindow.py
from PyQt5.QtWidgets import QMainWindow, QApplication
import sys
from Widget import Widget
from storage import my_settings
class MainWindow(QMainWindow):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
QMainWindow.__init__(self)
self.open_some_widget()
def open_some_widget(self):
widget = Widget()
widget.show()
widget.test()
self._widget = widget
my_settings.foo = 10
app = QApplication(sys.argv)
_mainWindow = MainWindow()
_mainWindow.show()
app.exec_()
Widget.py
from PyQt5.QtWidgets import QWidget
from storage import my_settings
class Widget(QWidget):
def test(self):
print(my_settings.foo)

Related

Calling function in parent class and accessing parent self

In my main window I set a variable self.print_this. I then call another class PhotoViewer and then in that class I call a function from my main window. In that function I try to print the self.print_this but I get the following error: AttributeError: PhotoViewer object has no attribute print_this
How do I access the self of the window class or avoid sending the self of PhotoViewer to the printfromwindow function?
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QPoint, QRect, QSize, pyqtSignal
from PyQt5.QtWidgets import QMainWindow, QApplication, QRubberBand, QColorDialog
from PyQt5.QtGui import QPixmap, QPainter, QPen
import sys
class PhotoViewer(QtWidgets.QGraphicsView):
photoClicked = QtCore.pyqtSignal(QtCore.QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(PhotoViewer, self).__init__(parent)
Window.printfromwindow(self)
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.print_this='test'
PhotoViewer(self)
def printfromwindow(self):
print(self.print_this)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 800, 600)
window.show()
sys.exit(app.exec_())
Untested, but perhaps something like this. Note that in your code, you're calling methods of the Window and PhotoViewer classes but not constructing an instance of those classes.
You need to instantiate and retain those instances within their parent/child class instances, if you want to be able to reference their methods/properties.
As noted in my comment above, Window.printfromwindow(self) should not have the self argument (and should instead refer to <instance of Window>.printfromwindow().
In the Window constructor, I assign self.viewer an instance of the PhotoViewer class and pass self (which is a Window instance) as the parent argument to its constructor.
Then, in PhotoViewer class constructor, we do self.window = parent which should allow you to call self.window.printfromwindow():
class PhotoViewer(QtWidgets.QGraphicsView):
photoClicked = QtCore.pyqtSignal(QtCore.QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(PhotoViewer, self).__init__(parent)
self.window = parent # relates the "parent" Window instance to this "child" PhotoViewer instance
self.window.printfromwindow() # calls the printfromwindow method from the "parent" Window instance
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.print_this='test'
self.viewer = PhotoViewer(self) # creates an instance of PhotoViewer class as an attribute of this Window instance
def printfromwindow(self):
print(self.print_this)
If you want to make this more readily available (i.e., not just from within the constructor of PhotoViewer) then assign the Window.printfromwindow to an attribute of the PhotoViewer, like:
class PhotoViewer(QtWidgets.QGraphicsView):
photoClicked = QtCore.pyqtSignal(QtCore.QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(PhotoViewer, self).__init__(parent)
self.window = parent # relates the "parent" Window instance to this "child" PhotoViewer instance
self.printfromwindow = self.window.printfromwindow
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.print_this='test'
self.viewer = PhotoViewer(self) # creates an instance of PhotoViewer class as an attribute of this Window instance
def printfromwindow(self):
print(self.print_this)
Since functions are first-level objects in python, you can do this:
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.viewer.printfromwindow()
To access a parent class you need to pass the parent class through the function. def printfromwindow(Window). Then you inherit all of the attributes from the parent class. You can also modify a subclass with super().__init__ to add changes to the sub classes without effecting the parent class

python qwidget closeEvent doesn't call

I created form using designer.
So, I have 3 files:
1. Form.py: - autocreated from designer
..... bla-bla-bla ......
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(1920, 1000)
Form.setMaximumSize(QtCore.QSize(1920, 1000))
..... bla-bla-bla ......
2. FormProc.py: - manual created for processing
from Form import *
class FormProc(Ui_Form):
def setupUi(self, Form):
Ui_Form.setupUi(self, Form)
..... bla-bla-bla ......
3. Main.py: - main file
import sys
from FormProc import *
def main():
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QWidget()
mw=FormProc()
mw.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I need to catch closeEvent, but I can't. Defining of closeEvent function in FormProc.py does not work.
If you look at the class definition in Form.py, you'll see that it's just a simple namespace that inherits from object. The setupUi method creates all the widgets specified in Qt Deisgner and makes them attributes of this namespace. The only excetion to this is the top-level widget, which must be passed in to setupUi as the Form argument.
So the FormProc class you created in FormProc.py is currently completely redundant. To make it useful, you need to make it a subclass of the top-level widget, and then add the ui to that. There are several ways to do this. Here's one way:
FormProc.py:
from PyQt4 import QtGui
from Form import Ui_Form
class FormProc(QtGui.QWidget):
def __init__(self, parent=None):
super(FormProc, self).__init__(parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
def closeEvent(self, event):
print('close event')
Main.py:
import sys
from PyQt4 import QtGui
from FormProc import FormProc
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
MainWindow = FormProc()
MainWindow.show()
sys.exit(app.exec_())
For some other examples, see Using Qt Designer in the PyQt4 docs.

Updating child widget in Qt

I have a simple project with the following classes
class MainWindow(QMainWindow)
class Home(QWidget)
class Login(QWidget)
All I want is to be able to nest the QWidget classes (make them children of the QMainWindow) and display them INSIDE the MainWindow. I can't seam to figure out how to make the QWidgets "appear" after I've called them in the MainWindow.
Code is bellow:
import sys
from gui.MainWindow import Ui_MainWindow
from gui.home import Ui_Home
from gui.login import Ui_Login
from PyQt4.QtGui import QMainWindow, QApplication, QWidget
class Home(QWidget, Ui_Home):
def __init__(self):
QWidget.__init__(self)
self.setupUi(self)
class Login(QWidget, Ui_Login):
def __init__(self):
QWidget.__init__(self)
self.setupUi(self)
class MainWindow(QMainWindow,Ui_MainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
#INSERT pushButton.click to go to HOME here
#INSERT pushButton.click to go to LOGIN here
def setHome(self):
self.label_Screen.setText("HOME")
self.mainwidget = Home()
#NEEDS SOMETHING HERE
def setLogin(self):
self.label_Screen.setText("LOGIN")
self.mainwidget = Login()
#NEEDS SOMETHING HERE
if __name__ == '__main__':
app = QApplication(sys.argv)
Main = MainWindow()
Main.show()
sys.exit(app.exec_())
I think I just need something where I've tagged "#NEEDS SOMETHING HERE", but I'm not sure what!
Cheers!
RESOLVED: thanks to kh25
Just had to add a layout to the QMainWindow and change the setHome to this:
def setHome(self):
self.label_Screen.setText("HOME")
self.currentScreen = Home()
self.layout.addWidget(self.currentScreen)
self.setLayout(self.layout)
The equivalent should be done for the setLogin method also.
You need to create a layout and add the widgets to this layout first. There are various types of layout. Read here:
http://doc.qt.io/qt-4.8/layout.html
For a simple case like yours I'd suggest either using a QHBoxLayout or QVBoxLayout.
Declare this layout. Call addWidget() on the layout for each of the Login and Home widgets and then call setLayout() on the QMainWindow.

How to generate Python code of GUI created under Taurusdesigner or Qt?

First of all let me tell you that I am new to Qt and also to Python.
I am using Qt(Taurusdesigner) to create my GUIs.
After starting Qt(Taurusdesigner), I generate my python code for that particular GUI using:
taurusuic4 -x -o file.py file.ui
or
pyuic4 -x -o file.py file.ui
After executing this command on command line I am able to generate python file, but the auto generated classes looks like:
class MainWindow(object):
def setupUi(self, MainWindow):
Where as when I am searching for any help on Google I find class written like:
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
What would I do to generate 2nd type of class file using Qt(Taurusdesigner)??
Why there is a syntax difference in my class and class which are written for help on internet.
Please Help regarding this.
Thanks in advance.
The ui module generated by taurusuic4/pyuic4 should be imported into your main application. You do not need to use the -x option, and obviously you should choose a better module name than "file":
taurusuic4 -o mainwindow.py file.ui
Your main application module should look something like this:
from PyQt4.QtGui import QMainWindow
from mainwindow import Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.handleButton)
def handleButton(self):
print('Hello World!')
This approach means that all the widgets from Qt(Taurus) Designer end up as attributes of the MainWindow class. Another approach is to have the ui elements within a separate namespace:
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(self.handleButton)
setupUI and __init__ are two methods of the class MainWindow. For one class, there can be any number of method and you can put them in whatever order you like.
There is always an __init__ method, it's called a constructor. This method is called when you create an object (for example when you do myWindow=MainWindow()). It's usually put at the beginning because it'll be call first. Specifically for QT, you have to call the parent's constructor with super.
setupUI is the method created by your designer, to take care of layout and such. It should be called in the constructor.
Your code should look like:
class MainWindow(object):
def setupUi(self, MainWindow):
#code made by the designer
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
#some code
def another_method(self):
#some more code

How to re-implement Ui_MainWindow generated by Qt

I've created a interface in Qt as .ui file and then converted it to a python file. Then, I wanted to add some functionality to the components such as radio button, etc. For doing so, I tried to re-implement the class from Qt and add my events. But it gives the following error:
self.radioButton_2.toggled.connect(self.radioButton2Clicked)
NameError: name 'self' is not defined
My first question is whether this is the correct/proper way to deal with classes generated by Qt? And second, why do I get the error?
My code is here:
import sys
from PySide import QtCore, QtGui
from InterfaceClass_Test01 import Ui_MainWindow
class MainInterface(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainInterface, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
def setupUi(self, MainWindow):
super(MainInterface, self).setupUi(parent, MainWindow)
self.radioButton.toggled.connect(self.radioButtonClicked)
self.radioButton_2.toggled.connect(self.radioButton2Clicked)
self.radioButton_3.toggled.connect(self.radioButton3Clicked)
def radioButton3Clicked(self, enabled):
pass
def radioButton2Clicked(self, enabled):
pass
def radioButtonClicked(self, enabled):
pass
The generated files are a little unintuitive. The UI class is just a simple wrapper, and is not a sub-class of your top-level widget from Qt Designer (as you might expect).
Instead, the UI class has a setupUi method that takes an instance of your top-level class. This method will add all the widgets from Qt Designer and make them attributes of the passed in instance (which would normally be self). The attribute names are taken from the objectName property in Qt Designer. It is a good idea to reset the default names given by Qt to more readable ones so that they are easy to refer to later. (And don't forget to re-generate the UI module after you've made your changes!)
The module that imports the UI should end up looking like this:
import sys
from PySide import QtCore, QtGui
from InterfaceClass_Test01 import Ui_MainWindow
class MainInterface(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainInterface, self).__init__(parent)
# inherited from Ui_MainWindow
self.setupUi(self)
self.radioButton.toggled.connect(self.radioButtonClicked)
self.radioButton_2.toggled.connect(self.radioButton2Clicked)
self.radioButton_3.toggled.connect(self.radioButton3Clicked)
def radioButton3Clicked(self, enabled):
pass
def radioButton2Clicked(self, enabled):
pass
def radioButtonClicked(self, enabled):
pass

Categories

Resources