Замечания по стандартной реализации представления QTableView и модели QSqlRelationalTableModel.
Поработаем отладчиком , сделаем заходы в функции и посмотрим , что там делается ( такое становится возможно только при сборке qt из исходников ).Настраиваем статику и динамику
QTableView
Теперь пора разобраться как QTableView отрисовывает ячейки таблицы. Для этого как обычно унаследуемся от QTableView и начнем переопределять виртуальные функции и потом отладчиком можно будет заглянуть что там внутри творится.
А творится там много чего и это не для слабонервных...
Сначала возникает какое либо событие от мышки ,клавиатуры и т.д. Значит надо искать входы этих событий в QTableView.
Но начинать надо с начала (не правда ли?..). А что есть начало?...
Допустим открыли мы QTableView , можно переопределить event() и посмотреть какие события приходят в QTableView (от ОС).
17:06:00 Debug: my_QTableView::event "ChildPolished"
17:06:00 Debug: my_QTableView::event "ChildPolished"
17:06:00 Debug: my_QTableView::event "ChildPolished"
17:06:00 Debug: my_QTableView::event "ChildAdded"
17:06:00 Debug: my_QTableView::event "Polish"
17:06:00 Debug: my_QTableView::event "DynamicPropertyChange"
17:06:00 Debug: my_QTableView::event "FontChange"
17:06:00 Debug: my_QTableView::event "ChildPolished"
17:06:00 Debug: my_QTableView::event "ChildPolished"
17:06:00 Debug: my_QTableView::event "ChildPolished"
17:06:00 Debug: my_QTableView::event "Move"
17:06:00 Debug: my_QTableView::event "Resize"
17:06:00 Debug: my_QTableView::event "Show"
17:06:00 Debug: my_QTableView::event "ShowToParent"
17:06:00 Debug: my_QTableView::event "WindowActivate"
17:06:00 Debug: my_QTableView::event "PolishRequest"
17:06:00 Debug: my_QTableView::event "MetaCall"
17:06:00 Debug: my_QTableView::event "MetaCall"
17:06:00 Debug: my_QTableView::event "Timer"
17:06:00 Debug: my_QTableView::event "MetaCall"
17:06:00 Debug: my_QTableView::event "MetaCall"
17:06:00 Debug: my_QTableView::event "LayoutRequest"
17:06:00 Debug: my_QTableView::event "Paint"
17:06:00 Debug: my_QTableView::event "Timer"
17:06:01 Debug: my_QTableView::event "WindowDeactivate"
17:06:01 Debug: my_QTableView::event "Paint"
17:06:01 Debug: my_QTableView::event "Paint"
Далее как происходит интерактивное взаимодейтсвие? Щелкаем мышкой (левой кнопкой) на числовом поле, вбиваем цифру и нажимаем Enter, происходит выход из режима редактирования:
При перемещении мыши над QTableView будут возникать события Enter. Но сам обработчик Enter ничего не делает , только зачем-то посылает событие QStatusTipEvent в случае :
case QEvent::Enter:
#ifndef QT_NO_STATUSTIP
if (d->statusTip.size()) {
QStatusTipEvent tip(d->statusTip);
QApplication::sendEvent(const_cast(this), &tip);
}
#endif
enterEvent(event);
break;
Далее прилетает FocusIn и попадаем мы после этого в обработчик:
bool QAbstractItemView::event(QEvent *event)
он проверяем свои типы событий и перекидывает в
bool QAbstractScrollArea::event(QEvent *e)
тут вроде проверяются свои типы событий и перекидывают дальше в :
bool QFrame::event(QEvent *e)
Далее в
bool QWidget::event(QEvent *event)
и наконец заходим в :
focusInEvent((QFocusEvent*)event);
но это уже почему-то в :
void QAbstractItemView::focusInEvent(QFocusEvent *event)
void QAbstractItemView::focusInEvent(QFocusEvent *event)
{
Q_D(QAbstractItemView);
QAbstractScrollArea::focusInEvent(event);
const QItemSelectionModel* model = selectionModel();
const bool currentIndexValid = currentIndex().isValid();
if (model
&& !d->currentIndexSet
&& !currentIndexValid) {
bool autoScroll = d->autoScroll;
d->autoScroll = false;
QModelIndex index = moveCursor(MoveNext, Qt::NoModifier); // first visible index
if (index.isValid() && d->isIndexEnabled(index) && event->reason() != Qt::MouseFocusReason)
selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
d->autoScroll = autoScroll;
}
if (model && currentIndexValid) {
if (currentIndex().flags() != Qt::ItemIsEditable)
setAttribute(Qt::WA_InputMethodEnabled, false);
else
setAttribute(Qt::WA_InputMethodEnabled);
}
if (!currentIndexValid)
setAttribute(Qt::WA_InputMethodEnabled, false);
d->viewport->update();
}
QModelIndex index = moveCursor(MoveNext, Qt::NoModifier) - тут определяется текущий индекс.
Далее проверяется его Qt::ItemIsEditable и как результат - для виджета устанавливаем аттрибут Qt::WA_InputMethodEnabled:
setAttribute(Qt::WA_InputMethodEnabled, true);
QApplicationPrivate::setFocusWidget
void QWidget::setFocus(Qt::FocusReason reason)
bool QApplication::notify(QObject *receiver, QEvent *e)
res = d->notify_helper(w, w == receiver ? mouse : &me);
bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
// send to all receiver event filters
if (sendThroughObjectEventFilters(receiver, e)) !!!! вот здесь срабатывает indexAt
return true;
bool QAbstractItemView::viewportEvent(QEvent *event)
bool QAbstractScrollArea::viewportEvent(QEvent *e)
void QAbstractItemView::mousePressEvent(QMouseEvent *event)
....
QPersistentModelIndex index = indexAt(pos);
...
if (edit(index, NoEditTriggers, event))
return;
...
bool QAbstractItemView::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
} else {
w->setAttribute(Qt::WA_NoMouseReplay, false);
res = d->notify_helper(w, w == receiver ? mouse : &me);
e->spont = false;
}
KeyRelease
KeyPress
Изучаем QTableView::paintEvent(e) .
Сразу при открытие окна с QTableView начинается прорисовка всех ячеек таблицы. И это логично ведь само ничего не прорисуется.
После подготовительных операций вызывается drawCell для каждой видимой ячейки:
d->drawCell(&painter, option, index);
Это хорошо видно по index .
Далее после запроса флага Qt::ItemIsEnabled у модели данных выбирается соответсвующий вариант палитры. Также проверяется ниличие выделения по State_Selected. Проверяется QStyle::State_MouseOver над ячейкой. QStyle::State_HasFocus.
Отрисовка происходит по drawPrimitive. Тут указывается PrimitiveElement = PE_PanelItemViewRow.
q->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, q);
q->itemDelegate(index)->paint(painter, opt, index);
Внутри itemDelegate всегда происходит отрисовка :
style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
CE_ItemViewItem это тип элемента управления (enum ControlElement из QStyle).
Кстати очень подробно освещается тема управления событиями на странице QTableView новые возможности.