嗯,第一次,稍微有点紧张,写的不好希望大佬不要批评我,会伤心的
相信上标这个简单而不简单的问题一定难道了不少像我一样想用简单方式,尝试通过Word、WPS里面的字符进行实现的傻缺。
话不多说,我们进入正题。
QTableView和QTableWidget方法一样,所以我只讲QTableWidget
说道QTableWidget我们肯定需要一个QTableWidget来做这个东西先随便建一个QTableWidget
然后进入正题,对于QTableWidget\QTableView我们需要用到QItemDelegate代理来进行绘制,这样可以节省很多时间,但是由于QTableView和QTableWiget的表头是独立的QHeadView而且代理设置是不生效的可以查阅QT表中的说明可知As a result, calling a header's setItemDelegate() function will have no effect.因此我们QHeadView只能从他本身的绘制事件入手
然后贴上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #ifndef TOPRICH_H #define TOPRICH_H #include <QTableView> #include <QHeaderView> #include <QCheckBox> #include <QItemDelegate> #include <QTableWidgetItem> class RichEditDelegate: public QItemDelegate { Q_OBJECT public : RichEditDelegate(QObject*parent=nullptr) :QItemDelegate(parent){ } void paint(QPainter*painter, const QStyleOptionViewItem&option, const QModelIndex&index) const; private : }; class HeaderView : public QHeaderView { Q_OBJECT public: HeaderView(Qt::Orientation orientation, QWidget *parent = Q_NULLPTR) :QHeaderView(orientation, parent){ } HeaderView(QHeaderView tb) :QHeaderView(tb.orientation()){ } void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const; }; #endif // TOPRICH_H |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | #include "TopRich.h" #include <QDebug> #include <QTextDocument> #include <QtWidgets/QApplication> #include <QStylePainter> #include <QAbstractTextDocumentLayout> #include <QStyleOptionViewItem> #include <QPainter> void RichEditDelegate::paint(QPainter*painter, const QStyleOptionViewItem&option, const QModelIndex&index) const { QStyleOptionViewItem viewOption(option); if (option.state.testFlag(QStyle::State_HasFocus)) viewOption.state = viewOption.state ^ QStyle::State_HasFocus; QStyle *pStyle = viewOption.widget? viewOption.widget->style() : QApplication::style(); QString strHTML = QString(""); strHTML = index.model()->data(index, Qt::DisplayRole).toString(); QRect textRect = pStyle->subElementRect(QStyle::SE_ItemViewItemText, &viewOption); QFont fontDefault; int fwidth = QFontMetrics(fontDefault).width(strHTML); if(fwidth>textRect.width()) {//此处是为了进行换行 QString str; for(QString::iterator iter = strHTML.begin(); iter!=strHTML.end(); ++iter) { str += *iter; fwidth = QFontMetrics(fontDefault).width(str); if(fwidth>textRect.width()-8) { if(str.indexOf("\n") == -1){ if((*iter) != '-' && *(++iter) != 's'){ str += '\n'; --iter; } else{ str += *iter; str += '\n'; } } for(++iter;iter!=strHTML.end();++iter) str += *iter; break; } } strHTML = str; } strHTML.replace("/s", "<sup>-s</sup>"); strHTML.replace("\n","<br>"); QTextDocument doc; doc.setHtml(strHTML); QAbstractTextDocumentLayout::PaintContext paintContext; if((option.state & QStyle::State_Selected) == QStyle::State_Selected){ drawBackground(painter, viewOption, index); } painter->save(); // 坐标变换,将左上角设置为原点 painter->translate(textRect.topLeft()); // 设置HTML绘制区域 painter->setClipRect(textRect.translated(-textRect.topLeft())); doc.documentLayout()->draw(painter, paintContext); painter->restore(); } //---------------------------------------------------------------------------------------------------------------------------- void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const { QAbstractItemModel * mo = model(); QVariant hData = mo->headerData(logicalIndex, Qt::Horizontal); QString hDataStr = hData.toString(); if(hDataStr.contains("<sup>") || hDataStr.contains("/s")){ //设置显示文本为空,使用默认样式 QStyleOptionHeader viewOption; initStyleOption(&viewOption); QStyle * pStyle = style(); viewOption.rect = rect; viewOption.text = ""; pStyle->drawControl(QStyle::CE_Header, &viewOption, painter); //需要显示的HTML QString strHTML = QString(hDataStr); QRect textRect = pStyle->subElementRect(QStyle::SE_HeaderLabel, &viewOption); QPoint textPoint= textRect.topLeft(); textPoint.setX(textPoint.x()); strHTML.replace("/s","<sup>-s</sup>"); strHTML.replace("\n","<br>"); //qDebug() << "HeaderView::paintSection -- fwidth:" << strHTML; QTextDocument doc; doc.setHtml(strHTML); QAbstractTextDocumentLayout::PaintContext paintContext; painter->save(); //坐标变换,将左上角设置为原点 painter->translate(textPoint); //设置HTML绘制区域 painter->setClipRect(textRect.translated(-textPoint)); doc.documentLayout()->draw(painter, paintContext); painter->restore(); } else { painter->save(); QHeaderView::paintSection(painter, rect, logicalIndex); painter->restore(); } updatesEnabled(); } |
最后简单的调用设置
1 2 | ui->tableWidget->setItemDelegateForRow(0,new RichEditDelegate); ui->tableWidget->setHorizontalHeader(new HeaderView(ui->tableWidget->horizontalHeader()->orientation())); |
见证奇迹的时候到了
整个解决方法中核心的地方就在于QT支持两种文本一个是PlainText一个是RichText,而RichText可以支持Html格式字符,所以我们在重载的时候就需要按照Html的格式进行修改,另一个就是需要了解Qt控件的绘图机制,QStyle的原理。了解以上之后,QMenu设置上标的方法就很简单了。附上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | void TopStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { if(element == QStyle::CE_MenuItem){ if(const QStyleOptionMenuItem * btn = qstyleoption_cast<const QStyleOptionMenuItem *>(option)){ QStyleOptionMenuItem suopt = *btn; QString strHTML = suopt.text; suopt.text = ""; QProxyStyle::drawControl(element, &suopt, painter, widget); strHTML.replace("/s", "<sup>-s</sup>"); QTextDocument doc; doc.setHtml(strHTML); QAbstractTextDocumentLayout::PaintContext paintContext; painter->save(); //坐标转换 QPoint textPoint = suopt.rect.topLeft(); textPoint.setX(textPoint.x()+30); painter->translate(textPoint); painter->setClipRect(suopt.rect.translated(-textPoint)); doc.documentLayout()->draw(painter, paintContext); painter->restore(); } } else return QProxyStyle::drawControl(element, option, painter, widget); } |
重载QProxyStyle然后设置QMenu的style就行了。
感谢浏览,写的不好,希望不要计较,共同进步!