7

I have a QWidget and inside that, there is a QTableView. I need to have a find functionality on the first column of the table, so when I click on Ctrl+F, a find dialog will pop-up.

class Widget(QWidget):
    def __init__(self,md,parent=None):
        QWidget.__init__(self,parent)
        layout=QVBoxLayout(self)

        # initially construct the visible table
        tv = QTableView()
        # uncomment this if the last column shall cover the rest
        tv.horizontalHeader().setStretchLastSection(True)
        tv.show()

        # set black grid lines
        self.setStyleSheet("gridline-color: rgb(39, 42, 49)")

        # construct the Qt model belonging to the visible table
        model = NvmQtModel(md)
        tv.setModel(model)
        tv.resizeRowsToContents()
        tv.resizeColumnsToContents()

        # set the shortcut ctrl+F for find in menu
        shortcut = QShortcut(QKeySequence('Ctrl+f'), self)
        shortcut.activated.connect(self.handleFind)

        # delegate for decimal
        delegate = NvmDelegate()
        tv.setItemDelegate(delegate)
        self.setGeometry(200,200,600,600) # adjust this later
        layout.addWidget(tv)

        # set window title
        self.setWindowTitle("TITLE")

    # shows and handles the find dialog
    def handleFind(self):
        findDialog = QDialog()
        grid = QGridLayout()
        findDialog.setLayout(grid)

        findLabel = QLabel("Find what", findDialog)
        grid.addWidget(findLabel,1,0)
        findField = QLineEdit(findDialog)
        grid.addWidget(findField,1,1)
        findButton = QPushButton("Find", findDialog)
        findButton.clicked.connect(self.find)
        grid.addWidget(findButton,2,1)

        findDialog.exec_()

    # find function: search in the first column of the table   
    def find(self):
        #to do

    # prevent closing the window  without confirmation
    def closeEvent(self, event):
        reply=QMessageBox.question(self,'Message',"Are you sure to quit?",QMessageBox.Yes|QMessageBox.No,QMessageBox.No)
        if reply==QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

# create the application and the new tree view container
app=QApplication(sys.argv)
wid=Widget(md)
wid.show()
wid.raise_()

I have problem in the findButton action where it should search in the first column of the table. I would appreciate if you guide me in this issue.

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
Orcl User
  • 293
  • 1
  • 5
  • 20

1 Answers1

10

Firstly, you will need to change the way the findButton is connected, so that it sends the text to be searched for:

findButton.clicked.connect(
    lambda: self.find(findField.text()))

Then you can search in your table by using the match method of the tableview's model:

def find(self, text, column=0):
    model = self.table.model()
    start = model.index(0, column)
    matches = model.match(
        start, QtCore.Qt.DisplayRole,
        text, 1, QtCore.Qt.MatchContains)
    if matches:
        index = matches[0]
        # index.row(), index.column()
        self.table.selectionModel().select(
            index, QtGui.QItemSelectionModel.Select)

UPDATE:

The method above will find the first cell that contains the given text, and then select it. If you wanted to find the next cell that matches, start would need to be set to the appropriate index of the current selection (if there is one). This could be obtained with:

    indexes = self.table.selectionModel().selectedIndexes()
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • tnx, AttributeError: 'Widget' object has no attribute 'table' in line : "model = self.table.model()" – Orcl User Dec 20 '13 at 00:40
  • 1
    @OrclUser. Yes, sorry, I missed that. You will need to change `tv` in `Widget.__init__` to `self.table`. – ekhumoro Dec 20 '13 at 00:43
  • Now it is supposed to print the index but I can not see the print result in the console..And how to show where in the table the corresponding text is found? for example by highlighting the row or pointing to it? what is the common way to do so? – Orcl User Dec 20 '13 at 00:58
  • Tnx for the update..I still have problem in the last step when it wants to select the row corresponding to the index.."if matches" never executes! – Orcl User Dec 20 '13 at 14:18
  • @OrclUser. That would suggest there is no match for the text you entered. Try entering something simple (like a single letter) that you are certain is somewhere in the first column. – ekhumoro Dec 20 '13 at 18:17
  • @ekhumoro. Can i select multiple rows that have the given text? – And3r50n 1 Jul 05 '18 at 13:25
  • 2
    @And3r50n1. Sure, yes. Just use `-1`in the `match` method to get all matches and then iterate over them. You may also need to change the [selection mode](https://doc.qt.io/qt-5/qabstractitemview.html#selectionMode-prop) of the table to allow multiple selections. – ekhumoro Jul 05 '18 at 15:38
  • @ekhumoro. Thanks. Worked like a charm – And3r50n 1 Jul 05 '18 at 18:48
  • For others coming here, so you don't have to look it up, if you are using PyQt6 you would replace `QtCore.Qt.DisplayRole` with `QtCore.Qt.ItemDataRole.DisplayRole` and replace `QtQui.QItemSelectionModel.Select` with `QtCore.QItemSelectionModel.SelectionFlag.Select` – wooshuwu Jul 14 '23 at 03:57