Russian Qt Forum
Декабрь 10, 2022, 10:53 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QTableView: текст ячейки с делегатом  (Прочитано 537 раз)
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 822


Мы должны приносить пользу людям.


Просмотр профиля
« : Май 26, 2022, 16:24 »

Коллеги,
столкнулся с неожиданной проблемой, когда потребовалось получить текстовое значение ячеек QTableView, в которых используются делегаты. Это мне потребовалось, чтобы организовать поиск в таблице. Понятно, что использовать модель, прицепленную к таблице, нельзя потому, что в ней содержится не то, что отображается в таблице.
Я не нашел внятного решения, поэтому, думаю, кому-нибудь это может показаться полезным. Не привожу полного "компилябельного" примера, но идея должна быть понятна.

Она проста - в самом делегате нужно предусмотреть открытый метод getItemText(const QModelIndex &index), который используется как для отрисовки делегата в таблице, так и при получении содержимого ячейки QTableView. Опуская детали, на примере делегата с использованием QComboBox:

Код
C++ (Qt)
class ComboItem;
 
class CComboDelegate : public QStyledItemDelegate
{
   Q_OBJECT
private:
   QList<ComboItem> items;
//
public:
//
   QString getItemText(const QModelIndex &index) const;
 
   // QAbstractItemDelegate interface
public:
   QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
   void setEditorData(QWidget *editor, const QModelIndex &index) const override;
   void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
   void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
   void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
 
class ComboItem {
public:
   QString item;
   QVariant data;
 
   ComboItem() = default;
   ComboItem(QString text, QVariant value) {
       item = text;
       data = value;
   }
   bool operator == (const ComboItem& other) const {
       return other.data == data;
   }
};

Класс ComboItem содержит отображаемый текст и данные модели:

Код
C++ (Qt)
QWidget *CComboDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
   QComboBox* combo = new QComboBox(parent);
   combo->setEditable(false);
   combo->setAutoFillBackground(true);
 
   foreach (auto i, items) {
       combo->addItem(i.item, i.data);
   }
 
   return combo;
}
 
QString CComboDelegate::getItemText(const QModelIndex &index) const
{
   int i = items.indexOf(ComboItem("",index.data()));
   return (i>=0)? items[i].item : index.data().toString();
}
 
void CComboDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
   Qt::ItemFlags flag = index.model()->flags(index);
 
   painter->save();
 
   if (option.state & QStyle::State_HasFocus || (option.state & QStyle::State_Selected && option.state & QStyle::State_Active)) {
       painter->fillRect(option.rect, option.palette.highlight());
       painter->setPen(option.palette.highlightedText().color());
   } else if (option.state & QStyle::State_Selected) {
       painter->fillRect(option.rect, option.palette.color(QPalette::Inactive, QPalette::Highlight));
   } else if((flag & Qt::ItemIsEditable) == false) {
       painter->fillRect(option.rect, QBrush(QColor(255, 245, 238)));
   }
 
   QRect rect = option.rect;
   rect.setX(rect.x()+3);
   painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, getItemText(index));
 
   painter->restore();
}
 
Из всего того, что я привел выше, существенно только то, что то, что делается в getItemText, все равно используется в CComboDelegate::paint, я его только выполнил в виде метода и сделал открытым. Кстати, попутно тут я привел код отрисовки делегата для разных случаев (фокуса, выбранного, неактивного, только для чтения) - тоже может быть полезным.
Далее, как это используется при поиске по столбцу таблицы:

Код
C++ (Qt)
void MainWindow::finderSlot(const QString &text)
{
   if(!text.size())
       return;
 
   bool find = false;
   QModelIndex index = tableViewData->currentIndex();
   if(index.isValid()) {
 
       QAbstractItemDelegate* delegate = tableViewData->itemDelegateForColumn(index.column());
       CComboDelegate* comboDelegate = qobject_cast<CComboDelegate*>(delegate);
 
       QAbstractItemModel* model = tableViewData->model();
       for(int i=0; i<model->rowCount(); i++) {
           index = index.siblingAtRow(i);
           QString value = (comboDelegate)? comboDelegate->getItemText(index) : model->data(index).toString();
           if(value.startsWith(text, Qt::CaseInsensitive)) {
               tableViewData->setCurrentIndex(index);
               find = true;
               break;
           }
       }
   } else {
       QMessageBox (QMessageBox::Warning, "Search", "The search field is not selected", QMessageBox::Ok).exec();
       lineEditFind->clear();
   }
 
   if(!find)
       QApplication::beep();
}

Если текст найден, то курсор перемещается на соответствующую ячейку.
« Последнее редактирование: Май 26, 2022, 16:33 от sergek » Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.114 секунд. Запросов: 22.