This question already has answers here:
Python convert tuple to string
(5 answers)
Closed 3 years ago.
Apologies if my title is unclear; I'm trying to retrieve some data from an SQLLite database (which is working) and show it to the user on a window in PyQt5. So far, I've managed to retrieve the result and print in Python, but when trying to add/view the results in the window Python simply crashes.
I've inserted the code which isn't working below. (The indentation has gone slightly funny when copying it, but it is perfectly fine in my file).
class Profile(QWidget):
def __init__(self, Type):
super().__init__()
self.window = QWidget()
self.window.setGeometry(100,100, 350, 400)
self.window.setWindowTitle("Welcome")
self.window.show()
self.Choices()
def Choices(self):
self.layout = QGridLayout()
c.execute('''SELECT username, teamname FROM Users WHERE username = ?''',
(user,))
result = c.fetchone()
print(result)
print(user)
self.TeamInfo = QLabel(result)
self.layout.addWidget(self.TeamInfo)
self.window.setLayout(self.layout)
self.window.show()
user is a global variable in a previous window (the log in page) to avoid the user having to reenter their username. This section is not included, as that is not the problem. All the other buttons in the class are working - it is just this particular section. Any help as to how to solve this is greatly appreciated, I figure the problem is the line self.TeamInfo = QLabel(result) but I don't have the PyQT5 knowledge on how to solve this.
Edit: I have included a screenshot of the error message I'm getting.
If I understand right you are trying to add a text to QLabel, right?
According to the documentation adding text to it is done by: QLabel().setText(result).
Edit: Could you please try this and tell me what the compiler is complaining about?
label = QLabel()
label.setText(result)
self.layout.addWidget(label)
Try it:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import sqlite3
class Profile(QWidget):
def __init__(self, Type=None):
super().__init__()
self.window = QWidget()
self.window.setGeometry(100,100, 350, 400)
self.window.setWindowTitle("Welcome")
self.Choices()
def Choices(self):
self.layout = QGridLayout()
# c.execute('''SELECT username, teamname FROM Users WHERE username = ?''',
# (user,))
# result = c.fetchone()
#
user = "Nick"
try:
self.conn = sqlite3.connect("database.db")
self.c = self.conn.cursor()
# result = self.c.execute("SELECT * from students WHERE name='{}'".format(user) )
result = self.c.execute("SELECT * from students WHERE name=?", (user, ))
row = result.fetchone() # <---
print("\nrow->", type(row), row)
serachresult = "Rollno : "+str(row[0])+'\n'+"Name : "+str(row[1])+'\n'+"Branch : "+str(row[2])+'\n'+"Sem : "+str(row[3])+'\n'+"Address : "+str(row[4])
QMessageBox.information(QMessageBox(), 'Successful', serachresult)
self.conn.commit()
self.c.close()
self.conn.close()
except Exception:
QMessageBox.warning(QMessageBox(), 'Error', 'Could not Find student from the database.')
print(result)
print(user)
self.TeamInfo = QLabel(", ".join([ str(i) for i in row ])) # <---
self.layout.addWidget(self.TeamInfo)
self.window.setLayout(self.layout)
self.window.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Profile()
main.show()
sys.exit(app.exec_())
Related
I'm trying to build a little GUI application in Python using PyQT5 that takes orders and save them into a database.
On inserting the data, it seems to be going in but I'm never going inside the loop when trying to retrieve
Here's the code:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
import sys
from PyQt5.uic import loadUiType
ui, _ = loadUiType('jkp.ui')
# Declaring global variables to be used
global name, quantity, regular, xlsize, cheeze, ham
class MainApp(QMainWindow, ui):
def __init__(self, parent=None):
super(MainApp, self).__init__(parent)
QMainWindow.__init__(self)
self.setupUi(self)
self.initUi()
self.HandleButtons()
def initUi(self):
# Creating the database
con = QSqlDatabase.addDatabase('QSQLITE')
con.setDatabaseName('clients.sqlite')
if not con.open():
print('Unable to connect to the database')
sys.exit(1)
#
createTableQuery = QSqlQuery()
createTableQuery.exec("""
CREATE TABLE orders IF NOT EXISTS (
name VARCHAR (100) NOT NULL,
quantity INTEGER NOT NULL,
regular BOOLEAN,
xlsize BOOLEAN,
cheeze BOOLEAN,
ham BOOLEAN,
)
""")
def HandleButtons(self):
# connecting buttons to functions
self.pushButton_5.clicked.connect(self.Inserted)
self.pushButton_2.clicked.connect(self.ShowOrders)
def Inserted(self):
# Getting values from Gui and puttin em in variables
name = self.lineEdit.text()
quantity = self.spinBox.value()
regular = self.checkBox_3.isChecked()
xlsize = self.checkBox_4.isChecked()
cheeze = self.checkBox.isChecked()
ham = self.checkBox_2.isChecked()
# Insertion
query = QSqlQuery()
try:
query.exec(f"""
INSERT INTO orders (name, quantity, regular, xlsize, cheeze, ham)
VALUES('{name}','{quantity}','{regular}','{xlsize}','{cheeze}','{ham}',)
""")
print('inserted !')
except:
print('failed')
def ShowOrders(self):
query = QSqlQuery()
query.first()
print('so far so good') ### works till here ###
while query.next():
print('do we get here ?')
print(
query.value(name),
query.value(quantity),
query.value(regular),
query.value(xlsize),
query.value(cheeze),
query.value(ham),
)
def main():
app = QApplication(sys.argv)
window = MainApp()
window.show()
app.exec_()
if __name__ == '__main__':
main()
So upon executing the Gui appears the values entered are stored inside the variable, the insertion says 'inserted' but later on I don't know where the issue
You have the following errors:
You have syntax errors in SQL statements.
Qt does not throw exceptions when some function has an internal error but uses other methods (like returning a boolean).
It is not necessary to use global variables (also the use that the OP gives it is confusing).
class MainApp(QMainWindow, ui):
def __init__(self, parent=None):
super(MainApp, self).__init__(parent)
self.setupUi(self)
self.init_ui()
self.handle_buttons()
def init_ui(self):
# Creating the database
con = QSqlDatabase.addDatabase("QSQLITE")
con.setDatabaseName("clients.sqlite")
if not con.open():
print("Unable to connect to the database")
sys.exit(1)
#
query = QSqlQuery()
if not query.exec(
"""
CREATE TABLE IF NOT EXISTS orders (
name VARCHAR (100) NOT NULL,
quantity INTEGER NOT NULL,
regular BOOLEAN,
xlsize BOOLEAN,
cheeze BOOLEAN,
ham BOOLEAN
)
"""
):
print(query.lastError().text())
def handle_buttons(self):
# connecting buttons to functions
self.pushButton_5.clicked.connect(self.insert)
self.pushButton_2.clicked.connect(self.show_orders)
def insert(self):
# Getting values from Gui and puttin em in variables
name = self.lineEdit.text()
quantity = self.spinBox.value()
regular = self.checkBox_3.isChecked()
xlsize = self.checkBox_4.isChecked()
cheeze = self.checkBox.isChecked()
ham = self.checkBox_2.isChecked()
# Insertion
query = QSqlQuery()
query.prepare(
"INSERT INTO orders (name, quantity, regular, xlsize, cheeze, ham) VALUES (?, ?, ?, ?, ?, ?)"
)
query.addBindValue(name)
query.addBindValue(quantity)
query.addBindValue(regular)
query.addBindValue(xlsize)
query.addBindValue(cheeze)
query.addBindValue(ham)
if not query.exec_():
print(query.lastError().text())
print("failed")
else:
print("inserted !")
def show_orders(self):
query = QSqlQuery("SELECT * FROM orders")
record = query.record()
while query.next():
print("row")
for i in range(record.count()):
print(f"{record.fieldName(i)}: {query.value(i)}")
PyQt5 - QComboBox populated with QQueryModel including Id; Name; ..etc fields. Using Name as QComboBox.modelColumn. Hope to retrive id field from the clicked item.
I shifted the ModelColumn back and forth without doing any good. Also I accessed the QQueryModel.record to find that it is on the first record always, not on the current one.
import MySQL_Connector
import sys
from PyQt5.QtCore import QVariant, Qt
from PyQt5.QtSql import QSqlDatabase, QSqlQueryModel,QSqlQuery , QSqlTableModel, QSqlError, QSqlQueryModel, QSqlQuery
from PyQt5.QtWidgets import QApplication, QMainWindow
from MainUI import Ui_MainWindow
class QConnectionError(Exception):
pass
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
#setup Qsql databaase objects
cnn = MySQL_Connector.MysqlConnection('config.ini')
con_string = cnn.read_db_config()[1]
try:
db = QSqlDatabase.addDatabase("QMYSQL")
db.setHostName(con_string['host'])
db.setUserName(con_string['user'])
db.setDatabaseName(con_string['database'])
db.setPassword(con_string['password'])
ok = db.open()
if not ok:
raise QConnectionError("Connection failed--- Is the server running?")
except QConnectionError as err:
print("You'll have to wait until a connection is established")
return
finally:
if db.isOpen():
db.close()
self.qdb = db
self.qdb.open()
# set combobox
self.comboQuery = combo_query(self.qdb)
self.comboModel = QSqlQueryModel()
self.comboModel.setQuery(self.comboQuery)
self.comboBox.setModel(self.comboModel)
self.comboBox.setModelColumn(1)
self.comboBox.activated[int].connect(self.do_action)
#populate textView
self.query = test(self.qdb)
self.model = QSqlQueryModel()
self.model.setQuery(self.query)
self.model.setHeaderData(0,Qt.Horizontal, "ID")
self.model.setHeaderData(1, Qt.Horizontal, "Nombre")
self.tableView.rowHeight(2)
self.tableView.fontMetrics()
self.tableView.setModel(self.model)
self.show()
if self.qdb.isOpen():
self.qdb.close()
def do_action(self, str): #Experimenting
print(str, type(str))
self.tableView.selectRow(5)
def main():
app = QApplication(sys.argv)
window = MainWindow()
app.exec()
Need advise on how to go forward. All the database I'm using is based on ID fields with I need to further query for whatever the reason. Maybe a tools change? A different approach.
QCombobox has two signals suitable for your needs:
activated() is sent when the user chooses an item, even if the choice is not changed, see QComboBox.activated()
currentIndexChanged() is sent if the current index is changed, either by users choice or programmatically, see QComboBox.currentIndexChanged()
Both signals pass the current index.
Using this index you get the needed data by QSqlQuery.data().
Here a simple example using sqlite3, i think you can adapt it to your database:
import sqlite3
from PyQt5 import QtWidgets, QtSql
class MyWidget(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.database = QtSql.QSqlDatabase('QSQLITE')
self.database.setDatabaseName('tc.db')
self.database.open()
self.dataModel = QtSql.QSqlQueryModel()
self.dataModel.setQuery('select id, name from items', self.database)
self.comboBox = QtWidgets.QComboBox(self)
self.comboBox.setModel(self.dataModel)
self.comboBox.setModelColumn(1)
self.comboBox.currentIndexChanged.connect(self.do_action)
# self.comboBox.activated.connect(self.do_action)
def do_action(self, i):
id = self.dataModel.data(self.dataModel.index(i, 0)) # self.dataModel.index(row, column)
name = self.dataModel.data(self.dataModel.index(i, 1))
print(i, 'id: ', id, 'name: ', name)
qApp = QtWidgets.QApplication([])
widget = MyWidget()
widget.show()
qApp.exec_()
here the dump of the database tc.db:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "items" (
"id" INTEGER PRIMARY KEY NOT NULL,
"name" TEXT NOT NULL
);
INSERT INTO items VALUES(0,'abcde');
INSERT INTO items VALUES(1,'fghijk');
INSERT INTO items VALUES(2,'lmnop');
INSERT INTO items VALUES(3,'qrstuv');
COMMIT;
I am having trouble running if part of code where user name and password is wrong.program does not show any error.
And how can i set userfullname of Index class to lable in admin_object = userFullname.setText() ?
import sqlite3
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtWidgets import QMessageBox
from Login_form import Login_form
from Admin_Home_form import AdminHome_Form
class Index(QtWidgets.QDialog, Login_form):
def __init__(self):
QtWidgets.QDialog.__init__(self)
self.loginFormDesign(self)
self.login_button.clicked.connect(self.login_check)
def login_check(self):
uname = self.U_name_text.text()
password = self.pass_text.text()
# self.userfullname = userfullname
connection = sqlite3.connect("taylorDB.db")
result = connection.execute("SELECT USER_EMAIL FROM USERS WHERE USER_EMAIL = ? AND USER_PASSWORD = ?",
(uname, password))
for dbemail in result: # After this code does not work if value does not match
print(dbemail[0])
if dbemail[0] != uname:
buttonReply = QMessageBox.question(self, 'Login Invalid', "Check User Name or Password!",
QMessageBox.Close)
if buttonReply == QMessageBox.Close:
print("invalid login")
else:
result = connection.execute("SELECT USER_FULLNAME FROM USERS WHERE USER_EMAIL = ?", (dbemail))
self.userfullname = result.fetchone()
print(self.userfullname)
self.accept()
class admin_operation(QtWidgets.QMainWindow, AdminHome_Form, Index):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.adminHomeFormDesign(self)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
login_object = Index()
admin_object = admin_operation()
if login_object.exec() == QtWidgets.QDialog.Accepted:
# admin_object.userFullname.setText() #I want to set the value of userfullname here?
admin_object.show()
sys.exit(app.exec_())
My basic are not so strong please guide me .
You must improve your logic, instead of the select return USER_EMAIL must return the USER_FULLNAME so you avoid making a new query, on the other hand to get the results you must use fetchall(), this will return a tuple of the results, if no results will be empty, otherwise there will be results. In your case, I assume that you restrict the USER_EMAIL to being unique so that the result will be a tuple of a single element. That data you keep in one member of the class, and you set it in the other window.
On the other hand it is not necessary that admin_operation inherit from Index, so delete it.
import sqlite3
from PyQt5.QtWidgets import QMessageBox, QDialog, QMainWindow, QApplication
from Login_form import Login_form
from Admin_Home_form import AdminHome_Form
class Index(QDialog, Login_form):
def __init__(self):
QDialog.__init__(self)
self.loginFormDesign(self)
self.login_button.clicked.connect(self.login_check)
def login_check(self):
uname = self.U_name_text.text()
password = self.pass_text.text()
connection = sqlite3.connect("taylorDB.db")
result = connection.execute("SELECT USER_FULLNAME FROM USERS WHERE USER_EMAIL = ? AND USER_PASSWORD = ?",
(uname, password)).fetchall()
if result:
self.userfullname = result[0][0]
self.accept()
else:
buttonReply = QMessageBox.question(self, 'Login Invalid', "Check User Name or Password!",
QMessageBox.Close)
if buttonReply == QMessageBox.Close:
print("invalid login")
# self.reject()
class Admin_operation(QMainWindow, AdminHome_Form):
def __init__(self):
QMainWindow.__init__(self)
self.adminHomeFormDesign(self)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
login_object = Index()
admin_object = Admin_operation()
if login_object.exec() == QDialog.Accepted:
admin_object.userFullname.setText(login_object.userfullname)
admin_object.show()
sys.exit(app.exec_())
I want to use ListView in Pyqt4 to display some items with a checkbox in front of each item.
And, I want to get those selected items,but return value of self.ui.listView.selectedIndexes() is None, I really don’t know what to do to get what I want.
My codes are as following:
#coding=utf-8
from loadtsklist import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os
class MyLoadTskList(QDialog):
def __init__(self):
QDialog.__init__(self)
self.initTaskList()
def initTaskList(self):
global connectserver
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.btsure.clicked.connect(self.test)
tsklist = [u'北京',u'南京', u'海南', u'青岛', u'西安']
model = QStandardItemModel()
for task in tsklist:
print(task)
item = QStandardItem(QString(task))
check = Qt.Unchecked
item.setCheckState(check)
item.setCheckable(True)
model.appendRow(item)
self.ui.listView.setModel(model)
def test(self):
print len(self.ui.listView.selectedIndexes())
print "hello this is LoadTskList"
app = QApplication(sys.argv)
tsk = MyLoadTskList()
tsk.show()
app.exec_()
Could someone please tell me how to do? thanks in advance!
Firstly, your code for loading the list can be made more efficient, like this:
model = QStandardItemModel(self)
self.ui.listView.setModel(model)
for task in tsklist:
item = QStandardItem(task)
item.setCheckable(True)
model.appendRow(item)
And then to get the checked items, you need another loop, like this:
def test(self):
model = self.ui.listView.model()
for row in range(model.rowCount()):
item = model.item(row)
if item.checkState() == QtCore.Qt.Checked:
print('Row %d is checked' % row)
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()
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.
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.
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.
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.
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)
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).
There are a few things going on here:
You don't need the global declaration in your init method (textedit and rows are not global)
You're seeing the error you're seeing from the line: MyTableStatus(self.mystruct1, 145, 4) because you haven't defined the self.mystruct1 variable yet - you define it in the get_data_status method, which isn't called until the signal is emitted. You'll generally want to define your class members before doing anything else (just good practice)
I'm not really sure why you have the time.sleep(2) call in there, the processing of the signal should happen pretty quickly in Qt
You have to watch out when doing things like self.layout = QtGui.QVBoxLayout(self). The layout symbol is actually an inherited QWidget method (self.layout()). Setting this can potentially break Qt internals.
Generally, unless you are trying to connect other widgets to the update_ready_status signal, you don't really need it
Anyway, I'm not 100% sure what you are trying to do - but I hope that helps!