1

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

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):

import sys
from PyQt4.QtGui import QTableWidget 
from PyQt4 import QtGui,QtCore,Qt
import MySQLdb as mdb
import time
class Window(QtGui.QDialog):

    def __init__(self,parent=None):
        super(Window, self).__init__()
        self.custom_choice = QtGui.QLineEdit()
        self.layout = QtGui.QVBoxLayout(self)
        self.db = mdb.connect('serv','user','pass','db')
        self.model = self.db.cursor()
        self.button = QtGui.QPushButton('Test', self)
        self.button.clicked.connect(self.updateAllViews)
        self.layout.addWidget(self.button)
        self.initialData = self.get_data_status()
        self.table1 = MyTableStatus(self.initialData, 145, 4)
        self.layout.addWidget(self.table1)  

        # check every half-second

    def handleHeaderMenu(self, pos):
        self.menu = QtGui.QMenu()
        self.custom_choice.setPlaceholderText("Server")
        self.wac = QtGui.QWidgetAction(self.menu)
        self.wac.setDefaultWidget(self.custom_choice)
        self.menu.setStyleSheet("QMenu::item {background-color: #264F7D;color: white; font-weight:bold;}")
        self.menu.addAction("Choose Server to Monitor:")
        self.menu.addSeparator()
        self.actionJuliet = self.menu.addAction('Juliet')
        self.actionJulietleft = self.menu.addAction('JulietLeft')
        self.actionPong = self.menu.addAction('Pong')
        self.actionHulk = self.menu.addAction('Hulk')
        self.actionCustom = self.menu.addAction(self.wac)
        self.connect(self.custom_choice, QtCore.SIGNAL("returnPressed()"),self.updateAllViews)
        action = self.menu.exec_(QtGui.QCursor.pos())
        if action == self.actionPong:
            print("pong")
    def get_data_status(self):
        self.tx = self.custom_choice.text()
        self.model.execute("show TABLES;")
        table_array = []
        table_names = self.model.fetchall()
        for lines in table_names:
            lines = str(lines)
            lines = lines.strip("()""''"",")
            table_array.append(lines)
        if any("%s" % self.tx in s for s in table_array):
            table_name = self.tx
            self.model.execute("""SELECT computer_name 
                                  FROM %s""" % (table_name))
            new_user_name = self.model.fetchall()
            self.model.execute("""SELECT idle_time 
                                  FROM %s""" % (table_name))
            new_idle = self.model.fetchall()
            self.model.execute("""SELECT files_opened 
                                  FROM %s""" % (table_name))
            new_files = self.model.fetchall()
            self.model.execute("""SELECT active_time 
                                  FROM %s""" % (table_name))
            new_active = self.model.fetchall()
            self.model.execute("""SELECT session_type 
                               FROM %s""" % (table_name))
            new_session = self.model.fetchall()
#            self.model.execute("""SELECT number_of_machines 
#                                  FROM %s WHERE date = (SELECT MAX(date) 
#                                  FROM %s""" % (table_name,table_name))
            #new_machines = self.model.fetchall()
            self.model.execute("""SELECT cpu 
                               FROM %s""" % (table_name))
            new_cpu_load = self.model.fetchall()
            self.model.execute("""SELECT avg_disk_queue 
                               FROM %s""" % (table_name))
            new_disk_queue_load = self.model.fetchall()
            new_data_user = [item0[0] for item0 in new_user_name]
            new_data_idle = [item1[0] for item1 in new_idle]
            new_data_files = [item2[0] for item2 in new_files]
            new_data_active = [item3[0] for item3 in new_active]
            new_data_session = [item4[0] for item4 in new_session]
            new_data_cpu_load = [item5[0] for item5 in new_cpu_load]
            new_data_disk_queue_load = [item6[0] for item6 in new_disk_queue_load]
#            self.lista.append(new_data_user)
#            self.listb.append(new_data_idle)
#            self.listc.append(new_data_files)
#            self.listd.append(new_data_active)
#            self.liste.append(new_data_session)
#            self.listf.append(new_data_cpu_load)
#            self.listg.append(new_data_disk_queue_load)  
            self.lista = new_data_user
            self.listb = new_data_disk_queue_load
            self.listc = new_data_cpu_load
            self.listd = new_data_active
            self.liste = new_data_files
            self.listf = new_data_session
            self.listg = new_data_idle  
            self.mystruct2 = {'A':self.lista, 'B':self.listb, 'C':self.listc,'E':self.liste,'D':self.listd,'F':self.listf,'G':self.listg}  
        else:
            self.NotFound()
        return self.mystruct2

    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(False)


        self.data = {}
        self.setmydata()

    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)
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()
4

2 回答 2

3

这段代码中的逻辑有点混乱,但我可以看到你的数据没有更新的问题。

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

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

您可以采用两种方式将数据提供给表。您可以直接从窗口更新 Table 上的数据模型,然后告诉它刷新,或者,您可以通过信号传递新数据并让 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 现在有一个方法可以接受一个字典,并更新它自己的内部数据结构。

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

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 的插槽上的视图(来自上一个示例)。

于 2012-08-08T17:37:57.277 回答
0

这里发生了一些事情:

  1. 您不需要 init 方法中的全局声明(textedit 和 rows 不是全局的)
  2. 您从以下行看到了错误: MyTableStatus(self.mystruct1, 145, 4) 因为您尚未定义 self.mystruct1 变量 - 您在 get_data_status 方法中定义它,该方法未被调用直到信号发出。您通常希望在做任何其他事情之前定义您的班级成员(只是好的做法)
  3. 我不太确定为什么你在那里有 time.sleep(2) 调用,信号的处理应该在 Qt 中很快发生
  4. 在执行self.layout = QtGui.QVBoxLayout(self) 之类的操作时必须小心。布局符号实际上是一个继承的 QWidget 方法(self.layout())。设置它可能会破坏 Qt 内部。
  5. 通常,除非您尝试将其他小部件连接到 update_ready_status 信号,否则您实际上并不需要它

无论如何,我不是 100% 确定你想要做什么 - 但我希望这会有所帮助!

于 2012-08-07T22:48:43.987 回答