PyQt4: My database displays empty cells - python

I am using the pyqt4 framework to do some displays for database forms. Unfortunately, I hit a snag while trying to filter and display my database by last name. Assume that the database connection works. Also assume that I have the correct amount of items in my tupleHeader since I use the same initializeModel method for other methods (like the search() function described below, and it works fine.
I call the display() function and it works perfectly fine, but when creating a proxyModel from the sourceModel, and trying to display the proxyModel with my search function, I have empty cells displayed. When I restrict my search so that it filters half my database, it shows that many cells (so most of this is working). But it will not display anything from the database itself.
Below is some of my code:
from PyQt4 import QtGui, QtCore, QtSql
self.caseSensitivity = QtCore.Qt.CaseInsensitive
self.syntax = QtCore.QRegExp.FixedString
def initializeModel(self, model):
model.setTable(self.table)
#model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
b = 0
for a in self.tupleHeader:
model.setHeaderData(b, QtCore.Qt.Horizontal, QtGui.qApp.tr(a))
b += 1
model.select()
def display(self):
'''reads all row data and displays it on a tableview'''
self.connectdb(self.db, self.localhost, self.dbname, self.username, self.password)
model = QtSql.QSqlTableModel()
self.initializeModel(model)
self.view.setModel(model)
self.disconnectdb(self.db)
def search(self, searchQuery):
'''queries database data, filters it, and displays it on a tableview'''
sourceModel = QtSql.QSqlTableModel()
proxyModel = QtGui.QSortFilterProxyModel()
self.initializeModel(sourceModel)
proxyModel.setSourceModel(sourceModel) # allows to edit proxyModel without changing underying model
#searchQuery contains the last name that I am filtering with
regExp = QtCore.QRegExp(searchQuery, self.caseSensitivity, self.syntax)
proxyModel.setFilterRegExp(regExp)
proxyModel.setFilterKeyColumn(2) # this column holds the last names
# self.view contains the table itemview my application uses to display the database
self.view.setModel(proxyModel)
EDIT: I am not interested in keeping this piece of code, I just want to know why it allows the table to show the table's content instead of a bunch of empty cells
print self.proxyModel.filterAcceptsRow(2, self.sourceModel)
Also, if you put in this after the last statement ( self.view.setModel(proxyModel) ), it will show the table, even if it does send an error:
print self.proxyModel.filterAcceptsRow(2, self.sourceModel)
TypeError: QSortFilterProxyModel.filterAcceptsRow(int, QModelIndex): argument 2 has unexpected type 'QSqlTableModel'
It doesn't matter what the arguments are or whether I use filterAcceptsRow ro filterAcceptsColumn, it displays the table. Does this narrow down the problem some?
Thank you for your time searching for this coding error/bug, and happy hunting!

While I could not find the solution to my problem, it solved itself. I am not certain, but I think it was this code snippet that made it work.
self.dbmanip = CoreDB(self.userTableView, self.table)
This was put inside of the SetupUi() method created by the Qt4 Designer. I think either the dbmanip that contained the TableView lost the information from the proxyModel, or (more likely), I may have referenced the wrong table between the proxyModel and the original Model (that created the proxyModel), and then couldn't display because it was calling the cell structure from one table and the actual information from another.
These are all guesses though. Still, problem solved.

Related

How gets QtreeView and TreeModel synchronized

I'm using pyqt5 and python 3.6.
I am confused about index functions in QModel/TreeView and ask here to clear my knot in brain. Some threads confused me more because they are very special. My question is more or less a basic one.
I have a model (based on Uludag's great tutorials) with data and did set it to my tree:
treeView = QTreeView()
treeView.show()
treeView.setModel(model)
#additional code
treeView.clicked.connect(treeViewStructure_clicked)
Now I have to prepare further action in the program based on the selected item. I can get the item by
def treeViewStructure_clicked(self):
#get the row of the click and print
index = treeView.currentIndex()
print(index.row())
print('selected item index at %s with data: %s' % (index.row(), index.data()))
So far so good. But the index is generated from treeView (model doesn't work). How can I connect the selection form the view to the model, so that I have the correct Modelindex and can change data in the model?
And of course, how to write them back that they will get synchronized? In other words, which index do I need for what and where and where do they come from?
I would love to leave a comment but I don't have enough reputation.
Since your implementation of model did not include a method that could return the selected index, I have to get it from pyqt5. Since treeView is a QTreeView, you can:
treeView.selectionModel().selectedIndexes()
the information is from here.
These will return a QModelIndex list, which has an api here.
(note that although there are code examples on this website, it's in C++, but it should still be readable)
In the api, you can get the row and column as well as parent from the QModelIndex object.
Normally, I'd just modify the data via the object returned by treeView.selectionModel().selectedIndexes().
for example:
arr = treeView.selectionModel().selectedIndexes()
index = arr[0]
then just modify index.
but if you MUST use your own model for whatever reason, there is one thing you can do.
Since it extends QAbstractItemModel, you can use the index function.
For example:
arr = treeView.selectionModel().selectedIndexes()
indexTemp = arr[0]
index = model.index(indexTemp.row(), indexTemp.column(), indexTemp.parent())
then modify the value through setData funtion
But as you can see, it's an extra step to get the same object

PyQt : Mapping between table Widget and list widget

I was wondering of any function that can ease/solve above challenge. Basically, when a GUI (containing list and table widgets) starts. Whenever user click on each item in the list, the table should also responds to data corresponding to the list item. Refer to the following example for better understanding.
From time to time, the data in list or table can be removed, modified or added by user. I would also like to implement function to gather those. Currently, I am thinking of playing around python list and dict.
You can
use the QListWidget.itemClicked signal.
Connect it to a function, that takes an QListWidgetItem as argument.
Identify the item and act accordingly
Example
...
self.myListWidget.itemClicked.connect(self.showDataInTable)
....
def showDataInTable(item):
item_name = str(item.text()) # getting item name as python string
... # show data or do what ever you like
dataToShow = myDataDict[item_name]

Getting the currently selected item in QTreeView

I have a number of items in a QTreeView. Each item is generated using this class:
class Branch(QStandardItem):
def __init__(self, label, uri = None):
QStandardItem.__init__(self, label)
self.uri = uri
This is my actual tree:
class FileTree(QTreeView):
def __init__(self):
QTreeView.__init__(self)
def keyPressEvent(self, event):
if event.key() == Qt.Key_Space or event.key() == Qt.Key_Return:
crawler = self.selectedIndexes()[0].model().item(self.selectedIndexes()[0].row())
print(crawler.uri)
QTreeView.keyPressEvent(self, event)
As you can see, I'm a little unsure as to how to get the uri variable from the selected item. I found that selectedIndexes() returns a model and not the item itself. I'm not sure how to get from one to the other. Trying to get the item number using self.selectedIndexes()[0].row() was a bit of a shot in the dark, but it seems to ignore the various branches in the tree (for instance, it will give me a 0 for the first row in a branch, but won't tell me anything about what branch it's in).
What's the proper way to get the selected item from the QTreeView? Or is there a better way of detecting the spacebar or return keys being hit that would make this easier? There's a severe lack of Python documentation for Qt, so it's really hard to know if I'm ever doing things in a sensical manner.
You are calling the right function, it actually returns a QModelIndexList which is just a typedef for QList<QModelIndex> with the QModelIndex being the data structure that can point to any part of the tree. QModelIndex is not a Model in the sense of Model View Controller (MVC) but an adress of an object in a QAbstractItemModel which is the datastructure under all of Qt's ItemView objects, including your tree. You are actually pretty close, QAbstractModelIndex consists of a row, a column and a parent, which lets it adress any position in a hierarchical data structure. If you use the line
index = self.selectedIndexes()[0]
crawler = index.model().itemFromIndex(index)
you should get to the object that you are looking for.
As for documentation, even though there is no python specific documentation it helps to read through the official Qt documentation, the class hierarchy and functionality is still the same. There is very little C++ specific information in the docs.
Harald's answer didn't work for me, because I'm using a QSqlQueryModel as the model (I got the error {AttributeError}'QSqlQueryModel' object has no attribute 'itemFromIndex').
The below did the trick for me though, to get the 0th column data of the selected row:
dbQueryModel.itemData(treeView.selectedIndexes()[0])

Access gtk.TreeIter inside render() Function of gtk.CellRenderer -- pygtk

I am trying to code the following: Two Columns. One contains a itemId, the other one contains a typeId. I want to render the itemId only when the typeId equals a specific value.
class IDRenderer(gtk.CellRendererText):
def __init__(self):
gtk.CellRendererText.__init__(self)
def do_render(self,window, widget, background_area, cell_area, expose_area, flags):
if ----} Condition to ask for value of the typeId - Cell {-----:
gtk.CellRendererText.do_render(self, window, widget, background_area, cell_area,
expose_area, flags)
gobject.type_register(IDRenderer)
I don't know how to get the iter of the currently rendered row which i need to determine the value of the typeId. Is this even possible?
I now found out, thanks to a nice guy on #pygtk on gimpIRC:
You can do that, with binding so called cell data functions to the corresponding gtk.TreeViewColumn as done here in this example
def renderId(celllayout, cell, model, iter):
if model.get_value(iter,1) == 3:
cell.set_property('visible',True)
else:
cell.set_property('visible',False)
treeviewcolumn = gtk.TreeViewColumn()
renderer = gtk.CellRendererText()
treeviewcolumn.add_attribute(renderer,'text',0)
treeviewcolumn.set_cell_data_func(renderer,renderId)
I ommited some code relevant to render a complete treeview, but i think it shows what i wanted to do and how to do it.
The column renderes the value in the first column (0) of the model only if the value in the second modelcolumn (1) equals 3
I hope this could help someone some time.
It's not possible as far as I know. You need to use properties of the custom renderer which will be set automatically by the code calling the rendering function. (Like the text property of CellRendererText -- the rendering code doesn't get the text from the tree model, but the tree model sets the text property of the renderer before calling the rendering code.)

Passing of a variable (an ID) to another compiled UI in pyqt

I've been stumped for more than an hour on how to pass a variable, specifically an ID in sqlite which was recently accessed, to be used to another UI generated. I'm using eric4 (with python, pyqt, qtdesigner and sqlite).
Basically the program I'm coding makes members and each member has a unique ID when the information of the member is generated. When there is a new member made, the ID assigned to the new member must be passed to another part of the program. But there are also instances where there must be modifications made in the member, the ID must be known to display the right information of the member.
Basically, when a new member is added, it first inputs the the information in the database. What I did is like this in the dialog code of that ui named newmember.py:
def on_button_Save_released(self):
Nik = unicode(self.LineEdit_Nickname.text())
self.NMem = NewMem()
self.NMem.input_data(Nik)
self.close()
The NewMem is a class in another py file which has access to the database. Parts of the input_data method goes like this:
cur.execute("insert into Members (Nick) values (?)",(Nik))
I added this code so that it will know what ID the new member is assigned::
CurrentID = cur.lastrowid
return CurrentID
So I changed this line self.NMem.input_data(Nik) in the ui dialog code newmember.py into this
ID = self.NMem.input_data(Nik)
so that the ID will be passed.
Now, the dialog code will open another window and I want the returned ID be used to another ui. Basically the whole method in ui dialog code in newmember.py is like this so far:
def on_button_Save_released(self):
Nik = unicode(self.LineEdit_Nickname.text())
self.NMem = NewMem()
ID = self.NMem.input_data(Nik)
self.close()
self.Pts = Points()
self.Pts.show()
The Points() is a class in another ui dialog code which will show in the Points ui the information of the member. But the returned ID information must be passed to the Points() ui so that the right information be displayed. I have a hunch that I would be needing to change some parts in the compiled ui form so that it knows the ID to be displayed but how will I pass it in there compiled ui form?
Any help is very much appreciated bows deeply
Edit: Is there a way in this code -
self.Pts = Points()
self.Pts.show()
be the variable ID be also incorporated and will pass into the ui? Like
self.Pts = Points
self.Pts.show(ID)
that the ID will be going to the ui also?
Edit2: Is there a way how to pass variables in classes of a ui in python just like how it was shown here - http://www.daniweb.com/forums/thread64758.html
I believe using a Qt model with a QDataWidgetMapper is the Qt way of solving this problem. An example here. (QSLTableModel or subclass QAbstractTableModel if you want to program the database communication yourself).
You can also check SQL Widget mapper example in the Qt docs.
Personally I prefer to use a custom model because I've previously stumbled upon deployment problems using Qt's SQL, but your mileage may vary.

Categories