0

I wrote a class that makes a window, part of this class is a function dynamic_table_view that creates a TableView widget with a possibility to view data and edit it right in that same window:

def dynamic_table_view(self, cur, table_name, edit=True, add=True, layout=None):
    if layout is None:
        layout = self.main_layout
    df = pd.read_sql(f"SELECT * FROM {table_name}", conn)
    col_types = parse_types(cur, table_name)
    model = QStandardItemModel(df.shape[0], df.shape[1])
    model.setHorizontalHeaderLabels(list(df.columns))
    for row in range(df.shape[0]):
        for col in range(df.shape[1]):
            print(col, df.columns, df.columns[col])
            item = QStandardItem(str(df.iat[row, col]))
            if edit and df.columns[col] != 'id':
                item.setEditable(True)
            else:
                item.setEditable(False)
            model.setItem(row, col, item)
    
    table_view = QTableView()
    table_view.setModel(model)
    
    if edit:
        table_view.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked | QAbstractItemView.EditTrigger.SelectedClicked)
        table_view.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
        table_view.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
         
    table_view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
    self.add_widget(table_view, layout)
    
    #changing selected item onclick
    def on_item_changed(item):
        row = item.row()
        col = item.column()
        new_value = item.text()
        column_name = df.columns[col]
        row_id = df.iloc[row]["id"]
        if col_types[column_name] == "integer":
            query = f"UPDATE {table_name} SET {column_name} = {new_value} WHERE id = {row_id}"
        else:
            query = f"UPDATE {table_name} SET {column_name} = '{new_value}' WHERE id = {row_id}"
        execute_query(cur, query)
    model.itemChanged.connect(on_item_changed)

Basically, I need to make all cells in a specific column to act like QComboBox. I've read that I'd need to use a delegate for that, but I don't really understand how to implement it. From what I've seen, it could be done with creating a separate class for the delegate or overriding it somehow, but I was wondering if there's a way to make it shorter because I would only need that to be created in that one specific piece of code (for example, I wouldn't create a class for creating windows if I only needed to write one instance of that code).

3
  • 1
    You could set a QComboBox for every row in that column using setIndexWidget(), but you'd need to properly connect signals, possibly using a lambda, in order to set the model data whenever each combo changes index. Be careful, though, as lambdas need special care when created in for loops; in reality, using a custom delegate could actually be more appropriate (other than reliable and more consistent), and you could take it as an opportunity to learn something new (and often useful to know). Commented May 27 at 18:57
  • @musicamante so for that the best solution would be creating a class from a QStyledItemDelegate and change the way it works a little? Commented May 29 at 12:51
  • I can't say it's the best (it depends on your needs and capabilities) but it generally is more appropriate. The fact that you may only use a class in one "instance" is irrelevant, the requirement to create a new class is the effectiveness of its creation: if avoiding a new class makes your code cumbersome or difficult to read/debug, then what's the point? Commented May 29 at 20:59

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.