当前位置: 首页 > news >正文

保存 QTextEdit 内容打包成一个文件(包含文本和图片)

例子:

所有文档包含图版打包成一个文档

函数:f_packageToByteArray

/// <summary>
/// 保存 QTextEdit 内容到 QByteArray(包含文本和图片)
/// </summary>
/// <returns></returns>
/// 创建时间:2025-03-14    最后一次修改时间:2025-03-14  (摘录自 DeepSeek)
QByteArray my_QTextEdit::f_packageToByteArray()
{QTextDocument* doc = this->document();QString html = doc->toHtml(); // 获取 HTML 内容// 收集文档中的所有图片资源(URL -> 图片数据)QMap<QUrl, QByteArray> imageResources;QTextFrame::iterator rootIter = doc->rootFrame()->begin();while (!rootIter.atEnd()) {QTextBlock block = rootIter.currentBlock();if (block.isValid()) {QTextBlock::iterator blockIter = block.begin();while (!blockIter.atEnd()) {QTextFragment fragment = blockIter.fragment();if (fragment.isValid() && fragment.charFormat().isImageFormat()) {QTextImageFormat imageFormat = fragment.charFormat().toImageFormat();QUrl imageUrl(imageFormat.name()); // 图片资源 URLQVariant imageData = doc->resource(QTextDocument::ImageResource, imageUrl);if (imageData.isValid() && imageData.canConvert<QImage>()) {QImage image = imageData.value<QImage>();QByteArray byteArray;QBuffer buffer(&byteArray);buffer.open(QIODevice::WriteOnly);image.save(&buffer, "PNG"); // 保存为 PNG 格式的二进制数据imageResources.insert(imageUrl, byteArray);}}++blockIter;}}++rootIter;}// 将 HTML 和图片资源序列化到 QByteArrayQByteArray data;QDataStream stream(&data, QIODevice::WriteOnly);stream << html; // 写入 HTML 文本stream << imageResources; // 写入图片资源(QMap<QUrl, QByteArray>)return data;
}

函数:f_splitFromByteArray

/// <summary>
/// // 从 QByteArray 加载内容到 QTextEdit
/// </summary>
/// <param name="data"></param>
/// 创建时间:2025-03-14    最后一次修改时间:2025-03-14  (摘录自 DeepSeek)
void my_QTextEdit::f_splitFromByteArray(const QByteArray& data)
{   this->clear();QTextDocument* doc = new QTextDocument(this);   QDataStream stream(data);QString html;QMap<QUrl, QByteArray> imageResources;// 反序列化 HTML 和图片资源stream >> html >> imageResources;// 将图片资源重新绑定到文档for (auto it = imageResources.begin(); it != imageResources.end(); ++it) {QUrl url = it.key();QByteArray imageData = it.value();QImage image;image.loadFromData(imageData, "PNG"); // 从二进制数据加载图片doc->addResource(QTextDocument::ImageResource, url, image);}// 设置 HTML 内容并更新 QTextEditdoc->setHtml(html);setDocument(doc);     //创建QTextEdi时初始化无效,要重新设置,重新初始化字体。this->initTextEdit();/*----------------------------------------------------------------------* 问题:切换文档时导致下方空白,大部分文字是空白的。为什么这两行代码能解决问题?setValue(0)强制滚动到顶部,避免残留的旧滚动位置导致显示错位。如果不重置,新文档可能继承旧文档的滚动位置,但新文档高度较小,导致下方空白。setRange(0, doc->size().height())显式设置滚动条的最大范围为文档的实际高度。默认情况下,Qt 可能在文档切换后未及时更新滚动范围,导致滚动条无法到达底部。------------------------------------------------------------------------*/// 强制更新布局和视图//doc->adjustSize();                      // 调整文档尺寸//viewport()->update();                      // 立即重绘视图//ensureCursorVisible();                     // 确保光标可见(触发滚动区域更新)// 如果是多页文档,可能需要重置滚动条verticalScrollBar()->setValue(0);          // 滚动到顶部verticalScrollBar()->setRange(0, doc->size().height()); // 重置滚动范围}

类my_QTextEdit

my_QTextEdit.h

/**********************************************************************************************
文件名					: my_QTextEdit.h  编码格式(Unicode(UTF-8带签名)-代码页65001)功能						:编辑器控件目的						: 熟悉QTextEdit(希望深入学习编辑器开发的底层技术,同时计划自己开发编译器)作者						: 李锋联系电话					: 13828778863创建时间					: 2025年02月17日最后一次修改时间		    :  2025年03月03日**********************************************************************************************/#pragma once#ifdef _QT_
_QT_#include "_p.h"
#include "_headlineStyle.h"
#include "_textAnalysis.h"#include<qtextedit>
#include<qthread>
#include<qmutex>
#include<qlabel>
#include<QNetworkAccessManager>_LF_BEGIN_
lf
//前置声明
class my_QTextEdit;enum class _LanguageType;/// <summary>
/// 编辑类型
/// </summary>
enum class _EditorType
{ttCode,ttBook,ttText,
};class my_QTextEdit : public QTextEdit
{Q_OBJECTprivate:QMenu* m_setStyle = null;QMenu* m_getStyle = null;   QAction* m_cutAction = null;QAction* m_copyAction = null;QAction* m_deepSeekAction = null;QAction* m_baiduAction = null;QAction* m_aiAction = null;QNetworkAccessManager* m_networkManager;_TextAnalysis m_analysis;/// <summary>/// 公文格式模板/// </summary>static _HeadlineStyle m_headlineStyle;static int m_count;_EditorType EditorType;/// <summary>/// 按Tab时的空格个数/// </summary>const size_t m_tabStopCount = 4;_TextAnalysis m_textAnalysis;/// <summary>/// QElapsedTimer 必须显式调用 start() 后才能正确使用 elapsed() 或 restart() 获取时间间隔。/// 如果不调用 start(),返回的时间值是 未定义的(可能为负数或随机值)。/// </summary>QElapsedTimer m_timer;qint64 m_lastFetchTime = 0;
public:void lock(const bool& bLock);QMenu* m_rightMenu = null;QMenu* m_insertMenu = null;QMenu* m_textCommonSymbols = null;/// <summary>/// 行号/// </summary>int m_currentLineCount;/// <summary>/// 列号/// </summary>int m_currentColumn;QLabel* m_statusLable1 = null;QLabel* m_statusLabel2 = null;/// <summary>/// 当前行文本/// </summary>_string m_currentLineText;/// <summary>/// 当前行和列信息/// </summary>_string m_currentLineColumnInfo;/// <summary>/// 是否按下键盘的 Ctrl 键/// </summary>bool m_isControlKey = false;/// <summary>/// 特殊符号/// </summary>const _string m_specificSymbol = _t("◆☑•□●*■☐◍◎★"); //gcnew String(_CommonSymbols::SymbolPattern);//private KeyEventArgs m_PrevKeyEventArgs = null;  //上一次按键,下次用堆栈处理int m_old_currentLineFirstCharIndex = 0;  //上一次当前行的第一个字符索引/// <summary>/// 记录当前光标前面行中发现序号的行数和序号标记/// </summary>/// 创建时间:2025-04-27    最后一次修改时间:2025-04-27 _Pair<int, _string>  m_orderLineStart = _Pair<int, _string>(-1, _string());/// <summary>/// 记录当前光标前面行中发现特殊符号的行数和特殊符号标记/// </summary>/// 创建时间:2025-04-27    最后一次修改时间:2025-04-27 _Pair<int, _string>  m_specificLineStart = _Pair<int, _string>(-1, _string());/// <summary>/// 查找特殊符号与序号标记的有效行./// </summary>/// 创建时间:2025-04-27    最后一次修改时间:2025-04-27 const  int m_rangeLine = 10;  //默认10内有效public: //------------------------------------------------------------------------------构造与析构/// <summary>/// 初始化左键菜单/// </summary>void f_initRightMenu();/// <summary>/// 当调用f_splitFromByteArray时,要重新初始化字体和 m_tabStopCount/// </summary>void initTextEdit();explicit my_QTextEdit(QWidget* parent = nullptr);~my_QTextEdit();public: //--------------------------------------------------------------重写/// <summary>/// 使QTextEdit支持图片粘贴/// </summary>/// <param name="source"></param>/// 创建时间:2025-03-14    最后一次修改时间:2025-03-14  (摘录自 DeepSeek)void insertFromMimeData(const QMimeData* source) override;/// <summary>/// 重写左键菜单/// </summary>/// <param name="event"></param>/// 创建时间:2025-04-04    最后一次修改时间:2025-04-04void contextMenuEvent(QContextMenuEvent* event) override;/// <summary>/// 键盘事件/// </summary>/// <param name="event"></param>void keyPressEvent(QKeyEvent* event) override;void mousePressEvent(QMouseEvent* e) override;void mouseReleaseEvent(QMouseEvent* e) override;void mouseDoubleClickEvent(QMouseEvent* event) override;void inputMethodEvent(QInputMethodEvent* e) override;public://--------------------------------------------------------------成员函数/// <summary>/// 保存 QTextEdit 内容到 QByteArray(包含文本和图片)/// </summary>/// <returns></returns>/// 创建时间:2025-03-14    最后一次修改时间:2025-03-14  (摘录自 DeepSeek)QByteArray f_packageToByteArray();/// <summary>/// // 从 QByteArray 加载内容到 QTextEdit/// </summary>/// <param name="data"></param>/// 创建时间:2025-03-14    最后一次修改时间:2025-03-14  (摘录自 DeepSeek)void f_splitFromByteArray(const QByteArray& data);void f_colorCode(const _LanguageType& lt);/// <summary>/// 插入一新行,并把当前行的前charCount个字符拷贝到新行。/// </summary>/// <param name="textEdit"></param>/// <param name="charCount"></param>/// 创建时间:2025-04-10    最后一次修改时间:2025-04-10   (参考自 DeepSeek)void g_copyFormattedTextToNextLine(QTextEdit* textEdit, const size_t& charCount);/// <summary>/// 获取文本中的通用符号/// </summary>/// <returns></returns>/// 创建时间:2023-03-26    最后一次修改时间:2023-03-26 _string f_textCommonSymbols();void f_setCurrLineTextStyle(const QTextCharFormat& ts, const _string sLine = _string());void f_setCurrLineText(const QString sLine);/// <summary>/// 只影响选中的文本///     1. this->textCursor().setCharFormat(tf)///行为:///    直接操作当前临时副本光标(textCursor() 返回的是副本)///    仅修改当前选中文本的格式(如果有选中区域),或不生效(如果无选中区域)///    不会影响后续输入的默认格式/// ///    2. this->setCurrentCharFormat(tf)/// 行为:///    修改当前光标位置的默认字符格式///    立即影响后续新输入的文字格式///    如果有选中文本,会同时更新选中区域的格式/// </summary>/// <param name="tf"></param>void f_setSelectedCharFormat(const QTextCharFormat& tf) { this->textCursor().setCharFormat(tf); }/// <summary>/// 影响光标当前的格式/// </summary>/// <param name="tf"></param>void f_setCurrentCharFormat(const QTextCharFormat& tf);bool f_setBook篇部分样式();bool f_setBook标题样式();bool f_setBook章节样式();/// <summary>/// 获取指定行前面的若干行文本,时间成本约60微秒/// 使用例子:获取光标前一行文本为:/// ///     f_getLineListBeforeOfCursor(-1, 1)/// /// 注意: 返回前10行。 光标前一行索引是   9///                    光标前二行索引是  8///                    ..../// </summary>/// <param name="nCurrentLineIndex">目标行号(从0开始),-1表示当前光标行</param>/// <param name="nCount">要获取的行数</param>/// <returns>包含前nCount行的字符串列表(按行号升序排列)</returns>/// 创建时间:2025-04-10    最后一次修改时间:2025-04-10   (参考自 DeepSeek)_StringList  f_getLineListBeforeOfCursor(const int& nCurrentLineIndex, const int& nCount = 20);_StringList  f_getLineListBackOfCursor(const int& nCurrentLineIndex, const int& nCount = 20);/// <summary>/// 记录序号信息。/// </summary>/// <returns></returns>/// 创建时间:2025-04-27    最后一次修改时间:2025-04-27 bool f_scanOrder();/// <summary>/// 记录特殊符号信息/// </summary>/// <returns></returns>bool f_scanSpecific();/// <summary>/// 判断当前行是否在特殊区间/// /// (1)    ● cap,指向分配的内存末尾之后的位置/// (2) 图13.2说明了这些指针的含义。/// (3) 当前行/// /// 在第(3)和(1)之间任何一行没有 缩进 或 空格 则返回false。/// </summary>/// <returns></returns>bool f_isSpecificRange();/// <summary>/// 把所选文本缩进/// </summary>/// <returns></returns>/// 创建时间:2025-05-13    最后一次修改时间:2025-05-13   (摘自 DeepSeek)bool f_indent();/// <summary>/// 把所选文本反缩进/// </summary>/// <returns></returns>/// 创建时间:2025-05-13    最后一次修改时间:2025-05-13   (摘自 DeepSeek)bool f_unindent();/// 创建时间:2025-05-11    最后一次修改时间:2025-05-17   (摘自 DeepSeek)void f_speakSelectedText();/// <summary>/// /// </summary>/// <param name="text"></param>/// 创建时间:2025-05-17    最后一次修改时间:2025-05-17   (摘自 DeepSeek)void f_queryDeepSeek(const QString& text);/// 创建时间:2025-05-17    最后一次修改时间:2025-05-17   (摘自 DeepSeek)void f_searchBaidu(const QString& text);/// <summary>/// /// </summary>/// <param name="text"></param>/// 创建时间:2025-05-17    最后一次修改时间:2025-05-17   (摘自 DeepSeek)void f_queryAI(const QString& text);public:/*void textChanged();void undoAvailable(bool b);void redoAvailable(bool b);void currentCharFormatChanged(const QTextCharFormat& format);void copyAvailable(bool b);void selectionChanged();void cursorPositionChanged();*/std::function<void()> pf_textChanged = 0;std::function<void(bool b)> pf_undoAvailable = 0;std::function<void(bool b)> pf_redoAvailable = 0;std::function<void(const QTextCharFormat& format)> pf_currentCharFormatChanged = 0;std::function<void(bool b)> pf_copyAvailable = 0;std::function<void()> pf_selectionChanged = 0;std::function<void()> pf_cursorPositionChanged = 0;signals: //----------------------------------------------------------------------信号/// <summary>/// 鼠标按下时会调用/// </summary>void s_mousePressEvent(QMouseEvent* e);/// <summary>/// 鼠标释放时会调用/// </summary>/// <param name="e"></param>void s_mouseReleaseEvent(QMouseEvent* e);/// <summary>/// 在右键菜单显示以前会调用/// </summary>/// <param name="m"></param>void s_rightMenuBeforeShowing(QMenu* m);public: //--------------------------------------------------------------------格式设置// 设置上标static void g_setSuperscript(QTextEdit* editor);void f_superscript();// 设置下标static void g_setSubscript(QTextEdit* editor);void f_subscript();void f_link(const QString& sLink);/*** @brief 设置 QTextEdit 当前光标所在行的文本为指定字符串* @param textEdit QTextEdit 控件指针* @param sLineText 要设置的字符串*/void g_setCurrentLineText(QTextEdit* textEdit, const QString& sLineText);public://----------------------------------------------------------------------虚函数与默认处理virtual void do_redo();void default_do_redo();virtual void do_undo();void default_do_undo();virtual void do_copy();void default_do_copy();virtual void do_cut();void default_do_cut();virtual void do_paste();void default_do_paste();virtual void do_unicode();void default_do_unicode();void default_do_headlineStyle(const _TextStyle& ts);void default_do_getHeadlineStyle(const _TextStyle& ts);/// <summary>/// 添加一个样式/// </summary>virtual void do_addHeadlineNewStyle();void default_do_addHeadlineNewStyle();void default_do_cursorMoved();/// <summary>/// ASM着色/// </summary>virtual void do_asmColor();void default_do_asmColor();virtual void do_cColor();void default_do_cColor();virtual void do_javaColor();void default_do_javaColor();virtual void do_csharpColor();void default_do_csharpColor();virtual void do_pythonColor();void default_do_pythonColor();virtual void do_javaScriptColor();void default_do_javaScriptColor();virtual void do_htmlColor();void default_do_htmlColor();//数学运算符 virtual void do_mathematicalOperatorColor();void default_do_mathematicalOperatorColor();/// <summary>/// 线性代数(Linear Algebra)/// </summary>virtual void do_linearAlgebraColor();void default_do_linearAlgebraColor();virtual void do_textChanged();void default_do_textChanged();/// <summary>/// 把所选文本设为ts样式/// </summary>/// <param name="ts"></param>virtual void do_setEditTextForHeadlineStyle(const _TextStyle& ts);/// <summary>/// 删除一个样式/// </summary>virtual void do_deleteHeadlineNewStyle();void default_do_rightMenu_hovered(QAction* action);void default_do_SpecialCharTriggered(const _string& special);/// <summary>/// 把ts设为所选文本样式/// </summary>/// <param name="ts"></param>virtual void do_getEditTextToHeadlineStyle(_TextStyle& ts);//------------------------------------------------------------键盘事件virtual bool do_keyPressEvent_KeyReturnKeyEnter(QKeyEvent* event);/// <summary>/// 处理按Enter键,如果返回ture,则父类不处理/// </summary>bool default_do_keyPressEvent_KeyReturnKeyEnter(QKeyEvent* event);virtual bool do_keyPressEvent_KeyBackspace(QKeyEvent* event);/// <summary>/// 处理按Qt::Key_Back键(Backspace)/// </summary>bool default_do_keyPressEvent_KeyBackspace(QKeyEvent* event);//---------------------------------------------------------------鼠标事件virtual void do_leftButtonClicked(QMouseEvent* e);void default_do_leftButtonClicked(QMouseEvent* e);virtual bool do_keyPressEvent_Key_Tab(QKeyEvent* event);bool default_do_keyPressEvent_Key_Tab(QKeyEvent* event);virtual bool do_keyPressEvent_Key_Backtab(QKeyEvent* event);bool default_do_keyPressEvent_Key_Backtab(QKeyEvent* event);};lf
_LF_END_#endif
_QT_

my_QTextEdit.cpp


#ifdef _QT_
_QT_#include "my_QTextEdit.h"#include "global_c_all.h"
#include "_headlineStyle.h"
#include "my_QAction.h"
#include "my_qt_extension.h"
#include "my_QDialog.h"
#include "_syntax.h"
#include "_rtf.h"#include<qwidget>
#include<QMimeData>
#include<qbuffer>
#include<QTextDocument>
#include<qfile>
#include<QImageReader>
#include<QDragEnterEvent>
#include<QTextDocumentWriter>
#include<qmessagebox>
#include<QTextFrame>
#include<qapplication>
#include<QClipboard>
#include<qmenu>
#include<qlabel>
#include<QWidgetAction>
#include<qlistview>
#include<QStandardItemModel>
#include<qcheckbox>
#include<QPropertyAnimation>
#include<QTextTable>
#include<QTextDocumentFragment>
#include<qpushbutton>
#include<QScrollBar>
#include<QTextToSpeech>
#include<QNetworkAccessManager>
#include<QNetworkRequest>
#include<QNetworkReply>
#include<QJsonDocument>
#include<QJsonObject>
#include<QJsonArray>
#include<QMessageBox>
#include<QTextCursor>#define _D_using namespace std;_LF_BEGIN__LF__HeadlineStyle my_QTextEdit::m_headlineStyle;
int my_QTextEdit::m_count = 0;void my_QTextEdit::initTextEdit()
{ // 设置等宽字体QFont f = m_headlineStyle.mainBody().font;setFont(f);// 或者根据字体动态计算(更精确)QFontMetrics metrics(f);setTabStopDistance(m_tabStopCount * metrics.horizontalAdvance(' ')); // 4个空格宽度}my_QTextEdit::my_QTextEdit(QWidget* parent) : QTextEdit(parent)
{    this->initTextEdit();this->m_networkManager = new QNetworkAccessManager(this);if (m_count == 0) {auto b = app.readData("m_headlineStyle");  if (b.length() > 0) {m_headlineStyle.splitFromMemory(b.data());_log.add("读取m_headlineStyle", "my_QTextEdit::my_QTextEdit", "my_QTextEdit");}}++m_count;connect(this, &QTextEdit::textChanged, this, &my_QTextEdit::do_textChanged);m_timer.start();m_textAnalysis.setEditControl(this,"my_QTextEdit");
}my_QTextEdit::~my_QTextEdit()
{--m_count;if (m_count == 0) {if (m_headlineStyle.isChanged) {auto ba = m_headlineStyle.packageMemory();app.writeData("m_headlineStyle", ba);_log.add("保存m_headlineStyle", "my_QTextEdit::~my_QTextEdit()", "my_QTextEdit");} }
}void my_QTextEdit::f_initRightMenu()
{if (m_rightMenu == null) {m_rightMenu = new QMenu(this);QAction* unicodeAction = m_rightMenu->addAction(QIcon(app.m_imageDir +"/help.ico"), "UNICODE符号", this, &my_QTextEdit::do_unicode);m_setStyle = new QMenu();m_setStyle->setTitle("套用标题样式");m_setStyle->setIcon(QIcon(app.m_imageDir + "/format2.png"));m_rightMenu->addMenu(m_setStyle);for (auto& ts : m_headlineStyle.styleList()) {my_QAction* qa = new my_QAction(ts.name, ts.foreColor, ts.font, this);connect(qa, &QWidgetAction::triggered, [this, &ts]() {do_setEditTextForHeadlineStyle(ts);});m_setStyle->addAction(qa);}m_getStyle = new QMenu();m_getStyle->setTitle("设为标题样式");m_getStyle->setIcon(QIcon(app.m_imageDir + "/format2.png"));m_rightMenu->addMenu(m_getStyle);my_QAction* pAdd = new my_QAction("添加新样式");connect(pAdd, &QAction::triggered, [this]() {do_addHeadlineNewStyle();});m_getStyle->addAction(pAdd);my_QAction* pDelete = new my_QAction("删除新样式");connect(pDelete, &QAction::triggered, [this]() {do_deleteHeadlineNewStyle();});m_getStyle->addAction(pDelete);m_getStyle->addSeparator();for (auto& ts : m_headlineStyle.styleList()) {my_QAction* qa = new my_QAction(ts.name, ts.foreColor, ts.font,this);connect(qa, &QWidgetAction::triggered, [this, &ts]() {do_getEditTextToHeadlineStyle(ts);});m_getStyle->addAction(qa);}/*// 添加自定义菜单项QAction* undoAction = m_rightMenu->addAction("撤销", this, &my_QTextEdit::do_undo);undoAction->setEnabled(document()->isUndoAvailable());QAction* redoAction = m_rightMenu->addAction("重做", this, &my_QTextEdit::do_redo);redoAction->setEnabled(document()->isRedoAvailable());m_rightMenu->addSeparator();*/m_cutAction = m_rightMenu->addAction("剪切", this, &my_QTextEdit::do_cut);m_cutAction->setEnabled(textCursor().hasSelection());m_copyAction = m_rightMenu->addAction("复制", this, &my_QTextEdit::do_copy);m_copyAction->setEnabled(textCursor().hasSelection());m_rightMenu->addAction("粘贴", this, &my_QTextEdit::do_paste);m_rightMenu->addSeparator();//--------------------------------------------------------------------插入菜单m_insertMenu = new QMenu("插入", this);         connect(m_rightMenu, &QMenu::hovered, [this](QAction* action) {if(action != null)default_do_rightMenu_hovered(action);});m_rightMenu->addMenu(m_insertMenu);m_rightMenu->addSeparator();QMenu* textColoringMenu = new QMenu("文本着色", this);textColoringMenu->setIcon(QIcon(app.m_imageDir + "/color.png"));// 添加自定义功能QAction* qa1 = textColoringMenu->addAction("ASM");connect(qa1, &QAction::triggered, this, [this]() { do_asmColor();});QAction* qa2 = textColoringMenu->addAction("C++");connect(qa2, &QAction::triggered, this, [this]() { do_cColor(); });QAction* qa3 = textColoringMenu->addAction("Java");connect(qa3, &QAction::triggered, this, [this]() { do_javaColor(); });QAction* qa4 = textColoringMenu->addAction("C#");connect(qa4, &QAction::triggered, this, [this]() { do_csharpColor(); });QAction* qa5 = textColoringMenu->addAction("Python");connect(qa5, &QAction::triggered, this, [this]() { do_pythonColor(); });QAction* qa6 = textColoringMenu->addAction("JavaScript");connect(qa6, &QAction::triggered, this, [this]() { do_javaScriptColor(); });QAction* qa7 = textColoringMenu->addAction("HTML");connect(qa7, &QAction::triggered, this, [this]() { do_htmlColor(); });QAction* qa8 = textColoringMenu->addAction("数学运行符");connect(qa8, &QAction::triggered, this, [this]() { do_mathematicalOperatorColor(); });QAction* qa9 = textColoringMenu->addAction("线性代数");connect(qa9, &QAction::triggered, this, [this]() { do_linearAlgebraColor(); });m_rightMenu->addMenu(textColoringMenu);// 添加分隔线m_rightMenu->addSeparator();m_deepSeekAction = new QAction("DeepSeek解释", this);connect(m_deepSeekAction, &QAction::triggered, [this]() {f_queryDeepSeek(this->textCursor().selectedText());});m_rightMenu->addAction(m_deepSeekAction);// 添加百度搜索动作m_baiduAction = new QAction("百度搜索", this);connect(m_baiduAction, &QAction::triggered, [this]() {f_searchBaidu(this->textCursor().selectedText());});m_rightMenu->addAction(m_baiduAction);// 添加AI解释动作m_aiAction = new QAction("AI解释", this);connect(m_aiAction, &QAction::triggered, [this]() {f_queryAI(this->textCursor().selectedText());});m_rightMenu->addAction(m_aiAction);m_rightMenu->addSeparator();}
}void my_QTextEdit::lock(const bool& bLock)
{if (bLock){this->blockSignals(true);}else {this->blockSignals(false);}
}void my_QTextEdit::contextMenuEvent(QContextMenuEvent* event) {f_initRightMenu();m_copyAction->setEnabled(this->textCursor().hasSelection());m_cutAction->setEnabled(this->textCursor().hasSelection());emit s_rightMenuBeforeShowing(m_rightMenu);// 获取选中的文本QString selectedText = textCursor().selectedText().trimmed();//m_deepSeekAction->setText("DeepSeek解释: " + selectedText);//m_baiduAction->setText("百度搜索:" + selectedText);//m_aiAction->setText("AI解释:" + selectedText);// 在鼠标位置显示菜单m_rightMenu->exec(event->globalPos());
}void my_QTextEdit::keyPressEvent(QKeyEvent* event)
{lf::_Finally f([this]() {default_do_cursorMoved();});if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {if (do_keyPressEvent_KeyReturnKeyEnter(event))   return; }else if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down || event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) {}else if (event->key() == Qt::Key_Backspace) {/*1. Qt::Key_Backspace用途:标准的退格键(键盘上的 Backspace 键)行为:删除光标前的字符文本编辑的常规删除操作平台:所有主流平台(Windows/macOS/Linux)的物理键盘对应硬件键盘的 Backspace 键2. Qt::Key_Back用途:移动设备或系统的返回键(非文本删除)行为:导航返回(如 Android 的返回按钮)关闭当前窗口或返回上一级界面平台:主要针对移动设备(Android/iOS)某些嵌入式系统的导航键*/if (do_keyPressEvent_KeyBackspace(event)) return;}else if (event->key() == Qt::Key_Tab) {  //tabif(do_keyPressEvent_Key_Tab(event)) return;}else if (event->key() == Qt::Key_Backtab) { //shift + tabif (default_do_keyPressEvent_Key_Backtab(event)) return;}// 确保原有功能不受影响QTextEdit::keyPressEvent(event);
}void my_QTextEdit::mousePressEvent(QMouseEvent* e)
{QTextEdit::mouseMoveEvent(e);default_do_cursorMoved();emit s_mousePressEvent(e);if (e->button() == Qt::MouseButton::LeftButton) {do_leftButtonClicked(e);}  
}void my_QTextEdit::mouseReleaseEvent(QMouseEvent* e)
{QTextEdit::mouseReleaseEvent(e);emit s_mouseReleaseEvent(e);
}void my_QTextEdit::mouseDoubleClickEvent(QMouseEvent* event){// 先调用基类处理,确保正常选择文本行为QTextEdit::mouseDoubleClickEvent(event);/*// 获取双击位置的文本QTextCursor cursor = cursorForPosition(event->pos());cursor.select(QTextCursor::WordUnderCursor);QString selectedWord = cursor.selectedText();*/this->f_speakSelectedText();// 在这里添加你的自定义处理逻辑// 例如:发音、高亮、弹出菜单等event->accept(); // 表示事件已处理
}void my_QTextEdit::inputMethodEvent(QInputMethodEvent* e)
{  /*QTextEdit::inputMethodEvent(e); // 默认处理  // 中文输入中,手动触发光标移动处理default_do_cursorMoved();*/// 先保存旧的光标位置const int oldPos = textCursor().position();// 执行默认处理(这会实际更新文档内容)QTextEdit::inputMethodEvent(e);// 获取新光标位置const int newPos = textCursor().position();// 只有当光标位置确实发生变化时才触发处理if (oldPos != newPos || !e->preeditString().isEmpty() || !e->commitString().isEmpty()) {default_do_cursorMoved();  // 完全同步调用}
}void my_QTextEdit::insertFromMimeData(const QMimeData* source)
{if (source->hasImage()) {QImage image = qvariant_cast<QImage>(source->imageData());QTextCursor cursor = this->textCursor();QTextDocument* document = this->document();// 将图片添加到文档资源中document->addResource(QTextDocument::ImageResource, QUrl("image"), image);cursor.insertImage("image");}else if (source->hasFormat("text/rtf")) {// 获取 RTF 数据QByteArray rtfData = source->data("text/rtf");QString rtfText = QString::fromUtf8(rtfData);// 插入 RTF 内容this->setText(rtfText);} else if (source->hasText()) {QTextEdit::insertFromMimeData(source);}
}/// <summary>
/// 保存 QTextEdit 内容到 QByteArray(包含文本和图片)
/// </summary>
/// <returns></returns>
/// 创建时间:2025-03-14    最后一次修改时间:2025-03-14  (摘录自 DeepSeek)
QByteArray my_QTextEdit::f_packageToByteArray()
{QTextDocument* doc = this->document();QString html = doc->toHtml(); // 获取 HTML 内容// 收集文档中的所有图片资源(URL -> 图片数据)QMap<QUrl, QByteArray> imageResources;QTextFrame::iterator rootIter = doc->rootFrame()->begin();while (!rootIter.atEnd()) {QTextBlock block = rootIter.currentBlock();if (block.isValid()) {QTextBlock::iterator blockIter = block.begin();while (!blockIter.atEnd()) {QTextFragment fragment = blockIter.fragment();if (fragment.isValid() && fragment.charFormat().isImageFormat()) {QTextImageFormat imageFormat = fragment.charFormat().toImageFormat();QUrl imageUrl(imageFormat.name()); // 图片资源 URLQVariant imageData = doc->resource(QTextDocument::ImageResource, imageUrl);if (imageData.isValid() && imageData.canConvert<QImage>()) {QImage image = imageData.value<QImage>();QByteArray byteArray;QBuffer buffer(&byteArray);buffer.open(QIODevice::WriteOnly);image.save(&buffer, "PNG"); // 保存为 PNG 格式的二进制数据imageResources.insert(imageUrl, byteArray);}}++blockIter;}}++rootIter;}// 将 HTML 和图片资源序列化到 QByteArrayQByteArray data;QDataStream stream(&data, QIODevice::WriteOnly);stream << html; // 写入 HTML 文本stream << imageResources; // 写入图片资源(QMap<QUrl, QByteArray>)return data;
}/// <summary>
/// // 从 QByteArray 加载内容到 QTextEdit
/// </summary>
/// <param name="data"></param>
/// 创建时间:2025-03-14    最后一次修改时间:2025-03-14  (摘录自 DeepSeek)
void my_QTextEdit::f_splitFromByteArray(const QByteArray& data)
{   this->clear();QTextDocument* doc = new QTextDocument(this);   QDataStream stream(data);QString html;QMap<QUrl, QByteArray> imageResources;// 反序列化 HTML 和图片资源stream >> html >> imageResources;// 将图片资源重新绑定到文档for (auto it = imageResources.begin(); it != imageResources.end(); ++it) {QUrl url = it.key();QByteArray imageData = it.value();QImage image;image.loadFromData(imageData, "PNG"); // 从二进制数据加载图片doc->addResource(QTextDocument::ImageResource, url, image);}// 设置 HTML 内容并更新 QTextEditdoc->setHtml(html);setDocument(doc);     //创建QTextEdi时初始化无效,要重新设置,重新初始化字体。this->initTextEdit();/*----------------------------------------------------------------------* 问题:切换文档时导致下方空白,大部分文字是空白的。为什么这两行代码能解决问题?setValue(0)强制滚动到顶部,避免残留的旧滚动位置导致显示错位。如果不重置,新文档可能继承旧文档的滚动位置,但新文档高度较小,导致下方空白。setRange(0, doc->size().height())显式设置滚动条的最大范围为文档的实际高度。默认情况下,Qt 可能在文档切换后未及时更新滚动范围,导致滚动条无法到达底部。------------------------------------------------------------------------*/// 强制更新布局和视图//doc->adjustSize();                      // 调整文档尺寸//viewport()->update();                      // 立即重绘视图//ensureCursorVisible();                     // 确保光标可见(触发滚动区域更新)// 如果是多页文档,可能需要重置滚动条verticalScrollBar()->setValue(0);          // 滚动到顶部verticalScrollBar()->setRange(0, doc->size().height()); // 重置滚动范围}void my_QTextEdit::f_colorCode(const _LanguageType& lt)
{ /*// 2. 再清除选中文本的字符背景色QTextCharFormat charFormat;charFormat.clearBackground(); // 清除字符背景色cursor.mergeCharFormat(charFormat);/*_Syntax sy(m_rtbEx->SelectedText);_SyntaxData sd;_DList<_TextColor> kcList;switch (lt){case lf::_LanguageType::Java:kcList = sy.GetTextColorPos_C(sd);break;case lf::_LanguageType::C:kcList = sy.GetTextColorPos_C(sd);break;case lf::_LanguageType::Python:kcList = sy.GetTextColorPos_Python(sd);break;case lf::_LanguageType::JavaScript:kcList = sy.GetTextColorPos_JavaScript(sd);break;case lf::_LanguageType::CSharp:kcList = sy.GetTextColorPos_C(sd);break;case lf::_LanguageType::Swift:break;case lf::_LanguageType::GO:break;case lf::_LanguageType::PHP:break;case lf::_LanguageType::Ruby:break;default:break;}	 m_rtbEx->IsLockPaint = true;m_rtbEx->SelectionFont = gcnew System::Drawing::Font("Consolas", 14, FontStyle::Bold);int nOldSelectionStart = m_rtbEx->SelectionStart;int nOldSelectionLength = m_rtbEx->SelectionLength;for (_TextColor tc : kcList){m_rtbEx->SelectionStart = nOldSelectionStart + tc.Pos;m_rtbEx->SelectionLength = tc.Length;m_rtbEx->SelectionColor = tc.ForeColor;//m_rtbEx.SelectionFont = new Font(m_rtbEx.HeadlineStyle.MainBody, FontStyle.Bold);if (tc.IsBold){m_rtbEx->SelectionFont = gcnew Drawing::Font(m_rtbEx->SelectionFont, FontStyle::Bold);}}m_rtbEx->SelectionStart = nOldSelectionStart;m_rtbEx->SelectionLength = nOldSelectionLength;m_rtbEx->IsLockPaint = false;*//*功能	.NET RichTextBox	Qt QTextCursor设置选择起点	SelectionStart = position	setPosition(position, MoveAnchor)设置选择终点	SelectionLength = length	setPosition(position, KeepAnchor)获取选择范围	SelectedText	selectedText() + selectionStart()/selectionEnd()*/auto cur = this->textCursor();/*如果您的 QTextCursor 跨越多行,且使用 selectedText() 获取内容时遇到问题(如行尾关键字着色异常),以下是 完整解决方案:问题根源分析selectedText() 的特殊行为对于多行选择,Qt 会将换行符转换为 Unicode 段落分隔符 \u2029(而非 \n)行尾位置计算可能因换行符处理方式不同而偏移跨行选择的边界问题行首/行尾的空白字符(空格、制表符)可能被错误包含不同操作系统换行符差异(\n vs \r\n)*/转换为标准换行符(可选)//selectedText.replace(QChar(0x2029), '\n');//_Syntax sy(cur.selectedText());_Syntax sy(cur.selectedText().replace(QChar(0x2029), '\n'));_SyntaxData sd;//--------------------------------------------------------------------深色主题(Dark Theme)QColor c = sy.GetBackgroundColorColor(); // //QColor("#1E1E1E"); // 直接支持十六进制字符串(Qt 5.14+)// 1. 获取选中文本所在的段落(Block)QTextBlockFormat blockFormat = cur.blockFormat();blockFormat.setBackground(c); // 整个段落灰色背景cur.setBlockFormat(blockFormat);_DList<_TextColor> kcList;switch (lt){case lf::_LanguageType::Java:kcList = sy.GetTextColorPos_C(sd);break;case lf::_LanguageType::C:kcList = sy.GetTextColorPos_C(sd);break;case lf::_LanguageType::Python:kcList = sy.GetTextColorPos_Python(sd);break;case lf::_LanguageType::JavaScript:kcList = sy.GetTextColorPos_JavaScript(sd);break;case lf::_LanguageType::CSharp:kcList = sy.GetTextColorPos_C(sd);break;case lf::_LanguageType::Swift:break;case lf::_LanguageType::GO:break;case lf::_LanguageType::PHP:break;case lf::_LanguageType::Ruby:break;default:break;}//qt.showText(cur.selectedText());blockSignals(true);setUpdatesEnabled(false);  // 暂停重绘// 进行文本着色操作// ...int nOldSelectionStart = cur.selectionStart();int nOldSelectionEnd = cur.selectionEnd();auto cf = cur.charFormat();auto f = cf.font();f.setBold(true);cf.setFont(f);//QBrush bold = cf.foreground();for (_TextColor tc : kcList){cur.setPosition(nOldSelectionStart + tc.Pos, QTextCursor::MoveAnchor);cur.setPosition(nOldSelectionStart + tc.Pos + tc.Length, QTextCursor::KeepAnchor);cf.setForeground(QBrush(tc.ForeColor));cur.setCharFormat(cf); //cur.mergeCharFormat(cf);//qt.showInfo(cur.selectedText());}cur.setPosition(nOldSelectionStart, QTextCursor::MoveAnchor);cur.setPosition(nOldSelectionEnd, QTextCursor::KeepAnchor);setUpdatesEnabled(true);  // 恢复重绘update();  // 触发一次完整重绘blockSignals(false);}void my_QTextEdit::g_copyFormattedTextToNextLine(QTextEdit* textEdit, const size_t& charCount)
{QTextCursor cursor = textEdit->textCursor();cursor.beginEditBlock();  // 开始编辑块(撤销/重做时作为一个操作)// 1. 选择要复制的文本cursor.movePosition(QTextCursor::StartOfLine);int startPos = cursor.position();cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, charCount);// 2. 获取包含所有格式的文档片段QTextDocumentFragment fragment = cursor.selection();// 3. 创建新行cursor.clearSelection();cursor.movePosition(QTextCursor::EndOfLine); //光标称动行尾//-------------------------------------插入两个新行cursor.insertBlock();  cursor.insertBlock();  // 4. 插入带格式的文本cursor.insertFragment(fragment);cursor.endEditBlock();  // 结束编辑块   textEdit->setTextCursor(cursor);
}_string my_QTextEdit::f_textCommonSymbols()
{  _string sSymbols = _CommonSymbols::GetAllSymbols().removeASCII_copy();sSymbols = sSymbols.removeCharArray_copy(_CommonSymbols::punctuation);_string sText = this->toPlainText();_string sResult;sResult.setBuffer(sSymbols.length());for(auto c : sSymbols){if (sText.indexOf(c) != -1 && sResult.indexOf(c) == -1){sResult.add(c);}}return sResult;    
}void my_QTextEdit::f_setCurrentCharFormat(const QTextCharFormat& tf)
{this->setCurrentCharFormat(tf);
}bool my_QTextEdit::f_setBook篇部分样式()
{_string sLine = m_currentLineText.trim();_char* p = (_char*)sLine.getData();if (p[0] != _t('第')) return false;int  i = sLine.indexOf(_t('部'));if (i == -1){i = sLine.indexOf(_t('篇'));}if (i == -1) return false;_string s = sLine.substr(1, i - 1);if (!s.isNumberString()){return false;}//d.printError(s);    auto cfOld = this->textCursor().charFormat();this->f_setCurrLineTextStyle(m_headlineStyle.bookAPieceOf().getTextCharFormat(true, true));this->f_setCurrentCharFormat(cfOld);return true;
}bool my_QTextEdit::f_setBook标题样式()
{if (m_currentLineText.trim().length() == 0) return false;// |         第七章  跨程序共享数据、探究内容提供器if (m_currentLineText.Is章标题行()){this->f_setCurrLineTextStyle(m_headlineStyle.bookChapters().getTextCharFormat(true, true));       return true;}QTextCharFormat cfOld = this->textCursor().charFormat(); //csharp_SelectionStyle^ ss正文样式 = ssTemp;_string sTag = m_currentLineText.getBook_章节标记();//lg->ShowInfo("sTag=" + sTag);if (sTag.length() == 0) { return false; }int nCurLineIndex = m_currentLineCount - 1;  //当前行//篇.章.节if (sTag.indexOf('.') != -1){auto sList = sTag.split('.', false);auto ssNew = this->textCursor().charFormat();if (sList.length() == 1){ssNew.setFont(m_headlineStyle.bookChapters().font);ssNew.setForeground(QBrush(m_headlineStyle.bookChapters().foreColor));}else if (sList.length() == 2){ssNew.setFont(m_headlineStyle.bookSection().font);ssNew.setForeground(QBrush(m_headlineStyle.bookSection().foreColor));}else if (sList.length() == 3){ssNew.setFont(m_headlineStyle.bookSmallSection().font);ssNew.setForeground(QBrush(m_headlineStyle.bookSmallSection().foreColor));}else{ssNew.setFont(m_headlineStyle.orderNumber().font);  //加粗标记ssNew.setForeground(QBrush(m_headlineStyle.orderNumber().foreColor));}this->f_setCurrLineTextStyle(ssNew);this->f_setCurrentCharFormat(cfOld);return true;}else{return false;}
}bool my_QTextEdit::f_setBook章节样式()
{_string sTag = m_currentLineText.getBook_章节标记();//d.printInfo(m_currentLineText, "my_QTextEdit::f_setBook章节样式");if (sTag.length() != 0){this->f_setCurrLineTextStyle(m_headlineStyle.bookSection().getTextCharFormat(true, true), sTag);   //在当前位置插入换行符this->insertPlainText("\n");  //在光标处插入换行符this->insertPlainText(sTag.tryStrAndOne());}else{  return false;}return true;
}_StringList my_QTextEdit::f_getLineListBeforeOfCursor(const int& nCurrentLineIndex, const int& nCount){_StringList result;if (nCount <= 0) return result;QTextDocument* doc = document();QTextBlock targetBlock;// 确定目标行if (nCurrentLineIndex == -1) {// 获取光标所在行targetBlock = textCursor().block();}else {// 获取指定行(注意行号从0开始)targetBlock = doc->findBlockByLineNumber(nCurrentLineIndex);}// 验证目标行有效性if (!targetBlock.isValid()) {qWarning() << "Invalid line index:" << nCurrentLineIndex;return result;}// 向前回溯nCount行int linesCollected = 0;QTextBlock currentBlock = targetBlock.previous(); // 从目标行的前一行开始while (currentBlock.isValid() && linesCollected < nCount) {result.inseart_front(currentBlock.text()); // 保证顺序为行号升序currentBlock = currentBlock.previous();linesCollected++;}return result;
}/// <summary>
/// 获取后面的nCount行
/// </summary>
/// <param name="nCurrentLineIndex"></param>
/// <param name="nCount"></param>
/// <returns></returns>
_StringList my_QTextEdit::f_getLineListBackOfCursor(const int& nCurrentLineIndex, const int& nCount)
{return f_getLineListBeforeOfCursor(nCurrentLineIndex + nCount, nCount);
}bool my_QTextEdit::f_scanOrder()
{//if(m_orderLineStart.first != -1 && m_currentLineCount - m_orderLineStart.first < 10) {//    return true;//}auto sl = this->f_getLineListBeforeOfCursor(-1, m_rangeLine);//-------------------------------------------------------检查特殊符号int n = 0;_string sOrder;for (auto& s : sl) {sOrder = s.getBook_序号标记();if (sOrder.length() > 0) {m_orderLineStart.first = n;m_orderLineStart.second = sOrder;return true;}else {if (s.getBook_特殊符号标记(m_specificSymbol).length() > 0) { //是特殊序号,停止处理break;}}++n;}m_orderLineStart.first = -1;m_orderLineStart.second = _string();return false;
}bool my_QTextEdit::f_scanSpecific() {/*if (m_specificLineStart.first != -1 && m_currentLineCount - m_specificLineStart.first < 10) {return true;}*/auto sl = this->f_getLineListBeforeOfCursor(-1, m_rangeLine);//-------------------------------------------------------检查特殊符号int n = 0;_string sSpecific;auto node = sl.last();while(node != null){_string s = node->data;//如果行的第一个字符不是空格或控制字符,则返因falseif (s.length() > 0) {if (!gs.c_isControl(s[0]) && !gs.c_isWhiteSpace(s[0])) { //没有缩进break;} }sSpecific = s.getBook_特殊符号标记(m_specificSymbol);if (sSpecific.length() > 0) {m_specificLineStart.first = n;m_specificLineStart.second = sSpecific;return true;}else {if (s.getBook_序号标记().length() > 0) { //是序号,停止处理break;}}++n;node = node->prev;}m_specificLineStart.first = -1;m_specificLineStart.second = _string();return false;
}bool my_QTextEdit::f_indent()
{// 获取当前选中的文本块QTextCursor cursor = textCursor();if (textCursor().hasSelection()) {/*QTextCursor cursor = textCursor();int start = cursor.selectionStart();int end = cursor.selectionEnd();cursor.setPosition(start);int startBlock = cursor.blockNumber();cursor.setPosition(end);int endBlock = cursor.blockNumber();// 开始编辑cursor.beginEditBlock();// 对每一行添加缩进for (int i = startBlock; i <= endBlock; ++i) {// 移动到指定行cursor.movePosition(QTextCursor::Start);for (int j = 0; j < i; ++j) {cursor.movePosition(QTextCursor::NextBlock);}// 移动到行首并插入制表符cursor.movePosition(QTextCursor::StartOfBlock);cursor.insertText("\t");}cursor.endEditBlock();// 恢复选中状态cursor.setPosition(start);cursor.movePosition(QTextCursor::StartOfBlock);cursor.setPosition(end + (endBlock - startBlock + 1), QTextCursor::KeepAnchor);setTextCursor(cursor);return true;*/QTextCursor cursor = textCursor();int start = cursor.selectionStart();int end = cursor.selectionEnd();cursor.beginEditBlock();// 获取文档的第一个块QTextBlock block = document()->findBlock(start);QTextBlock endBlock = document()->findBlock(end);// 如果选区结束位置不是行首,需要包含下一行if (end > endBlock.position()) {endBlock = endBlock.next();}while (block.isValid() && block != endBlock) {QTextCursor blockCursor(block);blockCursor.movePosition(QTextCursor::StartOfBlock);blockCursor.insertText("\t");block = block.next();}cursor.endEditBlock();// 调整选区cursor.setPosition(start);cursor.setPosition(end + (endBlock.blockNumber() - document()->findBlock(start).blockNumber()),QTextCursor::KeepAnchor);setTextCursor(cursor);return true;}return false;
}bool my_QTextEdit::f_unindent()
{if (!textCursor().hasSelection()) {return false;}QTextCursor cursor = textCursor();int start = cursor.selectionStart();int end = cursor.selectionEnd();cursor.beginEditBlock();// 获取选区涉及的第一个和最后一个文本块QTextBlock startBlock = document()->findBlock(start);QTextBlock endBlock = document()->findBlock(end);// 如果选区结束位置不在行首,需要包含当前行if (end > endBlock.position()) {endBlock = endBlock.next();}int removedChars = 0; // 记录总共移除的字符数bool hasRemoved = false;// 遍历所有选中的行for (QTextBlock block = startBlock; block.isValid() && block != endBlock; block = block.next()) {QTextCursor blockCursor(block);blockCursor.movePosition(QTextCursor::StartOfBlock);// 检查行首是否是制表符或空格blockCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1);QString firstChar = blockCursor.selectedText();if (firstChar == "\t" || firstChar == " ") {blockCursor.removeSelectedText();removedChars++;hasRemoved = true;}blockCursor.clearSelection();}cursor.endEditBlock();// 调整选区位置(因为移除了字符,选区范围会变化)if (hasRemoved) {cursor.setPosition(start);cursor.setPosition(end - removedChars, QTextCursor::KeepAnchor);setTextCursor(cursor);}return hasRemoved;
}void my_QTextEdit::f_speakSelectedText()
{QString selectedText = textCursor().selectedText();if (!selectedText.isEmpty()) {QTextToSpeech* speech = new QTextToSpeech(this);// 尝试自动检测语言(简单实现)bool isChinese = selectedText.contains(QRegularExpression("[\\u4e00-\\u9fa5]"));if (isChinese) {speech->setLocale(QLocale::Chinese);}else {speech->setLocale(QLocale::English);}speech->say(selectedText);// 发音完成后清理connect(speech, &QTextToSpeech::stateChanged, [speech](QTextToSpeech::State state) {if (state == QTextToSpeech::State::Ready)speech->deleteLater();});}
}void my_QTextEdit::f_queryDeepSeek(const QString& text){// 构造API请求QNetworkRequest request(QUrl("https://api.deepseek.com/v1/chat/completions"));request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");// 注意: 实际使用时需要替换为你的API密钥// request.setRawHeader("Authorization", "Bearer YOUR_DEEPSEEK_API_KEY");QJsonObject body;body["model"] = "deepseek-chat";body["messages"] = QJsonArray{QJsonObject {{"role", "system"},{"content", "你是一个专业的技术术语解释助手,请用简洁易懂的语言解释以下概念,并给出一个示例。"}},QJsonObject {{"role", "user"},{"content", QString("请解释'%1'").arg(text)}}};body["temperature"] = 0.7;QNetworkReply* reply = m_networkManager->post(request,QJsonDocument(body).toJson());connect(reply, &QNetworkReply::finished, [this, reply, text]() {if (reply->error() == QNetworkReply::NoError) {QJsonDocument doc = QJsonDocument::fromJson(reply->readAll());QString response = doc["choices"][0]["message"]["content"].toString();// 显示解释结果QMessageBox::information(this,QString("DeepSeek对'%1'的解释").arg(text),response);}else {QMessageBox::warning(this, "错误",QString("API请求失败: %1").arg(reply->errorString()));}reply->deleteLater();});
}void my_QTextEdit::f_searchBaidu(const QString& text)
{// 构造百度搜索URLQUrl url(QString("https://www.baidu.com/s?wd=%1").arg(text));QDesktopServices::openUrl(url);
}void my_QTextEdit::f_queryAI(const QString& text)
{// 这里可以替换为实际的AI API调用// 示例中使用QMessageBox模拟AI解释QString explanation;if (text.length() > 10) {explanation = QString("'%1' 是一个较长的文本,可能是一个短语或句子。").arg(text);}else {explanation = QString("'%1' 可能是一个关键词或术语,建议查阅专业词典获取详细解释。").arg(text);}QMessageBox::information(null, "AI解释",QString("对 '%1' 的解释:\n\n%2").arg(text, explanation));
}void my_QTextEdit::f_setCurrLineTextStyle(const QTextCharFormat& ts, const _string sLine)
{// 获取当前光标位置QTextCursor cursor = textCursor();// 选中整行文本cursor.movePosition(QTextCursor::StartOfLine);cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);cursor.setCharFormat(ts);if (sLine.length() > 0) {        cursor.insertText(sLine); // 替换选中文本}// 检查是否有选中内容(处理空行情况)//if (!cursor.hasSelection() && !cursor.atEnd()) {//    cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);//}// 恢复光标位置(不选中文本)cursor.clearSelection();setTextCursor(cursor);
}void my_QTextEdit::f_setCurrLineText(const QString sLine)
{this->g_setCurrentLineText(this, sLine);  
}void my_QTextEdit::g_setSuperscript(QTextEdit* editor)
{   QTextCharFormat format;format.setForeground(QBrush(_Color::Red));format.setVerticalAlignment(QTextCharFormat::AlignSuperScript);editor->mergeCurrentCharFormat(format);
}void my_QTextEdit::f_superscript()
{g_setSuperscript(this);
}void my_QTextEdit::g_setSubscript(QTextEdit* editor)
{QTextCharFormat format;format.setForeground(QBrush(_Color::Red));format.setVerticalAlignment(QTextCharFormat::AlignSubScript);editor->mergeCurrentCharFormat(format);
}void my_QTextEdit::f_subscript()
{g_setSubscript(this);
}void my_QTextEdit::f_link(const QString& sLink)
{auto format = this->currentCharFormat();format.setAnchor(true);format.setAnchorHref(sLink);format.setForeground(Qt::blue);format.setFontUnderline(true);  // 通常超链接带下划线this->setCurrentCharFormat(format);}void my_QTextEdit::g_setCurrentLineText(QTextEdit* textEdit, const QString& sLineText)
{if (!textEdit) {return; // 确保指针有效}QTextCursor cursor = textEdit->textCursor();// 选中当前行cursor.movePosition(QTextCursor::StartOfLine);cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);// 替换选中文本cursor.insertText(sLineText);// 恢复光标位置(可选)textEdit->setTextCursor(cursor);
}void my_QTextEdit::do_redo()
{default_do_redo();
}void my_QTextEdit::do_undo()
{default_do_undo();
}void my_QTextEdit::do_copy()
{default_do_copy();
}void my_QTextEdit::do_cut()
{default_do_cut();
}void my_QTextEdit::do_paste()
{default_do_paste();
}void my_QTextEdit::do_unicode()
{default_do_unicode();
}void my_QTextEdit::do_setEditTextForHeadlineStyle(const _TextStyle& ts)
{auto m_format = currentCharFormat();m_format.setFont(ts.font);QBrush b(ts.foreColor);m_format.setForeground(b);this->setCurrentCharFormat(m_format);
}void my_QTextEdit::do_getEditTextToHeadlineStyle(_TextStyle& ts)
{if (app.question("真的要把当前格式设置为 “" + ts.name + "” 吗?")) {// 获取当前文本光标QTextCursor cursor = textCursor();auto cf = cursor.charFormat();ts.font = cf.font();ts.foreColor = cf.foreground().color();ts.backColor = cf.background().color();m_headlineStyle.isChanged = true;}}void my_QTextEdit::do_addHeadlineNewStyle()
{// 获取当前文本光标QTextCursor cursor = textCursor();/*// 获取当前所选文本的字符格式QTextCharFormat format = cursor.charFormat();// 现在可以查询格式属性QFont font = format.font();QColor textColor = format.foreground().color();bool isBold = font.bold();bool isItalic = font.italic();// 其他属性...*/if (!cursor.hasSelection()) {app.about("未选择文本!");return;}QString  sName = app.getInputString("请输入样式名。");if (sName.length() > 0) {_TextStyle ts;ts.name = sName;ts.font = cursor.charFormat().font();ts.foreColor = cursor.charFormat().foreground().color();ts.backColor = cursor.charFormat().background().color();m_headlineStyle.addNewStyle(ts);m_headlineStyle.isChanged = true;app.about("添加成功!");}
}void my_QTextEdit::do_deleteHeadlineNewStyle()
{_list<_string> sl;for (auto& ts : m_headlineStyle.styleList()) {sl.add(ts.name);}_string s = qt.d_getSelectString(sl);if (s.length() > 0) {if (app.question("真的要删除 “" + s + "” 吗?")) {if (m_headlineStyle.removeTextStyle(s)) {qt.showInfo("删除成功。");}else {qt.showInfo("删除失败!");}m_headlineStyle.isChanged = true;}} }void my_QTextEdit::do_asmColor()
{default_do_asmColor();
}void my_QTextEdit::do_cColor()
{default_do_cColor();
}void my_QTextEdit::do_javaColor()
{default_do_javaColor();
}void my_QTextEdit::do_csharpColor()
{default_do_csharpColor();
}void my_QTextEdit::do_pythonColor()
{default_do_pythonColor();
}void my_QTextEdit::do_javaScriptColor()
{default_do_javaScriptColor();
}void my_QTextEdit::do_htmlColor()
{default_do_htmlColor();
}void my_QTextEdit::do_mathematicalOperatorColor()
{default_do_mathematicalOperatorColor();
}void my_QTextEdit::do_linearAlgebraColor()
{default_do_linearAlgebraColor();
}void my_QTextEdit::default_do_redo()
{redo();
}void my_QTextEdit::default_do_undo()
{undo();
}void my_QTextEdit::default_do_copy()
{copy();
}void my_QTextEdit::default_do_cut()
{cut();
}bool hasRtfData(const QMimeData* mimeData) {const QStringList rtfFormats = {"text/rtf","Rich Text Format","application/rtf"};for (const QString& format : rtfFormats) {if (mimeData->hasFormat(format)) {return true;}}return false;
}void my_QTextEdit::default_do_paste()
{const QMimeData* mimeData = QApplication::clipboard()->mimeData();if (mimeData->hasFormat("Rich Text Format")) {//QByteArray  rtfData = mimeData->data("Rich Text Format"); //this->insertHtml(rtfData);paste();}else {paste(); // 回退到普通粘贴} 
}void my_QTextEdit::default_do_unicode()
{/*阿拉伯数字英文字母标点符号中文汉字数字,包括阿拉伯数字和中文数字数字符号数学运算符数学符号各种科技符号控制图形光电识别符号包围起来的字母数字*/my_QDialog d;d.setWindowTitle("符号选择窗体");QLabel lab1("符号分类:",&d);lab1.setGeometry(10, 20, 60, lab1.height());QComboBox cb(&d);cb.addItem("阿拉伯数字");cb.addItem("英文字母");cb.addItem("标点符号");cb.addItem("中文汉字");cb.addItem("数字,包括阿拉伯数字和中文数字");cb.addItem("数字符号");cb.addItem("数学运算符");cb.addItem("数学符号");cb.addItem("各种科技符号");cb.addItem("控制图形");cb.addItem("光电识别符号");cb.addItem("包围起来的字母数字");QRect rc = lab1.geometry();cb.setGeometry(rc.x() + lab1.width() + 10, rc.y(), 250, cb.height());QLabel lab2("手动输入字符值:", &d);rc = cb.geometry();lab2.setGeometry(rc.x() + cb.width() + 10, rc.y(), lab2.width(), lab2.height());rc = lab2.geometry();QPlainTextEdit pte(&d);pte.setGeometry(rc.x() + lab2.width() + 10, rc.y(), 50, lab2.height());rc = pte.geometry();QCheckBox chb1("显示UNICODE值", &d);chb1.setGeometry(rc.x() + pte.width() + 10, rc.y(), chb1.width(), chb1.height());rc = chb1.geometry();QCheckBox chb2("十六进制", &d);chb2.setGeometry(rc.x() + chb1.width() + 10, rc.y(), chb2.width(), chb2.height());QTextEdit qe(&d);qe.setGeometry(lab1.geometry().x(), lab1.geometry().y() + 50, 700, 400);connect(&cb, &QComboBox::currentIndexChanged, [this,&qe,&cb](int index) {/*阿拉伯数字英文字母标点符号中文汉字数字,包括阿拉伯数字和中文数字数字符号数学运算符数学符号各种科技符号控制图形光电识别符号包围起来的字母数字*/auto cf = qe.currentCharFormat();cf.setFont(this->m_headlineStyle.bookChapters().font);qe.setCurrentCharFormat(cf);QString itemtext = cb.itemText(index);if (itemtext == "阿拉伯数字"){//rtb->Text = ga.s_GetCharTypes(_CharType::ArabicDigit);qe.setText(ga.s_GetCharTypes(_CharType::ArabicDigit));}else if (itemtext == "英文字母"){qe.setText(ga.s_GetCharTypes(_CharType::EnglishLetters));}else if (itemtext == "标点符号"){qe.setText(ga.s_GetCharTypes(_CharType::Punctuation));}else if (itemtext == "中文汉字"){qe.setText(ga.s_GetCharTypes(_CharType::ChineseCharacter));}else if (itemtext == "数字,包括阿拉伯数字和中文数字"){qe.setText(ga.s_GetCharTypes(_CharType::Number));}else if (itemtext == "数字符号"){qe.setText(ga.s_GetCharTypes(_CharType::NumberForms));}else if (itemtext == "数学运算符"){qe.setText(ga.s_GetCharTypes(_CharType::MathematicalOperators));}else if (itemtext == "数学符号"){qe.setText(ga.s_GetCharTypes(_CharType::MiscellaneousMathematicalSymbols));}else if (itemtext == "各种科技符号"){qe.setText(ga.s_GetCharTypes(_CharType::MiscellaneousTechnical));}else if (itemtext == "控制图形"){qe.setText(ga.s_GetCharTypes(_CharType::ControlPictures));}else if (itemtext == "光电识别符号"){qe.setText(ga.s_GetCharTypes(_CharType::OpticalCharacterRecognition));}else if (itemtext == "包围起来的字母数字"){qe.setText(ga.s_GetCharTypes(_CharType::EnclosedAlphanumerics));}else{qt.showInfo("未知类型!", "cb_符号列表_SelectedIndexChanged");}});d.exec();}void my_QTextEdit::default_do_headlineStyle(const _TextStyle& ts)
{
}void my_QTextEdit::default_do_getHeadlineStyle(const _TextStyle& ts)
{
}void my_QTextEdit::default_do_addHeadlineNewStyle()
{
}void my_QTextEdit::default_do_cursorMoved()
{QTextCursor cursor = textCursor();m_currentLineText.clear();m_currentLineText.add((wchar_t*)cursor.block().text().begin());// 计算新位置m_currentLineCount = cursor.blockNumber() + 1;m_currentColumn = cursor.positionInBlock() + 1;// 更新行号列号显示if (m_statusLable1 != nullptr) {m_currentLineColumnInfo.clear();m_currentLineColumnInfo.add(_t("行:"));m_currentLineColumnInfo.add(_Math::intToStr(m_currentLineCount));m_currentLineColumnInfo.add(_t("   列:"));m_currentLineColumnInfo.add(_Math::intToStr(m_currentColumn));m_statusLable1->setText(m_currentLineColumnInfo);}if (m_statusLabel2 != nullptr) { m_statusLabel2->setText(m_currentLineText);}   }void my_QTextEdit::default_do_asmColor()
{f_colorCode(_LanguageType::ASM);
}void my_QTextEdit::default_do_cColor()
{f_colorCode(_LanguageType::C);
}void my_QTextEdit::default_do_javaColor()
{f_colorCode(_LanguageType::Java);
}void my_QTextEdit::default_do_csharpColor()
{f_colorCode(_LanguageType::CSharp);
}void my_QTextEdit::default_do_pythonColor()
{f_colorCode(_LanguageType::Python);
}void my_QTextEdit::default_do_javaScriptColor()
{f_colorCode(_LanguageType::JavaScript);
}void my_QTextEdit::default_do_htmlColor()
{f_colorCode(_LanguageType::HTML);
}void my_QTextEdit::default_do_mathematicalOperatorColor()
{
}void my_QTextEdit::default_do_linearAlgebraColor()
{
}void my_QTextEdit::default_do_rightMenu_hovered(QAction* action)
{assert(m_insertMenu != null);if (action->text() == m_insertMenu->title()) {auto actions = m_insertMenu->actions();if (actions.count() == 0) {auto m_coolMenu = new QMenu(QString::fromWCharArray(lf::_CommonSymbols::Cools_cn));m_insertMenu->addMenu(m_coolMenu);m_textCommonSymbols = new QMenu("文中符号");m_insertMenu->addMenu(m_textCommonSymbols);for (auto& p : _CommonSymbols::GetSymbolList()) {auto menu = new QMenu(QString::fromWCharArray(p.first));m_insertMenu->addMenu(menu);_string s = p.second;              auto action = new my_QAction(s.connectForSplit(_t("<br>"), 20),_Color::Random());menu->addAction(action);connect(action, &QAction::triggered, [action,this]() {default_do_SpecialCharTriggered(action->m_lable->text());});}      }      }else if(action->text() == "文中符号"){  //每次动态从文中获取特殊符号if (m_textCommonSymbols->actions().length() == 0) {       m_textCommonSymbols->clear();_string s = f_textCommonSymbols().set_union(m_specificSymbol);for (auto c : s) {auto action = new my_QAction(QString(c), _Color::Random());m_textCommonSymbols->addAction(action);connect(action, &QAction::triggered, [action, this]() {insertPlainText(action->m_lable->text());});}}}
}void my_QTextEdit::default_do_SpecialCharTriggered(const _string& special)
{/*int iColumnCount = 20;  //列数,每行显示的个数String^ SpecialChar = gca::s_RemoveUnprintableAndWhitespace(((ToolStripDropDownItem^)(tsmiCharSender))->Text);Form^ SpecialCharForm = gcnew Form();SpecialCharForm->Text = L"插入特殊符号";SpecialCharForm->Width = 40 * iColumnCount + 20;SpecialCharForm->Height = (SpecialChar->Length / iColumnCount + 2) * 40 + 10;//StringList_ sCharList = sChar->_Split(" ",true);int ii = 0;for each (wchar_t cItem in SpecialChar){Button^ bt = gcnew Button();bt->Text = cItem.ToString();Drawing::Font^ f = gcnew Drawing::Font(bt->Font->Name, 18, FontStyle::Bold);bt->Font = f;bt->ForeColor = gca::color_RandomColor();bt->Width = 40;bt->Height = 40;bt->Left = (ii % iColumnCount) * bt->Width;bt->Top = (ii / iColumnCount) * bt->Height;++ii;bt->Parent = SpecialCharForm;bt->Click += gcnew System::EventHandler(this, &RichTextBoxForm::Bt_SpecialChar_Click);}gca::f_SetTheme(SpecialCharForm);gca::f_ShowTopMostInNearMouse(SpecialCharForm);*/int iColumnCount = 20;  //列数,每行显示的个数_string SpecialChar = special.replaceAll_copy(_t("<br>"), _t(""));my_QDialog dlg;    dlg.setWindowTitle("插入特殊符号");int w = 40 * iColumnCount;int h = (SpecialChar.length() / iColumnCount + 1) * 40 ;dlg.resize(w, h);int ii = 0;for(wchar_t cItem : SpecialChar){QPushButton* bt = new QPushButton(QString(cItem),&dlg);QFont f(bt->font().family(), 18);f.setBold(true);bt->setFont(f);bt->setStyleSheet(_Color::Random().toStyleSheet_foregroundColor());bt->setGeometry( (ii % iColumnCount) * 40, (ii / iColumnCount) * 40, 40, 40);++ii;      connect(bt, &QPushButton::clicked, [this,bt]() {insertPlainText(bt->text());  // 在当前光标处插入字符});}QRect cr = this->cursorRect(); // 获取光标在控件内的坐标QPoint globalPos = mapToGlobal(cr.bottomLeft());  // 转换为全局屏幕坐标dlg.move(globalPos); dlg.exec();}bool my_QTextEdit::do_keyPressEvent_KeyReturnKeyEnter(QKeyEvent* event)
{return default_do_keyPressEvent_KeyReturnKeyEnter(event);
}bool my_QTextEdit::default_do_keyPressEvent_KeyReturnKeyEnter(QKeyEvent* event)
{_string sorder = m_currentLineText.getBook_序号标记();if (sorder.length() > 0) {   f_setCurrLineTextStyle(m_headlineStyle.orderNumber().getTextCharFormat(true, true));this->insertPlainText("\n\n");f_setCurrLineTextStyle(m_headlineStyle.orderNumber().getTextCharFormat(true, true), sorder.tryNumberAddOne());return true;}if (this->f_setBook篇部分样式() || f_setBook标题样式()){//d.printInfo("31", "default_do_keyPressEvent_KeyReturnKeyEnter");this->setCurrentCharFormat(this->m_headlineStyle.mainBody().getTextCharFormat(true, true));this->insertPlainText("\n\n");return true;}if (this->f_setBook章节样式()) {return true;}_string sSpecific = m_currentLineText.getBook_特殊符号标记(m_specificSymbol);if (sSpecific.length()) {this->insertPlainText("\n\n" + sSpecific);return true;}//-------------------------------------如果当前行是缩进的,那么下一行也是缩进的        //当sCopy.length() = 0,是空行_string sCopy = m_currentLineText.copyControlAndWhiteSpace();this->insertPlainText(_t("\n") + sCopy);return true;/*//(1)-----------------------------------------------------------------------处理行号与特殊符号      lock(true);_string sEnterOrder = m_currentLineText.getBook_序号标记();if (m_currentLineText.getBook_特殊符号标记(m_specificSymbol).length() != 0)  //有特殊字符,且特殊字符前面全是空格或者不可打印字符{//d.printInfo("1", "default_do_keyPressEvent_KeyReturnKeyEnter");int nPos = m_currentLineText.indexOfAnyChar(m_specificSymbol).first;_string ch;ch.add(m_currentLineText[nPos]);int nSelectLength = m_currentLineText.findFirstPrintable(ch);if (nSelectLength != -1){m_is特殊符号段落内 = true;lock(true);this->g_copyFormattedTextToNextLine(this, nSelectLength);lock(false);}else {qt.showInfo("程序设计错误!");}}else if (sEnterOrder != _t("")){//d.printInfo("2", "default_do_keyPressEvent_KeyReturnKeyEnter");m_is序号段落内 = true;_string sEnterNext = sEnterOrder.tryStrAndOne();this->f_setCurrLineTextStyle(m_headlineStyle.orderNumber().getTextCharFormat(true, true));//在当前位置插入换行符this->insertPlainText("\n\n");  //在光标处插入两个换行符,这里插入两个换行符,之前是一个(2022-09-25 修改)this->insertPlainText(sEnterNext);this->f_setCurrLineTextStyle(m_headlineStyle.orderNumber().getTextCharFormat(true, true));}else { //-----------------------------------------------------------------------行号和字符End//d.printInfo("3", "default_do_keyPressEvent_KeyReturnKeyEnter");//(2)处理章节,例:1->1->1  ????//                1->1->2  if (this->f_setBook篇部分样式() || f_setBook标题样式()){//d.printInfo("31", "default_do_keyPressEvent_KeyReturnKeyEnter");this->insertPlainText("\n");this->f_setCurrLineTextStyle(this->m_headlineStyle.mainBody().getTextCharFormat(true, true));}else if (!m_is序号段落内)  //1->  2->  3->{//d.printInfo("32", "default_do_keyPressEvent_KeyReturnKeyEnter");if (this->f_setBook章节样式()){m_is序号段落内 = true;this->f_setCurrentCharFormat(m_headlineStyle.mainBody().getTextCharFormat(true, true));}else //-------------------------------------如果当前行是缩进的,那么下一行也是缩进的        {//当sCopy.length() = 0,是空行_string sCopy = m_currentLineText.copyControlAndWhiteSpace();this->insertPlainText(_t("\n") + sCopy);      }}else //---------------------------------------------------------------------------------在序号段落中 {if (m_currentLineText.length() > 0){if (!gs.c_IsUnPrintableOrWhiteSpace(m_currentLineText[0])) //不是空格或者控制字符{m_is序号段落内 = false;}else {if (this->f_setBook章节样式()) {}else {int n = m_currentLineText.findLastPrintable();if (n == -1) { //空白行           int nSelectLength = m_currentLineText.findFirstPrintable();//如果当前行是缩进的,那么下一行也是缩进的this->g_copyFormattedTextToNextLine(this, nSelectLength);}else {_string sCurrLineOrder = m_currentLineText.getBook_序号标记();if (sCurrLineOrder.length() == 0)  //-------------------------------------------------------------------当前行不含序号{if (m_currentLineText[n] == _t('。')) { //序号标记以句号和Enter//lg->StartTime();//查找前面20行内的序号标记,不包含当前行。auto slBefore = this->f_getLineListBeforeOfCursor(m_currentLineCount - 1);_string sOrder;_string sblankSpace;for (auto& s : slBefore) {sOrder = s.getBook_序号标记();if (sOrder.length() != 0){sblankSpace = s.copyControlAndWhiteSpace();break;}}if (sOrder.length() != 0) {_string sOrderNext = sOrder.tryStrAndOne();bool bFind = false;//查找后面二十行的序号标记auto slBack = f_getLineListBackOfCursor(m_currentLineCount - 1);for (auto& s : slBack){if (s.getBook_序号标记().removeUnprintableAndWhitespace() == sOrderNext.removeUnprintableAndWhitespace()){bFind = true;break;}}if (!bFind){this->insertPlainText("\n\n" + sOrderNext);this->f_setCurrentCharFormat(m_headlineStyle.mainBody().getTextCharFormat(true, true));}}else  //-----------------找不到标记{//gce::D("222222222222222222222222222222");//如果当前行是缩进的,那么下一行也是缩进的_string sCopy = m_currentLineText.copyControlAndWhiteSpace();if (sCopy.length() > 0){this->insertPlainText(_t("\n") + sCopy);}}}else{//gce::D("333333333333333333333333333333");//如果当前行是缩进的,那么下一行也是缩进的_string sCopy = m_currentLineText.copyControlAndWhiteSpace();if (sCopy.length() > 0){this->insertPlainText(_t("\n") + sCopy);}}}else //--------------------------------------------当前行含有序号,不用再查找 {//重新设置加粗 或者 加粗重设一遍this->f_setCurrLineTextStyle(m_headlineStyle.orderNumber().getTextCharFormat(true, true), sCurrLineOrder);//这里要设为默认字体     this->f_setCurrentCharFormat(m_headlineStyle.mainBody().getTextCharFormat(true, true));_string sOrderNext = sCurrLineOrder.tryStrAndOne();bool bFind = false;//查找后面二十行的序号标记auto slBack = f_getLineListBackOfCursor(m_currentLineCount - 1);for (auto& s : slBack){if (s.getBook_序号标记().removeUnprintableAndWhitespace() ==sOrderNext.removeUnprintableAndWhitespace()){bFind = true;break;}}if (!bFind){this->insertPlainText(_t("\n\n") + sOrderNext);this->f_setCurrLineTextStyle(m_headlineStyle.orderNumber().getTextCharFormat(true, true), sOrderNext);this->f_setCurrentCharFormat(m_headlineStyle.mainBody().getTextCharFormat(true, true));}else  //序号标记已出现在下面,可能只是修改前面的内容。{//缩进 + sCurrLineOrder->Length + 空格_string sCopy = m_currentLineText.copyControlAndWhiteSpace();if (sCopy.length() > 0){_string s = _t("\n  ") + sCopy + _string().appendString(_t(" "), sCurrLineOrder.length());this->insertPlainText(s);}}//lg->D("1", this);                                         }}}}}else {int nSelectLength = m_currentLineText.findFirstPrintable();this->g_copyFormattedTextToNextLine(this, nSelectLength);}} }lock(false);*/
}bool my_QTextEdit::do_keyPressEvent_KeyBackspace(QKeyEvent* event)
{return default_do_keyPressEvent_KeyBackspace(event);
}bool my_QTextEdit::default_do_keyPressEvent_KeyBackspace(QKeyEvent* event)
{ static _Pair<int, int> pHistory;size_t oldLine = 0;/*auto s1 = m_currentLineText.getBook_序号标记();auto s2 = m_currentLineText.GetBook_序号标记2();auto s3 = m_currentLineText.getBook_特殊符号标记();auto s4 = m_currentLineText.getBook_章节标记();*///if(s1.length() == 0 && s2.length() == 0 && s2.length() == 0 && s3.length() == 0)QTextEdit::keyPressEvent(event);_string s = m_currentLineText.trim();if (m_currentLineCount != pHistory.first) {pHistory.first = m_currentLineCount;pHistory.second = 0;}// d.printInfo(_tostr(m_currentLineCount), "m_currentLineCount");//d.printInfo(_tostr(pHistory.second), "pHistory.second");if (s.length() == 0) { //如果全是空格,查10行以内if (f_scanSpecific()) {if (pHistory.first == m_currentLineCount && pHistory.second < 3) {g_setCurrentLineText(this, m_specificLineStart.second);++pHistory.second;return true;}}if (f_scanOrder()) {if (pHistory.first == m_currentLineCount && pHistory.second < 3) {this->f_setCurrLineTextStyle(m_headlineStyle.orderNumber().getTextCharFormat(true, true),m_orderLineStart.second.tryNumberAddOne());++pHistory.second;return true;}}//-----------------------------------------------------}else if(s.length() == 1){if (f_scanSpecific()) { //-----------------------------------------------在特殊符号区间/*bool bContainAnySpecial = false; //是否有特殊符号//全部是特殊符号或者是空格或者是控制字符if (m_currentLineText.isAllRules([&bContainAnySpecial, this](wchar_t& ch)->bool {if (gs.c_isControl(ch)) return true; //控制字符if (ch == ' ') return true;  //空格if (m_specificSymbol.indexOf(ch) != -1) {  //特殊字符ch = ' '; //用空格代替特殊符号bContainAnySpecial = true;return true;}return false;}) && bContainAnySpecial){g_setCurrentLineText(this, m_currentLineText);   return true;}*/if (pHistory.first == m_currentLineCount && pHistory.second < 3) {if (m_specificSymbol.indexOf(s[0]) != -1) {g_setCurrentLineText(this, m_currentLineText.replaceChar(s[0], ' '));++pHistory.second;return true;}}             }else if (f_scanOrder()) {//-----------------------------------------------在序号区间_string s = m_currentLineText.getBook_序号标记();if (s.length() + 1 >= m_currentLineText.length()) {if (s.indexOf('(') != -1) {_string tmp(s.length() + 4, ' ');this->f_setCurrLineText(tmp);}else {_string tmp(s.length() + 2, ' ');this->f_setCurrLineText(tmp);}}}}else if (s.length() < 2) {
#ifdef _D_//d.printInfo("m_currentLineText.trim() < 2", "bool my_QTextEdit::default_do_keyPressEvent_KeyBackspace(QKeyEvent * event)");
#endifthis->f_setCurrentCharFormat(m_headlineStyle.mainBody());}else if(s.length() < 3) {
#ifdef _D_//d.printInfo("m_currentLineText.trim() < 3", "bool my_QTextEdit::default_do_keyPressEvent_KeyBackspace(QKeyEvent * event)");
#endifthis->f_setCurrLineTextStyle(m_headlineStyle.mainBody());}else {}  return true;
}void my_QTextEdit::do_leftButtonClicked(QMouseEvent* e)
{default_do_leftButtonClicked(e);
}void my_QTextEdit::default_do_leftButtonClicked(QMouseEvent* e)
{if (this->m_currentLineText.trim().length() < 3) {this->setCurrentCharFormat(m_headlineStyle.mainBody().getTextCharFormat(true, true));return;}QFont f2 = m_headlineStyle.mainBody().font;QFont f1 = this->currentCharFormat().font();if (f1 != f2) {     return;   }  //已经设置过格式,退出_string sTag = m_currentLineText.getBook_章节标记();if (sTag.length() != 0){this->f_setCurrLineTextStyle(m_headlineStyle.bookSection().getTextCharFormat(true, true));}else {if (!this->f_setBook标题样式()) {this->f_setBook篇部分样式();}}       
}bool my_QTextEdit::do_keyPressEvent_Key_Tab(QKeyEvent* event)
{return default_do_keyPressEvent_Key_Tab(event);
}bool my_QTextEdit::default_do_keyPressEvent_Key_Tab(QKeyEvent* event)
{return f_indent(); 
}bool my_QTextEdit::do_keyPressEvent_Key_Backtab(QKeyEvent* event)
{return default_do_keyPressEvent_Key_Backtab(event);
}bool my_QTextEdit::default_do_keyPressEvent_Key_Backtab(QKeyEvent* event)
{return f_unindent();}void my_QTextEdit::do_textChanged()
{default_do_textChanged();
}void my_QTextEdit::default_do_textChanged()
{/*qint64 currentTime = m_timer.elapsed();//当文本改变后一秒钟,再次文本改变后触发下面代码。if (currentTime - m_lastFetchTime >= 1000) {  QString s = this->toPlainText();d.printInfo("void my_QTextEdit::default_do_textChanged()");m_lastFetchTime = currentTime;}   */}_LF_END__LF_#endif

相关文章:

  • 提示词模板设计:LangGPT的提示词设计框架
  • 《深度解析:如何打造高性能短剧平台?完整技术方案与行业实践》
  • 深入理解PHP中的面向对象编程
  • C3新增特性
  • ps外发光
  • Flink维表应用:从思考到实践的全面解析
  • Vue 中 filter 过滤的语法详解与注意事项
  • 项目上线(若依前后分离版)
  • ganymed-ssh2连接openssh 8.2
  • 没有产品说明书和需求文档的情况下能够进行黑盒测试吗?
  • 黑马python(十五)
  • Python异步爬虫编程技巧:从入门到高级实战指南
  • 爬虫002-----urllib标准库
  • 【GNSS软件接收机】【理论简介】Chapter.3 RAIM 和 FDE[2025年6月]
  • QML革命:下一代GUI开发的核心优势详解
  • Redis基本介绍
  • 速通KVM(云计算学习指南)
  • 【网络安全】DNS 域原理、危害及防御
  • 限制应用程序只能运行一个实例
  • 防火墙基本功能介绍
  • 网络培训的网站建设/如何开一个自己的网站
  • 租个国内服务器做网站多少钱/淘宝引流推广平台
  • 出口外贸交易平台/杭州seo网
  • 新沂做网站/seo技术最新黑帽
  • 手机网站可以做公众号/nba西部排名
  • 今日军事新闻联播在线播放/长沙百度快速优化