#ifndef PICTEXTITEM_H #define PICTEXTITEM_H #include #include #include #include #include #include class QFocusEvent; class QGraphicsItem; class QGraphicsScene; class QGraphicsSceneMouseEvent; enum ItemDirectionType { NORMAL, MIRROR_V, MIRROR_H, MIRROR_VH, MIRROR_H_R270, R90, R270, MIRROR_V_R270, }; /** * @brief 元素类型 * @remark * 使用 @see PicTextItem::type() 获取元素类型 * 使用 @see PicTextItem::setSource 和 @see PicTextItem::source 读写item的来源 * 不同类型的元素,来源也不同 */ enum SourceType{ UNKNOWN, // 未知, 目前未知类仅剩计数器类型 TEXT, // 文字类型,source: QString 文本字符串 IMAGE, // 图片类型, source: QString 图片位于本地的绝对路径 DATETIME, // 日期类型 SCHEDULE_SHIFT, CODE, // 条形码和二维码 COUNTER, }; class PicTextItem; /** * @brief 图元通用属性的ViewModel * * 目的:解耦UI编辑器与PicTextItem,支持灵活的数据绑定和批量操作。 * UI修改属性时先更新VM,再决定何时应用到item(实时或延迟)。 */ struct TextItemModel { // 图元类型,用于判断是否显示字间距 SourceType sourceType = SourceType::UNKNOWN; ItemDirectionType direction = NORMAL; int boldMultiple = 1; int letterSpace = 0; bool colorReversal = false; QString fontFamily = "WenQuanYi7"; int fontSize = 9; std::function imageGenerator; // 图片生成函数 // 便利方法:从PicTextItem快照创建VM static TextItemModel fromItem(PicTextItem *item); // 检查是否有改动 bool hasDifference(const TextItemModel &other) const { return sourceType != other.sourceType || direction != other.direction || boldMultiple != other.boldMultiple || letterSpace != other.letterSpace || colorReversal != other.colorReversal; } static QString toString(const TextItemModel& model); }; class PicTextItem : public QGraphicsTextItem { Q_OBJECT public: enum { Type = UserType + 3 }; explicit PicTextItem(QGraphicsItem *parent = 0, QGraphicsScene *scene = 0, const SourceType type = SourceType::UNKNOWN); virtual ~PicTextItem(); // 重写 QGraphicsTextItem 的 type 方法,用于 Qt graphics 系统标识区别于内置 Item 类型 int type() const { return Type; } SourceType sourceType() const { return m_sourceType; } // 粗体,即水平拉伸倍率, 1倍率为保持原样 int boldMultiple() { return m_boldMultiple; } int setBoldMultiple(int multiple); // 图元方向 ItemDirectionType direction() { return m_direction; } void setDirection(ItemDirectionType dir); // 颜色翻转 bool colorReversal() { return m_colorReversal; } void setColorReversal(bool b); // 设置字体使用该方法而不是 QGraphicsItem::setFont void setCustomFont(QString name); // 文字列间距 int letterSpace(); void setLetterSpace(int space); /** * @brief 重写 QGraphicsTextItem 的 paint 方法,用于自定义绘制文字 */ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; /** * @brief 重写 QGraphicsTextItem 的 boundingRect 方法,用于自定义计算文字的边界矩形 */ virtual QRectF boundingRect() const override; /** * @brief 重写 QGraphicsTextItem 的 shape 方法,用于自定义计算文字的路径 */ QPainterPath shape() const override; /** * @brief setAttrs 将从xml工程文件中读取到的图元属性集应用到图元 * @param attrs * @remark * 该方法在 @see TestPrintWidget 从xml文件中载入场景文件时被调用,用于恢复图元状态 * setAttrs 从属性集中读取 direction, boldMultiple, colorReversal, letterSpace, fontSize 并应用这些属性 * setAttrs 在最后会调用 @see setCustomAttrs , 子类可以实现该方法继续读取自定义的属性 */ void setAttrs(const QXmlStreamAttributes& attrs); /** * @brief saveAttrs @see setAttrs 的反向操作,用于将图元的属性集保存到xml文件,@see TestPrintWidget 在保存场景文件时会调用此方法 * @param attrs 图元将属性集保存到 attrs */ void saveAttrs(QXmlStreamAttributes& attrs); /** * @brief applyModify 应用 方向、水平拉伸、属性更改 */ void applyModify(); /** * @brief preview 获取图元当前的预览 * @return */ QImage preview(); void setTextItemModel(const TextItemModel& model); TextItemModel textItemModel(); QPointF clampItemPos(const QPointF& p); QString text() { return m_source.toString(); } void setText(const QString& txt); signals: void lostFocus(PicTextItem *item); void selectedChange(QGraphicsItem *item); void itemEdit(QString); protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value); void focusOutEvent(QFocusEvent *event); void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent * event); void keyPressEvent(QKeyEvent *event); /** * @brief emptyImage 返回一张10x10的空图片 * @return * @remark 用于子类在 source 为空时返回一张空图片,避免渲染错误 */ QImage emptyImage(); /** * @brief itemImage 子类可以重新实现该方法用于返回已经渲染好了的但未应用方向、水平拉伸的图像 * @return * @remark * 对图元进行方向、水平拉伸的步骤由 @see applyImgeTranslation 实现,因此子类不需要 */ virtual QImage itemImage(); virtual void setCustomAttrs(const QXmlStreamAttributes& attrs); virtual void saveCustomAttrs(QXmlStreamAttributes& attrs); /** * @brief colorReversalChanged 颜色翻转通知, 子类重写该方法用于响应属性变更 */ virtual void colorReversalChanged(); /** * @brief letterSpaceChanged 字间距更改通知, 子类重写该方法用于响应属性变更 */ virtual void letterSpaceChanged(); /** * @brief strToImage 将字符串渲染至图片 * @param str 要转换的字符串 * @return 渲染文字后的图片已经被裁剪至最小 boudningRect * @remark * 方向将应用 PicTextItem 的字体和颜色翻转进行渲染 */ QImage strToImage(const QString& str); public slots: private: QImage applyImgeTranslation(QImage img); public: const SourceType m_sourceType; QVariant m_source; bool SpecialConditions; int CatchCnt1StartValue; int CatchCnt1CurrValue; int m_boldMultiple = 1; ItemDirectionType m_direction = NORMAL; bool m_colorReversal = false; QImage m_itemImage; QImage m_untransImage; }; #endif // PICTEXTITEM_H