#include "qgui.h" #include #include const int AlignRight = Qt::AlignRight | Qt::AlignVCenter; int operator*(const QString& key, QTreeView &table) { return ((TreeWidget&)table).fdmap.at(key); } int operator*(const char *key, QTreeView &table) { return ((TreeWidget&)table).fdmap.at(key); } TreeWidget::TreeWidget(std::initializer_list colAttrs, QWidget *parent) : QTreeWidget{parent} { header()->setMinimumSectionSize(16); int i = 0; auto item = headerItem(); for(auto attr = colAttrs.begin(); attr < colAttrs.end(); ++attr) { item->setText(i, attr->text); item->setData(i, FieldRole, attr->field); if(attr->width > 0) header()->resizeSection(i, attr->width); if(attr->resizeMode != QHeaderView::Interactive) { if(attr->resizeMode==QHeaderView::Stretch && attr->width > 0) { item->setData(i, WidthRole, attr->width); noStretch = false; } else header()->setSectionResizeMode(i, attr->resizeMode); } fdmap.emplace(attr->field, i++); } hasRowNum = i && colAttrs.begin()->field=="_num_"; connect(header(), &QHeaderView::sectionResized, this, &TreeWidget::onSectionResized); header()->installEventFilter(this); } bool TreeWidget::eventFilter(QObject *watched, QEvent *event) { if(isSectionResized && event->type()==QEvent::Leave && watched==header()) { isSectionResized = false; auto item = headerItem(); for(int cc=0; ccdata(cc, WidthRole).isValid()) item->setData(cc, WidthRole, header()->sectionSize(cc)); } return QTreeWidget::eventFilter(watched, event); } void TreeWidget::resizeEvent(QResizeEvent *event) { QTreeWidget::resizeEvent(event); if(noStretch || event->size().width() == event->oldSize().width()) return; adjSections(-1, 0); } void TreeWidget::drawRow(QPainter *painter, const QStyleOptionViewItem &options, const QModelIndex &index) const { QTreeWidget::drawRow(painter, options, index); if(columnWidth(0)>40) return; if(hasRowNum) { QRect rect(options.rect.left(), options.rect.top(), columnWidth(0), options.rect.height()); painter->fillRect(rect, QColor(128, 128, 128, 32)); painter->drawText(rect, Qt::AlignCenter, QString::number(index.row()+1)); } if(hasGrid) { QBrush color({128, 128, 128, 128}); painter->fillRect(options.rect.left(), options.rect.bottom(), options.rect.width(), 1, color); QRect rec(options.rect.left()-1, options.rect.top(), 1, options.rect.height()); auto end = columnCount() - 1; for(int i=0; ifillRect(rec, color); } } } void TreeWidget::onSectionResized(int logicalIndex, int oldSize, int newSize) { if(blocked || noStretch || newSize==0 || oldSize==0) return; if(! headerItem()->data(logicalIndex, WidthRole).isValid()) return; if(adjSections(logicalIndex, newSize)) isSectionResized = true; } bool TreeWidget::adjSections(int index, int size) { auto item = headerItem(); int remain = header()->width() - size, stretchWidth = 0, width; for(int cc=0; ccdata(cc, WidthRole).toInt()) > 0) stretchWidth += width; else remain -= header()->sectionSize(cc); } if(remain<=0 || stretchWidth==0) return false; auto min = header()->minimumSectionSize(); blocked = true; for(int cc=0; ccdata(cc, WidthRole).toInt()) > 0) header()->resizeSection(cc, qMax(min, width * remain / stretchWidth)); blocked = false; return true; } Table::Table(std::initializer_list colAttrs, int rows, QWidget *parent) : QTableWidget{rows, (int)colAttrs.size(), parent} { int i = 0; for(auto attr = colAttrs.begin(); attr < colAttrs.end(); ++attr) { auto item = horizontalHeaderItem(i); if(item==0) setHorizontalHeaderItem(i, item = new QTableWidgetItem); item->setText(attr->text); item->setData(FieldRole, attr->field); if(attr->width > 0) horizontalHeader()->resizeSection(i, attr->width); if(attr->resizeMode != QHeaderView::Interactive) { if(attr->resizeMode==QHeaderView::Stretch && attr->width > 0) { item->setData(WidthRole, attr->width); noStretch = false; } else horizontalHeader()->setSectionResizeMode(i, attr->resizeMode); } fdmap.emplace(attr->field, i++); } connect(horizontalHeader(), &QHeaderView::sectionResized, this, &Table::onSectionResized); horizontalHeader()->installEventFilter(this); } bool Table::eventFilter(QObject *watched, QEvent *event) { if(isSectionResized && event->type()==QEvent::Leave && watched==horizontalHeader()) { isSectionResized = false; QTableWidgetItem *item; for(int cc=0; ccdata(WidthRole).isValid()) item->setData(WidthRole, horizontalHeader()->sectionSize(cc)); } return QTableWidget::eventFilter(watched, event); } void Table::resizeEvent(QResizeEvent *event) { QTableWidget::resizeEvent(event); if(noStretch || event->size().width() == event->oldSize().width()) return; adjSections(-1, 0); } void Table::onSectionResized(int logicalIndex, int oldSize, int newSize) { if(blocked || noStretch || newSize==0 || oldSize==0) return; if(! horizontalHeaderItem(logicalIndex)->data(WidthRole).isValid()) return; if(adjSections(logicalIndex, newSize)) isSectionResized = true; } bool Table::adjSections(int index, int size) { QTableWidgetItem *item; int remain = horizontalHeader()->width() - size, stretchWidth = 0, width; for(int cc=0; ccdata(WidthRole).toInt()) > 0) stretchWidth += width; else remain -= horizontalHeader()->sectionSize(cc); } if(remain<=0 || stretchWidth==0) return false; auto min = horizontalHeader()->minimumSectionSize(); blocked = true; for(int cc=0; ccdata(WidthRole).toInt()) > 0) horizontalHeader()->resizeSection(cc, qMax(min, width * remain / stretchWidth)); blocked = false; return true; }