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); } }
-
@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); } };