Делегаты для ячеек таблицы
Делегаты -- это специальные классы, которые могут использоваться для управления режимами отображения или редактирования ячеек таблицы QTableView, равно как и элементов других представлений (QListView, QTreeView). В данном разделе мы определим делегатов для редактирования дат и чисел в ячейках таблицы.
В листингах . и . приведён текст программы, а на рис. показан внешний вид окна в момент ввода даты рождения.
Делегаты (файл examples-qt/db03/db03.cpp)
1 // Таблица базы данных: делегаты 2 3 #include <QtGui>
4 #include <QtSql>
5 6 #include "db03.h" 7 8 MyModel::MyModel(QObject *parent) 9 : QSqlQueryModel(parent) { 10 refresh();
11 } 12 13 Qt::ItemFlags MyModel::flags( 14 const QModelIndex &index) const { 15 16 Qt::ItemFlags flags = QSqlQueryModel::flags(index);
17 if (index.column() >
= 1 && index.column() < 4) 18 flags |= Qt::ItemIsEditable; 19 if (index.column() == 4) 20 flags |= Qt::ItemIsUserCheckable; 21 return flags; 22 } 23 24 QVariant MyModel::data( 25 const QModelIndex &index, 26 int role) const { 27 28 QVariant value = QSqlQueryModel::data(index, role);
29 30 switch (role) { 31 32 case Qt::DisplayRole: 33 case Qt::EditRole: 34 if (index.column() == 0) 35 return value.toString().prepend(tr("№"));
36 else if (index.column() == 2 && role == Qt::DisplayRole) 37 return value.toDate().toString("dd.MM.yyyy");
38 else if (index.column() == 3 && role == Qt::DisplayRole) 39 return tr("%1") 40 .arg(value.toDouble(), 0, 'f', 2);
41 else if (index.column() == 4 && role == Qt::DisplayRole) 42 return value.toInt() != 0 ? tr("Да") : tr("Нет");
43 else 44 return value; 45 46 case Qt::TextColorRole: 47 if(index.column() == 1) 48 return qVariantFromValue(QColor(Qt::blue));
49 else 50 return value; 51 52 case Qt::TextAlignmentRole: 53 if(index.column() == 3) 54 return int(Qt::AlignRight | Qt::AlignVCenter);
55 else if(index.column() == 2 index.column() == 4) 56 return int(Qt::AlignHCenter | Qt::AlignVCenter);
57 else 58 return int(Qt::AlignLeft | Qt::AlignVCenter);
59 60 case Qt::FontRole: 61 if(index.column() == 1) { 62 QFont font = QFont("Helvetica", 10, QFont::Bold);
63 return qVariantFromValue(font);
64 }else 65 return value; 66 67 case Qt::BackgroundColorRole: { 68 int a = (index.row() % 2) ? 14 : 0; 69 if(index.column() == 0) 70 return qVariantFromValue(QColor(220,240-a,230-a));
71 else if(index.column() == 4) 72 return qVariantFromValue(QColor(200,220-a,255-a));
73 else 74 return value; 75 } 76 case Qt::CheckStateRole: 77 if (index.column() == 4) 78 return (QSqlQueryModel::data(index).toInt() != 0) ? 79 Qt::Checked : Qt::Unchecked; 80 else 81 return value; 82 83 case Qt::SizeHintRole: 84 if (index.column() == 0) 85 return QSize(70, 10);
86 if (index.column() == 4) 87 return QSize(60, 10);
88 else 89 return QSize(110, 10);
90 } 91 return value; 92 } 93 94 bool MyModel::setData( 95 const QModelIndex &index, 96 const QVariant &value, 97 int /* role */) { 98 if (index.column() < 1 index.column() >
4) 99 return false; 100 101 QModelIndex primaryKeyIndex = QSqlQueryModel::index( 102 index.row(), 0);
103 int id = QSqlQueryModel::data(primaryKeyIndex).toInt();
104 105 //clear();
// Если надо полностью перерисовать таблицу. 106 107 bool ok; 108 QSqlQuery query; 109 if (index.column() == 1) { 110 query.prepare("update employee set name = ? where id = ?");
111 query.addBindValue(value.toString());
112 query.addBindValue(id);
113 }else if(index.column() == 2) { 114 query.prepare("update employee set born = ? where id = ?");
115 query.addBindValue(value.toDate());
116 query.addBindValue(id);
117 }else if(index.column() == 3) { 118 query.prepare("update employee set salary = ? where id = ?");
119 query.addBindValue(value.toDouble());
120 query.addBindValue(id);
121 }else if(index.column() == 4) { 122 query.prepare("update employee set married = ? where id = ?");
123 query.addBindValue(value.toInt());
124 query.addBindValue(id);
125 } 126 ok = query.exec();
127 refresh();
128 return ok; 129 } 130 131 void MyModel::refresh() { 132 setQuery("select * from employee");
133 134 setHeaderData(0, Qt::Horizontal, 135 tr("Табельн.\nномер"));
136 setHeaderData(1, Qt::Horizontal, 137 tr("Имя"));
138 setHeaderData(2, Qt::Horizontal, 139 tr("День рождения"));
140 setHeaderData(3, Qt::Horizontal, 141 tr("Зарплата"));
142 setHeaderData(4, Qt::Horizontal, 143 tr("Женат/\nзамужем"));
144 } 145 146 //------------------------------------ 147 MyView::MyView(QWidget *parent) 148 : QTableView(parent) { 149 150 MyDSBDelegate *dsbd = new MyDSBDelegate( 151 0.0, 999999.99, 0.05, 2, this);
152 setItemDelegateForColumn(3, dsbd);
153 154 MyDEDelegate *ded = new MyDEDelegate( 155 true, this);
156 setItemDelegateForColumn(2, ded);
157 } 158 159 void MyView::resizeEvent(QResizeEvent *event) { 160 resizeRowsToContents();
161 // resizeColumnsToContents();
162 QTableView::resizeEvent(event);
163 } 164 165 //------------------------------------ 166 MyDSBDelegate::MyDSBDelegate( 167 double min, 168 double max, 169 double step, 170 int precision, 171 QObject *parent) 172 : QItemDelegate(parent), 173 m_min(min), 174 m_max(max), 175 m_step(step), 176 m_precision(precision) { 177 } 178 179 QWidget *MyDSBDelegate::createEditor( 180 QWidget *parent, 181 const QStyleOptionViewItem& /* option */, 182 const QModelIndex& /* index */) const { 183 QDoubleSpinBox *editor = new QDoubleSpinBox(parent);
184 editor->
setMinimum(m_min);
185 editor->
setMaximum(m_max);
186 editor->
setDecimals(m_precision);
187 editor->
setSingleStep(m_step);
188 editor->
installEventFilter(const_cast<MyDSBDelegate*>
(this));
189 return editor; 190 } 191 192 void MyDSBDelegate::setEditorData( 193 QWidget *editor, 194 const QModelIndex &index) const { 195 double value = index.model()->
data( 196 index, Qt::EditRole).toDouble();
197 QDoubleSpinBox *dsb = static_cast<QDoubleSpinBox*>
(editor);
198 dsb->
setValue(value);
199 } 200 201 void MyDSBDelegate::setModelData( 202 QWidget *editor, 203 QAbstractItemModel *model, 204 const QModelIndex& index) const { 205 QDoubleSpinBox *dsb = static_cast<QDoubleSpinBox*>
(editor);
206 dsb->
interpretText();
207 double value = dsb->
value();
208 model->
setData(index, value);
209 } 210 211 void MyDSBDelegate::updateEditorGeometry( 212 QWidget *editor, 213 const QStyleOptionViewItem &option, 214 const QModelIndex& /* index */) const { 215 editor->
setGeometry(option.rect);
216 } 217 218 //------------------------------------ 219 MyDEDelegate::MyDEDelegate( 220 bool calpopup, 221 QObject *parent) 222 : QItemDelegate(parent), 223 m_calpopup(calpopup) { 224 } 225 226 QWidget *MyDEDelegate::createEditor( 227 QWidget *parent, 228 const QStyleOptionViewItem& /* option */, 229 const QModelIndex& /* index */) const { 230 QDateEdit *editor = new QDateEdit(parent);
231 editor->
setCalendarPopup(m_calpopup);
232 editor->
installEventFilter(const_cast<MyDEDelegate*>
(this));
233 return editor; 234 } 235 236 void MyDEDelegate::setEditorData( 237 QWidget *editor, 238 const QModelIndex &index) const { 239 QDate value = index.model()->
data( 240 index, Qt::EditRole).toDate();
241 QDateEdit *de = static_cast<QDateEdit*>
(editor);
242 de->
setDate(value);
243 } 244 245 void MyDEDelegate::setModelData( 246 QWidget *editor, 247 QAbstractItemModel *model, 248 const QModelIndex& index) const { 249 QDateEdit *de = static_cast<QDateEdit*>
(editor);
250 de->
interpretText();
251 QDate value = de->
date();
252 model->
setData(index, value);
253 } 254 255 void MyDEDelegate::updateEditorGeometry( 256 QWidget *editor, 257 const QStyleOptionViewItem &option, 258 const QModelIndex& /* index */) const { 259 editor->
setGeometry(option.rect);
260 } 261 262 //------------------------------------ 263 int main(int argc, char *argv[]) { 264 265 QApplication app(argc, argv);
266 267 QTextCodec *codec = QTextCodec::codecForName("CP1251");
268 QTextCodec::setCodecForTr(codec);
269 QTextCodec::setCodecForCStrings(codec);
270 271 QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
272 db.setDatabaseName("mysql_db1");
273 db.setUserName("");
274 db.setPassword("");
275 db.open();
276 277 // QSqlQuery q; 278 // q.exec(QObject::tr("SET NAMES 'cp1251'"));
279 280 MyModel *model = new MyModel();
281 282 MyView *view = new MyView();
283 view->
setModel(model);
284 285 view->
setAlternatingRowColors(true);
286 view->
resizeRowsToContents();
287 view->
resizeColumnsToContents();
288 view->
show();
289 290 return app.exec();
291 }
(1-144) Начало листинга повторяет текст предыдущей программы. (150-151) Создаём экземпляр делегата для редактирования вещественных чисел; первые два параметра конструктора -- разрешённый диапазон, третий параметр -- шаг изменения, четвёртый -- количество знаков после запятой, пятый -- родительский виджет. (152) Связали только что созданный экземпляр делегата с третим (считая с нуля) столбцом таблицы. (154-156) Создали экземпляр делегата для редактирования даты (первый параметр конструктора определяет, будет ли при вводе даты использоваться всплывающее окно календаря) и связали его со вторым столбцом таблицы. (159-163) Реализация метода resizeEvent взята из предыдущей программы. (166-177) Конструктор делегата для редактирования вещественных чисел. Параметры: диапазон, шаг, точность и указатель на родительский виджет. (179-190) () ()
Делегаты (файл examples-qt/db03/db03.h)
1 #include <QtGui>
2 #include <QtSql>
3 4 class MyModel : public QSqlQueryModel { 5 Q_OBJECT 6 public: 7 MyModel(QObject *parent = 0);
8 Qt::ItemFlags flags(const QModelIndex &index) const; 9 QVariant data(const QModelIndex &index, 10 int role = Qt::DisplayRole) const; 11 bool setData(const QModelIndex &index, 12 const QVariant &value, int role);
13 private: 14 void refresh();
15 }; 16 17 //----------------------------------------------- 18 class MyView : public QTableView { 19 Q_OBJECT 20 public: 21 MyView(QWidget *parent = 0);
22 private: 23 virtual void resizeEvent(QResizeEvent *event);
24 }; 25 26 //----------------------------------------------- 27 class MyDSBDelegate : public QItemDelegate { 28 Q_OBJECT 29 public: 30 MyDSBDelegate(double min=0.00, 31 double max=999999999.99, 32 double step=0.1, 33 int precision=2, 34 QObject *parent = 0);
35 QWidget *createEditor( 36 QWidget *parent, 37 const QStyleOptionViewItem &option, 38 const QModelIndex &index) const; 39 void setEditorData(QWidget *editor, 40 const QModelIndex &index) const; 41 void setModelData(QWidget *editor, 42 QAbstractItemModel *model, 43 const QModelIndex &index) const; 44 void updateEditorGeometry( 45 QWidget *editor, 46 const QStyleOptionViewItem &option, 47 const QModelIndex &index) const; 48 private: 49 double m_min; 50 double m_max; 51 double m_step; 52 int m_precision; 53 }; 54 55 //--------------------------------------------- 56 class MyDEDelegate : public QItemDelegate { 57 Q_OBJECT 58 public: 59 MyDEDelegate(bool calpopup = true, 60 QObject *parent = 0);
61 QWidget *createEditor( 62 QWidget *parent, 63 const QStyleOptionViewItem &option, 64 const QModelIndex &index) const; 65 void setEditorData(QWidget *editor, 66 const QModelIndex &index) const; 67 void setModelData(QWidget *editor, 68 QAbstractItemModel *model, 69 const QModelIndex &index) const; 70 void updateEditorGeometry( 71 QWidget *editor, 72 const QStyleOptionViewItem &option, 73 const QModelIndex &index) const; 74 private: 75 bool m_calpopup; 76 };
(4-15) Модель таблицы. (18-24) Представление таблицы. (27-53) Класс-делегат для вещественных чисел (на основе элемента QDoubleSpinBox). (56-76) Класс-делегат для ввода даты (на основе элемента QDateEdit).