{"id":318758,"date":"2021-02-28T15:00:15","date_gmt":"2021-02-28T15:00:15","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=318758"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=318758","title":{"rendered":"\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 Qt"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a \u0432\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u043d\u0430 <strong>Qt<\/strong> \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0441 \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u043e\u0439 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0445 \u0441\u043b\u043e\u0432 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043c\u0435\u043d\u044b \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u044c <strong>hunspell<\/strong>.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3a9\/f8e\/715\/3a9f8e715de674bf54ef5567d7f5b24b.PNG\" width=\"403\" height=\"155\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u0438 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0445 \u0441\u043b\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 <strong>QSyntaxHighlighter<\/strong>, \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438 \u0432\u0432\u043e\u0434\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 <strong>QTextEdit<\/strong>. <\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 <strong>hunspell<\/strong>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0435\u0451 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 .pro \u0444\u0430\u0439\u043b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0443: <strong>LIBS += -lhunspell<\/strong>.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0432\u043e\u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 <strong>QSyntaxHighlighter<\/strong> \u0438 <strong>QTextEdit<\/strong>.<\/p>\n<p>\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0439 \u0444\u0430\u0439\u043b classes.h:<\/p>\n<pre><code class=\"cpp\">#ifndef CLASSES_H #define CLASSES_H #include &lt;QSyntaxHighlighter&gt; #include &lt;QTextEdit&gt;   class SpellingHighlighter : public QSyntaxHighlighter \/\/ \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 {     Q_OBJECT      public:     SpellingHighlighter(QTextEdit *parent) :QSyntaxHighlighter(parent) {}      protected:     virtual void highlightBlock(const QString &amp;text) override; };  class BodyTextEdit : public QTextEdit \/\/ \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0430 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 {     Q_OBJECT      public:     BodyTextEdit(QWidget* parent = 0);           public slots:     void openCustomMenu(QPoint);     void correctWord(QAction * act);      protected:     SpellingHighlighter * m_highLighter; }; #endif \/\/ CLASSES_H<\/code><\/pre>\n<p>\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435, \u0430 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0437\u0430\u043c\u0435\u043d\u044b. \u0414\u0430\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u0434\u0435\u043b\u0430\u043d\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <a href=\"https:\/\/intmaker.com\/spellchecking-desktop-application-in-c\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0430\u0442\u044c\u0438<\/a>, \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u043e\u0439 \u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0430\u0445 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430.<\/p>\n<pre><code class=\"cpp\">\/\/ correct - \u0444\u043b\u0430\u0433 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043b\u0438 \u0441\u043b\u043e\u0432\u043e, getSuggests - \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043b\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0445 \u0441\u043b\u043e\u0432 QStringList suggestCorrections(const QString &amp;word, bool &amp;correct, bool getSuggests = false) {     static Hunspell * m_hunSpell = new Hunspell(\"\/usr\/share\/hunspell\/ru_RU.aff\", \"\/usr\/share\/hunspell\/ru_RU.dic\");\/\/\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b \u0434\u043b\u044f debian     static QString  encoderStr = QString::fromLatin1( m_hunSpell-&gt;get_dic_encoding());\/\/ \u041c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043a\u043e\u0434\u0435\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 KOI8-R      static QTextCodec * m_codec = QTextCodec::codecForName(encoderStr.toLatin1().constData());      correct = m_hunSpell-&gt;spell(m_codec-&gt;fromUnicode(word).constData()) != 0; \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0435\u0441\u0442\u044c \u043b\u0438 \u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435     if (getSuggests == false)         return QStringList();     QStringList suggestions;     char **suggestWordList = NULL;      try {         \/\/ Encode from Unicode to the encoding used by current dictionary         int count = m_hunSpell-&gt;suggest(&amp;suggestWordList, m_codec-&gt;fromUnicode(word).constData());\/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432         QString lowerWord = word.toLower();          for (int i = 0; i &lt; count; ++i) {             QString suggestion = m_codec-&gt;toUnicode(suggestWordList[i]);             suggestions &lt;&lt; suggestion;             free(suggestWordList[i]);         }     }     catch(...)     {         qDebug() &lt;&lt;\"Error keyword\";     }     return suggestions; } <\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043b\u0430\u0441\u0441\u044b \u0438 \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e:<\/p>\n<pre><code class=\"cpp\">#include &lt;QSyntaxHighlighter&gt; #include &lt;QCompleter&gt; #include &lt;QTextCodec&gt; #include &lt;QAction&gt; #include &lt;QTextEdit&gt; #include &lt;QMenu&gt; #include \"hunspell\/hunspell.hxx\" \/\/ from package libhunspell-dev #include &lt;QDebug&gt; #include \"classes.h\"  \/\/\u041e\u043f\u0438\u0441\u0430\u043d\u043d\u0430\u044f \u0447\u0443\u0442\u044c \u0432\u044b\u0448\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f  QStringList suggestCorrections(const QString &amp;word, bool &amp;correct, bool getSuggests = false) {     static Hunspell * m_hunSpell = new Hunspell(\"\/usr\/share\/hunspell\/ru_RU.aff\", \"\/usr\/share\/hunspell\/ru_RU.dic\");     static QString  encoderStr = QString::fromLatin1( m_hunSpell-&gt;get_dic_encoding());     static QTextCodec * m_codec = QTextCodec::codecForName(encoderStr.toLatin1().constData());      correct = m_hunSpell-&gt;spell(m_codec-&gt;fromUnicode(word).constData()) != 0;     if (getSuggests == false)         return QStringList();     QStringList suggestions;     char **suggestWordList = NULL;      try {         \/\/ Encode from Unicode to the encoding used by current dictionary         int count = m_hunSpell-&gt;suggest(&amp;suggestWordList, m_codec-&gt;fromUnicode(word).constData());         QString lowerWord = word.toLower();          for (int i = 0; i &lt; count; ++i) {             QString suggestion = m_codec-&gt;toUnicode(suggestWordList[i]);             suggestions &lt;&lt; suggestion;             free(suggestWordList[i]);         }     }     catch(...)     {         qDebug() &lt;&lt;\"Error keyword\";     }     return suggestions; }  \/\/ \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 void SpellingHighlighter::highlightBlock(const QString &amp;text) {     QStringList list = text.split(QRegExp(\"\\\\s+\"), QString::KeepEmptyParts);\/\/\u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u043e\u0438\u0441\u043a\u0443 \u0441\u043b\u043e\u0432     QTextCharFormat spellingFormat;\/\/\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u0430     spellingFormat.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);     spellingFormat.setUnderlineColor(Qt::red);     int count_word = list.size();     int pointer = 0;     for (int i= 0; i&lt; count_word; i++)     {         bool correct = false;         QString sect = text.section(QRegExp(\"\\\\s+\"), i, i, QString::SectionIncludeLeadingSep);         sect.remove(QRegExp(\"[,!?&amp;*|]\"));\/\/ \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043b\u0438\u0448\u043d\u0438\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b         suggestCorrections(sect, correct);\/\/\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043b\u0438 \u0441\u043b\u043e\u0432\u043e         if (!correct)         {             setFormat(pointer, sect.length(),spellingFormat);         }         pointer += sect.length();     } };   BodyTextEdit::BodyTextEdit(QWidget* parent ) : QTextEdit(parent) {     this-&gt;setContextMenuPolicy(Qt::CustomContextMenu);     m_highLighter = new SpellingHighlighter(this);     connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(openCustomMenu(QPoint))); }  \/\/\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e \u0441 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u043c\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u043c\u0438 \u0437\u0430\u043c\u0435\u043d\u044b void BodyTextEdit::openCustomMenu(QPoint pos) {     QMenu* popupmenu = this-&gt;createStandardContextMenu();     QTextCursor cursor = this-&gt;textCursor();     cursor.select(QTextCursor::WordUnderCursor);     this-&gt;setTextCursor(cursor);     if (this-&gt;textCursor().hasSelection())     {         QString text = this-&gt;textCursor().selectedText();         bool correct = false;         QStringList suggest = suggestCorrections(text, correct, true);         auto firstAction = popupmenu-&gt;actions().first();         if (!correct)         {             QList&lt;QAction*&gt; addedActions;             for (auto word  : suggest)             {                 QAction * act = new QAction(word, popupmenu);                 act-&gt;setData(word);                 addedActions.append(act);             }             popupmenu-&gt;insertActions(firstAction, addedActions);             connect(popupmenu, SIGNAL(triggered(QAction*)), this, SLOT(correctWord(QAction*)));         }     }     popupmenu-&gt;exec(this-&gt;mapToGlobal(pos));     delete popupmenu; }  \/\/\u0417\u0430\u043c\u0435\u043d\u0430 \u0441\u043b\u043e\u0432\u0430 \u043d\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435 \u0432 \u043c\u0435\u043d\u044e void BodyTextEdit::correctWord(QAction *act) {     if (act-&gt;data().isNull())         return;     QString word = act-&gt;data().toString();     QTextCursor cursor = this-&gt;textCursor();     cursor.beginEditBlock();      cursor.removeSelectedText();     cursor.insertText(word);     cursor.endEditBlock(); } <\/code><\/pre>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:<\/h2>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0437\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 150 \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430 \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043f\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0432\u0430\u0448\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043d\u0430 Qt \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/544650\/\"> https:\/\/habr.com\/ru\/post\/544650\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u043a\u0430\u043a \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a \u0432\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u043d\u0430 <strong>Qt<\/strong> \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0441 \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u043e\u0439 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0445 \u0441\u043b\u043e\u0432 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043c\u0435\u043d\u044b \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u044c <strong>hunspell<\/strong>.<\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u0438 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0445 \u0441\u043b\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 <strong>QSyntaxHighlighter<\/strong>, \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438 \u0432\u0432\u043e\u0434\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 <strong>QTextEdit<\/strong>. <\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 <strong>hunspell<\/strong>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0435\u0451 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 .pro \u0444\u0430\u0439\u043b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0443: <strong>LIBS += -lhunspell<\/strong>.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0432\u043e\u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 <strong>QSyntaxHighlighter<\/strong> \u0438 <strong>QTextEdit<\/strong>.<\/p>\n<p>\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0439 \u0444\u0430\u0439\u043b classes.h:<\/p>\n<pre><code class=\"cpp\">#ifndef CLASSES_H #define CLASSES_H #include &lt;QSyntaxHighlighter&gt; #include &lt;QTextEdit&gt;   class SpellingHighlighter : public QSyntaxHighlighter \/\/ \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 {     Q_OBJECT      public:     SpellingHighlighter(QTextEdit *parent) :QSyntaxHighlighter(parent) {}      protected:     virtual void highlightBlock(const QString &amp;text) override; };  class BodyTextEdit : public QTextEdit \/\/ \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0430 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 {     Q_OBJECT      public:     BodyTextEdit(QWidget* parent = 0);           public slots:     void openCustomMenu(QPoint);     void correctWord(QAction * act);      protected:     SpellingHighlighter * m_highLighter; }; #endif \/\/ CLASSES_H<\/code><\/pre>\n<p>\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435, \u0430 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0437\u0430\u043c\u0435\u043d\u044b. \u0414\u0430\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u0434\u0435\u043b\u0430\u043d\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <a href=\"https:\/\/intmaker.com\/spellchecking-desktop-application-in-c\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0430\u0442\u044c\u0438<\/a>, \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u043e\u0439 \u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0430\u0445 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430.<\/p>\n<pre><code class=\"cpp\">\/\/ correct - \u0444\u043b\u0430\u0433 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043b\u0438 \u0441\u043b\u043e\u0432\u043e, getSuggests - \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043b\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0445 \u0441\u043b\u043e\u0432 QStringList suggestCorrections(const QString &amp;word, bool &amp;correct, bool getSuggests = false) {     static Hunspell * m_hunSpell = new Hunspell(\"\/usr\/share\/hunspell\/ru_RU.aff\", \"\/usr\/share\/hunspell\/ru_RU.dic\");\/\/\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b \u0434\u043b\u044f debian     static QString  encoderStr = QString::fromLatin1( m_hunSpell-&gt;get_dic_encoding());\/\/ \u041c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043a\u043e\u0434\u0435\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 KOI8-R      static QTextCodec * m_codec = QTextCodec::codecForName(encoderStr.toLatin1().constData());      correct = m_hunSpell-&gt;spell(m_codec-&gt;fromUnicode(word).constData()) != 0; \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0435\u0441\u0442\u044c \u043b\u0438 \u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435     if (getSuggests == false)         return QStringList();     QStringList suggestions;     char **suggestWordList = NULL;      try {         \/\/ Encode from Unicode to the encoding used by current dictionary         int count = m_hunSpell-&gt;suggest(&amp;suggestWordList, m_codec-&gt;fromUnicode(word).constData());\/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432         QString lowerWord = word.toLower();          for (int i = 0; i &lt; count; ++i) {             QString suggestion = m_codec-&gt;toUnicode(suggestWordList[i]);             suggestions &lt;&lt; suggestion;             free(suggestWordList[i]);         }     }     catch(...)     {         qDebug() &lt;&lt;\"Error keyword\";     }     return suggestions; } <\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043b\u0430\u0441\u0441\u044b \u0438 \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e:<\/p>\n<pre><code class=\"cpp\">#include &lt;QSyntaxHighlighter&gt; #include &lt;QCompleter&gt; #include &lt;QTextCodec&gt; #include &lt;QAction&gt; #include &lt;QTextEdit&gt; #include &lt;QMenu&gt; #include \"hunspell\/hunspell.hxx\" \/\/ from package libhunspell-dev #include &lt;QDebug&gt; #include \"classes.h\"  \/\/\u041e\u043f\u0438\u0441\u0430\u043d\u043d\u0430\u044f \u0447\u0443\u0442\u044c \u0432\u044b\u0448\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f  QStringList suggestCorrections(const QString &amp;word, bool &amp;correct, bool getSuggests = false) {     static Hunspell * m_hunSpell = new Hunspell(\"\/usr\/share\/hunspell\/ru_RU.aff\", \"\/usr\/share\/hunspell\/ru_RU.dic\");     static QString  encoderStr = QString::fromLatin1( m_hunSpell-&gt;get_dic_encoding());     static QTextCodec * m_codec = QTextCodec::codecForName(encoderStr.toLatin1().constData());      correct = m_hunSpell-&gt;spell(m_codec-&gt;fromUnicode(word).constData()) != 0;     if (getSuggests == false)         return QStringList();     QStringList suggestions;     char **suggestWordList = NULL;      try {         \/\/ Encode from Unicode to the encoding used by current dictionary         int count = m_hunSpell-&gt;suggest(&amp;suggestWordList, m_codec-&gt;fromUnicode(word).constData());         QString lowerWord = word.toLower();          for (int i = 0; i &lt; count; ++i) {             QString suggestion = m_codec-&gt;toUnicode(suggestWordList[i]);             suggestions &lt;&lt; suggestion;             free(suggestWordList[i]);         }     }     catch(...)     {         qDebug() &lt;&lt;\"Error keyword\";     }     return suggestions; }  \/\/ \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 void SpellingHighlighter::highlightBlock(const QString &amp;text) {     QStringList list = text.split(QRegExp(\"\\\\s+\"), QString::KeepEmptyParts);\/\/\u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u043e\u0438\u0441\u043a\u0443 \u0441\u043b\u043e\u0432     QTextCharFormat spellingFormat;\/\/\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u0430     spellingFormat.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);     spellingFormat.setUnderlineColor(Qt::red);     int count_word = list.size();     int pointer = 0;     for (int i= 0; i&lt; count_word; i++)     {         bool correct = false;         QString sect = text.section(QRegExp(\"\\\\s+\"), i, i, QString::SectionIncludeLeadingSep);         sect.remove(QRegExp(\"[,!?&amp;*|]\"));\/\/ \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043b\u0438\u0448\u043d\u0438\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b         suggestCorrections(sect, correct);\/\/\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043b\u0438 \u0441\u043b\u043e\u0432\u043e         if (!correct)         {             setFormat(pointer, sect.length(),spellingFormat);         }         pointer += sect.length();     } };   BodyTextEdit::BodyTextEdit(QWidget* parent ) : QTextEdit(parent) {     this-&gt;setContextMenuPolicy(Qt::CustomContextMenu);     m_highLighter = new SpellingHighlighter(this);     connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(openCustomMenu(QPoint))); }  \/\/\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e \u0441 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u043c\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u043c\u0438 \u0437\u0430\u043c\u0435\u043d\u044b void BodyTextEdit::openCustomMenu(QPoint pos) {     QMenu* popupmenu = this-&gt;createStandardContextMenu();     QTextCursor cursor = this-&gt;textCursor();     cursor.select(QTextCursor::WordUnderCursor);     this-&gt;setTextCursor(cursor);     if (this-&gt;textCursor().hasSelection())     {         QString text = this-&gt;textCursor().selectedText();         bool correct = false;         QStringList suggest = suggestCorrections(text, correct, true);         auto firstAction = popupmenu-&gt;actions().first();         if (!correct)         {             QList&lt;QAction*&gt; addedActions;             for (auto word  : suggest)             {                 QAction * act = new QAction(word, popupmenu);                 act-&gt;setData(word);                 addedActions.append(act);             }             popupmenu-&gt;insertActions(firstAction, addedActions);             connect(popupmenu, SIGNAL(triggered(QAction*)), this, SLOT(correctWord(QAction*)));         }     }     popupmenu-&gt;exec(this-&gt;mapToGlobal(pos));     delete popupmenu; }  \/\/\u0417\u0430\u043c\u0435\u043d\u0430 \u0441\u043b\u043e\u0432\u0430 \u043d\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435 \u0432 \u043c\u0435\u043d\u044e void BodyTextEdit::correctWord(QAction *act) {     if (act-&gt;data().isNull())         return;     QString word = act-&gt;data().toString();     QTextCursor cursor = this-&gt;textCursor();     cursor.beginEditBlock();      cursor.removeSelectedText();     cursor.insertText(word);     cursor.endEditBlock(); } <\/code><\/pre>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:<\/h2>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0437\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 150 \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430 \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043f\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0432\u0430\u0448\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043d\u0430 Qt \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/544650\/\"> https:\/\/habr.com\/ru\/post\/544650\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-318758","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/318758","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=318758"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/318758\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=318758"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=318758"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=318758"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}