#include "tcdelegate.h" #include #include #include #include #include #include #include #include #include #include QString formatNumber(qreal value, const QString &format, int precision = -1); QString formatValue(const QVariant &value, const QString &format); QString formatNumber(qreal value, const QString &format, int precision) { QString result; int start = 0; QString fmt(format); if (value < 0.00 && !fmt.startsWith("-")) fmt.insert(0, '-'); bool showNegative = fmt.startsWith('-'); if (showNegative) start = 1; for (int i = start; i < fmt.length(); ++i) { QChar c = fmt[i]; switch (c.unicode()) { case '.': case ',': case '#': case '0': case '?': { bool grouping = false; bool gotDot = false; bool gotE = false; bool gotFraction = false; int decimalPlaces = 0; int integerDigits = 0; int optionalDecimalPlaces = 0; int optionalIntegerDigits = 0; int exponentDigits = 0; int numeratorDigits = 0; int denominatorDigits = 0; char ch = fmt[i].toLatin1(); do { if (ch == '.') { gotDot = true; } else if (ch == ',') { grouping = true; } else if (ch == 'E' || ch == 'e') { // SET_TYPE_OR_RETURN(KoGenStyle::NumericScientificStyle); if (i >= fmt.length() - 1) break; const char chN = fmt[i + 1].toLatin1(); if (chN == '-' || chN == '+') { gotE = true; ++i; } } else if (ch == '0' && gotE) { ++exponentDigits; } else if (ch == '0' && !gotDot && !gotFraction) { ++integerDigits; } else if (ch == '#' && !gotDot && !gotFraction) { ++optionalIntegerDigits; } else if (ch == '0' && gotDot && !gotFraction) { ++decimalPlaces; } else if (ch == '#' && gotDot && !gotFraction) { ++optionalDecimalPlaces; } else if (ch == '?' && !gotFraction) { ++numeratorDigits; } else if (ch == '?' && gotFraction) { ++denominatorDigits; } else if (ch == '/') { // SET_TYPE_OR_RETURN(KoGenStyle::NumericFractionStyle); if (gotDot) return QString(); // invalid gotFraction = true; } if (i >= fmt.length() - 1) break; ch = fmt[++i].toLatin1(); if (ch == ' ') { // spaces are not allowed - but there's an exception: if this is a fraction. Let's check for '?' or '/' const char c = fmt[i + 1].toLatin1(); if (c == '?' || c == '/') ch = fmt[++i].toLatin1(); } } while (i < fmt.length() && (ch == '.' || ch == ',' || ch == '#' || ch == '0' || ch == 'E' || ch == 'e' || ch == '?' || ch == '/')); if (!(ch == '.' || ch == ',' || ch == '#' || ch == '0' || ch == 'E' || ch == 'e' || ch == '?' || ch == '/')) { --i; } QString v(QString::number(qAbs(value), 'f', precision >= 0 ? precision : (optionalDecimalPlaces + decimalPlaces))); int p = v.indexOf('.'); QString integerValue = p >= 0 ? v.left(p) : v; if (integerValue.length() < integerDigits) integerValue.prepend(QString().fill('0', integerDigits - integerValue.length())); QString decimalValue = p >= 0 ? v.mid(p + 1) : QString(); if (decimalValue.length() < decimalPlaces) decimalValue.append(QString().fill('0', decimalPlaces - decimalValue.length())); if (grouping && integerValue.size() > 3) { QLocale lc; int y = -1, sz = integerValue.size(); for (int i = sz; i > 0; i--) { y++; if (y == 3) { integerValue.insert(i, lc.groupSeparator()); y = 0; } } } if (showNegative && value < 0) result.append('-'); result.append(integerValue); if (!decimalValue.isEmpty()) result.append('.' + decimalValue); } break; case '\\': { // backslash escapes the next char if (i < fmt.length() - 1) { result.append(fmt[++i]); } } break; default: result.append(c); break; } } return result; } QString formatValue(const QVariant &value, const QString &format) { switch (value.type()) { case QVariant::Bool: break; case QVariant::Int: case QVariant::UInt: case QVariant::LongLong: case QVariant::ULongLong: case QVariant::Double: return formatNumber(value.toDouble(), format); case QVariant::String: return value.toString(); case QVariant::Date: { QDate dt(value.toDate()); return dt.toString(format.isEmpty() ? "yyyy-MM-dd" : format); } case QVariant::Time: { QTime dt(value.toTime()); return dt.toString(format.isEmpty() ? "HH:mm:ss" : format); } case QVariant::DateTime: { QDateTime dt(value.toDateTime()); return dt.toString(format.isEmpty() ? "yyyy-MM-dd HH:mm:ss" : format); } default: return value.toString(); } return ""; } class TCDateTimeDelegatePrivate { public: TCDateTimeDelegatePrivate() {} TCItemDelegate::ItemType type = TCItemDelegate::ItemType::LINEEDIT; QColor textColor = "0"; QString checkText = "true"; QString uncheckText = "false"; QStringList comboboxLists; QStringList comboboxUserDateList; double min = 0; double max = 999; QString format; public: void paintProgress(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintButton(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawCheckBox(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; //日期时间 void drawDateTimeEdit(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; //日期 void drawDateEdit(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; //时间 void drawTimeEdit(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawColor(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawLineEdit(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawCombobox(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; void TCDateTimeDelegatePrivate::paintProgress(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { int value = index.data().toInt(); QStyleOptionProgressBar progressBarOption; progressBarOption.rect = option.rect.adjusted(4, 4, -4, -4); progressBarOption.minimum = 0; progressBarOption.maximum = 100; progressBarOption.textAlignment = Qt::AlignRight; progressBarOption.textVisible = true; progressBarOption.progress = value; progressBarOption.text = QString("%1%").arg(progressBarOption.progress); painter->save(); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); painter->setBrush(option.palette.highlightedText()); } QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); painter->restore(); } void TCDateTimeDelegatePrivate::paintButton(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString value = index.data().toString(); QStyleOptionButton button; button.text = value; button.rect = option.rect.adjusted(4, 4, -4, -4); button.state |= QStyle::State_Enabled; painter->save(); if (option.state & QStyle::State_Selected) painter->fillRect(option.rect, option.palette.highlight()); painter->restore(); QApplication::style()->drawControl(QStyle::CE_PushButton, &button, painter); } void TCDateTimeDelegatePrivate::drawCheckBox(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { bool data = index.data(Qt::DisplayRole).toBool(); QColor bgColorOff, textColorOff; //关闭时背景颜色 QColor bgColorOn, textColorOn; //打开时背景颜色 bgColorOff = QColor(111, 122, 126); bgColorOn = QColor(21, 156, 119); textColorOff = QColor(250, 250, 250); textColorOn = QColor(255, 255, 255); QColor bgColor = data ? bgColorOn : bgColorOff; painter->setBrush(bgColor); QRect rect = option.rect; painter->drawRoundedRect(rect, 0, 0); if (data) { painter->setPen(textColorOn); painter->drawText(rect, Qt::AlignCenter, checkText); } else { painter->setPen(textColorOff); painter->drawText(rect, Qt::AlignCenter, uncheckText); } // QStyleOption styleOption; // styleOption.rect = option.rect; // styleOption.state = data ? QStyle::State_On : QStyle::State_Off; // styleOption.state |= QStyle::State_Enabled; // QCheckBox widget; // QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, // &styleOption, // painter, // &widget); } void TCDateTimeDelegatePrivate::drawDateTimeEdit(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { const QVariant dateTime = index.data(Qt::DisplayRole).toDateTime(); painter->drawText(option.rect, Qt::AlignLeft | Qt::AlignVCenter, formatValue(dateTime, format)); } void TCDateTimeDelegatePrivate::drawDateEdit(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { const QVariant dateTime = index.data(Qt::DisplayRole).toDate(); painter->drawText(option.rect, Qt::AlignLeft | Qt::AlignVCenter, formatValue(dateTime, format)); } void TCDateTimeDelegatePrivate::drawTimeEdit(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { const QVariant time = index.data(Qt::DisplayRole).toTime(); painter->drawText(option.rect, Qt::AlignLeft | Qt::AlignVCenter, formatValue(time, format)); } void TCDateTimeDelegatePrivate::drawColor(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString data = index.data(Qt::DisplayRole).toString(); data = (data == "transparent") ? "black" : data; QColor color(data); if (color.isValid()) { //根据背景色自动计算合适的前景色 double gray = (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255; QColor textColor = gray > 0.5 ? Qt::black : Qt::white; painter->save(); painter->fillRect(option.rect, color); painter->setPen(textColor); painter->drawText(option.rect, Qt::AlignCenter, color.name().toUpper()); painter->restore(); } } void TCDateTimeDelegatePrivate::drawLineEdit(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString data = index.data(Qt::DisplayRole).toString(); int len = data.length(); QString text; for (int i = 0; i < len; i++) { text += "-"; } QRect rect = option.rect; rect.setX(rect.x() + 2); painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, text); } void TCDateTimeDelegatePrivate::drawCombobox(QPainter * /*painter*/, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const { // TODO: 处理翻译 // const QString displayText = index.data(Qt::DisplayRole).toString(); // const QString userText = index.data(Qt::UserRole).toString(); // const QString text = userText.isEmpty() ? displayText : userText; // qDebug() << displayText << userText << text; // painter->fillRect(option.rect, index.data(Qt::BackgroundRole).value()); // painter->drawText(option.rect, Qt::AlignLeft | Qt::AlignVCenter, text); // qApp->translate(text.constData())); // painter->restore(); } TCItemDelegate::TCItemDelegate(QObject *parent) : QStyledItemDelegate(parent) , d(new TCDateTimeDelegatePrivate) { QWidget *w = qobject_cast(parent); if (w) { d->textColor = w->palette().color(QPalette::WindowText).name(); // selectBgColor = w->palette().color(QPalette::Window).name(); } } TCItemDelegate::TCItemDelegate(ItemType type, QObject *parent) : QStyledItemDelegate(parent) , d(new TCDateTimeDelegatePrivate) { d->type = type; QWidget *w = qobject_cast(parent); if (w) { d->textColor = w->palette().color(QPalette::WindowText).name(); // selectBgColor = w->palette().color(QPalette::Window).name(); } } TCItemDelegate::~TCItemDelegate() { delete d; } void TCItemDelegate::setCheckText(const QString &checkText, const QString &uncheckText) { d->checkText = checkText; d->uncheckText = uncheckText; } void TCItemDelegate::addComboxItems(const QStringList &texts, const QStringList &userDate) { d->comboboxLists = texts; if (userDate.isEmpty()) { d->comboboxUserDateList = texts; } else { if (texts.size() != userDate.size()) { qDebug() << "size err "; d->comboboxUserDateList = texts; } else { d->comboboxUserDateList = userDate; } } } void TCItemDelegate::setSpinBoxRange(double min, double max) { d->min = min; d->max = max; } void TCItemDelegate::setFormat(const QString &format) { d->format = format; } QWidget *TCItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const { switch (d->type) { case TCItemDelegate::LINEEDIT: { return new QLineEdit(parent); } case TCItemDelegate::CHECKBOX: { return nullptr; // new QCheckBox(parent); } case TCItemDelegate::INTSPIN: { QSpinBox *editor = new QSpinBox(parent); editor->setMinimum(d->min); editor->setMaximum(d->max); return editor; } case TCItemDelegate::DOUBLESPIN: { QDoubleSpinBox *editor = new QDoubleSpinBox(parent); editor->setMinimum(d->min); editor->setMaximum(d->max); return editor; } case TCItemDelegate::PROGRESS: { QSpinBox *editor = new QSpinBox(parent); return editor; } case TCItemDelegate::BUTTON: { return new QLineEdit(parent); } case TCItemDelegate::COMBOBOX: { QComboBox *combobox = new QComboBox(parent); for (int var = 0; var < d->comboboxLists.size(); ++var) { combobox->addItem(d->comboboxLists[var], d->comboboxUserDateList[var]); } return combobox; } case TCItemDelegate::DATETIME: { QDateTimeEdit *dateTime = new QDateTimeEdit(parent); dateTime->setCalendarPopup(true); dateTime->setDisplayFormat("yyyy-MM-dd HH:mm:ss"); dateTime->calendarWidget()->setLocale(QLocale::Chinese); return dateTime; } case TCItemDelegate::DATE: { QDateEdit *date = new QDateEdit(parent); date->setCalendarPopup(true); date->setDisplayFormat("yyyy-MM-dd"); date->calendarWidget()->setLocale(QLocale::Chinese); return date; } case TCItemDelegate::TIME: { QTimeEdit *time = new QTimeEdit(parent); time->setDisplayFormat("HH:mm:ss"); return time; } default: return nullptr; } } void TCItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QVariant value = index.data(); if (!value.isValid()) { QStyledItemDelegate::setEditorData(editor, index); return; } switch (d->type) { case TCItemDelegate::LINEEDIT: { QLineEdit *pEdit = static_cast(editor); if (pEdit) { pEdit->setText(value.toString()); } } break; // case TCItemDelegate::CHECKBOX: { // QCheckBox *pEdit = static_cast(editor); // if (pEdit) { // pEdit->setChecked(value.toInt() == 1); // } // } break; case TCItemDelegate::INTSPIN: { QSpinBox *pEdit = static_cast(editor); if (pEdit) { pEdit->setValue(value.toInt()); } } break; case TCItemDelegate::DOUBLESPIN: { QDoubleSpinBox *pEdit = static_cast(editor); if (pEdit) { pEdit->setValue(value.toDouble()); } } break; case TCItemDelegate::PROGRESS: { QSpinBox *pEdit = static_cast(editor); if (pEdit) { pEdit->setValue(value.toInt()); } } break; case TCItemDelegate::BUTTON: { QLineEdit *pEdit = static_cast(editor); if (pEdit) { pEdit->setText(value.toString()); } } break; case TCItemDelegate::COMBOBOX: { QComboBox *pEdit = static_cast(editor); if (pEdit) { pEdit->setCurrentText(value.toString()); } } break; case TCItemDelegate::DATETIME: { QDateTime dateTime = index.data().toDateTime(); QDateTimeEdit *pEdit = static_cast(editor); if (pEdit) { pEdit->setDateTime(dateTime); } } break; case TCItemDelegate::DATE: { QDate date = index.data().toDate(); QDateEdit *dateEdit = static_cast(editor); if (dateEdit) { dateEdit->setDate(date); } } break; case TCItemDelegate::TIME: { QTime time = index.data().toTime(); QTimeEdit *timeEdit = static_cast(editor); if (timeEdit) { timeEdit->setTime(time); } } break; default: QStyledItemDelegate::setEditorData(editor, index); } } void TCItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QVariant data = QVariant(); switch (d->type) { case TCItemDelegate::LINEEDIT: { QLineEdit *pEdit = static_cast(editor); if (pEdit) { data = pEdit->text(); } } break; // case TCItemDelegate::CHECKBOX: { // QCheckBox *pEdit = static_cast(editor); // if (pEdit) { // data = pEdit->isChecked() ? 1 : 0; // } // } break; case TCItemDelegate::INTSPIN: { QSpinBox *pEdit = static_cast(editor); if (pEdit) { pEdit->interpretText(); data = pEdit->value(); } } break; case TCItemDelegate::DOUBLESPIN: { QDoubleSpinBox *pEdit = static_cast(editor); if (pEdit) { pEdit->interpretText(); data = pEdit->value(); } } break; case TCItemDelegate::PROGRESS: { QSpinBox *pEdit = static_cast(editor); if (pEdit) { pEdit->interpretText(); data = pEdit->value(); } } break; case TCItemDelegate::BUTTON: { QLineEdit *pEdit = static_cast(editor); if (pEdit) { data = pEdit->text(); } } break; case TCItemDelegate::COMBOBOX: { QComboBox *pEdit = static_cast(editor); if (pEdit) { data = pEdit->currentData(); } } break; case TCItemDelegate::DATETIME: { QDateTimeEdit *dateTime = static_cast(editor); if (dateTime) { data = dateTime->dateTime(); //.toString("yyyy-MM-dd HH:mm:ss"); } } break; case TCItemDelegate::DATE: { QDateEdit *date = static_cast(editor); if (date) { data = date->date(); //.toString("yyyy-MM-dd"); } } break; case TCItemDelegate::TIME: { QTimeEdit *time = static_cast(editor); if (time) { data = time->time(); //.toString("HH:mm:ss"); } } break; default: data = index.data(); } model->setData(index, data); } void TCItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const { editor->setGeometry(option.rect); } bool TCItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if (event->type() == QEvent::MouseButtonRelease) { switch (d->type) { case TCItemDelegate::CHECKBOX: { QVariant value = index.data(); if (value.isValid()) { bool checked = value.toBool(); model->setData(index, !checked, Qt::EditRole); } } break; default: return QStyledItemDelegate::editorEvent(event, model, option, index); } } return QStyledItemDelegate::editorEvent(event, model, option, index); } void TCItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { painter->setPen(d->textColor); switch (d->type) { // case TCItemDelegate::COLOR: // break; // case TCItemDelegate::COMBOBOX: // d->drawCombobox(painter, option, index); // break; case TCItemDelegate::LINEEDIT: d->drawLineEdit(painter, option, index); break; case TCItemDelegate::CHECKBOX: d->drawCheckBox(painter, option, index); // QStyledItemDelegate::paint(painter, option, index); break; case TCItemDelegate::INTSPIN: QStyledItemDelegate::paint(painter, option, index); break; case TCItemDelegate::DOUBLESPIN: QStyledItemDelegate::paint(painter, option, index); break; case TCItemDelegate::PROGRESS: d->paintProgress(painter, option, index); break; case TCItemDelegate::BUTTON: d->paintButton(painter, option, index); break; case TCItemDelegate::DATETIME: d->drawDateTimeEdit(painter, option, index); break; case TCItemDelegate::DATE: d->drawDateEdit(painter, option, index); break; case TCItemDelegate::TIME: d->drawTimeEdit(painter, option, index); break; default: { QStyledItemDelegate::paint(painter, option, index); break; } } }