PyQT5 query.next() doesn't seem to be working - python

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)}")

Related

I want to call another class in tkinter. i have 2 classes and i can't call the database class below my window class

I am new to tkinter and i have only started working on Tkinter and i have 2 classes, i am trying to call a class that i have done right under my window class. it is giving me a type error database_basket , name of the class is not callable. can someone give me a hint?
This is the problem that i am facing
class Window3:
def __init__(self, master):
self.master = master
self.master.title("Payment")
self.master.geometry("1500x800")
self.frame = Frame(self.master)
self.frame.pack()
self.customer_basket = Database_Basket() # Calling the class below
self.customer_basket.connection()
def insert_data(self):
if len(self.prod_id_var.get()) != 0:
self.customer_basket(self.prod_id_var.get(), self.prod_name_var.get(), self.prod_qty_var.get(),self.prod_price_var.get())
self.basket_listbox.delete(0, END)
self.basket_listbox.insert(END, self.prod_id_var.get(), self.prod_name_var.get(), self.prod_qty_var.get(),self.prod_price_var.get())
class Database_Basket:
def connection(self):
print("Database is now connected")
db_conn = sqlite3.connect("basketinfo.db")
cursor = db_conn.cursor()
my_query = "create table if not exists tblbasket(product_id integer primary key, prod_name text, quantity text, price text) "
cursor.execute(my_query)
db_conn.commit()
db_conn.close()
print("Database connection is finished")
def data_entry(self, prod_id, prod_name, quantity, price):
print("Data Entry Method is called")
connection = sqlite3.connect("basketinfo.db")
cursor = connection.cursor()
insert_query = "insert into tblbasket value(?,?,?,?)"
cursor.execute(insert_query, (prod_id, prod_name, quantity, price))
connection.commit()
connection.close()
print("Data Entry Method is finished")
Did you mean to call data_entry:
self.customer_basket.data_entry(self.prod_id_var.get(), self.prod_name_var.get(), self.prod_qty_var.get(),self.prod_price_var.get())
I think this line :
self.customer_basket(....)
should be :
self.customer_basket.data_entry(.....)
You are trying to call the instance, where as you should be calling the data_entry method.

Python crashing when trying to view data in PyQT5 [duplicate]

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

QComboBox using QQueryModel, getting the id field (not display) from the clicked

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;

How do i use a list that is made in another file

Hello i am trying to get a variable out of another file but i don't know what i am doing wrong.
This is the first file. I am trying to take values from a list that is made in the second file and put them into a combobox but i don't know how to return the list to the first file. I tried the return statement thing but it tells me there should be none
import sys
from PyQt5.QtWidgets import (QWidget, QLabel,
QComboBox, QApplication)
import selectColumn
class Example(QWidget):
def __init__(self):
super().__init__()
ItemList=selectColumn.Column()
print(ItemList)
self.lbl = QLabel("1", self)
combo = QComboBox(self)
for i in range(len(ItemList)):
Item=ItemList[i]
combo.addItem(Item)
combo.move(50, 50)
self.lbl.move(50, 150)
combo.activated[str].connect(self.onActivated)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('QComboBox')
self.show()
def onActivated(self, text):
self.lbl.setText(text)
self.lbl.adjustSize()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
This is the second file. This is the file that makes the column values into a list.
import sqlite3
class Column(object):
def __init__(self):
db= sqlite3.connect("SQLite database")
cursor = db.cursor()
cursor.execute("""SELECT Item_ID FROM Items_Table""")
data = cursor.fetchall()
print(data)
db.commit()
cursor.close()
Thank you for your time.
In the second file, selectColumn.py, you define class Column. Its __init__() method performs a select query on the database and retrieves all rows which it stores in the variable data. At the end of the method data goes out of scope and is deleted. Therefore you can not retrieve it again later, it is lost.
What you need to do is assign the results of the query to a member (or attribute) of the object. To do this use self.data = cursor.fetchall(). Now you can access data through a instance of the Column class.
import sqlite3
class Column(object):
def __init__(self):
with sqlite3.connect("SQLite database") as db:
cursor = db.cursor()
cursor.execute("""SELECT Item_ID FROM Items_Table""")
self.data = [item[0] for item in cursor.fetchall()]
Notice that I have changed the code to use a context manager when opening the database. This is a little cleaner as you don't need to worry about closing the cursor or database connection.
Also, cursor.fetchall() will return a list of tuples. Each tuple contains a single element, item ID. It will be more convenient to users of this class to have a list of just the IDs without the tuple wrapper. To do that I have used a list comprehension to extract the first (and only) element of each tuple. This results in a list of IDs.
Now, in the first file you can do this:
column = selectColumn.Column()
...
for item_id in column.data:
combo.addItem(item_id)
It will be a simpler design if you remove the class Column in the second file. As you have shown a function can solve your problem.
import sqlite3
def getData():
db = sqlite3.connect("SQLite database")
cursor = db.cursor()
cursor.execute("""SELECT Item_ID FROM Items_Table""")
data = cursor.fetchall()
db.close()
return data
And, in the first file, change the line ItemList=selectColumn.Column() by itensIds = selectColumn.getData()

Updating QtableWidget pyqt

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!

Categories

Resources