PyQt自定义数据结构

时间:2013-09-25 08:46:52

标签: python data-structures widget pyqt pyqt4

我有一个简单的PyQt4程序,每当我点击OK按钮并将其保存为二进制文件时,它会接收3个详细信息(姓名,性别和地址)(3个细节在程序中被硬编码用于测试目的)。然后,稍后将加载该信息并将其显示在QTableWidget

这是我的程序布局:

它有2个脚本: DContainer.py Data_Main.py

enter image description here

Dcontainer.py

import bisect
from PyQt4 import QtCore

class Person(object):

    def __init__(self, Name = None, Gender = None , Address = None ):
        self.Name = Name
        self.Gender = Gender
        self.Address = Address

class PersonContainer(object):

    def __init__(self):
        self.__fname = QtCore.QString("mydatabase.mqb")
        self.__persons = []
        self.__personFromId = {}

    def __iter__(self):
        for pair in iter(self.__persons):
            yield pair[1]

    def __len__(self):
        return len(self.__persons)

    def Clear(self):
        self.__persons = []
        self.__personFromId ={}

    def add(self,person):
        if id(person)in self.__personFromId:
            return False
        key = person.Name
        bisect.insort_left(self.__persons, [key,person])
        self.__personFromId[id(person)] = person
        return True

    def save(self):
        fh = QtCore.QFile(self.__fname)
        if not fh.open(QtCore.QIODevice.WriteOnly):
            raise IOError , unicode(fh.errorString())
        stream = QtCore.QDataStream(fh)
        for key, person in self.__persons:
            stream << person.Name << person.Gender << person.Address

    def load(self):
        fh = QtCore.QFile(self.__fname)
        if not fh.open(QtCore.QIODevice.ReadOnly):
            raise IOError , unicode(fh.errorString())
        stream = QtCore.QDataStream(fh)
        while not stream.atEnd():
            Name = QtCore.QString()
            Gender = QtCore.QString()
            Address = QtCore.QString()
            stream >> Name >> Gender >> Address
        self.add(Person(Name,Gender,Address))

Data_Main.py

import sys
from PyQt4 import QtCore,QtGui
import DContainer

class MainDialog(QtGui.QDialog):

    def __init__(self, parent = None):
        super(MainDialog,self).__init__(parent)
        self.InitGui()
        self.persons = DContainer.PersonContainer()
        self.Update()


    def InitGui(self):
        buttonbox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel)
        self.table = QtGui.QTableWidget()
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.table)
        layout.addWidget(buttonbox)
        self.setLayout(layout)
        self.connect(buttonbox.button(buttonbox.Ok), QtCore.SIGNAL("clicked()"),self.OK)

    def OK(self):
        NewPerson = DContainer.Person(QtCore.QString('This is another test'),QtCore.QString('Male'),QtCore.QString('Strand Road'))
        self.persons.add(NewPerson)
        self.persons.save()
        self.Update()

    def Update(self):
        self.table.clear()
        self.persons.load()
        self.table.setRowCount(len(self.persons))
        self.table.setColumnCount(3)

        for row,person in enumerate(self.persons):
            item = QtGui.QTableWidgetItem(person.Name)
            self.table.setItem(row,0,item)


def Main():
    app = QtGui.QApplication(sys.argv)
    dialog = MainDialog()
    dialog.show()
    app.exec_()

if __name__ == "__main__":
    Main()

我的问题是每当我点击确定按钮时,它会创建多个表条目

第二次点击后

after 2nd click

它不应该像我使用

那样创建多个表条目
if id(person)in self.__personFromId:
            return False

在Dcontainer.py中的Add方法中。

理所当然,它应该只显示表中的一个项目,除非我给新的person对象赋予不同的名称。

导致问题的原因是什么?

1 个答案:

答案 0 :(得分:1)

单击“确定”按钮时,将调用PersonContainer.add方法两次:

  1. 直接来自MainDialog.OK方法
  2. 间接来自MainDialog.Update方法,self.persons.load()
  3. 您可以为Update方法添加可选参数,以触发对load的调用:

    def Update(self, load=False):
        self.table.clear()
        if load:
            self.persons.load()
    

    并在load方法中将True设置为__init__并调用此方法:

    def __init__(self, parent = None):
        super(MainDialog,self).__init__(parent)
        self.InitGui()
        self.persons = DContainer.PersonContainer()
        self.Update(True)
    

    顺便说一句,PyQt5不再支持旧式信号/插槽。这是如何写新风格:

        buttonbox.accepted.connect(self.OK)
        buttonbox.rejected.connect(self.reject)