I have the following outline of a Python program (using PyQt4):
class Polygon( QtGui.QGraphicsItem ):
def __init__(self):
super(Polygon, self).__init__()
def addpoint( self, point ):
if last_point:
# trying to add auto-save here
class MainWidget(QtGui.QWidget):
openFileName = ""
list_of_polygons = []
def __init__(self):
super(MainWidget, self).__init__()
def openFile( self ):
call dialog
self.openFileName = ...
def saveFile( self ):
# needs to access a couple something with self.variables, like self.openFileName
def main():
app = QtGui.QApplication(sys.argv)
ex = MainWidget()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Functionality is an image viewer where I'm creating polygons to tag object. I'd like to call an auto-save once a polygon has been created.
So for saving a polygon I need to call it from the saveFile function MainWidget class. My problem is that the saving functionality is implemented in the MainWidget class, and I don't know how to access them from inside the Polygon class.
What would be the best idea to do this? Should I make saveFile global? If yes, then how do I access the self. variables of the MainWidget?
You probably need to pass the widget object to the Polygon when you create it so that it knows what its "parent" widget object is:
class Polygon( QtGui.QGraphicsItem ):
def __init__(self, parent):
self.parent = parent
# ...
(and then foo = Polygon(your_widget) when you create it).
Then you can just call self.parent.saveFile(...) or whatnot.
Related
My main window has a variable self.x setup in the INIT. Then I need to access this value from the popup password box that is created. This is just a test script to get my point accross. I'm assuming it's something with the inheritance stuff, all that is still a little foreign to me.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from PyQt5 import QtWidgets
# Created by MyWindow
class LoginDlg(QtWidgets.QDialog):
def __init__(self):
super(LoginDlg, self).__init__()
self.password = QtWidgets.QLineEdit()
# THIS IS THE LINE I NEED IT TO PULL X FROM PARENT
self.password.setText(self.x)
self.button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
layout = QtWidgets.QFormLayout()
layout.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
layout.addRow('Password', self.password)
layout.addWidget(self.button_box)
self.setLayout(layout)
self.setWindowTitle("Login")
self.setMinimumWidth(350)
# Main parent window
class MyWindow(QtWidgets.QWidget):
def __init__(self):
super(MyWindow, self).__init__()
self.edit = QtWidgets.QLineEdit()
button = QtWidgets.QPushButton("Get input from dialog")
button.clicked.connect(self.get_login)
layout = QtWidgets.QHBoxLayout()
layout.addWidget(self.edit)
layout.addWidget(button)
self.setLayout(layout)
self.x = "PASS THIS STRING"
def get_login(self):
login = LoginDlg()
if login.exec_():
self.edit.setText(login.password.text())
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Normally I would just pass this data through the constructor, but let's say I have a lot of data that I don't want to pass back and forth, is there a way to access parent attributes another way?
Don't get too complicated and just pass the value of that variable through the constructor:
class LoginDlg(QtWidgets.QDialog):
def __init__(self, x):
super(LoginDlg, self).__init__()
self.password = QtWidgets.QLineEdit()
self.password.setText(x)
# ...
class MyWindow(QtWidgets.QWidget):
# ...
def get_login(self):
login = LoginDlg(self.x)
if login.exec_():
self.edit.setText(login.password.text())
Another similar option is to access "password" in get_login:
class LoginDlg(QtWidgets.QDialog):
def __init__(self):
super(LoginDlg, self).__init__()
self.password = QtWidgets.QLineEdit()
# self.password.setText(self.x)
self.button_box = QtWidgets.QDialogButtonBox(
QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel
)
# ...
class MyWindow(QtWidgets.QWidget):
# ...
def get_login(self):
login = LoginDlg()
login.password.setText(self.x)
if login.exec_():
self.edit.setText(login.password.text())
Note: my answer does not try to implement what the OP asks is to "access a class from another" (there is no relationship so using parent-child is incorrect) since that complicates the modularization because if a object could affect the other, in general. I think the OP has an XY problem as it asks how to implement a possible solution instead of the underlying problem which is "how to share information between classes"
My question is similar to this one, except in one thing: what if classes widget1 and widget2 are big and I want to put them in two separate files. Problem gets in method Check(). So, is there a way to call self.parent().setCentralWidget(w2) even though widget2 isn't in the same file as widget1 (but they are both imported in main file containing MainWindow).
Code taken from How to set the central widget of existing MainWidnow in Python PyQt4?
class widget1(QtGui.QFrame):
def __init__(self,parent = None):
......
......
def Check(self):
if (condition):
w2=widget2(self)
self.parent().setCentralWidget(w2)
class widget2(QtGui.QFrame):
def __int__(self,parent = None):
.....
.....
class MainWindow(QtGui.QMainWindow):
def __init__(self,parent = None):
QtGui.QMainWindow.__init__(self,parent)
....
mywidgetone = widget1()
self.setCentralWidget(mywidgetone)
if __name__ == '__main__':
app = QtGui.QApplicaiton(sys.argv)
main = MainWindow()
main.show()
app.exec_()
I am sending a signal from another class to update a PySide QTableWidget but nothing is coming though. I have made this very simple for this demonstration:
This is in the controller module called Records.py
class Records(QDialog, randomDialog.Ui_watchingDialog):
signal = 1
atSig = Signal(int)
def add_button_clicked(self):
# Do some stuff
self.signal = 1
self.atSig.emit(self.signal)
# Do some other Stuff
This sits out side the controller called main.py
from controller import Records
class main(QMainWindow, pyMainWindow.Ui_mainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
signal_records = Records.Records()
signal_records.atSig.connect(self.showNewData)
def showNewData(self, signal):
if signal == 1:
print "It worked!"
else:
print "Problem"
How come this signal is not coming through? No error messages are being thrown and neither of the print statements aren't being called. How can I fix this?
signal_records falls out of scope as soon as main.__init__() returns and is garbage collected. You need to make it a member of main so that it persists for the lifetime of the class.
self.signal_records = Records.Records()
self.signal_records.atSig.connect(self.showNewData)
Alternatively, you could assign main as the parent of signal_records
signal_records = Records.Records(self)
Both methods ensure a reference to signal_records sticks around.
If It's possibly, please define this before caller to receive;
.
.
#Slot (int)
def showNewData(self, signal):
.
.
Or it not, Please check your caller def add_button_clicked(self). I work in pyqt4 (same pySide) and (I cut some part out and put some path for test in your) code, It's work.
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
class QRecordsDialog (QtGui.QDialog):
addButtonClickedSignal = QtCore.pyqtSignal(int)
def __init__ (self, parent = None):
super(QRecordsDialog, self).__init__(parent)
self.myQPushButton = QtGui.QPushButton('Test Signal', self)
self.myQHBoxLayout = QtGui.QHBoxLayout()
self.myQHBoxLayout.addWidget(self.myQPushButton)
self.setLayout(self.myQHBoxLayout)
self.myQPushButton.clicked.connect(self.addButtonClicked)
def addButtonClicked (self):
self.addButtonClickedSignal.emit(1)
class QMainWindow (QtGui.QMainWindow):
def __init__ (self, parent = None):
super(QMainWindow, self).__init__(parent)
myQRecordsDialog = QRecordsDialog(self)
myQRecordsDialog.addButtonClickedSignal.connect(self.showNewData)
myQRecordsDialog.show()
#QtCore.pyqtSlot(int)
def showNewData (self, signal):
if signal == 1:
print "It worked !"
else:
print "Problem ?"
myQApplication = QtGui.QApplication(sys.argv)
myQMainWindow = QMainWindow()
myQMainWindow.show()
sys.exit(myQApplication.exec_())
If you want to modify your PyQt code to use the PySide naming scheme, that can be done using a simple definition:
QtCore.Signal = QtCore.pyqtSignal
QtCore.Slot = QtCore.pyqtSlot
Reference this
Regards,
I'm using Qt's Graphics View Framework to display a large number of images, and implementing it using PyQt4 and Python 2.7. I instantiate a number of QPixmapItem objects and add them to my QGraphicsScene. It all works as I'd expect it to until I exit the application, and the program crashes instead of exiting normally.
class ImgDisplay(QtGui.QWidget):
NUM_ITEMS = 5000
VIEW_WIDTH,VIEW_HEIGHT = 400, 400
def __init__(self):
super(ImgDisplay, self).__init__()
self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT))
self.view = QtGui.QGraphicsView(self.scene)
self.view.setParent(self)
#Load the texture
self.texture = QtGui.QPixmap('image.png')
self.populateScene()
def populateScene(self):
for i in range(0, ImgDisplay.NUM_ITEMS-1):
item = QtGui.QGraphicsPixmapItem(self.texture)
self.scene.addItem(item)
I'm thinking that all those PixMapItems I'm creating aren't being cleaned up properly, or maybe I need to free the texture that I load (there doesn't seem to be a method to free it, so I assumed it happened in the background).
I've tried calling self.scene.clear in a destructor to delete the PixmapItems, but it didn't help.
Any suggestions on how I can fix this problem?
*I'm aware that the posted code just puts the images all on top of each other, my actual program assigns them random positions and rotations, but I wanted to reduce this to the minimal problem.
OK, understood. Problem is QtGui.QGraphicsPixmapItem can't clear itself your have to manual just like you says, but not destructor. I recommend doing after have signal close program by using closeEvent, like this;
def closeEvent (self, eventQCloseEvent):
self.scene.clear() # Clear QGraphicsPixmapItem
eventQCloseEvent.accept() # Accept to close program
and this implemented you code;
import sys
from PyQt4 import QtCore, QtGui
class ImgDisplay (QtGui.QWidget):
NUM_ITEMS = 5000
VIEW_WIDTH,VIEW_HEIGHT = 400, 400
def __init__ (self):
super(ImgDisplay, self).__init__()
self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT))
self.view = QtGui.QGraphicsView(self.scene)
self.view.setParent(self)
#Load the texture
self.texture = QtGui.QPixmap('image.png')
self.populateScene()
def populateScene (self):
for i in range(0, ImgDisplay.NUM_ITEMS-1):
item = QtGui.QGraphicsPixmapItem(self.texture)
self.scene.addItem(item)
def closeEvent (self, eventQCloseEvent):
self.scene.clear()
eventQCloseEvent.accept()
app = QtGui.QApplication([])
window = ImgDisplay()
window.show()
sys.exit(app.exec_())
I use PyQt4 (Windows 7).
And this useful to implement close event, Hope is helps;
QWidget Close Event Reference : http://pyqt.sourceforge.net/Docs/PyQt4/qwidget.html#closeEvent
LAST EDITED : 8 / 11 / 2014 01:51
If your want to control your parent & child widget to delete together, I have to implement destructor method (As your say). By use safe delete method QObject.deleteLater (self), Like this;
import sys
from PyQt4 import QtCore, QtGui
class ImgDisplay (QtGui.QWidget):
NUM_ITEMS = 5000
VIEW_WIDTH, VIEW_HEIGHT = 400, 400
def __init__ (self, parent = None):
super(ImgDisplay, self).__init__(parent)
self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT), parent = self)
self.view = QtGui.QGraphicsView(self.scene, parent = self)
#Load the texture
self.texture = QtGui.QPixmap('image.png')
self.populateScene()
def populateScene (self):
for i in range(0, ImgDisplay.NUM_ITEMS-1):
item = QtGui.QGraphicsPixmapItem(self.texture)
self.scene.addItem(item)
def __del__ (self):
self.deleteLater() # Schedules this object for deletion
app = QtGui.QApplication([])
window = ImgDisplay()
window.show()
sys.exit(app.exec_())
Warning : Don't forget set parent in your widget ! (Because some time It can't be delete itself.)
deleteLater Reference : http://pyqt.sourceforge.net/Docs/PyQt4/qobject.html#deleteLater
Regards,
I would like to highlight Josh's answer in the comments.
If you create the scene by setting the QGraphicsView as parent the crash will automatically go away.
self.view = QtGui.QGraphicsView(parent = self)
self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT), parent = self.view)
self.view.setScene(self.scene)
I am creating a GUI with a code like this:
class MyClass2(QtGui.QMainWindow):
def __init__(self, win_parent = None):
def on_blahblah_clicked(x):
if __name__ == "__main__":
# Someone is launching this directly
# Create the QApplication
app = QtGui.QApplication(sys.argv)
#The Main window
main_window = HyperlinkWindow()
main_window.show()
# Enter the main loop
app.exec_()
And I have a code for an add-in button like this:
class MyClass(object):
"""Impementation of Some_addin.button (Button)"""
def __init__(self):
#Code here
def onClick(self):
# Code
pass
I want to create an add-in button that when clicked it brings out the GUI created above. So I want to be able to call the class of the GUI code, MyClass2 in function onClick. Just like I do with a in y in the code below:
class x:
a = 1 + 1
class y:
print x.a