[I'm using PyQt4, but I think this Qt4 issue is not Python specific.]
I have a QTableWidget. In each row, the first column holds a button. When clicked, the row is removed.
To remove the row, I use removeRow(int row) method, which takes as argument the index of the row. When connecting the signal, I can't know the index of the row because it might change in the meantime (for instance if the first row is removed, all row indexes are changed).
The accepted answer here suggests to pass the callback an instance of a QTableWidgetItem in the line, then get the row number from this item at deletion time.
This would be nice, except none of the elements of the row is a QTableWidgetItem. The elements are the button itself and a few ComboBoxes.
I can't figure out a way around this.
Can I somehow fit one of my elements into a QTableWidgetItem? Should I add a QTableWidgetItem in some sort of hidden column?
Our current implementation uses indexAt(QtGui.qApp.focusWidget()) (see other answer to question mentioned above), which looks like a sorry workaround to me.
If I replace the button with a checkable QTableWidgetItem like this
rm_item = QtGui.QTableWidgetItem()
rm_item.setFlags(QtCore.Qt.ItemIsUserCheckable |
QtCore.Qt.ItemIsEnabled)
I have a QTableWidgetItem I can use to get back to the row index. But I don't know how to catch a "checked" or "clicked" event from it like I do with the button. All I found is the itemClicked signal of QTableWidget, but then I'd have to filter all the other widgets out.
There has to be something obvious I'm missing.
Edit
From what I read here, I could add both a QTableWidgetItem with setItem and a Button widget with setCellWidget to the same cell. This doesn't seem so natural to me, but apparently it works (can't test right now).
I guess I'll do that. Add the Button, plus a dummy QTableWidgetItem on the same cell to pass as a reference to the row.
Is this how it is meant to be?
Edit 2
Or maybe QTableWidget is not the proper Widget and I should be using a Layout, as suggested here.
It seems that using a layout rather than a table is possibly the most "correct" answer, but that may come with it's own difficulties, as seen in my answer to this question:
How to delete widgets from gridLayout
If you want to continue using a table, a somewhat cleaner solution than adding dummy items would be to use a persistent model index:
button = QtGui.QPushButton(text, self.table)
self.table.setCellWidget(row, column, button)
index = QtCore.QPersistentModelIndex(
self.table.model().index(row, column))
button.clicked.connect(
lambda *args, index=index: self.handleButton(index))
def handleButton(self, index):
print('button clicked:', index.row())
if index.isValid():
self.table.removeRow(index.row())
If I understand your question correctly:
def set_button(self, row, col):
# create a push button
btn = QtGui.QPushButton('Remove row')
# connect to action
btn.clicked.connect(self.remove_row)
# set in cell
self.setCellWidget(row, col, btn)
def remove_row(self):
# find what is clicked
clicked = QtGui.qApp.focusWidget()
# position
idx = self.indexAt(clicked.pos())
# remove this row
self.removeRow(idx.row())
Related
I wonder if someone knows this.
as in attached pic let's say I have a tabwidget in qt designer and some lineEdit fields. What
I want to achieve is, if the user clicks on a row of the tabwidgets the values of the items will be moved to the lineEdit fields. I saw I can somehow connect them but how to achieve this with the signal and slot functionality in qt designer without programming.
No, it is not possible without implementing code manually as there is no signal to send the text. The logic is:
self.tableWidget.cellDoubleClicked.connect(self.handle_cellDoubleClicked)
# or self.tableWidget.cellClicked.connect(self.handle_cellDoubleClicked)
def cellDoubleClicked(self, row, column):
item = self.tableWidget.item(row, column)
text = item.text() if item is not None else ""
self.lineEdit.setText(text)
I want to know how to trigger the function "self.runEverything" when a specific item in a list widget is selected.
I tried this but nothing is happening because I am not entering the if-statement.
if(self.listwidget.item(0).isSelected()):
self.runEverything(filepath)
You may want to check QListWidget currentRowChanged signal.
So, depending on the thing you want:
# example call
# QListWidget::currentRowChanged() emits an int value.
self.listwidget.currentRowChanged.connect(self.slotOrLambdaFunction)
def slotOrLambdaFunction(self, idx : int):
if idx == 0:
self.runEverything(filePath)
And then trigger stuff you need from the currently selected row in the widget.
You can also use QListWidget::itemClicked(QListWidgetItem item).
I have been looking for a treeView widget option where I can select only a single row at a time by clicking it and then de-select it by clicking on it again. I found how to make it so that you can select only one row at a time, but I was unable to find an option that allowed u to click the selected row to de-select it.
Does anyone know how this can be done? Any help would be appreciated.
You can set a custom binding to deselect the item if it's currently selected. If your binding returns the string break, it will stop event propagation and thus prevent the default behavior for double-click.
...
self.tree = ttk.Treeview(...)
self.tree.bind("<1>", self.on_click)
...
def on_click(self, event):
selection = self.tree.selection()
item = self.tree.select_row(event.y)
if item in selection:
self.tree.selection_remove(item)
return "break"
Unfortunately, the only built-in pattern to toggle the selection state of a treeview item is by selecting a different item but you can do a hack of your own.
I have a question regarding QTableWidget at PyQt4. Say I have a QTableWidget, where I want to have an event connected to a cell click using:
table.cellClicked.connect(cellClick)
then, cellClick function does its job. The thing is: some cells contain a button, like so (coordinates 0,0 as an example):
button = QtGui.QPushButton()
table.setCellWidget(0,0, button)
Now comes my problem. The presence of the button in a cell (which takes up the entire cell space) completely disables the cellClicked - the cell doesn't get clicked, the action can't be detected. But I do want my button to fill the cell.
So, in short, my question is - how can I select (click) a QTableWidget cell when there's a button inside it?
The simple answer would seem to be:
button.clicked.connect(cellClick)
But then how would you know the row/column of the cell that was clicked? So the next iteration might be:
button = QPushButton()
table.setCellWidget(row, column, button)
button.clicked.connect(
lambda *args, row=row, column=column: cellClick(row, column))
Which is okay if the table is static. But what if the rows and columns can be rearranged? The row/column cached in the button's clicked handler could be invalidated in that case. So the next iteration might be:
index = QtCore.QPersistentModelIndex(table.model().index(row, column))
button.clicked.connect(
lambda *args, index=index: cellClick(index.row(), index.column()))
(NB: you can connect other slots to the button's clicked signal, but the order they will be invoked in is undefined)
Is there a way to get and change the active row in a QTreeView (not QTreeWidget)? By active, I mean the row with the focus highlight, not the selected row. In the paint event, I can use QStyle.State_HasFocus to get the active row, but this doesn't seem to work elsewhere.
You can get/set the active row with the currentIndex() and setCurrentIndex() functions that you can find in both QTreeView and QItemSelectionModel (the latter is returned by QTreeView.selectionModel()).
And despite its name, the QItemSelectionModel handles the view current item, and the view selection independently.
Current item is the one which is indicated by the focus rectangle. You can change it using selectionModel function of the tree view. If you don't want to change currently selected items, pass QtGui.QItemSelectionModel.NoUpdate as a second parameter to setCurrentIndex method. Below is an example:
index = model.index(3, 0);
view.selectionModel().setCurrentIndex(index, QtGui.QItemSelectionModel.NoUpdate)
this should move current item to the item with index 3
hope this helps, regards
For me it got nothing here new to ask such question, why because simple; you can use Qt-Designer and create QTreeView and then create line edit, then link them using the action editor, then transform the UI file to Py file, then you will see how things work behind the scene.
You will find this if you try:
QtCore.QObject.connect(self.treeView, QtCore.SIGNAL(_fromUtf8("clicked(QModelIndex)")), self.test)