I broke my question down to a very basic setup. Each tab allows a user to click a button and append and item to the list. At the same time the item is added to the list, it's also added to a global variable called ALLITEMs. Each tab is given it's over dictionary to append to as seen here..
ALLITEMS = {
"A" : [],
"B" : []
}
In the main widget on the 'closeEvent' i save this variable to a json file. Also in the main widgets 'showEvent' i load this data back into the global bariable ALLITEMS. This allows users to retain the data each time the launch the application. What I'm not sure about is how to refresh the tab widgets to repopulate the GUI's with the data from the variable. But only when the tool is initially launched. I don't want it to load each time the user clicks that tab, that would produce duplicate data.
import sys
import json
import os
from PySide import QtGui, QtCore
ALLITEMS = {
"A" : [],
"B" : []
}
# Widgets
# ------------------------------------------------------------------------------
class ExampleA(QtGui.QWidget):
def __init__(self):
super(ExampleA, self).__init__()
self.initUI()
def initUI(self):
# formatting
self.resize(550, 400)
self.setWindowTitle("Tab A")
# widgets
self.ui_listview = QtGui.QListWidget()
self.ui_add = QtGui.QPushButton("Add Item")
# signals
self.ui_add.clicked.connect(self.add_item_clicked)
# main layout
main_layout = QtGui.QVBoxLayout()
main_layout.addWidget(self.ui_add)
main_layout.addWidget(self.ui_listview)
main_layout.setContentsMargins(0,0,0,0)
self.setLayout(main_layout)
def add_item_clicked(self):
global ALLITEMS
item = "Another item A"
ALLITEMS["A"].append(item)
self.ui_listview.addItem( item )
class ExampleB(QtGui.QWidget):
def __init__(self):
super(ExampleB, self).__init__()
self.initUI()
def initUI(self):
# formatting
self.resize(550, 400)
self.setWindowTitle("Tab A")
# widgets
self.ui_listview = QtGui.QListWidget()
self.ui_add = QtGui.QPushButton("Add Item")
# signals
self.ui_add.clicked.connect(self.add_item_clicked)
# main layout
main_layout = QtGui.QVBoxLayout()
main_layout.addWidget(self.ui_add)
main_layout.addWidget(self.ui_listview)
main_layout.setContentsMargins(0,0,0,0)
self.setLayout(main_layout)
def add_item_clicked(self):
global ALLITEMS
item = "Another item B"
ALLITEMS["B"].append(item)
self.ui_listview.addItem( item )
class ExampleMain(QtGui.QWidget):
def __init__(self):
super(ExampleMain, self).__init__()
self.initUI()
def initUI(self):
# formatting
self.resize(200, 200)
self.setWindowTitle("Test")
# widgets
tab_panel = QtGui.QTabWidget()
tab_panel.addTab(ExampleA(), "Tab A")
tab_panel.addTab(ExampleB(), "Tab B")
# main layout
main_layout = QtGui.QVBoxLayout()
main_layout.addWidget(tab_panel)
main_layout.setContentsMargins(0,0,0,0)
self.setLayout(main_layout)
def closeEvent(self, event):
self.save_data()
def showEvent(self, event):
self.load_data()
def save_data(self):
print "Saving..."
global ALLITEMS
json.dump(ALLITEMS, open("Example_Data.json",'w'), indent=4)
def load_data(self):
global ALLITEMS
if os.path.exists( "Example_Data.json" ):
with open( "Example_Data.json" ) as f:
data = json.load(f)
ALLITEMS = data
# Main
# ------------------------------------------------------------------------------
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = ExampleMain()
ex.show()
sys.exit(app.exec_())
The simpliest (although not very effective) way would be to update list widget from ALLITEMS dictionary each time you change it. So on every button press you could update ALLITEMS first, then clear the content of list widget and refill it according to new value of ALLITEMS["TabName"]. Then on show event you could do the same - load ALLITEMS from file once and then update list widget.
For more effective approach take a look at Qt Model/View programming (http://doc.qt.io/qt-5/model-view-programming.html) You will probably need to replace QListWidget with QListView
I would remove the global variable entirely.
In your closeEvent, instead of saving the global variable, read the items from the listview directly and save them. In your add_item method, don't modify the global variable at all.
Then in your load_data function, read the data from the file and add the items to the listviews.
You will need to store references to the ex.ample widgets
self.example_a = ExampleA()
self.example_b = ExampleB()
tab_panel.addTab(self.example_a), "Tab A")
tab_panel.addTab(self.example_b), "Tab B")
Here's how you could save and load the data:
def save_data(self):
print "Saving..."
all_items = {}
for i in range(self.example_a.ui_listview.count()):
text = self.example_a.ui_listview.item(i).text()
all_items.set_default('A', []).append(text)
for i in range(self.example_b.ui_listview.count()):
text = self.example_b.ui_listview.item(i).text()
all_items.set_default('B', []).append(text)
json.dump(all_items, open("Example_Data.json",'w'), indent=4)
def load_data(self):
if os.path.exists( "Example_Data.json" ):
with open( "Example_Data.json" ) as f:
all_items = json.load(f)
for text in all_items.get('A', []):
self.example_a.ui_listview.addItem(text)
for text in all_items.get('B', []):
self.example_b.ui_listview.addItem(text)
Also, in general, it's usually bad design for a parent widget to access grandchild widgets directly (ui_listview is a grandchild of your main widget ExampleMain class). It's generally better form for your widgets to define some type of interface for portraying what they need saved and loaded.
class ExampleMain:
def save_data(self):
data = {}
data['example_a'] = self.example_a.save_data()
data['example_b'] = self.example_b.save_data()
# Save to file
def load_data(self):
data = ... # read from file
self.example_a.load_data(data.get('example_a'))
self.example_b.load_data(data.get('example_b'))
class ExampleA:
def save_data(self):
data = []
for i in range(self.ui_listview.count()):
text = self.ui_listview.item(i).text()
data.append(text)
return data
def load_data(self, data):
for text in data:
self.ui_listview.addItem(text)
Related
I am developing a GUI that imports and plots data (csv file). Data are initially imported in the TabWidget() class using getfile() and on_pushButtonLoad_clicked() and passed to the FirstTab() class, where MRChart() is plotted in the infrastructure() widget. To achieve this, I created the firstTab instance in TabWidget() (apologies if my terminology is incorrect here).
The end goal is to update the plot based on the numerical range selected on a rangeslider. Firstly, I want to pass the value of slider1 to FirstTab() and I should be able to manage from there. To do this, I have attempted to create the tabwidget instance in FirstTab(). However, I get the following: "RecursionError: maximum recursion depth exceeded". I presume this is due to each class having an instance of itself contained in the other.
Any help appreciated.
Code:
class TabWidget(QDialog):
def __init__(self, data):
super(TabWidget, self).__init__()
self.data = data
self.firstTab = FirstTab(self.data)
self.showMaximized()
# create Header
FilterLayout = QHBoxLayout()
FilterLayout.addWidget(self.createHeader1a(), 1)
FilterLayout.addWidget(self.createHeader2a(), 4)
# create Tab
tabwidget = QTabWidget()
tabwidget.addTab(self.firstTab, "Tab 1")
vbox = QVBoxLayout()
vbox.addLayout(FilterLayout)
vbox.addWidget(tabwidget)
self.setLayout(vbox)
def createHeader1a(self): #Import
HeaderBox = QGroupBox("Import Data")
inputfilebtn = QPushButton("Import")
inputfilebtn.clicked.connect(self.on_pushButtonLoad_clicked)
# importrow1
importrow1layout = QHBoxLayout()
importrow1layout.addWidget(inputfilebtn)
HeaderLayout = QVBoxLayout()
HeaderLayout.addLayout(importrow1layout)
HeaderBox.setLayout(HeaderLayout)
HeaderBox.setFlat(True)
return HeaderBox
def createHeader2a(self): #Filter
HeaderBox = QGroupBox("Filter Data")
rightlayout = QHBoxLayout()
# range slider bar to filter column data for plotting
label4 = QLabel(self)
label4.setText("Filter range:")
rightlayout.addWidget(label4)
self.slider1 = QLabeledRangeSlider(Qt.Horizontal)
self.slider1.setRange(5, 500)
self.slider1.setValue((150, 300))
rightlayout.addWidget(self.slider1)
HeaderBox.setLayout(rightlayout)
HeaderBox.setFlat(True) #
return HeaderBox
#import and return file
def getfile(self):
option = QFileDialog.Options()
fname = QFileDialog.getOpenFileName(self, 'Open file',
'c:\\', "CSV files (*.csv)", options=option)
return pd.read_csv(fname[0])
#QtCore.pyqtSlot()
def on_pushButtonLoad_clicked(self):
importedfile = self.getfile()
if importedfile is None:
return
self.firstTab.MRChart(importedfile)
global database
database = importedfile
def getslider1value(self):
return self.slider1.value
class FirstTab(QWidget):
def __init__(self, data):
super(FirstTab, self).__init__()
self.data = data
self.tabwidget = TabWidget(self.data)# issue here. Attempting to # access TabWidget class
# Grid layout of entire tab
layout = QGridLayout()
layout.addWidget(self.infrastructure(self.data), 3, 0)
layout.setRowStretch(4, 3)
layout.setColumnStretch(0, 1)
self.setLayout(layout)
def MRChart(self, importedfile): # pie chart
if self.radioButton1.isChecked():
fig = go.Pie(labels=importedfile[self.radioButton1.label])
elif self.radioButton2.isChecked():
fig = go.Pie(labels=importedfile[self.radioButton2.label])
layout = go.Layout(autosize=True, legend=dict(orientation="h", xanchor='center', x=0.5))
fig = go.Figure(data=fig, layout=layout)
fig.update_layout(margin=dict(t=0, b=0, l=0, r=0))
self.browser.setHtml(fig.to_html(include_plotlyjs='cdn'))
def infrastructure(self, importedfile):
groupBox = QGroupBox("Plot")
self.browser = QtWebEngineWidgets.QWebEngineView(self)
right = QVBoxLayout()
# Change/update plot (MRChart) depending on what Radio button is selected
self.radioButton1 = QRadioButton("Label 1")
self.radioButton1.label = "Column_label_1"
self.radioButton1.toggled.connect(lambda: self.MRChart(database))
right.addWidget(self.radioButton1)
self.radioButton2 = QRadioButton("Label 2")
self.radioButton2.setChecked(True)
self.radioButton2.label = "Column_label_2"
self.radioButton2.toggled.connect(lambda: self.MRChart(database))
right.addWidget(self.radioButton2)
middleright = QHBoxLayout()
middleright.addWidget(self.browser)
middleright.addLayout(right)
groupBox.setLayout(middleright)
groupBox.setFlat(True)
print(self.tabwidget.getslider1value())# attempting to print slider value here
return groupBox
if __name__ == "__main__":
app = QApplication(sys.argv)
tabwidget = TabWidget(data=None)
tabwidget.show()
app.exec()
The recursion error is clear: TabWidget tries to create FirstTab, but there you're trying to create another TabWidget, which will create a further FirstTab and so on.
If you want to keep reference between objects, you must pass references, not create new instances (see the note below).
Also, since FirstTab calls infrastructure in the __init__, at that point the slider in the parent widget has not been created yet.
You must move the creation of FirstTab after the slider is created, and pass the reference in the constructor.
class TabWidget(QDialog):
def __init__(self, data):
super(TabWidget, self).__init__()
self.data = data
self.showMaximized()
# create Header
FilterLayout = QHBoxLayout()
FilterLayout.addWidget(self.createHeader1a(), 1)
FilterLayout.addWidget(self.createHeader2a(), 4)
self.firstTab = FirstTab(self) # <- pass the reference of the parent
# ...
class FirstTab(QWidget):
def __init__(self, tabwidget):
super(FirstTab, self).__init__()
self.tabwidget = tabwidget
self.data = tabwidget.data
# ...
Note that this is the same problem you had in your previous question. I strongly suggest you to review the basics of classes and instances and OOP in general, as knowledge and comprehension of those aspects cannot be ignored.
I'm trying to figure out how I can get the QWidget that I insert into a QListWidget as a QListWidgetItem to be able to access the list it is a part of so that it can do the following:
Increase/decrease it's position in the list
Remove itself from the list
Pass information from it's own class to a function in the main class
My script layout is a main.py which is where the MainWindow class is. The MainWindow uses the class generated from the main ui file. I also have the custom widget which is it's own class.
Example of GUI:
Relevant code snippets:
main.py
from PyQt4.QtGui import QMainWindow, QApplication
from dungeonjournal import Ui_MainWindow
from creature_initiative_object import InitCreatureObject
from os import walk
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(QMainWindow, self).__init__(parent)
self.setupUi(self)
etc......
def AddToInitiative(self):
creature = self.comboBoxSelectCharacter.currentText()
if(creature):
creatureInfo = ''
with open("creatures/"+str(creature)+".creature", "r") as f:
creatureInfo = f.read()
creatureInfo = creatureInfo.split("|")
customWidget = InitCreatureObject()
customWidgetItem = QtGui.QListWidgetItem(self.initiativeList)
customWidgetItem.setSizeHint(QtCore.QSize(400,50))
self.initiativeList.addItem(customWidgetItem)
self.initiativeList.setItemWidget(customWidgetItem, customWidget)
customWidget.setName(creatureInfo[0])
return
creature_initiative_object.py
class Ui_InitCreatureObject(object):
def setupUi(self, InitCreatureObject):
etc...
class InitCreatureObject(QtGui.QWidget, Ui_InitCreatureObject):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QWidget.__init__(self, parent, f)
self.setupUi(self)
Edit 1:
To clarify again, I need to be able to use the buttons in the widget to modify the position of itself in the list. The list is part of the main ui. The buttons for up arrow, down arrow, Select, and Remove are the one's I'm trying to get to interact with things outside of their class.
The function they call needs to be able to determine which listItem is being called, be able to modify the list.
For example, if I click remove, it then needs to know which item in the list to remove. So it needs to first know what the list is, then it needs to know what item it is. I'm not sure how to access the instance of the widget that is occupying that listitem. I also am not sure how to get that listitem based on a button press from inside that listitem's class.
Edit 2:
Per the first answer I tried to work that into my code.
main.py had the following function added
def RemoveItem(self):
cwidget = self.sender().parent()
item = self.initiativeList.itemAt(cwidget.pos())
row = self.initiativeList.row(item)
self.initiativeList.takeItem(row)
print(row)
creature_initiative_object.py had the following added to the InitCreatureObject class
class InitCreatureObject(QtGui.QWidget, Ui_InitCreatureObject):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QWidget.__init__(self, parent, f)
self.setupUi(self)
self.mainwidget = main.MainWindow()
self.btnRemove.clicked.connect(self.mainwidget.RemoveItem)
Item is still not being passed. The parent object seems to be right but when I get the row it always says -1.
The strategy to get the QTableWidgetItem is to use the itemAt() method but for this you must know the position of some point within the QTableWidgetItem.
Since the main objective is to get the item when a signal is sent, then the connected slot is used, so I recommend connecting all the signals to that slot. Given the above the following steps are taken:
Get the object that emits the signal through sender().
Get the sender parent() since this will be the custom widget that was added to the QListWidget() along with the item.
Get the position of the custom widget through pos(), this is the position that should be used in the itemAt() method.
Then you get the text of the button or some parameter that tells me the task to know what action you want to do.
The above can be implemented as follows:
def someSlot(self):
p = self.sender().parent()
it = self.lw.itemAt(p.pos())
text = self.sender().text()
if text == "task1":
do task1
elif text == "task2":
do task2
From the above, the following example is proposed:
class CustomWidget(QWidget):
def __init__(self, text, parent=None):
QWidget.__init__(self, parent)
self.setLayout(QHBoxLayout())
self.buttons = []
vb = QVBoxLayout()
self.layout().addLayout(vb)
self.btnTask1 = QPushButton("task1")
self.btnTask2 = QPushButton("task2")
vb.addWidget(self.btnTask1)
vb.addWidget(self.btnTask2)
self.buttons.append(self.btnTask1)
self.buttons.append(self.btnTask2)
self.btnTask3 = QPushButton("task3")
self.btnTask4 = QPushButton("task4")
self.btnTask5 = QPushButton("task5")
self.btnTask6 = QPushButton("task6")
self.layout().addWidget(self.btnTask3)
self.layout().addWidget(self.btnTask4)
self.layout().addWidget(self.btnTask5)
self.layout().addWidget(self.btnTask6)
self.buttons.append(self.btnTask3)
self.buttons.append(self.btnTask4)
self.buttons.append(self.btnTask5)
self.buttons.append(self.btnTask6)
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.lw = QListWidget(self)
self.setCentralWidget(self.lw)
for i in range(5):
cw = CustomWidget("{}".format(i))
for btn in cw.buttons:
btn.clicked.connect(self.onClicked)
item = QListWidgetItem(self.lw)
item.setSizeHint(QSize(400, 80))
self.lw.addItem(item)
self.lw.setItemWidget(item, cw)
def onClicked(self):
p = self.sender().parent()
it = self.lw.itemAt(p.pos())
row = self.lw.row(it)
text = self.sender().text()
print("item {}, row {}, btn: {}".format(it, row, text))
#if text == "task1":
# do task1
#elif text == "task2":
# do task2
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
In your Case:
class MainWindow(QMainWindow, Ui_MainWindow):
[...]
def AddToInitiative(self):
[...]
customWidget = InitCreatureObject()
customWidget.btnRemove.clicked.connect(self.RemoveItem)
# ^^^^^
[...]
def RemoveItem(self):
cwidget = self.sender().parent()
item = self.initiativeList.itemAt(cwidget.pos())
row = self.initiativeList.row(item)
self.initiativeList.takeItem(row)
print(row)
I have found a very nice solution here on this site in order to store gui settings in pyqt5: Python PyQt4 functions to save and restore UI widget values?
The solution is saved in the function guisave.
Now I'm trying to implement this to my code.
The idea is to close my gui with the exitAction button. This fires the closeApp function which fires the guisave function.
The guisave function should save now all my pyqt objects.
The problem is that this does not happen. I'm not sure how I need to assign the ui variable in the guisave function.
As you can see I tried to assign the mainwindow class. But this does not work. I'm also not sure if this works at all or if I need to scan all functions separately since the QEditLine are in the tab2UI function.
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import inspect
class mainwindow(QMainWindow):
def __init__(self, parent = None):
super(mainwindow, self).__init__(parent)
self.initUI()
def initUI(self):
exitAction = QAction(QIcon('icon\\exit.png'), 'Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(qApp.quit)
exitAction.triggered.connect(self.closeApp)
self.toolbar = self.addToolBar('Exit')
self.toolbar.setMovable(False)
self.toolbar.addAction(exitAction)
self.tab_widget = QTabWidget(self) # add tab
self.tab2 = QWidget()
self.tab_widget.addTab(self.tab2, "Tab_2")
self.tab2UI()
self.setCentralWidget(self.tab_widget)
def tab2UI(self):
self.layout = QFormLayout()
self.layout.addRow("Name",QLineEdit())
self.layout.addRow("Address",QLineEdit())
self.tab2.setLayout(self.layout)
def closeApp(self):
guisave()
def guisave():
ui = mainwindow
settings = QSettings('gui.ini', QSettings.IniFormat)
for name, obj in inspect.getmembers(ui):
if isinstance(obj, QComboBox):
name = obj.objectName() # get combobox name
index = obj.currentIndex() # get current index from combobox
text = obj.itemText(index) # get the text for current index
settings.setValue(name, text) # save combobox selection to registry
if isinstance(obj, QLineEdit):
print obj.objectName()
name = obj.objectName()
value = obj.text()
settings.setValue(name, value) # save ui values, so they can be restored next time
print name, value
if isinstance(obj, QCheckBox):
name = obj.objectName()
state = obj.isChecked()
settings.setValue(name, state)
if isinstance(obj, QRadioButton):
name = obj.objectName()
value = obj.isChecked() # get stored value from registry
settings.setValue(name, value)
def main():
app = QApplication(sys.argv)
ex = mainwindow()
ex.setGeometry(100,100,1000,600)
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The solution that I propose is responsible for saving the states of the QWidgets, but for this you must put a name through the property objectName:
objectName : QString
This property holds the name of this object. You can find an object by name (and type) using findChild(). You can
find a set of objects with findChildren().
Access functions:
QString objectName() const
void setObjectName(const QString &name)
So you should put a name, for example:
self.tab_widget.setObjectName("tabWidget")
We can use the QApplication :: allWidgets () function to get all the widgets of the application, and then we get the properties and save them, the process of restoring is the reverse of the previous one.
def restore(settings):
finfo = QFileInfo(settings.fileName())
if finfo.exists() and finfo.isFile():
for w in qApp.allWidgets():
mo = w.metaObject()
if w.objectName() != "":
for i in range(mo.propertyCount()):
name = mo.property(i).name()
val = settings.value("{}/{}".format(w.objectName(), name), w.property(name))
w.setProperty(name, val)
def save(settings):
for w in qApp.allWidgets():
mo = w.metaObject()
if w.objectName() != "":
for i in range(mo.propertyCount()):
name = mo.property(i).name()
settings.setValue("{}/{}".format(w.objectName(), name), w.property(name))
The complete example is found here
I have been trying to create a settings window for an application I'm developing and I want to populate the settings window with either a config file (which I will later write the answers to) or the system defaults if the config file is absent or cannot be opened.
I have seen examples where a few values are populated after the setupUi(self) is executed, however I have around 15-20 values and so having 2 huge if statements seems messy. Here is my current state of affairs and I can't figure out how to make it call the function I have created getConfig
Is this the best way to populate values? Or is there something else I should try?
class SettingsWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_SettingsWindow()
self.ui.setupUi(self)
self.ui.getConfig(self) #my problem is here
... #all the action bindings
def getConfig(self):
if not os.path.exists('app.config'):
self.ui.setDefaults(self) #fallback to defaults if no config file
with open('app.config') as f:
self.config = json.load(f)
... #bind all the default values
Here is an example using a dictionary to store the widgets - see my comment.
Only one EditLine updated but principal is there (Note the label could also be updated in the same way.
from PyQt4 import QtGui, QtCore
class MyWindow(QtGui.QWidget): # any super class is okay
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.settings = {}
var_label = QtGui.QLabel('Path')
self.settings['path'] = QtGui.QLineEdit(width=200)
quitbutton = QtGui.QPushButton('Quit')
loadbutton = QtGui.QPushButton('Load Settings')
savebutton = QtGui.QPushButton('Save Settings')
layout1 = QtGui.QHBoxLayout()
layout1.addWidget(var_label)
layout1.addWidget(self.settings['path'])
layout2 = QtGui.QHBoxLayout()
layout2.addWidget(loadbutton)
layout2.addWidget(savebutton)
layout2.addWidget(quitbutton)
layout = QtGui.QVBoxLayout()
layout.addLayout(layout1)
layout.addLayout(layout2)
self.setLayout(layout)
loadbutton.clicked.connect(self.get_config)
savebutton.clicked.connect(self.save_settings)
quitbutton.clicked.connect(QtGui.qApp.quit)
self.get_config()
def get_config(self):
# Read config file here into dictionary
# Example
config_data = {'path':'data path here'} # Example dictionary created when reading config file
for key in config_data:
self.settings[key].setText(config_data[key])
def save_settings(self): # Link to button
data = {}
for key in self.settings:
data[key] = self.settings[key].text()
# Save to config file here
print (data)
if __name__ == '__main__':
app = QtGui.QApplication([])
window = MyWindow()
window.show()
app.exec_()
If the widgets you use are not set by setText() or retrieved by text() then the code is a little more complex, various ways of doing that for TextEdit, Lists, Combo etc. can be incorporated.
I have created a window with QTableWidget having a cell with 2 buttons.
Buttons are created in seperate class where i am passing QTableWidget instance from main procedure.
I am not able to get the button events, which are connected in button Creation class. My code snippet is as below
class Buttons():
def __init__(self,tab):
buttonLayout = QtGui.QHBoxLayout()
buttonLayout.setContentsMargins(0,0,0,0)
self.saveButtonItem = QtGui.QPushButton('Save')
self.deleteButtonItem = QtGui.QPushButton('Delete')
buttonLayout.addWidget(self.saveButtonItem)
buttonLayout.addWidget(self.deleteButtonItem)
cellWidget = QtGui.QWidget()
cellWidget.setLayout(buttonLayout)
tab.insertRow(tab.rowCount())
tab.setCellWidget(tab.rowCount() - 1,0,cellWidget)
self.setconncection()
def setconncection(self):
self.saveButtonItem.clicked.connect(self.btnSaveClicked)
self.deleteButtonItem.clicked.connect(self.btnDeleteClicked)
print 'connections are set'
def btnSaveClicked(self):
print 'save clicked'
def btnDeleteClicked(self):
print 'delete clicked'
class testing(QtGui.QTableWidget):
def __init__(self):
super(testing,self).__init__()
self.setColumnCount(1)
for i in xrange(3):
self.r = Buttons(self)
if __name__ == "__main__" :
import sys
app = QtGui.QApplication (sys.argv)
win = testing ()
win.show()
sys.exit(app.exec_())
My window at run time is as below
After the __init__ of testing, the reference to Buttons instance is lost and the object is destroyed. (Variable r is affected but not used.)
Keeping a link to it (see last line in following code snippet) makes it work.
class testing(QtGui.QTableWidget):
def __init__(self):
super(testing,self).__init__()
self.setColumnCount(1)
self.setRowCount(1)
self.buttons = []
for i in xrange(3):
self.buttons.append(Buttons(self))