1

テーブル内のmysqlデータベースから1つのセルを更新しようとしていますが、グローバル変数をセルに渡すことができません。現在、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カスタムテーブルに渡してデータを初めて表示します。その後のトリガーで、メインウィンドウでそのディクショナリを上書きし、どういうわけかテーブルが同じ参照を持つと考えます。何が起こっているのかというと、ウィンドウには新しいディクショナリがあり、テーブルは元のオブジェクトとともにそこに座っています。
  2. 毎回ディクショナリを上書きするのではなく、ディクショナリをクリアしてその値を更新したとしても、テーブルはディクショナリが変更されたことを認識しません。データを更新するには、シグナルをテーブル自体に接続するか、テーブルで直接何かを呼び出す必要があります。属性に名前を付けるだけmodelでは、QModelと同じ機能は得られません。
  3. これはちょっとした補足ですが、Pythonの規則では通常__init__、クラスの最上位に配置されるため、それを読んでいる人は、メソッドを見る前に、クラスの設定をすぐに確認できます。

これを修正するには、最初にいくつかのがらくたを片付けます。この場合、別の信号を発信するスロットへの信号は必要ありません。それはそれをより混乱させる以外に何もしていません。更新を実行するテーブルのスロットに信号を直接接続するだけです。また、テーブルのメインウィンドウで再描画とリセットの呼び出しを取り除きます。

テーブルにデータを提供するには、2つのパスを使用できます。ウィンドウからテーブルのデータモデルを直接更新してから更新するように指示するか、新しいデータをシグナルに渡してテーブルに処理させることができます...

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)

テーブルに初期データを与えることができますが、将来のデータベースプルによって更新されるようにテーブルを設定する必要もあります。ここでは、タイマーをローカルデータを更新するメソッドに接続し、テーブルを含む使用しているさまざまなビューを更新するだけです。

テーブルには、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を期待するスロットのビューに配信するようにします。

于 2012-08-08T17:37:57.277 に答える
0

ここで起こっていることがいくつかあります:

  1. initメソッドにグローバル宣言は必要ありません(テキストエディットと行はグローバルではありません)
  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 に答える