更新 QtableWidget pyqt [英] Updating QtableWidget pyqt

查看:51
本文介绍了更新 QtableWidget pyqt的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to update one cell from a mysql database in my table but i am unable to pass the global variable to the cell. Currently I am getting an integer from a mysql database, then i try to globally define, then i pass the varaible to mystruct (the structure of the table), and finally i apply the mystruct to the table, and gives me the error AttributeError: 'Window' object has no attribute 'struct1', i know why since the self.mystruct1 is first used in __init__. Is there an alternative. Please look at the code below to understand. *Note position does not matter

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

Manual trigger (code 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()

推荐答案

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

The logic in this code is a bit messy, but I can see your problem with the data not updating.

  1. 有一个初始数据库拉取,然后您将 self.mystruct1 传递给您的自定义表以第一次显示数据.在随后的触发器中,您然后在主窗口中覆盖该字典,认为表格将以某种方式具有相同的引用.发生的事情是 Window 有新字典,而 Table 与原始对象坐在那里.
  2. 即使您只是清除字典并更新其值,而不是每次都覆盖它,表仍然不知道字典已更改.您需要将信号连接到表本身以刷新其数据,或者直接在表上调用某些内容.简单地命名属性 model 并不能赋予它与 QModel 相同的功能.
  3. 这有点旁注,但 Python 约定通常将 __init__ 放在类的顶部,因此阅读它的人可以立即看到是什么设置了您的类,然后再看到它的方法.
  1. There is an initial database pull, and then you pass self.mystruct1 to your custom Table to show the data for the first time. On subsequent triggers, you then overwrite that dictionary in the main window, thinking that somehow the Table will have the same reference. What is happening is the Window has the new dictionary, and the Table is sitting there with the original object.
  2. Even if you were to just clear the dict, and update its values, as opposed to overwriting it each time, the Table would still not know the dictionary changed. You would need to connect a signal to the table itself to refresh its data, or, call something directly on the table. Simply naming the attribute model doesn't give it the same functionality as a QModel.
  3. This is a little bit of a side-note, but python convention usually puts the __init__ at the top of the class so people reading it can immediately see what sets up your class before then seeing its methods.

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

To fix this, first clear out some cruft. You don't need a signal to a slot that emits another signal in this case. It isn't doing anything beyond making it more confusing. Just connect a signal directly to a slot on the Table that will perform an update. Also get rid of the repaint and reset calls in your main window on the table.

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

You can take two paths to providing the data to the Table. Either you can directly update the data model on the Table from your window and then tell it to refresh on that, or, you can pass the new data over the signal and let the Table handle it...

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)

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

You can give your table initial data, but you also need to set it up to be updated by future database pulls. Here we simply connect the timer to a method that updates the local data, and then refreshes the various views you are using, including the table.

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

The Table now has a method that can take a dict, and update its own internal data structure.

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

A slight variation on this approach would be to emit the new data structure in a signal, and just fire that when your local data structure changes in the Window...

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

In this example, you just let the signal deliver the new data structure to the view on a slot that expects a dict (from the previous example).

这篇关于更新 QtableWidget pyqt的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆