3

I have a working program that parses data from excel with Pandas. I tried several ways to display the output dataframe in a Qtextedit, but could never get the formatting to show up correctly. Long story short, I found a workaround online with a custom widget that works nicely. The problem I've run into is that the workaround example I found will display my data correctly in its own window, but I have not been able to figure out how to add the widget to my application. It seems to be an OOP issue. I'm learning, but cannot quite grasp what the problem is.

Below is the example widget that I have tried to add to my main application.

''' ps_QAbstractTableModel_solvents.py
use PySide's QTableView and QAbstractTableModel for tabular data
sort columns by clicking on the header title
here applied to solvents commonly used in Chemistry
PySide is the official LGPL-licensed version of PyQT
tested with PySide112 and Python27/Python33 by vegaseat  15feb2013
'''
import operator
from PySide.QtCore import *
from PySide.QtGui import *
class MyWindow(QWidget):
    def __init__(self, data_list, header, *args):
        QWidget.__init__(self, *args)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 200, 570, 450)
        self.setWindowTitle("Widget Title.")
        table_model = MyTableModel(self, data_list, header)
        table_view = QTableView()
        table_view.setModel(table_model)
        # set font
        font = QFont("Courier New", 14)
        table_view.setFont(font)
        # set column width to fit contents (set font first!)
        table_view.resizeColumnsToContents()
        # enable sorting
        table_view.setSortingEnabled(True)
        layout = QVBoxLayout(self)
        layout.addWidget(table_view)
        self.setLayout(layout)
class MyTableModel(QAbstractTableModel):
    def __init__(self, parent, mylist, header, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.mylist = mylist
        self.header = header
    def rowCount(self, parent):
        return len(self.mylist)
    def columnCount(self, parent):
        return len(self.mylist[0])
    def data(self, index, role):
        if not index.isValid():
            return None
        elif role != Qt.DisplayRole:
            return None
        return self.mylist[index.row()][index.column()]
    def headerData(self, col, orientation, role):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.header[col]
        return None
    def sort(self, col, order):
        """sort table by given column number col"""
        self.emit(SIGNAL("layoutAboutToBeChanged()"))
        self.mylist = sorted(self.mylist,
            key=operator.itemgetter(col))
        if order == Qt.DescendingOrder:
            self.mylist.reverse()
        self.emit(SIGNAL("layoutChanged()"))
# the solvent data ...
header = ['Solvent Name', ' BP (deg C)', ' MP (deg C)', ' Density (g/ml)']
# use numbers for numeric data to sort properly
data_list = [
('ACETIC ACID', 117.9, 16.7, 1.049),
('ACETIC ANHYDRIDE', 140.1, -73.1, 1.087),
('ACETONE', 56.3, -94.7, 0.791),
('ACETONITRILE', 81.6, -43.8, 0.786),
('ANISOLE', 154.2, -37.0, 0.995),
('BENZYL ALCOHOL', 205.4, -15.3, 1.045),
('BENZYL BENZOATE', 323.5, 19.4, 1.112),
('BUTYL ALCOHOL NORMAL', 117.7, -88.6, 0.81),
('BUTYL ALCOHOL SEC', 99.6, -114.7, 0.805),

]
app = QApplication([])
win = MyWindow(data_list, header)
win.show()
app.exec_()

Below is what I have attempted while trying to add the widget to my PyQT application.

#from PySide.QtCore import *
import sys
from PySide import QtCore, QtGui
import operator





##############################THIS IS THE EXAMPLE###############
# from PySide.QtCore import *
# from PySide.QtGui import *
class MyWindow(QtGui.QWidget): #changed from QWidget to QtGui.QWidget because of import difference.
    def __init__(self, data_list, header, *args):
        QtGui.QWidget.__init__(self, *args) #added QtGui. to QWidget..
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 200, 570, 450)
        self.setWindowTitle("Widget Title.")
        table_model = MyTableModel(self, data_list, header)
        table_view = QtGui.QTableView() #Added QtGui. to QTableView..
        table_view.setModel(table_model)
        # set font
        font = QtGui.QFont("Courier New", 14)   #Added QtGui. to QFont..
        table_view.setFont(font)
        # set column width to fit contents (set font first!)
        table_view.resizeColumnsToContents()
        # enable sorting
        table_view.setSortingEnabled(True)
        layout = QtGui.QVBoxLayout(self)    #Added QtGui. to QVBox..
        layout.addWidget(table_view)
        self.setLayout(layout)
class MyTableModel(QtCore.QAbstractTableModel):  #changed from QAbstractTableModel to QtCore.QAbstractTableModel
    def __init__(self, parent, mylist, header, *args):
        QtCore.QAbstractTableModel.__init__(self, parent, *args)    #changed from QAbstract to QtCore.QAbstract
        self.mylist = mylist
        self.header = header
    def rowCount(self, parent):
        return len(self.mylist)
    def columnCount(self, parent):
        return len(self.mylist[0])
    def data(self, index, role):
        if not index.isValid():
            return None
        elif role != QtCore.Qt.DisplayRole: #Added QtCore. to Qt.Display..
            return None
        return self.mylist[index.row()][index.column()]
    def headerData(self, col, orientation, role):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:   #Added QtCore. to Qt.Horiz.. and Qt.Display..
            return self.header[col]
        return None
    def sort(self, col, order):
        """sort table by given column number col"""
        self.emit(QtCore.SIGNAL("layoutAboutToBeChanged()"))    #Added QtCore. to SIGNAL..
        self.mylist = sorted(self.mylist,
            key=operator.itemgetter(col))
        if order == QtCore.Qt.DescendingOrder:  #added QtCore. to Qt.Descending...
            self.mylist.reverse()
        self.emit(QtCore.SIGNAL("layoutChanged()"))
# the solvent data ...
header = ['Solvent Name', ' BP (deg C)', ' MP (deg C)', ' Density (g/ml)']
# use numbers for numeric data to sort properly
data_list = [
('ACETIC ACID', 117.9, 16.7, 1.049),
('ACETIC ANHYDRIDE', 140.1, -73.1, 1.087),
('ACETONE', 56.3, -94.7, 0.791),
('ACETONITRILE', 81.6, -43.8, 0.786),
('ANISOLE', 154.2, -37.0, 0.995),
('BENZYL ALCOHOL', 205.4, -15.3, 1.045),
('BENZYL BENZOATE', 323.5, 19.4, 1.112),
('BUTYL ALCOHOL NORMAL', 117.7, -88.6, 0.81),
('BUTYL ALCOHOL SEC', 99.6, -114.7, 0.805),

]
# app = QApplication([])
# win = MyWindow(data_list, header)
# win.show()
# app.exec_()

###############################END EXAMPLE############################













######################THIS IS THE GUI FILE######################


class Ui_mainForm(object):
    def setupUi(self, mainForm):
        mainForm.setObjectName("mainForm")
        mainForm.resize(1075, 643)
        self.pushButton = QtGui.QPushButton(mainForm)
        self.pushButton.setGeometry(QtCore.QRect(510, 40, 93, 31))
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtGui.QLineEdit(mainForm)
        self.lineEdit.setGeometry(QtCore.QRect(40, 40, 451, 31))
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit_2 = QtGui.QLineEdit(mainForm)
        self.lineEdit_2.setGeometry(QtCore.QRect(40, 90, 451, 31))
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.pushButton_2 = QtGui.QPushButton(mainForm)
        self.pushButton_2.setGeometry(QtCore.QRect(510, 90, 93, 31))
        self.pushButton_2.setObjectName("pushButton_2")
        self.procButton = QtGui.QPushButton(mainForm)
        self.procButton.setGeometry(QtCore.QRect(260, 130, 93, 28))
        self.procButton.setObjectName("procButton")
        self.placeholderWidget = QtGui.QWidget (MyWindow(data_list, header))    ############Trying to activate the custom class in gui.. was mainForm
        self.placeholderWidget.setGeometry(QtCore.QRect(20, 179, 1011, 451))
        self.placeholderWidget.setObjectName("placeholderWidget")
        self.placeholderWidget.setAutoFillBackground(True)


        self.retranslateUi(mainForm)
        QtCore.QMetaObject.connectSlotsByName(mainForm)

    def retranslateUi(self, mainForm):
        mainForm.setWindowTitle(QtGui.QApplication.translate("mainForm", "Parser", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton.setText(QtGui.QApplication.translate("mainForm", "Browse", None, QtGui.QApplication.UnicodeUTF8))
        self.lineEdit.setPlaceholderText(QtGui.QApplication.translate("mainForm", "Select report", None, QtGui.QApplication.UnicodeUTF8))
        self.lineEdit_2.setPlaceholderText(QtGui.QApplication.translate("mainForm", "Select log file", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton_2.setText(QtGui.QApplication.translate("mainForm", "Browse", None, QtGui.QApplication.UnicodeUTF8))
        self.procButton.setText(QtGui.QApplication.translate("mainForm", "Process files", None, QtGui.QApplication.UnicodeUTF8))
        self.placeholderWidget.setToolTip(QtGui.QApplication.translate("mainForm", "THIS IS TOOLTIP", None, QtGui.QApplication.UnicodeUTF8))


###############THIS IS THE MAIN PROGRAM####################

class MainDialog(QtGui.QDialog, Ui_mainForm, MyWindow, MyTableModel):   #Attempting to add custom widget to main window. getting error "Internal C++ object (PySide.QtGui.QWidget) already deleted."
    def __init__(self, parent=None):
        super(MainDialog, self).__init__(parent)
        self.setupUi(self)


app = QtGui.QApplication(sys.argv)  #Changed from QApplication to QtGui.QApplication because of different import method from seperate gui file.
mainForm = MainDialog()
mainForm.show()
# win = MyWindow(data_list, header)     #These two lines display the custom example widget outside of the main window.
# win.show()                              #These two lines display the custom example widget outside of the main window.

app.exec_()

##########END MAIN PROGRAM##########


# app = QtGui.QApplication([])   #Added QtGui. to QApplication
# win = MyWindow(data_list, header)     #Now to somehow add this to main window............
# win.show()
# app.exec_()

I have not been able make the custom widget appear in the main application. Additionally I am getting an error message at execution. Below is the full error message.

C:\Python27\python.exe C:/Users/Dirk/PycharmProjects/QwidgetTest_fromExample/Attempt-incorporate-example2.py
Traceback (most recent call last):
  File "C:/Users/Dirk/PycharmProjects/QwidgetTest_fromExample/Attempt-incorporate-example2.py", line 143, in <module>
    mainForm = MainDialog()
  File "C:/Users/Dirk/PycharmProjects/QwidgetTest_fromExample/Attempt-incorporate-example2.py", line 139, in __init__
    self.setupUi(self)
  File "C:/Users/Dirk/PycharmProjects/QwidgetTest_fromExample/Attempt-incorporate-example2.py", line 116, in setupUi
    self.placeholderWidget.setGeometry(QtCore.QRect(20, 179, 1011, 451))
RuntimeError: Internal C++ object (PySide.QtGui.QWidget) already deleted.

Process finished with exit code 1
Dirk
  • 31
  • 1
  • Don't edit the gui module generated by pyside-uic/pyuic, use [widget promotion](http://stackoverflow.com/a/42076247/984421/). – ekhumoro Feb 10 '17 at 00:20
  • What are you trying to do with this ` self.placeholderWidget = QtGui.QWidget (MyWindow (data_list, header))`? – eyllanesc Feb 10 '17 at 01:38
  • and this: class MainDialog(QtGui.QDialog, Ui_mainForm, MyWindow, MyTableModel) – eyllanesc Feb 10 '17 at 01:39
  • I was importing the gui module generated by pyside-uic before, but included it for brevity for the post. The self.placeholderWidget was where I intended to incorporate the example code with the custom gui. – Dirk Feb 10 '17 at 01:43
  • PySide automatically removes all objects if you don't keep reference to them, but why `placeholderWidget` is removed is unclear. I would note PySide version and try with PyQt4. – anatoly techtonik Mar 11 '17 at 18:14

0 Answers0