Python and PyQt: run function from another class

2019-04-02 01:03发布

问题:

Update 3:

Here's the new code, trying to do what you told me to, with no results... I'm starting to think that I have done something very foolish somewhere in my program... Any new ideas?

program.py:

# -*- coding: utf-8 -*-
#imports:
import os
import platform
import sys
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import newchilddlg
from newchilddlg import *

#version:
__version__ = "1.0.0"


#Lists:
am = []
courtdate = []
board_number = []
namesurname = []
fathersname = []
mothersname = []
birthday = []
placeofbirth = []
nationality = []
address = []
tel = []
job = []
praxis = []
dayofdoing = []
placeofdoing = [] 
children = [am, courtdate, board_number, namesurname, fathersname, mothersname, birthday, placeofbirth, nationality, address, tel, job, praxis, dayofdoing, placeofdoing]


#Main Window Class:
class MainWindow(QMainWindow):


    #__init__ function:
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        #Window size:
        self.resize(800,600)
        self.centralwidget = QtGui.QWidget(self)
        self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)

        #Table Widget:
        self.tableWidget = QtGui.QTableWidget(self.centralwidget)
        self.vBar = self.tableWidget.verticalScrollBar()
        self._vBar_lastVal = self.vBar.value()
        self.horizontalLayout.addWidget(self.tableWidget)
        self.vBar.valueChanged.connect(self.scrollbarChanged)
        self.tableWidget.setGridStyle(QtCore.Qt.SolidLine)
        self.tableWidget.setRowCount(100)
        self.tableWidget.setColumnCount(15)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(2, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(3, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(4, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(5, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(6, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(7, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(8, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(9, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(10, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(11, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(12, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(13, item)
        item = QtGui.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(14, item)
        self.tableWidget.horizontalHeader().setDefaultSectionSize(140)
        self.tableWidget.horizontalHeader().setHighlightSections(True)
        self.tableWidget.horizontalHeader().setStretchLastSection(False)
        self.tableWidget.verticalHeader().setDefaultSectionSize(30)
        self.tableWidget.verticalHeader().setStretchLastSection(False)
        self.horizontalLayout.addWidget(self.tableWidget)
        self.setCentralWidget(self.centralwidget)

        #Window Title:
        self.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
        self.tableWidget.setSortingEnabled(False)

        #Collumns'names:
        item = self.tableWidget.horizontalHeaderItem(0)
        item.setText(QtGui.QApplication.translate("MainWindow", "Α.Μ.", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(1)
        item.setText(QtGui.QApplication.translate("MainWindow", "Ημερομηνία Δικάσιμου", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(2)
        item.setText(QtGui.QApplication.translate("MainWindow", "Αριθμός Πινακίου", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(3)
        item.setText(QtGui.QApplication.translate("MainWindow", "Ονοματεπώνυμο", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(4)
        item.setText(QtGui.QApplication.translate("MainWindow", "Όνομα Πατρός", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(5)
        item.setText(QtGui.QApplication.translate("MainWindow", "Όνομα Μητρός", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(6)
        item.setText(QtGui.QApplication.translate("MainWindow", "Ημερομηνία Γέννησης", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(7)
        item.setText(QtGui.QApplication.translate("MainWindow", "Τόπος Γέννησης", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(8)
        item.setText(QtGui.QApplication.translate("MainWindow", "Εθνικότητα", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(9)
        item.setText(QtGui.QApplication.translate("MainWindow", "Διεύθυνση Κατοικίας", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(10)
        item.setText(QtGui.QApplication.translate("MainWindow", "Τηλέφωνο", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(11)
        item.setText(QtGui.QApplication.translate("MainWindow", "Επάγγελμα-Ιδιότητα", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(12)
        item.setText(QtGui.QApplication.translate("MainWindow", "Πράξη", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(13)
        item.setText(QtGui.QApplication.translate("MainWindow", "Ημερομηνία Τέλεσης", None, QtGui.QApplication.UnicodeUTF8))
        item = self.tableWidget.horizontalHeaderItem(14)
        item.setText(QtGui.QApplication.translate("MainWindow", "Τόπος Τέλεσης", None, QtGui.QApplication.UnicodeUTF8))

        #menubar:
        self.menubar = QtGui.QMenuBar(self)
        self.menubar.setEnabled(True)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menuFile = self.menubar.addMenu("&File")
        self.menuFile.setSizeIncrement(QtCore.QSize(0, 0))
        self.menuEdit = self.menubar.addMenu("&Edit")
        self.setMenuBar(self.menubar)
        self.menuFile.setTitle(QtGui.QApplication.translate("MainWindow", "File", None, QtGui.QApplication.UnicodeUTF8))
        self.menuEdit.setTitle(QtGui.QApplication.translate("MainWindow", "Edit", None, QtGui.QApplication.UnicodeUTF8)) 

        #Creating Action filenewchild:
        self.filenewchild = self.createAction("&Εισαγωγή Ανηλίκου", self.doupdate, "Ctrl+C", "" ,"Εισαγωγή Δεδομέων Ανηλίκου")
        self.menuFile.addAction(self.filenewchild)
        self.filenewchild.setText(QtGui.QApplication.translate("MainWindow", "Εισαγωγή Ανηλίκου", None, QtGui.QApplication.UnicodeUTF8))

        #Adding objects from lists to the Table Widget:
        r=0
        c=0
        for x in children:
            for i in x:
                newItem = QtGui.QTableWidgetItem(i)
                self.tableWidget.setItem(r, c, newItem)
                r += 1
            r = 0
            c += 1


    # Growing rows while scrolling down....
    def scrollbarChanged(self, val):
        bar = self.vBar
        minVal, maxVal = bar.minimum(), bar.maximum()
        avg = (minVal+maxVal)/2
        rowCount = self.tableWidget.rowCount()
        if val > self._vBar_lastVal and val >= avg:
            self.tableWidget.insertRow(rowCount)
        elif val < self._vBar_lastVal:
            lastRow = rowCount-30
            empty = True
            for col in xrange(self.tableWidget.columnCount()):
                item = self.tableWidget.item(lastRow, col)
                if item and item.text():
                    empty=False
                    break
            if empty:
                self.tableWidget.removeRow(lastRow)
        self._vBar_lastVal = val    


    #A function to help us create Actions faster:
    def createAction(self,text, slot=None, shortcut=None, icon=None,
                     tip=None, checkable=False, signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action    


    #A function that updates the table:
    def updatetable(self):
        self.tableWidget.clear()
        r=0
        c=0
        for x in children:
            for i in x:
                newItem = QtGui.QTableWidgetItem(i)
                self.tableWidget.setItem(r, c, newItem)
                r += 1
            r = 0
            c += 1    


    #Handles NewChildDlg actions:
    def doupdate(self):
        newchilddlg.main()
        d = NewChildDlg(self)
        if d.accept():
            text = NewChildDlg.text()
            am.append(text)
            self.updatetable()


#Main loop:
if __name__ == '__main__':
    app = QApplication(sys.argv)
    myapp = MainWindow()
    myapp.show()
    sys.exit(app.exec_())

newchilddlg.py:

# -*- coding: utf-8 -*-
#imports:
from PyQt4 import QtCore, QtGui
import sys
from PyKDE4.kdeui import KDateComboBox
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import program
from program import *


#NewChildDialog Class:
class NewChildDlg(QDialog):


    #__init__ function:
    def __init__(self, parent=None):
       super(NewChildDlg, self).__init__(parent)
       self.resize(400, 600)
       self.lineEdit = QtGui.QLineEdit(self)
       self.lineEdit.setGeometry(QtCore.QRect(160, 20, 211, 23))
       self.lineEdit.editingFinished.connect(self.amlist)
       self.kdatecombobox = KDateComboBox(self)
       self.kdatecombobox.setGeometry(QtCore.QRect(160, 50, 211, 23))
       self.lineEdit2 = QtGui.QLineEdit(self)
       self.lineEdit2.setGeometry(QtCore.QRect(160, 80, 211, 23))
       self.lineEdit3 = QtGui.QLineEdit(self)
       self.lineEdit3.setGeometry(QtCore.QRect(160, 110, 211, 23))
       self.lineEdit4 = QtGui.QLineEdit(self)
       self.lineEdit4.setGeometry(QtCore.QRect(160, 140, 211, 23))
       self.lineEdit5 = QtGui.QLineEdit(self)
       self.lineEdit5.setGeometry(QtCore.QRect(160, 170, 211, 23))
       self.kdatecombobox2 = KDateComboBox(self)
       self.kdatecombobox2.setGeometry(QtCore.QRect(160, 200, 211, 23))
       self.lineEdit6 = QtGui.QLineEdit(self)
       self.lineEdit6.setGeometry(QtCore.QRect(160, 230, 211, 23))
       self.lineEdit7 = QtGui.QLineEdit(self)
       self.lineEdit7.setGeometry(QtCore.QRect(160, 260, 211, 23))
       self.lineEdit8 = QtGui.QLineEdit(self)
       self.lineEdit8.setGeometry(QtCore.QRect(160, 290, 211, 23))
       self.lineEdit9 = QtGui.QLineEdit(self)
       self.lineEdit9.setGeometry(QtCore.QRect(160, 320, 211, 23))
       self.lineEdit10 = QtGui.QLineEdit(self)
       self.lineEdit10.setGeometry(QtCore.QRect(160, 350, 211, 23))
       self.lineEdit11 = QtGui.QLineEdit(self)
       self.lineEdit11.setGeometry(QtCore.QRect(160, 380, 211, 23))
       self.kdatecombobox3 = KDateComboBox(self)
       self.kdatecombobox3.setGeometry(QtCore.QRect(160, 410, 211, 23))
       self.lineEdit12 = QtGui.QLineEdit(self)
       self.lineEdit12.setGeometry(QtCore.QRect(160, 440, 211, 23))
       self.pushButton = QtGui.QPushButton(self)
       self.pushButton.setGeometry(QtCore.QRect(90, 530, 211, 40))
       self.pushButton.clicked.connect(self.addtolists)
       self.label = QtGui.QLabel(self)
       self.label.setGeometry(QtCore.QRect(20, 20, 211, 23))
       self.label2 = QtGui.QLabel(self)
       self.label2.setGeometry(QtCore.QRect(20, 50, 211, 23))
       self.label3 = QtGui.QLabel(self)
       self.label3.setGeometry(QtCore.QRect(20, 80, 211, 23))
       self.label4 = QtGui.QLabel(self)
       self.label4.setGeometry(QtCore.QRect(20, 110, 211, 23))
       self.label5 = QtGui.QLabel(self)
       self.label5.setGeometry(QtCore.QRect(20, 140, 211, 23))
       self.label6 = QtGui.QLabel(self)
       self.label6.setGeometry(QtCore.QRect(20, 170, 211, 23))
       self.label7 = QtGui.QLabel(self)
       self.label7.setGeometry(QtCore.QRect(20, 200, 211, 23))
       self.label8 = QtGui.QLabel(self)
       self.label8.setGeometry(QtCore.QRect(20, 230, 211, 23))
       self.label9 = QtGui.QLabel(self)
       self.label9.setGeometry(QtCore.QRect(20, 260, 211, 23))
       self.label10 = QtGui.QLabel(self)
       self.label10.setGeometry(QtCore.QRect(20, 290, 211, 23))
       self.label11 = QtGui.QLabel(self)
       self.label11.setGeometry(QtCore.QRect(20, 320, 211, 23))
       self.label12 = QtGui.QLabel(self)
       self.label12.setGeometry(QtCore.QRect(20, 350, 211, 23))
       self.label13 = QtGui.QLabel(self)
       self.label13.setGeometry(QtCore.QRect(20, 380, 211, 23))
       self.label14 = QtGui.QLabel(self)
       self.label14.setGeometry(QtCore.QRect(20, 410, 211, 23))
       self.label15 = QtGui.QLabel(self)
       self.label15.setGeometry(QtCore.QRect(20, 440, 211, 23))

       self.setWindowTitle(QtGui.QApplication.translate("Form", "Εισαγωγή Ανηλίκου", None, QtGui.QApplication.UnicodeUTF8))
       self.label.setText(QtGui.QApplication.translate("Form", "Α.Μ.:", None, QtGui.QApplication.UnicodeUTF8))
       self.label2.setText(QtGui.QApplication.translate("Form", "Ημερομηνία Δικασίμου:", None, QtGui.QApplication.UnicodeUTF8))
       self.label3.setText(QtGui.QApplication.translate("Form", "Αριθμός Πινακίου:", None, QtGui.QApplication.UnicodeUTF8))
       self.label4.setText(QtGui.QApplication.translate("Form", "Ονοματεπώνυμο:", None, QtGui.QApplication.UnicodeUTF8))
       self.label5.setText(QtGui.QApplication.translate("Form", "Όνομα Πατρός:", None, QtGui.QApplication.UnicodeUTF8))
       self.label6.setText(QtGui.QApplication.translate("Form", "Όνομα Μητρός:", None, QtGui.QApplication.UnicodeUTF8))
       self.label7.setText(QtGui.QApplication.translate("Form", "Ημερομηνία Γέννησης:", None, QtGui.QApplication.UnicodeUTF8))
       self.label8.setText(QtGui.QApplication.translate("Form", "Τόπος Γέννησης:", None, QtGui.QApplication.UnicodeUTF8))
       self.label9.setText(QtGui.QApplication.translate("Form", "Εθνικότητα:", None, QtGui.QApplication.UnicodeUTF8))
       self.label10.setText(QtGui.QApplication.translate("Form", "Διεύθυνση Κατοικίας:", None, QtGui.QApplication.UnicodeUTF8))
       self.label11.setText(QtGui.QApplication.translate("Form", "Τηλέφωνο:", None, QtGui.QApplication.UnicodeUTF8))
       self.label12.setText(QtGui.QApplication.translate("Form", "Επάγγελμα-Ιδιότητα:", None, QtGui.QApplication.UnicodeUTF8))
       self.label13.setText(QtGui.QApplication.translate("Form", "Πράξη:", None, QtGui.QApplication.UnicodeUTF8))
       self.label14.setText(QtGui.QApplication.translate("Form", "Ημερομηνία Τέλεσης:", None, QtGui.QApplication.UnicodeUTF8))
       self.label15.setText(QtGui.QApplication.translate("Form", "Τόπος Τέλεσης:", None, QtGui.QApplication.UnicodeUTF8))
       self.pushButton.setText(QtGui.QApplication.translate("Form", "Εισαγωγή", None, QtGui.QApplication.UnicodeUTF8))

    def amlist(self):
        self.text = str(self.lineEdit.text())

    def addtolists(self):
        dialog.accept()        


#Main loop:        
def main():
    global dialog
    dialog = NewChildDlg()
    dialog.show()
    dialog.exec_()

回答1:

Specific error related problem

Remove the classmethod decorator on your update2 method. It makes "self" turn into the class object and there is no tableWidget attribute on your class. Only your widget. There is no use for the decorator here.

General design and fundamental issues

There are some severely major fundamental issues with this code. I realize you are new and learning, so its even more important that you address them now. This is a fantastic book, Rapid GUI Programming with Python and Qt that I can't praise enough, for learning PyQt

What you are doing here is taking a UI design file generate by Qt Designer, and editing it to slot in your logic into the setupUi methods. What you need to understand about this ui file is that it creates generic classes containing the widget setup code to be applied to your own class. You have that part of the concept at the bottom where you create a new QMainWindow and then call setupUi on it. What you shouldn't be doing is creating a huge number of global variable or adding extra methods and logic within these UI setup classes. You also have an example of a wrong @classmethod in there.

Object relationships in PyQt generally work like this... Parent classes can have attributes and child widgets. Child widgets can have attributes and generally don't know about their parents.

An example of how you would properly set up this QMainWindow would be to first keep that UI autogenerate code in its own file (myappUI.py or something like that). Then you would create a subclass for your QMainWindow, which will have your custom methods and data attributes:

class MainWindow(QtGui.QMainWindow, Ui_MainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setupUi(self)

        # create instance attributes to store data
        ...
        self.mothersname = []
        self.birthday = []
        self.placeofbirth = []
        self.nationality = []
        self.address = []
        ...

        r=0
        c=0
        for x in children:
            for i in x:
                newItem = QtGui.QTableWidgetItem(i)
                self.tableWidget.setItem(r, c, newItem)
                r += 1
            r = 0
            c += 1

    def newFile(self):
        ...

    def openFile(self):
        ...

    def Quit(self):
        # Dont force the exit of the app like this.
        # Just close the main window
        # sys.exit(app.exec_())

    # this was in no way a classmethod      
    # @classmethod
    def update2(self): 
        ...

    def actionewchild(self):
        ...
        # if you want to create a form dialog on the fly
        # and kill it after you get results
        form = Form(parent=self)
        form.exec_()

    def lists(self):
        ...

class Form(QtGui.QDialog, Ui_Form):

    def __init__(self, *args, **kwargs):
        super(Form, self).__init__(*args, **kwargs)
        self.setupUi(self)

    def amlist(self):
        ...

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

This was just a rough outline of how it would be reorganized into two classes, each inheriting from their UI design. Those large number of globals would be moved probably into your MainWindow as instance attributes. Don't use globals.

The reason I have taken this approach, in suggesting you completely reorganize, is because you are headed down a very messy and potentially frustrating path. Things will not work as you expect and you will find yourself posting on here constantly about why that is happening. If you take the time to review that book I suggested, you will have a much better experience.

Update #1: to match your code update

The concept between your main window and your dialog are backwards. You have the main window connecting an action to a function within your dialog module to launch it and do the work. What really should be happening is your main window connection to its own method. This method will launch the dialog, get the results and modify itself.

def addtolists(self):
    program.am.append(text)
    instance = MainWindow()
    instance.updatetable()
    dialog.close()  

You have that code in your dialog. First of all, calling MainWindow like that will not get you the instance. It will try and create a second main window widget. Don't try and get a reference to the parent and modify it. The children should have no knowledge of the parents that are using it. For all you know, down the line you might use this dialog in a different place.

# this is just a pseudo example of the right direction.
# A method in your MainWindow, starting the child dialog,
# waiting on its results, and updating itself.
def showDialog(self):
    d = MyDialog(self)
    if d.exec_():
        self.updateStuff(d.values)

myAction.triggered.connect(self.showDialog)

As for the globals... You should not need a single global in your application design. They are for special situations where you know you need them. I would say to make it a point that if you are using a global right now you might be doing it wrong. The reason is that you are using them to pass around data in different directions, instead of following a parent-child relationship, or communicating data over signals/slots. If a parent starts a child widget, it will know about the child and be able to call methods or get values from it.

Update #2: to match your code update

The creation of the dialog from your main window is a bit off. It should be like this:

def doupdate(self):
    d = NewChildDlg(self)
    # exec_ shows the dialog modally
    if d.exec_():
        # your dialog didn't have a pre-initialized
        # `text` attribute so it was not safe to assume
        text = d.lineEdit.text()
        # stop using globals. use attributes
        self.am.append(text)
        self.updatetable()

For the global... again stop using them. Move them into your main window class:

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.am = []
        self.courtdate = []
        self.board_number = []

And this part in your dialog class is wrong:

    def addtolists(self):
        # why use a global here? dialog == self
        # self.accept()
        dialog.accept()        

# you don't need a top level function that
# maintains a global instance and creates the dialog
# It should be the callers responsibility
def main():
    global dialog
    dialog = NewChildDlg()
    dialog.show()
    dialog.exec_()

And finally, just a comment about your import statements... You don't need to first import the module to be able to import members of that module:

# either you need the newchilddlg namespace
# or you only want the members...
# newchilddlg.NewChildDlg  vs  NewChildDlg
import newchilddlg
from newchilddlg import *

To help you out a bit more, I have posted a cleaned up version of your main window code here: http://pastebin.com/9b8gcGhU