PyQt Get cell from TableView with header label - python

I currently load the results of an SQL query into a TableView.
self.projectModel = QSqlQueryModel()
self.projectModel.setQuery(sql,db)
I then need to select a specific cell based on the header label (geometry). This column will move position depending on the different table that is search.
When the user clicks anywhere on the row (NOT the cell of geometry column) I would like to select the geometry column cell.
At the moment I have a this associated with the tableView
self.dlg.tableView.clicked.connect(self.cellClicked)
And in that function I have
row = self.projectModel.currentIndex()
If I use QTableView.model(row, column) to select the index, I have to speciify the row and column number. However, this would vary so I would want to do QTableView.model(row, 'geometry') however the model expects integers.
Any solutions?
thanks

So it seems all you need is a method to find a column from its header label, i.e. something like:
def columnFromLabel(self, label):
model = self.table.horizontalHeader().model()
for column in range(model.columnCount()):
if model.headerData(column, QtCore.Qt.Horizontal) == label:
return column
return -1

Related

Python PyQt - deleting selected table rows, and deletes wrong rows if row isn't selected

So I have created a CSV database with PyQT5.The user Has the option to delete last row and selected row
So I have a problem with selecting and deleting selected row:
(I apologize if my problem is hard to understand I don't know how to explain it properly, so here is a small visual representation)
1.data1 1.data1
2.data2 -> user selects 2.data2 row and deletes it-> 2.data3
3.data3 3.data4
4.data4
-> but if the user decides to delete last row without selecting the row this is what happens
1.data1 1.data1
2.data3 2.data4
3.data4 -> user presses Delete row button, without selecting 3.data4 row ->
-> but the last row doesn't get deleted instead the index of previously selected row gets passed
and the last selected row gets deleted
I have managed to locate the problem somewhere in this block of code, My guess is the problem comes from the .currentIndex(), but I don't know how to set the currentIndex to be None or empty so that it doesn't carry a number.
def deleteSelectedRow(self):
self.chosenRow = self.table_Database.currentIndex().row()
print(self.chosenRow)
if self.chosenRow < 0:
return
else:
self.table_Database.removeRow(self.chosenRow)
I had tried setting it to a negative number but that caused the same effect the index of the selected row prevailed the same
The currentIndex() of an item view doesn't indicate a selected index: while normally using setCurrentIndex() also selects the index, you can have a current index even if none is selected.
When an index that was the current is removed from the view, Qt automatically sets (but does not select!) the new current to the previous row and/or column depending on what was removed, unless there is no available index (rowCount() or columnCount() return 0) or the deleted index was in the first row or column (in this case, it sets the first available row and/or column).
The simple solution is to check whether there's a selected index or not:
def deleteSelectedRow(self):
if self.table_Database.selectedIndexes():
row = self.table_Database.currentIndex().row()
else:
row = self.table_Database.rowCount() - 1
if row >= 0:
self.table_Database.removeRow(row)
Considering what explained above, you could also have extended selections which don't show what the "current index" is; if you're supporting selections upon more than one row, you should create a list of rows based on the selected indexes, and remove rows in reversed order:
def deleteSelectedRow(self):
selected = self.table_Database.selectedIndexes()
if selected:
# create a set of *unique* rows
rows = set(i.row() for i in selected)
else:
rows = [self.table_Database.rowCount() - 1]
for row in sorted(rows, reverse=True):
self.table_Database.removeRow(row)

Streamlit selectbox is reseting the webpage

I am currently trying to use the selectbox to allow the users to pick a name of a column to run a model with. When I put a selectbox in the sidebar I didn’t have an issue, but when I put the selectbox on the main page as soon as the user selects a option the wepage resets. the code is below. I am still new to streamlit, so I am not sure if I am using this properly. I appreciate the help!
#add a blank space in the columnName section
columnNames = [" "]
#grab the column names of the dataframe
for column in df.columns:
columnNames.append(column)
#place the selectboxe in the col1 slot
with col1:
#display the column names to the user
#So that they can select the columns they want to use
columnValue = st.multiselect("Select the column:", columnNames)
#place a button in col2 slot
with col2:
#a button to add the selected column to a list of want to use columns
addButtonList = st.button("Add to select list: ")
#when 'addButtonList' is selected take the value from
#'columnValue' and place it on the screen.
if(addButtonList):
st.write(columnValue)
There seems to be a way by setting the session_state to the button. Check this https://discuss.streamlit.io/t/the-button-inside-a-button-seems-to-reset-the-whole-app-why/1051 OR https://gist.github.com/tvst/faf057abbedaccaa70b48216a1866cdd for the detailed explanation.

Access original index in QAbstractTableModel from selected row in QTableView

I am implementing a GUI for a python programme using Qt5 and PySide2. I have no problem understanding the C++ side of Qt, so feel free to point out Qt references not related with python.
I have some data that I display in a QTableView using a subclass of QAbstractTableModel. I also use a subclass of QSortFilterProxyModel to filter my table to only display a subset of the underlying data because it's a very large dataset. I offer the user the possibility to display only part of this data according to some criteria. This all works really well.
Then I have configured the QTableView so that the user can only select complete rows:
self.ui.candidatesTable.setSelectionBehavior(QTableView.SelectRows)
And in the object handling the UI I have implemented a slot that is called when the selection in the table changes:
#Slot(QItemSelection)
def handleSelectionChanged(self, item):
hasSelection = self.ui.candidatesTable.selectionModel().hasSelection()
if hasSelection:
selectedRows = self.ui.candidatesTable.selectionModel().selectedRows()
for row in selectedRows:
print(row.row())
My problem is that the value printed by print(row.row()) shows the row index in the currently displayed rows. If the user has selected filtering criteria that only displays 5 rows out of the several thousands, and then selects the first row, print(row.row()) will return 0 and not the original index in the underlying QAbstractTableModel.
My question is therefore the following: how can I access the original index in this situation?
You have to map the QModelIndex of the proxy model to the source model using the mapToSource() method:
#Slot(QItemSelection)
def handleSelectionChanged(self, item):
indexes = self.ui.candidatesTable.selectedIndexes()
proxy_model = self.ui.candidatesTable.model()
rows = set()
for index in indexes:
si = proxy_model.mapToSource(index)
rows.add(si.row())
for row in rows:
print(row)
Based on the previous answer by #eyllanesc, I implemented a solution using selectedRows() instead of selectedIndexes(). The latter returns indices for all selected columns and rows, while I was only interested in rows:
#Slot(QItemSelection)
def handleSelectionChanged(self, item):
hasSelection = self.ui.candidatesTable.selectionModel().hasSelection()
if hasSelection:
selectedRows = self.ui.candidatesTable.selectionModel().selectedRows()
for row in selectedRows:
proxy_model = self.ui.candidatesTable.model()
row_index = proxy_model.mapToSource(row).row()

What rows are in view of a QAbstractTableModel

I have a custom QTableView with a custom QAbstractTableModel. I update every row where data has changed. The class that manages the data has a dirty flag which works well to help cut down the number of updates.
When I have a large number of rows, 1000 or more, the table gets a little less responsive. Instead of a for loop for each row to check it is dirty, I'd like to just loop over the 20 or so rows visible to the user, but I can't seem to determine how to get that information.
Is there a method or a convenient way to determine what rows are visible to a QAbstractTableModel?
The following will update only the rows visible to the user:
minRow = treeView.rowAt(0) # very top of scrollable area
if minRow >= 0: # ensure there is at least one row
maxRow = treeView.rowAt(treeView.height()) # very bottom...
# there may not be enough rows to fill scrollable area
if maxRow < 0: maxRow = model.rowCount() - 1
for row in range(minRow, maxRow + 1):
model.dataChanged.emit(model.index(row, 0), model.index(row, model.columnCount()))

How to make QTableWidget's columns assume the maximum space?

The columns of my QTableWidget do not fill in the space of the table, so that an empty space is left on the right hand-side. How to make the columns of my QTableWidget assume the maximum space so as to fill in this space?
The headers of the table have methods for controlling this:
header = table.horizontalHeader()
header.setStretchLastSection(True)
or:
header.setResizeMode(QHeaderView.Stretch)
I don't know of any method to set this property to the QTableWidget's content. However, I could use the following to get the columns to resize:
def resizeEvent(self, event):
self.setColumnWidth(0, event.size().width())
This resizes the first column only. To resize all columns, one should get all children item and apply column width / number of items.

Categories