0

I have a QTableView, filled with the data coming from a QSqlTableModel.Each line of the QTableView represents an "article", coming from a website. The articles can be read or unread, exactly like an email. The state read/unread is stored in the database, under the field "new".

If the article is unread, it is displayed in a certain way in the view. If it is read, it is displayed on another way, like an email in any email manager.

When the user clicks on a article unread, the article is marked read, which means the model storing the data is updated:

def markOneRead(self, element):

    """Slot to mark an article read"""

    table = self.liste_tables_in_tabs[self.onglets.currentIndex()]
    model = self.liste_models_in_tabs[self.onglets.currentIndex()]
    proxy = self.liste_proxies_in_tabs[self.onglets.currentIndex()]
    new = table.model().index(element.row(), 12).data()

    if new == 0:
        return
    else:

        # Save the current line
        line = table.selectionModel().currentIndex().row()

        # Update the model
        table.model().setData(table.model().index(line, 12), 0)

        try:
            # Try to update the model
            model.setQuery(self.query)
            proxy.setSourceModel(model)
            table.setModel(proxy)
        except AttributeError:
            pass

        # Once the model is updated, reselect the line saved
        table.selectRow(line)

While this method works most of the time, I only save the current line number in the variable "line". So if the model has changed (from any other process of the program), when I do table.selectRow(line), I select the same line yes, but it can be a completely different item.

So I need a more precise way to store the clicked item, before I update the model.

Do you have any idea ?

JPFrancoia
  • 4,866
  • 10
  • 43
  • 73
  • I don't really understand your question. Why select the row programatically at all? If the user clicks in the table it will select that item/row. If you are worried about the selection changing if new data is added at the top of the table then you probably want to update your selection model when data is added. – justengel Feb 28 '15 at 12:54
  • I'm guessing that you are worrying about adding new data at the top shifting everything down, but the selection stays in place. You could try to add data at the bottom and change the QTableView's layout direction to BottomToTop. I don't know if that will work. The other option is to store the rowCount as well as the line variable and check for a different rowCount before you table.selectRow(line) – justengel Feb 28 '15 at 13:22
  • Yes, you got it in your second comment I think. Except that the QTableView is sorted by date, and the items added by other process are not necessarily added at the top or at the bottom, so I need to retrieve exactly the item selected. – JPFrancoia Feb 28 '15 at 16:58

1 Answers1

1

I managed to do it ! From this post (C++): How to refresh a QSqlTableModel while preserving the selection?

The resulting code in python is:

def markOneRead(self, element):

    """Slot to mark an article read"""

    table = self.liste_tables_in_tabs[self.onglets.currentIndex()]
    new = table.model().index(element.row(), 12).data()

    if new == 0:
        return
    else:

        # Save the current line
        line = table.selectionModel().currentIndex().row()
        selected_id = table.selectionModel().selection().indexes()[0].data()

        # Change the data in the model
        table.model().setData(table.model().index(line, 12), 0)

        # Update the view after the model is updated
        self.updateView(selected_id)


def updateView(self, current_item_id=None):

    """Method to update the view after a model change.
    If an item was selected, the item is re-selected"""

    model = self.liste_models_in_tabs[self.onglets.currentIndex()]
    table = self.liste_tables_in_tabs[self.onglets.currentIndex()]
    proxy = self.liste_proxies_in_tabs[self.onglets.currentIndex()]

    if current_item_id is not None:
        selected_id = current_item_id
    else:
        try:
            selected_id = table.selectionModel().selection().indexes()[0].data()
        except IndexError:
            selected_id = None

    try:
        # Try to update the model
        model.setQuery(self.query)
        proxy.setSourceModel(model)
        table.setModel(proxy)
    except AttributeError:
        pass

    if selected_id is not None:
        for index in range(1, model.rowCount() + 1):
            table.selectRow(index)
            if table.selectionModel().selection().indexes()[0].data() == selected_id:
                # If the previously selected item is found, leave
                return
        # If we are still here, the old item wasn't found, so deselect all
        table.clearSelection()
Community
  • 1
  • 1
JPFrancoia
  • 4,866
  • 10
  • 43
  • 73