Print data of a clicked row from tableView model - python

there is the dialog:
class classsearchresult(QDialog, Ui_Dialog):
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.setupUi(self)
self.tableView.setShowGrid(False)
self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
vh = self.tableView.verticalHeader()
vh.setVisible(False)
hh = self.tableView.horizontalHeader()
hh.setVisible(False)
hh.setStretchLastSection(True)
self.pushButton_2.clicked.connect(self.close)
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('formuladatabase')
db.open()
self.projectModel = QtSql.QSqlQueryModel(self)
self.projectModel.setQuery("select rowid, Name, Surname from search",db)
self.tableView.setModel(self.projectModel)
self.tableView.clicked.connect(self.handlebutton)
tableview works great just need to print that clicked row
def handlebutton(self):
rows = self.tableView.selectionModel().selectedIndexes()
print(self.projectModel.record(rows[0].row()).value("rowid").toInt())
self.newwindow = classformularesult(self)
self.newwindow.show()
been trying for a while but cant figure this one out.

Just a note: I noticed you tagged PyQt5, but the docs aren't so good there, and I'm pretty confident all I'm stating here still applies (from PyQt4).
It appears as though you're assuming that rows is going to contain the data from your query, which it does not. selectedRows(),selectedColumns,selectedIndexes() (documented here: http://pyqt.sourceforge.net/Docs/PyQt4/qitemselectionmodel.html#selectedRows) all return type list-of-QModelIndex, which are basically indexes.. not data.
list-of-QModelIndex QItemSelectionModel.selectedRows (self, int column
= 0)
Returns the indexes in the given column for the rows where all columns
are selected.
I think it's easier to use selectedIndexes
list-of-QModelIndex QItemSelectionModel.selectedIndexes (self)
Returns a list of all selected model item indexes. The list contains
no duplicates, and is not sorted.
To get the data, model.record.value() returns a QVariant, to which you have to cast to the proper type for printing. So, in your case:
rows = self.tableView.selectionModel().selectedIndexes()
print self.projectModel.record(rows[0].row()).value("rowid").toInt()
print self.projectModel.record(rows[0].row()).value("Name").toString()
print self.projectModel.record(rows[0].row()).value("Surname").toString()
The rows[0].row() is accessing element 0 of the "list-of-QModelIndex" type that's returned, and QModelIndex (http://pyqt.sourceforge.net/Docs/PyQt4/qmodelindex.html#details) has a row() method which returns the index of the row. Given the way you've set it up, the "list-of-QModelIndex" list should always be a single element list (you wired it up with the "clicked" signal), so the row[0] should return the proper element.
See here for additional information:
http://ftp.ics.uci.edu/pub/centos0/ics-custom-build/BUILD/PyQt-x11-gpl-4.7.2/doc/html/qtsql.html
About half way down there's a "Using the SQL Model Classes" heading with some good examples.

for the record and other in my situation the answers was
def handlebutton(self):
rows = self.tableView.selectionModel().selectedIndexes()
print(self.projectModel.record(rows[0].row()).value("rowid"))
self.newwindow = classformularesult(self)
self.newwindow.show()
thank you SEGFAULTCODER

Related

How to a convert a listbox item's name to a label in Python

For the program that I am required to write up, I need the name of a Listbox item to also be the text in the label. This is the code that I thought would work, but it only configurated the label to be the item's number in the Listbox, not the name:
def openAccount(self):
selectedItem = ltboxSrcUser.curselection()
for item in selectedItem:
rootMainPage.withdraw()
rootOthAccPage.deiconify()
lblOtherUserName.config(text = ltboxSrcUser.curselection())
Can anybody help me out?
The documentation for the listbox shows that curselection returns the index of the selected items, not the values. To get the values you must pass the index to the get method.
def openAccount(self):
selectedItems = ltboxSrcUser.curselection()
if selectedItems:
rootMainPage.withdraw()
rootOthAccPage.deiconify()
index = selectedItems[0]
item = ltboxSrcUser.get(index)
lblOtherUserName.config(text=item)

delete items from 3 different lists

I need some help with deleting some items from some lists at the same time, when a button is clicked.
This is the code:
class Window(QMainWindow):
list_1 = [] #The items are strings
list_2 = [] #The items are strings
def __init__(self):
#A lot of stuff in here
def fillLists(self):
#I fill the lists list_1 and list_2 with this method
def callAnotherClass(self):
self.AnotherClass().exec_() #I do this to open a QDialog in a new window
class AnotherClass(QDialog):
def __init__(self):
QDialog.__init__(self)
self.listWidget = QListWidget()
def fillListWidget(self):
#I fill self.listWidget in here
def deleteItems(self):
item_index = self.listWidget.currentRow()
item_selected = self.listWidget.currentItem().text()
for i in Window.list_2:
if i == item_selected:
?????????? #Here is where i get confussed
When i open the QDialog with a combination of keys, i see in the QListWidget some items. In the deleteItems method, i get the index and the text from the item that i selected in the QListWidget. That works fine.
What i need to do is to delete the item from the list_1, list_2, and the QListWidget when i press a button (that i have already created).
How can i do this? Hope you can help me.
Python lists have a "remove" object that perform that action directly:
Window.list_2.remove(item_selected)
(with no need for your for loop)
If you ever need to perform more complex operations on the list items, you can retrieve an item's index with the index method instead:
position = Window.list_2.index(item_selected)
Window.list_2[position] += "(selected)"
And in some ocasions you will want to do a for loop getting to the actual index, as well as the content at that index of a list or other sequence. In that case, use the builtin enumerate.
Using the enumerate pattern, (if removedid not exist) would look like:
for index, content in enumerate(Window.list_2):
if content == item_selected:
del Window.list_2[index]
# must break out of the for loop,
# as the original list now has changed:
break
if you have the value, then just find its index in each list and then delete it. Something like:
item_selected = self.listWidget.currentItem().text()
i = Window.list_2.index(item_selected)
if i >= 0:
del Window.list_2[i]
You can also use directly Widow.list_x.remove(value) but it can throw an exception if the value does not exist.

PyQt treeview edit text on doubleclick

So I've been trying to implement a proper TreeView that displays directories and files depending on user input - I am allowing the user to add directories and files to his "project" either recursively or otherwise, after which I create my own tree view of the contents of said project.
Now, my problem is that even though most of the documentation and other questions I've found on this subject seem to want to disable the editability of treeview items, I am trying ( and failing ) to find a way to enable it. What I would like is for the user to be able to double click on any cell in any column of my treeview and then edit its contents. Does anyone know how to do this?
Below is the code I am using to generate a tab in a tabView Widget, after which i then add the TreeView. The items of the TreeView are later added through the AddParent and AddChild methods.
class treeTab(QtWidgets.QWidget):
def __init__(self,core,main,label):
super (treeTab,self).__init__()
self.label = label
self.core = core
self.sizes = core.UISizes
self.tab_sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,QtWidgets.QSizePolicy.Expanding)
self.tree = QtWidgets.QTreeWidget(self)
self.tree.setColumnCount(len(self.sizes.projectTreeColumnLabels))
self.tree.setHeaderLabels(self.sizes.projectTreeColumnLabels)
self.tree.setSizePolicy(self.tab_sizePolicy)
self.tree_layout = QtWidgets.QGridLayout()
self.tree_layout.objectName = self.label + "TreeGridLayout"
self.tree.setLayout(self.tree_layout)
self.treeroot = self.tree.invisibleRootItem()
self.tree.setSelectionMode(Qt.QAbstractItemView.ContiguousSelection)
def addParent(self, parent, column, title, data):
item = QtWidgets.QTreeWidgetItem(parent, [title])
item.setData(column, QtCore.Qt.UserRole, data)
item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.ShowIndicator)
item.setExpanded (True)
return item
def addChild(self, parent, column, title, data):
item = QtWidgets.QTreeWidgetItem(parent, [title])
item.setData(column, QtCore.Qt.UserRole, data)
item.setText(1,data.print_tags())
item.setText(2,data.category.name)
item.setText(3,data.format)
item.setCheckState (column, QtCore.Qt.Unchecked)
item.setFlags(item.flags() or QtCore.Qt.ItemIsEditable)
return item
You have confused binary operators and Boolean operators. Boolean operators (such as and and or) are used with Boolean values (such as True and False) to produce a single True or False once the expression is evaluated.
However, the flags and not Boolean values. They are integers which are powers of 2 (or binary numbers with only one bit set), such that they can be combined into a single integer that represents whether each flag is enabled or disabled. For instance, 2 is represented in binary as 0b010. 4 is represented as 0b100. If you bitwise or these together, you get 0b110, indicating that both the flag equal to 2 and the flag equal to 4 is set. However the flag equal to 1 is not set (the 0 in the 0b110).
In short, you should set the flags using the bitwise or operator (|):
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
So I managed to figure this one out - it turned out to be quite simple in the end :)
In order to create an 'editable' treeView item where you can double click on the text of a particular item to edit it, you simply need to change the widget contained in that particular column of the item to a QLineEdit Widget that deletes itself upon pressing enter. The code for this looks as follows:
This is the code to connect the double click event to a method that gets the currently selected item and replaces it with a QLineEdit Widget:
self.tree.itemDoubleClicked.connect(self.editItem)
def editItem(self,*args):
itm = self.tree.itemFromIndex(self.tree.selectedIndexes()[0])
column = self.tree.currentColumn()
edit = QtWidgets.QLineEdit()
edit.returnPressed.connect(lambda*_:self.project.setData(column,edit.text(),itm,column,self.tree))
edit.returnPressed.connect(lambda*_:self.update())
self.tree.setItemWidget(itm,column,edit)
Note especially the combination of the following code:
itm = self.tree.itemFromIndex(self.tree.selectedIndexes()[0])
column = self.tree.currentColumn()
This code in effect gives you both the row and the column of the currently selected item, which is useful if you want to edit column items separately.
Now You'll be asking yourself why I'm passing so many parameters to the 'setData' method: this is purely for the purposes of my particular project, so don't worry about it. the 'returnPressed' event simply needs to connect to the proper method to handle whatever data it contains, and then delete itself. in my code, this looks like this:
def setData(self,dataTypeIndex,data,item,column,tree):
if dataTypeIndex == 0:
# filename
self.name = data
elif dataTypeIndex == 1:
# tags
data = data.split(",")
self.tags = []
for tag in data:
self.tags.append(Tag(tag))
elif dataTypeIndex == 2:
# category
self.category.name = data
tree.setItemWidget(item,column,None)
This last line of code ( tree.setItemWidget(item,column,None) ) is where the QlineEdit is unparented and therefore effectively removed.

Replacing value of variable in list of named tuples

I'm loading data about phone calls into a list of namedtuples called 'records'. Each phone call has information on the length of the call in the variable 'call_duration'. However, some have the variable set to None. I would like to replace None with zero in all of the records, but the following code doesn't seem to work:
for r in records:
if r.call_duration is None:
r = r._replace(call_duration=0)
How can replace the value in the list? I guess the problem is that the new 'r' isn't stored in the list. What would be the best way to capture in the change in the list?
You can replace the old record by using its index in the records list. You can get that index using enumerate():
for i, rec in enumerate(records):
if rec.call_duration is None:
records[i] = rec._replace(call_duration=0)
I suggest you create your own class, it will benefit you in the future as far as object management goes. When you want to create methods later on for a record, you'll be able to easily do so in a class:
class Record:
def __init__(self, number = None, length = None):
self.number = number
self.length = length
def replace(self, **kwargs):
self.__dict__.update(kwargs)
Now you can easily manage your records and replace object attributes as you deem necessary.
for r in records:
if r.length is None:
r.replace(length = 0)

Python Query Result in QTreeWidget

I am working on python plugins.I used PyQt4 Designer.
I want to list query result into QTreeWidget.
My code is as follows:
c = self.db.con.cursor()
self.db._exec_sql(c, "select est from bio")
for row in c.fetchall():
item_value=unicode(row[0])
top_node1 = QTreeWidgetItem(item_value)
self.treeWidget.insertTopLevelItem(0, top_node1)
The query returns the values as:
But when i list these values into QTreeWidget using above code,it is shown as below :
Only first character is shown.If i change '0' to some other number in self.treeWidget.insertTopLevelItem(0, top_node1) ,nothing appears in QTreeWidget.
How do i do it????
thanx.
If you take a look at the documentation for a QTreeWidgetItem, you will see there are a number of possible constructors for creating an instance. Though none of which it seems you are using in a way that is going to give you desirable results. The closest match to the signature you are providing is:
QTreeWidgetItem ( const QStringList & strings, int type = Type )
What this is probably doing is taking your string (I am assuming row[0] is a string because I don't know which drivers you are using) and applying it as a sequence, which would fullfill the requiremets of QStringList. Thus what you are getting is populating multiple columns of your item with each letter of your string value. If this is what you wanted, then you would n eed to tell your widget to show more columns: self.treeWidget.setColumnCount(10). But this isn't what you are looking for I am sure.
More likely what you should be trying is to create a new item, then add the value to the desired column:
item = QTreeWidgetItem()
item.setText(0, unicode(row[0]))
self.treeWidget.insertTopLevelItem(0, item)
You can use the default constructor with no arguments, set the text value of the first column to your database record field value, and then add that item to the tree. You could also build up a list of the items and add them at once:
items = []
for row in c.fetchall():
item = QTreeWidgetItem()
item.setText(0, unicode(row[0]))
items.append(item)
self.treeWidget.insertTopLevelItems(0, items)
Your first aproach could be corrected just add a list to the widgetitem not a string like this:
top_node1 = QTreeWidgetItem([item_value])

Categories

Resources