更新QtableWidget pyqt

时间:2012-08-07 20:19:14

标签: python pyqt

我正在尝试从我的表中的mysql数据库更新一个单元格,但我无法将全局变量传递给单元格。目前我从mysql数据库中获取一个整数,然后我尝试全局定义,然后我将变量传递给mystruct(表的结构),最后我将mystruct应用到表中,并给出了错误{{ 1}},我知道为什么因为self.mystruct1首先在AttributeError: 'Window' object has no attribute 'struct1'中使用。有替代方案吗?请查看下面的代码以了解。 *注意位置无关紧要

__init__

手动触发(代码2):

import sys
from PyQt4.QtGui import QTableWidget 
from PyQt4 import QtGui,QtCore
import MySQLdb as mdb
import time
class Window(QtGui.QDialog,object):
    def get_data_status(self):
        self.model.execute("""SELECT cpu FROM table
                              WHERE date = (SELECT MAX(date) FROM table)""")        
        rows_status = self.model.fetchone()
        self.listc1 = ['%s' % rows_status]#['%s %s' % self.rows_status]
        self.lista1 = 'Juliet','Julietleft','Pong','Hulk'
        self.listb1 = 'None','None','None','None'
        self.mystruct1 = {'A':self.lista1, 'B':self.listb1, 'C':self.listc1} 
        print self.mystruct1
        return self.mystruct1

        # this is only for the temp time test
    def new_data_status(self):
        self.update_ready_status.emit()

    update_ready_status = QtCore.pyqtSignal()
    def __init__(self,parent=None):
        super(Window, self).__init__()

        self.layout = QtGui.QVBoxLayout(self)
        self.db = mdb.connect('server','user','user','db')
        self.model = self.db.cursor()
        self.table1 = MyTableStatus(Window.get_data_status(self),145,4)
        self.table1.repaint()
        self.table1.reset()
        self.layout.addWidget(self.table1)  
        self.update_ready_status.connect(self.get_data_status)
        self.timer_status = QtCore.QTimer()
        self.timer_status.timeout.connect(self.new_data_status)
        # check every half-second
        self.timer_status.start(1000*2)


class MyTableStatus(QTableWidget):
    def sizeHint(self):
        width = 0

        for i in range(self.columnCount()):
            width += self.columnWidth(i)

        width += self.verticalHeader().sizeHint().width()

        width += self.verticalScrollBar().sizeHint().width()
        width += self.frameWidth()*2

        return QtCore.QSize(width,self.height())
    def __init__(self, thestruct,*args): 
        QTableWidget.__init__(self, *args)
        self.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Preferred)
        self.data = thestruct
        self.setHorizontalHeaderLabels(['Server', 'Avg. Disk Queue','CPU Load',"Status"])
        self.setmydata()
        QTableWidget.setSortingEnabled(self,True)





    def setmydata(self):
        for n, key in enumerate(self.data):
            for m, item in enumerate(self.data[key]):
                newitem = QtGui.QTableWidgetItem(item)
                self.setItem(m, n, newitem)


def main():
   app = QtGui.QApplication(sys.argv)
   app.setStyle(QtGui.QStyleFactory.create("plastique"))
   main_window = Window()
   main_window.repaint()
   main_window.show() 
   sys.exit(app.exec_())

if __name__ == '__main__':
   main()

2 个答案:

答案 0 :(得分:2)

此代码中的逻辑有点乱,但我可以看到数据未更新的问题。

  1. 初始数据库拉取,然后您将self.mystruct1传递到自定义表以首次显示数据。在后续触发器上,然后在主窗口中覆盖该字典,认为Table将具有相同的引用。发生的事情是Window有了新的字典,而Table就坐在原来的对象上。
  2. 即使您只是清除dict并更新其值,而不是每次都覆盖它,Table仍然不知道字典已更改。您需要将信号连接到表本身以刷新其数据,或者直接在表上调用某些内容。简单地命名属性model并不能赋予它与QModel相同的功能。
  3. 这是一个侧面注释,但是python约定通常会将__init__放在类的顶部,这样人们阅读它就可以在看到它的方法之前立即看到设置类的内容。 / LI>

    要解决这个问题,首先要清除一些问题。在这种情况下,您不需要向发出另一个信号的插槽发送信号。除了让它更加混乱之外,它没有做任何事情。只需将信号直接连接到Table上将执行更新的插槽即可。还要摆脱桌面主窗口中的重绘和重置调用。

    您可以采用两条路径向表中提供数据。您可以直接从窗口更新表格上的数据模型,然后告诉它刷新,或者,您可以通过信号传递新数据并让表格处理它......

    class Window(QtGui.QDialog):
    
        def __init__(self,parent=None):
            super(Window, self).__init__()
            ...
            initialData = self.get_data_status()
            self.table1 = MyTableStatus(initialData, 145, 4)
            ...
            self.timer_status = QtCore.QTimer()
            self.timer_status.timeout.connect(self.updateAllViews)
    
            # check every half-second
            self.timer_status.start(1000*2)
    
        def get_data_status(self):
            ...
            self.mystruct1 = {'A':self.lista1, 'B':self.listb1, 'C':self.listc1} 
            return self.mystruct1
    
        def updateAllViews(self):
            _ = self.get_data_status()
            self.updateTable()
    
        def updateTable(self):
            self.table1.updateFromDict(self.mystruct1)
    
    
    class MyTableStatus(QTableWidget):
    
        def __init__(self, thestruct, *args): 
            QTableWidget.__init__(self, *args)
            self.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Preferred)
            self.setHorizontalHeaderLabels(['Server', 'Avg. Disk Queue','CPU Load',"Status"])
            self.setSortingEnabled(True)
    
            self.data = {}
            self.setmydata(thestruct)
    
        def updateFromDict(self, aDict):
            self.data.clear()
            self.data.update(aDict)
    
            self.setmydata()
    
        def setmydata(self):
            for n, key in enumerate(self.data):
                for m, item in enumerate(self.data[key]):
                    newitem = QtGui.QTableWidgetItem(item)
                    self.setItem(m, n, newitem)
    

    您可以为表提供初始数据,但您还需要将其设置为将来的数据库提取更新。在这里,我们只需将计时器连接到更新本地数据的方法,然后刷新您正在使用的各种视图,包括表格。

    Table现在有一个方法可以接受dict,并更新自己的内部数据结构。

    这种方法的一个细微变化就是在信号中发出新的数据结构,并在窗口中本地数据结构发生变化时触发...

    class Window(QtGui.QDialog):
    
        update_ready = QtCore.pyqtSignal(dict)
    
        def __init__(self,parent=None):
            ...
            # call a generate update and emit wrapper
            self.timer_status.timeout.connect(self.refreshData)
            # connect each view with a slot that expects a dict
            self.update_ready.connect(self.table1.updateFromDict)
            ...
    
        def refreshData(self):
            new_data = self.get_data_status()
            self.update_ready.emit(new_data)
    

    在这个例子中,您只需让信号将新数据结构传递到需要dict的插槽上的视图(来自前面的示例)。

答案 1 :(得分:0)

这里有一些事情发生:

  1. 您的init方法中不需要全局声明(textedit和行不是全局的)
  2. 你看到你从行中看到的错误:MyTableStatus(self.mystruct1,145,4),因为你还没有定义self.mystruct1变量 - 你在get_data_status方法中定义它,直到发出信号才打电话。您通常希望在做其他任何事情之前定义您的班级成员(只是良好做法)
  3. 我不确定你为什么要在那里调用time.sleep(2),在Qt中信号的处理应该很快发生
  4. 你必须注意做什么,比如 self.layout = QtGui.QVBoxLayout(self) layout 符号实际上是一个继承的QWidget方法(self.layout())。设置此项可能会破坏Qt内部。
  5. 一般情况下,除非您尝试将其他小部件连接到update_ready_status信号,否则您根本不需要它
  6. 无论如何,我不是百分之百确定你要做什么 - 但我希望有所帮助!