2016-08-31 11 views
2

Я разрабатываю графический интерфейс для базы данных SQLite в Qt5. Я использую QSqlQueryModel и QTableView для хранения и отображения данных.Qt5 Подкласс QStyledItemDelegate Форматирование

Затем я создал пользовательский делегат, чтобы заменить числовые значения определенных столбцов на их литералы в представлении таблицы (например, 1 = «Hello», 2 = «World») с помощью оператора switch.

Делегат отображает данные как следует и работает функционально. Тем не менее, столбцы, которые пользовательский делегат рисует, имеют другой формат по сравнению с методом по умолчанию по умолчанию QStyledItemDelegate. Значения находятся вверху слева, а не в центре слева, измененный столбец больше не будет автоматически расширять столбец, чтобы отображать полные значения, а ячейки в столбце не становятся синими или имеют пунктирный контур при выборе.

Я создал этот пример программы:

#include <QApplication> 
#include <QModelIndex> 
#include <QPainter> 
#include <QStandardItemModel> 
#include <QStyledItemDelegate> 
#include <QTableView> 


class TestDelegate: public QStyledItemDelegate { 

    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) 
     const Q_DECL_OVERRIDE 
    { 
     if (index.column() == 0) { 
      int value = index.model()->data(index, Qt::DisplayRole).toInt(); 
      QString str; 
      switch (value) { 
      case 1: 
       str = "Hello0000"; 
       break; 
      case 2: 
       str = "World0000"; 
       break; 
      } 
      if (option.state.testFlag (QStyle::State_Selected)) { 
       painter->fillRect(option.rect, option.palette.highlight()); 
       qApp->style()->drawItemText(painter, option.rect, option.displayAlignment, option.palette, true, str, QPalette::HighlightedText); 
      } else { 
       painter->drawText(option.rect, option.displayAlignment, str); 
      } 
     } else { 
      return QStyledItemDelegate::paint(painter, option, index); 
     } 
    } 

}; 


int main(int argc, char **argv) { 
    QApplication app(argc, argv); 

    QStandardItemModel model(2, 2); 
    model.setHorizontalHeaderItem(0, new QStandardItem(QString("A"))); 
    model.setHorizontalHeaderItem(1, new QStandardItem(QString("B"))); 
    model.setData(model.index(0, 0, QModelIndex()), 1); 
    model.setData(model.index(1, 0, QModelIndex()), 2); 
    model.setItem(0, 1, new QStandardItem(QString("Hello"))); 
    model.setItem(1, 1, new QStandardItem(QString("World0000"))); 

    QTableView view; 
    view.setItemDelegate(new TestDelegate); 
    view.setModel(&model); 
    view.resizeColumnsToContents(); 

    view.show(); 
    app.exec(); 
} 

Это фиксирует выравнивание текста путем добавления options.displayAlignment к painter->drawText(); Я также добавил дополнительный код в операторе if(option.state & QStyle::State_Selected), который рисует ячейку в соответствии с ее состоянием выбора. Поэтому, если он не выбран, текст будет черным, если текст станет белым, а синий фон. Однако я до сих пор не могу получить столбцы для расширения, чтобы они соответствовали содержимому ячеек или добавляли пунктирную линию по внешней стороне ячейки, как это происходит со стандартным делегатом.

Есть ли простой способ сохранить стиль таблицы по умолчанию при использовании моего пользовательского метода рисования?

+0

Можете ли вы предоставить код своего делегата? –

+0

В нем мало кода. Он переопределяет метод рисования для делегатов, внутри тела метода: if (index.column() == 3) {// оператор switch // painter-> drawText (option.rect, literalStr);} else {return QStyledItemDelegate: : paint (painter, option, index) – mrwolf

+0

Если все, что вы хотите сделать, это заменить числовые значения на строковые значения для отображения, считаете ли вы, что хотите оставить делегат по умолчанию и вместо этого прокси-модель прокси? Вы можете подклассифицировать 'QIdentityProxyModel' и переопределить его метод' data() ', который может быть всем, что вам нужно. –

ответ

0

Делегат - довольно обходный и ненужный способ обойти его. У нас уже есть представление, которое красит элементы прекрасно, нет необходимости повторять это. Нам нужно только передать измененные данные в представление. Таким образом, мы вставляем модель вида QIdentityProxyModel между источником и представлением.

// https://github.com/KubaO/stackoverflown/tree/master/questions/proxy-reformat-39244309 
#include <QtWidgets> 

class RewriteProxy : public QIdentityProxyModel { 
    QMap<QVariant, QVariant> m_read, m_write; 
    int m_column; 
public: 
    RewriteProxy(int column, QObject * parent = nullptr) : 
     QIdentityProxyModel{parent}, m_column{column} {} 
    void addReadMapping(const QVariant & from, const QVariant & to) { 
     m_read.insert(from, to); 
     m_write.insert(to, from); 
    } 
    QVariant data(const QModelIndex & index, int role) const override { 
     auto val = QIdentityProxyModel::data(index, role); 
     if (index.column() != m_column) return val; 
     auto it = m_read.find(val); 
     return it != m_read.end() ? it.value() : val; 
    } 
    bool setData(const QModelIndex & index, const QVariant & value, int role) override { 
     auto val = value; 
     if (index.column() == m_column) { 
      auto it = m_write.find(value); 
      if (it != m_write.end()) val = it.value(); 
     } 
     return QIdentityProxyModel::setData(index, val, role); 
    } 
}; 

int main(int argc, char ** argv) { 
    QApplication app{argc, argv}; 
    QStandardItemModel model{2,2}; 
    model.setData(model.index(0, 0), 1); 
    model.setData(model.index(1, 0), 2); 
    model.setData(model.index(0, 1), "Zaphod"); 
    model.setData(model.index(1, 1), "Beeblebrox"); 

    RewriteProxy proxy{0}; 
    proxy.setSourceModel(&model); 
    proxy.addReadMapping(1, "Hello"); 
    proxy.addReadMapping(2, "World"); 

    QTableView ui; 
    ui.setModel(&proxy); 
    ui.show(); 
    return app.exec(); 
} 
+0

Решение не работает с QSqlQueryModel. «нет соответствующей функции для вызова« RewriteProxy :: setSourceModel (QSqlQueryModel **) ». – mrwolf

+0

@ Krippy_MD06 Решение определенно работает с любой моделью. Компилятор сообщает вам, что вы сделали неправильно. Ваша модель не является значением, это указатель, поэтому вам не нужно брать свой адрес с помощью оператора '&'. Не просто слепо копировать код, пытаться понять, что происходит, какие типы задействованы, и как отличается ваш код. –

+0

Я попробовал, чтобы вместо этого он возвращал «no match for» operator <'in' key1 mrwolf