Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to grey out items in a QTableview delegate editor



  • Hey , I am writing a setlist application in Qt C++ and have come across a couple of things I can't seem to find out how to do (Excuse me for messy code and if I am missing some basics as I am not a programmer! Any tips/criticism are/is welcome!);

    I have a dialog which I display some QTableviews in a QTabwidget (linked to SQLite DB with QSqlRelationalTableModels)
    In one tab I have a 'Column' tab where I have checkboxes to select the Columns I will want to output to the setlist. In another tab I have a 'SortBy' value that the outputted list will be sorted by.
    So, obviously if I have a particular column unticked then I want to avoid that column being selected in the other tab so I would like the unticked items to be greyed out, I still want to be able to see them but not select them. Can anyone give me some tips on how to do this? I have tried a few things and googled without success! Appreciate any help!

    I have used a standard delegate on the tableviews to allow editing.
    On the 'SortBy' column, I created a custom delegate to try to do it.
    I send the columns that are unticked into the delegate in a Qlist. In this delegate I tried to get the model from the combobox (from the delegate editor, as this is what Google told me to do!!!) but the program crashes)

    ##Dialog class

    #include "settingsdialogclass.h"
    #include "ui_settingsdialogclass.h"
    #include "proxymodelcheckboxes.h"
    #include "constants.h"
    #include <customdelegate.h>
    #include "customdelegatecombobox.h"
    
    #include <QTableView>
    #include <QMessageBox>
    #include <QComboBox>
    #include <QSpinBox>
    #include <QLabel>
    #include <QSqlRelationalDelegate>
    #include <QDebug>
    
    
    SettingsDialogClass::SettingsDialogClass(QStringList columnsToHide, QWidget *parent) :
       QDialog(parent),
       ui(new Ui::SettingsDialogClass)
    {
       ui->setupUi(this);
    
       m_modelColumns = new QSqlRelationalTableModel;
       m_modelSections = new QSqlRelationalTableModel;
    
       m_columnsToHide = columnsToHide;
    
       ui->tabWidget->addTab(columnTab(),SETTINGS_COLUMN_TAB_NAME);
       ui->tabWidget->addTab(sectionsTab(),SETTINGS_SECTION_TAB_NAME);
    
       setWindowTitle(SETTINGS_DIALOG_NAME);
    
       //This loop removes the 2 default tabs (Note once you remove first tab indexes change)
       for (int i=0;i<2;i++)
       {
           ui->tabWidget->removeTab(0);
       }
    
    }
    
    SettingsDialogClass::~SettingsDialogClass()
    {
       delete ui;
    }
    
    
    //Tabs
    QWidget *SettingsDialogClass::columnTab()
    {
       QString tableName = SETTINGS_TABLE_COLUMNS;
       QTableView *settingsViewColumns = new QTableView;;
    
    //****** Proxy Model for checkboxes
       ProxyModelCheckboxes *proxyModel = new ProxyModelCheckboxes;
       QList<bool> boolColumns;
    
       boolColumns.append(SETTINGS_COLUMN_ONOFF); //Sets the column which will have the checkboxes
       proxyModel->setParameters(boolColumns);
    
    
       proxyModel->setSourceModel(m_modelColumns);
       settingsViewColumns->setModel(proxyModel);
    //****** Proxy Model for checkboxes
    
    
    ////*****  Standard Model *****//
    //    settingsViewColumns->setModel(m_modelColumns);
    ////*****  Standard Model *****//
    
    
       m_modelColumns->setTable(tableName);
       m_modelColumns->setEditStrategy(QSqlTableModel::OnFieldChange);
       m_modelColumns->select();
    
       QWidget *newTab = new QWidget;
    
       QVBoxLayout *mainLayout = new QVBoxLayout;
       mainLayout->addWidget(settingsViewColumns);
       newTab->setLayout(mainLayout);
    
       return newTab;
    
    }
    
    QWidget *SettingsDialogClass::sectionsTab()
    {
       QString tableName = SETTINGS_TABLE_SECTIONS;
       QTableView *settingsViewSections = new QTableView;;
    
    
       QSqlRelationalTableModel *model = new QSqlRelationalTableModel;
    
       setSectionsModel(model);
    
       model->setTable(tableName);
       model->setEditStrategy(QSqlTableModel::OnFieldChange);
       // need to set this to change immediately so I can check if that column is ticked or not
       // The problem is that when you change it then press ok to close the window there is no field change
    
    
       model->setRelation(1,QSqlRelation(SETTINGS_TABLE_SECTIONS_INTEGERS,SETTINGS_TABLE_SECTION_INTEGERS_ID_HEADER,SETTINGS_TABLE_SECTION_INTEGERS_HEADER));
       model->setRelation(2,QSqlRelation(SETTINGS_TABLE_SECTIONS_COLUMNS,SETTINGS_TABLE_SECTION_COLUMNHEADER_ID_HEADER,SETTINGS_TABLE_SECTION_COLUMNHEADER_HEADER));
       model->setRelation(3,QSqlRelation(SETTINGS_TABLE_NO_OF_SONGS_PER_PAGE_INTEGERS,SETTINGS_TABLE_SECTION_INTEGERS_ID_HEADER,SETTINGS_TABLE_SECTION_INTEGERS_HEADER));
    
       model->setHeaderData(1,Qt::Horizontal,SETTINGS_TABLE_SECTION_SECTIONS_HEADER);
       model->setHeaderData(2,Qt::Horizontal,SETTINGS_TABLE_SECTION_SORT_HEADER);
       model->setHeaderData(3,Qt::Horizontal,SETTINGS_TABLE_SECTION_SONGS_PER_PAGE_HEADER);
    
       //I spent ages getting this to work. When I added in the Relations it wouldn't update the database
       //It worked fine without relations. Eventually I checked online and it suggested that one of the database tables columns needed to be a primary key
       // I made the first one a primary key but that didn't work. I eventually added a dummy column and made that a Primary key and that worked
    
       model->select();
    
       settingsViewSections->setModel(model);
       settingsViewSections->setColumnHidden(0,true);
       // I had to add a dummy column and call it Primary Key for this table to work so this just hides the column
       settingsViewSections->verticalHeader()->setVisible(false);
       //this gets rid of the Row header
    
       settingsViewSections->setItemDelegate(new QSqlRelationalDelegate(settingsViewSections));
       //standard delegate provides an editor widget for editing fields in the table
       settingsViewSections->setItemDelegateForColumn(2,new CustomDelegateComboBox(m_columnsToHide, settingsViewSections));
       // My custom delegate to try to grey out items in the settings Columns tab that are not selected in the Columns tab
    
       QWidget *newTab = new QWidget;
       //set up a frame so that spinbox and combobox are not stretched fully across the window or too far apart vertically
       QFrame *frame = new QFrame(newTab);
       frame->setAutoFillBackground(true);
       frame->setGeometry(0,0,DIALOGWIDTH/WIDTHSCALINGFACTOR,DIALOGHEIGHT/HEIGHTSCALINGFACTOR);
    
       QVBoxLayout *frameLayout = new QVBoxLayout;
       frameLayout->addWidget(settingsViewSections);
       frame->setLayout(frameLayout);
    
       return newTab;
    }
    
    
    void SettingsDialogClass::setSectionsModel(QSqlRelationalTableModel *model)
    {
       m_modelSections = model;
    }
    
    QSqlRelationalTableModel SettingsDialogClass::getSectionsModel()
    {
       //return m_modelSections;
    }
    
    // Not used
    void SettingsDialogClass::dataChangedSlot(const QModelIndex &topLeft, const QModelIndex &bottomRight)
    {
       QVariant value = m_modelSections->data(topLeft,Qt::DisplayRole);
    
       qDebug() << "Slot is running";
       qDebug() << "Top Left" << topLeft;
       qDebug() << "Top Right" << bottomRight;
       qDebug() << "Value" << value;
    
    
    
    
       m_modelSections->database().transaction();
       if (m_modelSections->submitAll())
       {
           m_modelSections->database().commit();
       }
       else
       {
           m_modelSections->database().rollback();
    
    //        qDebug() << m_modelSections->lastError().text();
    
           QMessageBox msgBox;
           msgBox.setWindowTitle("Database Error");
           msgBox.setIcon(QMessageBox::Warning);
    //        msgBox.setText(tr("The database reported an error: %1")
    //                       .arg(m_modelSections->lastError().text()));
           //msgBox.setInformativeText("More Text...!!");
           msgBox.setStandardButtons(QMessageBox::Ok);
           int reply = msgBox.exec();
    
           if(reply==QMessageBox::Ok)
           {
               return;
           }
           m_modelSections->select();
       }
    }
    
    
    // Pushbuttons slots
    void SettingsDialogClass::on_buttonBox_accepted()
    {
       //Update model for column Tab table
       m_modelColumns->database().transaction();
       if (m_modelColumns->submitAll())
       {
           m_modelColumns->database().commit();
       }
       else
       {
           m_modelColumns->database().rollback();
           QMessageBox msgBox;
           msgBox.setWindowTitle("Database Error");
           msgBox.setIcon(QMessageBox::Warning);
    //        msgBox.setText("Datbase Error: %1").arg(m_model->lastError().text());
           msgBox.setStandardButtons(QMessageBox::Ok);
           msgBox.exec();
       }
    
       //Update model for Sections Tab table
       m_modelSections->database().transaction();
       if (m_modelSections->submitAll())
       {
           m_modelSections->database().commit();
       }
       else
       {
           m_modelSections->database().rollback();
           QMessageBox msgBox;
           msgBox.setWindowTitle("Database Error");
           msgBox.setIcon(QMessageBox::Warning);
    //        msgBox.setText("Datbase Error: %1").arg(m_model->lastError().text());
           msgBox.setStandardButtons(QMessageBox::Ok);
           msgBox.exec();
       }
    }
    
    void SettingsDialogClass::on_buttonBox_rejected()
    {
       m_modelColumns->database().rollback();
       m_modelSections->database().rollback();
    }
    

    ##Custom delegate

    /****************************************************************************
    ** 
    ** 20/11/19
    **
    ** This custom delegate is to restrict the values shown in the settings dialog 'sort by'
    ** column to only allow selected columns to be chosen (Selected in the Columns tab
    **
    ** It reimplements setEditor data to restrict combobox values based on selected columns in columns tab
    **
    ** Dec 19 - Initially just uses a QMessageBox to say that you are trying to sort by unticked
    ** value but this doesn't work because it allows you select an incorrect value and then next time
    ** you try to edit it shows you the message box
    ** ?? - Ideally I want to have unticked values greyed out so they can't be selected
    **
    ****************************************************************************/
    
    
    
    #include <QtWidgets>
    #include <QWidget>
    #include "customdelegatecombobox.h"
    #include "constants.h"
    #include "sqlitedb.h"
    
    CustomDelegateComboBox::CustomDelegateComboBox(QStringList columnsToHide, QWidget *parent)
    {
        m_columnsToHide = columnsToHide;
    }
    
    QWidget *CustomDelegateComboBox::createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const
    {
    //    QComboBox *editor = new QComboBox(parent);
    
        QSqlRelationalDelegate::createEditor(parent,option,index);
    
    //    return editor;
    }
    
    void CustomDelegateComboBox::setEditorData(QWidget *editor, const QModelIndex &index) const
    {
        if (!m_columnsToHide.isEmpty())
        {
            QComboBox *cbox = static_cast<QComboBox *>(editor);
    //        QComboBox *cbox = qobject_cast<QComboBox *>(editor);
    //        cbox->addItem("Test");
    
    
    //        QStandardItemModel* model = qobject_cast<QStandardItemModel*>(cbox->model());
    //        QStandardItem* item= model->item(0); // *****crashes here!!****
    //        item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
    
            //disable unticked columns
            //?????
            // Tried a few things without success - Moving on and I will get some help and come back
    
    //https://stackoverflow.com/questions/11439773/disable-item-in-qt-combobox/21740341
            //QStandardItemModel *model = dynamic_cast<QStandardItemModel *> (cbox->model());
    
    ////https://stackoverflow.com/questions/11439773/disable-item-in-qt-combobox/21740341
    //        QListWidget *contents = new QListWidget(cbox);
    //        contents->hide();
    //        cbox->setModel(contents->model());
    
    //        QStringList list;
    //        list << "SID" << "Song" << "Artist" << "Tuning";
    
    //        for (int i=0;i<m_columnsToHide.size();i++)
    //        {
    //            contents->addItems(list);
    //        }
    
            //const QAbstractItemModel *model = index.model(); //This gives a model woth only 1 row
    
    
    // this crashes on model->rowcount
    //        for (int i=0;i<model->rowCount();i++)
    //        {
    //            QModelIndex indx = model->index(i,0);
    //            QVariant data = model->data(indx,Qt::DisplayRole);
    //        }
    
    
    
    
            //item->setEnabled(false); //DOn't know if this works yet
    
    
    
        }
        else
        {
            QSqlRelationalDelegate::setEditorData(editor, index);
        }
    
    }
    
    void CustomDelegateComboBox::setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const
    {
        int flag=0;
        if (!m_columnsToHide.isEmpty())
        {
            //Model value
            QString value = index.model()->data(index, Qt::EditRole).toString();
            qDebug() << value;
    
            QComboBox *cbox = static_cast<QComboBox *>(editor);
            //Selected value
            value = cbox->currentText();
            qDebug() << value;
    
            for (int i=0;i<m_columnsToHide.size();i++)
            {
                if (value == m_columnsToHide[i])
                {
                    flag = 1;
                    break;
                }
            }
            if (flag==1)
            {
                QMessageBox msgBox;
                QString windowTitle = "Column Error - " + QString("%1").arg(value);
                msgBox.setWindowTitle(windowTitle);
                msgBox.setIcon(QMessageBox::Warning);
                msgBox.setText("Column is not selected in Column tab");
                msgBox.setInformativeText("If you need to sort by this column, tick checkbox in column tab");
                msgBox.setStandardButtons(QMessageBox::Ok);
                int reply = msgBox.exec();
            }
            else
            {
                QSqlRelationalDelegate::setModelData(editor,model,index);
            }
    
    
        }
        else
        {
            QSqlRelationalDelegate::setModelData(editor,model,index);
        }
    }

  • Qt Champions 2019

    @cdontheqt said in How to grey out items in a QTableview delegate editor:

    but the program crashes

    Use a debugger and see where it crashes and fix your code.



  • @cdontheqt said in How to grey out items in a QTableview delegate editor:

    I have used a standard delegate on the tableviews to allow editing.

    I think it's much easier to do with a proxy model instead

    class GreyUncheckedProxy : public QIdentityProxyModel{
        Q_OBJECT
        Q_DISABLE_COPY(GreyUncheckedProxy)
    public:
        using QIdentityProxyModel::QIdentityProxyModel;
        Qt::ItemFlags flags(const QModelIndex &index) const override{
            if(index.data(Qt::CheckStateRole).toInt() == Qt::Unchecked)
                return Qt::NoItemFlags;
            return QIdentityProxyModel::flags(index);
        }
    };
    

Log in to reply