wxWidgets使用wxStyledTextCtrl(Scintilla編輯器)的正確姿勢

開發CuteMySQL/CuteSqlite開源客戶端的時候,需要使用Scintilla編輯器,來高亮顯示SQL語句,作為C/C++領域最成熟穩定又小巧的開源編輯器,Scintilla提供了強大的功能,wxWidgets對Scintilla進行包裝后的是控件類:wxStyledTextCtrl。下面我們用正確的姿勢來打開使用它。

先看下效果:

我們對該SQL編輯器的需求是:

1.顯示行號

2.SQL語法高亮

3.輸入SQL智能提示

4.適配DARK風格

好的,我們直接看下源碼,程序員還是代碼說話,其他都是廢話,不多說了。

一、聲明wxStyledTextCtrl的子類QSqlEditor

#pragma once
#include <wx/stc/stc.h>
#include <vector>class QSqlEditor : public wxStyledTextCtrl
{...// 重要函數一:初始化編輯器,適配SQL語法,高亮,行號等void setupSqlSyntax(int nSize, const char* face);// 重要函數二:自動彈出智能提示,參數tags為表名,視圖,字段名,函數,存儲過程等void autoShow(const std::vector<std::string> & tags);// 重要函數三:自動替換光標當前單詞void autoReplaceWord();private:......};

二、初始化編輯器,適配SQL語法


void QSqlEditor::setupSqlSyntax(int nSize, const char* face)
{// - lex setup (lex語法解釋器配置)SetLexer(wxSTC_LEX_SQL); // 選擇SQL解釋器// Divide each styling byte into lexical class bits (default: 5) and indicator// bits (default: 3). If a lexer requires more than 32 lexical states, then this// is used to expand the possible states.// 將每個樣式字節劃分為詞法類位(默認值:5)和指示符位(默認值:3)。// 如果詞法分析器需要超過 32 個詞法狀態,則用于擴展可能的狀態。// SetStyleBitsEx(5);StyleSetForeground(wxSTC_STYLE_DEFAULT, wxColour(255, 0, 0)); // 編輯器的文本默認的前景色(文本默認的顏色)StyleSetBackground(wxSTC_STYLE_DEFAULT, bkgColor); // 編輯器默認的背景色StyleClearAll(); // 清理編輯器所有的樣式// - OtherSetIndent(4); // 縮進4字符SetIndentationGuides(wxSTC_IV_LOOKBOTH); // 顯示或隱藏縮進參考線UsePopUpEx(true); // 設置當用戶在某些區域上按錯鼠標按鈕時是否自動顯示彈出菜單// Error markerMarkerDefine(0, wxSTC_MARK_ARROW); // 設置用于箭頭標記編號的符號,以及(可選)前景色(第三參數)和背景色(第四參數)MarkerSetBackground(0, wxColour(255, 255, 255)); // 設置第0個Marker的背景色MarkerSetForeground(0, wxColour(0, 0, 0)); // 設置第0個Marker的前景色// Font And Size 編輯器的字體和大小wxFont font(wxSize(0, nSize), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, face);StyleSetFont(wxSTC_STYLE_DEFAULT, font);StyleSetSize(wxSTC_STYLE_DEFAULT, nSize);// - Margins// number margin SetMarginType(0, wxSTC_MARGIN_NUMBER); // 行號邊距,將邊距設置為數字。此處設置第0個邊距是行號數字SetMarginWidth(0, 37); // 設置邊距寬度,第0個邊距邊寬// SetMarginBackground(0, bkgColor); // 注意,這里不生效的原因是SetMarginBackground只對SC_MARGIN_COLOUR類型的margin生效,這里第0邊距是wxSTC_MARGIN_NUMBER// folding margin 折疊線邊距SetMarginMask(1, wxSTC_MASK_FOLDERS);  // 設置第2個邊距為折疊標記SetMarginWidth(1, 12); // 設置邊距寬度,第2個邊距邊寬SetMarginSensitive(1, true); // 使第2個邊距對鼠標單擊敏感或不敏感。// - Choose folding icons 選擇折疊的小圖標MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS); // 定義折疊線打開的圖標:方框減號MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS); // 定義折疊線收縮的圖標:方框加號MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE); // 定義子折疊線:VLINEMarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER); // 定義折疊線結束的圖標:L型拐角MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUSCONNECTED); // 定義折疊線結束的圖標:方框加號連接MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUSCONNECTED); // 定義折疊線打開中間的圖標:方框減號連接MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_LCORNERCURVE); // 定義折疊線中間收尾的圖標:T型拐角曲線// - Choose folding icon colours 選擇折疊的小圖標顏色MarkerSetForeground(wxSTC_MARKNUM_FOLDEROPEN, textColor); // 設置折疊線打開小圖標的前景色MarkerSetBackground(wxSTC_MARKNUM_FOLDEROPEN, bkgColor); // 設置折疊線打開小圖標的背景色MarkerSetForeground(wxSTC_MARKNUM_FOLDER, textColor); // 設置折疊線收縮小圖標的前景色MarkerSetBackground(wxSTC_MARKNUM_FOLDER, bkgColor); // 設置折疊線收縮小圖標的背景色MarkerSetForeground(wxSTC_MARKNUM_FOLDERSUB, textColor); // 設置子折疊線的背景色MarkerSetBackground(wxSTC_MARKNUM_FOLDERSUB, textColor); // 設置子折疊線的背景色MarkerSetForeground(wxSTC_MARKNUM_FOLDERTAIL, textColor); // 設置折疊線收縮結束小圖標的背景色MarkerSetBackground(wxSTC_MARKNUM_FOLDERTAIL, textColor); // 設置折疊線收縮結束小圖標的背景色MarkerSetForeground(wxSTC_MARKNUM_FOLDEREND, textColor); // 設置折疊線結束小圖標的前景色MarkerSetBackground(wxSTC_MARKNUM_FOLDEREND, bkgColor); // 設置折疊線結束小圖標的背景色MarkerSetForeground(wxSTC_MARKNUM_FOLDEROPENMID, textColor); // 設置折疊線打開中間小圖標的前景色MarkerSetBackground(wxSTC_MARKNUM_FOLDEROPENMID, bkgColor); // 設置折疊線打開中間小圖標的背景色MarkerSetForeground(wxSTC_MARKNUM_FOLDERMIDTAIL, textColor); // 設置折疊線中間收尾的小圖標的前景色MarkerSetBackground(wxSTC_MARKNUM_FOLDERMIDTAIL, textColor); // 設置折疊線中間收尾的小圖標的背景色// 行號文本顏色,僅僅對SetMarginType(0, wxSTC_MARGIN_NUMBER);起作用StyleSetForeground(wxSTC_STYLE_LINENUMBER, textColor);// 行號背景顏色	StyleSetBackground(wxSTC_STYLE_LINENUMBER, bkgColor2);// 折疊邊背景色SetFoldMarginHiColour(true, bkgColor2);SetFoldMarginColour(true, bkgColor2);// - Set carlet 光標// Color of Carlet 光標的顏色SetCaretForeground(wxColour(0x00CEC0D6));// Width of Carlet 光標大小SetCaretWidth(2);// set the caret blinking time to 400 milliseconds 光標閃爍間隔SetCaretPeriod(400);// - Set caret line colour (設置光標所處行的顏色)SetCaretLineBackground(wxColour(38, 40, 46)); // 光標所處行的背景色SetCaretLineVisible(true); // 顯示光標所處行// - Comment block (注釋塊)StyleSetForeground(wxSTC_SQL_DEFAULT, wxColour(0, 0, 0)); // 默認SQL的前景色StyleSetForeground(wxSTC_SQL_COMMENT, wxColour(32768)); // SQL注釋的前景色// - Single comment line (注釋行)StyleSetForeground(wxSTC_SQL_COMMENTLINE, wxColour(32768)); // 默認SQL注釋的前景色// - SQL number 數字StyleSetForeground(wxSTC_SQL_NUMBER, wxColour(0x002AACB8)); // SQL數字的前景色StyleSetBold(wxSTC_SQL_NUMBER, true); // SQL數字加粗// - SQL string/operator/identifier (字符串/操作符/標識符)StyleSetForeground(wxSTC_SQL_STRING, wxColour(0x00cc99ff)); // SQL字符串的前景色StyleSetForeground(wxSTC_SQL_CHARACTER, wxColour(0x00cc99ff)); // SQL字符的前景色StyleSetForeground(wxSTC_SQL_OPERATOR, wxColour(0x00BCBEC4)); // SQL操作符的前景色StyleSetBold(wxSTC_SQL_OPERATOR, true); // SQL操作符加粗StyleSetForeground(wxSTC_SQL_IDENTIFIER, wxColour(0x00BCBEC4));// SQL標識符的前景色// - Color Of Selection (選中的顏色)SetSelBackground(true, wxColour(49, 106, 197)); // 選中項啟用并設置背景色SetSelForeground(true, wxColour(255, 255, 255)); // 選中項啟用并設置前景色// Set KeywordswxString keywords(sqlKeyWords);SetKeyWords(0, keywords);// Color Of KeywordStyleSetForeground(wxSTC_SQL_WORD, wxColour(0x00ff9966)); // 0x00CF8E6DStyleSetForeground(wxSTC_SQL_WORD2, wxColour(0x00ff9966));StyleSetForeground(wxSTC_SQL_USER1, wxColour(0x00ff9966));// 自動停頓的字符AutoCompStops(autoStopChars);// ignore the cmd key for CTRL+[key] 忽略CTRL+[key]int  n = static_cast<int>(sizeof(ignoreCtrlKey));for (int i = 0; i < n; i++) {CmdKeyClear(ignoreCtrlKey[i], wxSTC_KEYMOD_CTRL);}// Working Fold SetProperty("fold", "1");SetProperty("fold.compact", "1");SetProperty("fold.html", "1");SetProperty("fold.html.preprocessor", "1");SetProperty("fold.comment", "1");SetProperty("fold.at.else", "1");SetProperty("fold.flags", "1");SetProperty("fold.preprocessor", "1");SetProperty("styling.within.preprocessor", "1");// set tab width to 4SetTabWidth(4);
}

上述初始化代碼實現了SQL語法高亮,行號,折疊線,以及適配DARK風格的功能。因此我們的4個需求已經實現了3個,下面我們再用代碼實現智能提示。

三、智能提示

智能提示,我們首先需要一個外層QSqlEditor的類QueryPageEditor,該類主要的作用:

1.創建編輯器,并顯示到界面上。

2.捕捉QSqlEditor的各類事件。

3.調用QSqlEditor::autoShow函數,實現智能提示。

我們通過捕捉wxStyledTextCtrl的EVT_STC_AUTOCOMP_SELECTION事件,來實現智能提示。聲明的代碼簡略如下:

class QueryPageEditor :  public QPanel<DatabaseSupplier>
{DECLARE_EVENT_TABLE()
public:...
private:...// 編輯器QSqlEditor* editor;// 創建編輯器void createEditor();// 響應EVT_STC_CHARADDED字符輸入,智能提示void OnStcCharAdded(wxStyledTextEvent& event);// 響應EVT_STC_AUTOCOMP_SELECTION,自動替換當前單詞void OnAutoCSelection(wxStyledTextEvent& event);
}// 事件表
BEGIN_EVENT_TABLE(QueryPageEditor, wxPanel)...EVT_STC_CHARADDED(Config::DATABASE_QUERY_EDITOR_ID, OnStcCharAdded) // 字符輸入 EVT_STC_AUTOCOMP_SELECTION(Config::DATABASE_QUERY_EDITOR_ID, OnAutoCSelection) // 提示選擇...
END_EVENT_TABLE()// 創建創建編輯器
void QueryPageEditor::createEditor()
{...editor = new QSqlEditor();editor->Create(this, Config::DATABASE_QUERY_EDITOR_ID, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxCLIP_CHILDREN);editor->setup(12, FN("Courier New").c_str());editor->SetFocus();...
}// 響應EVT_STC_CHARADDED字符輸入,智能提示
void QueryPageEditor::OnStcCharAdded(wxStyledTextEvent& event)
{wxString line, preline, word;line = editor->GetCurLine();if (line.empty()) {return ;}preline = editor->getPrePositionTextOfCurLine();word = editor->getCurWord();size_t curPosInLine = editor->getCurPosInLine();std::vector<std::string> tags = delegate->getTags(line.ToStdString(), preline.ToStdString(), word.ToStdString(), curPosInLine);editor->autoShow(tags);
}// 響應EVT_STC_AUTOCOMP_SELECTION,自動替換當前單詞
void QueryPageEditor::OnAutoCSelection(wxStyledTextEvent& event)
{wxString selText = editor->GetSelectedText();if (selText.empty()) {editor->autoReplaceWord();return;}if ((char)selText.at(0) == '<' && (char)selText.Last() == '>') {editor->autoReplaceSelectTag();return;}editor->autoReplaceWord();
}

?然后我們再看下上述類調用兩個編輯器實現的函數:

editor->autoShow(tags); // 參數tags : 要提示的單詞,比如表名,函數,字段名等

editor->autoReplaceWord(); // 自動替換光標當前的單詞

// 自動提示,參數tags : 要提示的單詞,比如表名,函數,字段名等
void QSqlEditor::autoShow(const std::vector<std::string>& tags)
{if (tags.empty()) {return;}size_t n = tags.size();size_t sum = 0;std::for_each(tags.begin(), tags.end(), [&sum](const std::string& str) {sum += str.size();});char* itemList = new char[tags.size() + sum];memset(itemList, 0, tags.size() + sum);char * ptr = itemList;for (size_t i = 0; i < n; i++) {std::string tag = tags.at(i);if (i < n - 1) {tag += separator;}memcpy(ptr, tag.c_str(), tag.size());ptr += tag.size();}AutoCompSetSeparator(separator);AutoCompSetIgnoreCase(true);AutoCompSetCaseInsensitiveBehaviour(1);AutoCompStops(autoStopChars);AutoCompShow(0, itemList);delete[] itemList;
}//  自動替換光標當前的單詞
void QSqlEditor::autoReplaceWord()
{int curPos = GetCurrentPos();int start = WordStartPosition(curPos, true);int end = WordEndPosition(curPos, true);SetSelection(start, end);wxString text = AutoCompGetCurrentText();replaceSelText(text);AutoCompCancel();
}

好了,最后一個需求:輸入SQL智能提示,也完成了。?

四, 完整代碼:

Github - 類QSqlEditor代碼icon-default.png?t=O83Ahttps://github.com/CuteBitSoft/CuteMySQL/tree/master/src/ui/common/editor

Github - 類QueryPageEditor代碼icon-default.png?t=O83Ahttps://github.com/CuteBitSoft/CuteMySQL/tree/master/src/ui/database/rightview/page/editor

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/63683.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63683.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63683.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

構建高性能異步任務引擎:FastAPI + Celery + Redis

在現代應用開發中&#xff0c;異步任務處理是一個常見的需求。無論是數據處理、圖像生成&#xff0c;還是復雜的計算任務&#xff0c;異步執行都能顯著提升系統的響應速度和吞吐量。今天&#xff0c;我們將通過一個實際項目&#xff0c;探索如何使用 FastAPI、Celery 和 Redis …

介紹 Html 和 Html 5 的關系與區別

HTML&#xff08;HyperText Markup Language&#xff09;是構建網頁的標準標記語言&#xff0c;而 HTML5 是 HTML 的最新版本&#xff0c;包含了一些新的功能、元素、API 和屬性。HTML5 相對于早期版本的 HTML&#xff08;比如 HTML4&#xff09;有許多重要的改進和變化。以下是…

【win10+RAGFlow+Ollama】搭建本地大模型助手(教程+源碼)

一、RAGFlow簡介 RAGFlow是一個基于對文檔深入理解的開源RAG&#xff08;Retrieval-augmented Generation&#xff0c;檢索增強生成&#xff09;引擎。 主要作用&#xff1a; 讓用戶創建自有知識庫&#xff0c;根據設定的參數對知識庫中的文件進行切塊處理&#xff0c;用戶向大…

qwt 之 QwtPlotPicker

QwtPlotMarker 和 QwtPlotPicker 是 Qwt 庫中用于增強 QwtPlot 功能的兩個重要類。它們分別用于在圖中添加標記和實現交互式的選擇或拖動功能。 QwtPlotPicker 提供了交互式的選擇工具&#xff0c;它允許用戶通過鼠標點擊或拖動來選擇圖表中的數據點或區域。這對于實現縮放、平…

C/C++圣誕樹

系列文章 序號直達鏈接1C/C愛心代碼2C/C跳動的愛心3C/C李峋同款跳動的愛心代碼4C/C滿屏飄字表白代碼5C/C大雪紛飛代碼6C/C煙花代碼7C/C黑客帝國同款字母雨8C/C櫻花樹代碼9C/C奧特曼代碼10C/C精美圣誕樹11C/C俄羅斯方塊12C/C貪吃蛇13C/C孤單又燦爛的神-鬼怪14C/C閃爍的愛心15C…

lua dofile 傳參數

cat 1.lua arg[1] 111 arg[2] 222 dofile(./2.lua) cat 2.lua print("First argument is: " .. arg[1]) print("Second argument is: " .. arg[2]) 執行 lua 1.lua&#xff0c;結果為&#xff1a; First argument is: 111 Second argument is: 222 l…

電商數據流通的未來:API接口的智能化與自動化趨勢

在數字化時代&#xff0c;電子商務行業正在以前所未有的速度發展&#xff0c;而API&#xff08;應用程序編程接口&#xff09;接口作為電商領域的重要組成部分&#xff0c;其應用和發展趨勢也日益受到關注。API接口作為電商系統與外部服務或平臺交互的橋梁&#xff0c;對電商數…

投標心態:如何在“標海戰術”中保持清醒的頭腦?

在競爭激烈的市場環境下&#xff0c;“標海戰術”——即大規模參與投標——已經成為許多企業爭取市場份額的重要策略。然而&#xff0c;盲目追求投標數量可能導致資源浪費、團隊疲勞以及戰略目標的模糊化。在這種高強度的競爭模式中&#xff0c;如何保持清醒的頭腦&#xff0c;…

【蒼穹外賣】學習心得體會-隨筆

前言 寫了很久&#xff0c;終于可以完整運行項目了&#xff0c;記錄下這幾天的心得體會回顧一下知識點 第一天、Git 分布式版本控制工具 一、Git概述 定義&#xff1a;是分布式版本控制工具&#xff0c;用于管理軟件開發中的源代碼文件&#xff0c;像Java類、xml文件、html…

windows C#-使用構造函數

實例化類或結構時&#xff0c;將會調用其構造函數。 構造函數與該類或結構具有相同名稱&#xff0c;并且通常初始化新對象的數據成員。 在下面的示例中&#xff0c;通過使用簡單構造函數定義了一個名為 Taxi 的類。 然后使用 new 運算符對該類進行實例化。 在為新對象分配內存…

研發效能DevOps: Vite 使用 Element Plus

目錄 一、實驗 1.環境 2.初始化前端項目 3.安裝 vue-route 4.安裝 pinia 5.安裝 axios 6.安裝 Element Plus 7.gitee創建工程 8. 配置路由映射 9.Vite 使用 Element Plus 二、問題 1.README.md 文檔推送到gitee未自動換行 2.訪問login頁面顯示空白 3.表單輸入賬戶…

5G 模組 RG500Q常用AT命令

5G 模組 RG500Q常用AT命令 5G 模組 RG500Q常用AT命令 at ATQNWPREFCFG\"mode_pref\",nr5g && sleep 1 at ATQNWPREFCFG\"nr5g_band\",79 && sleep 1 at atqnwlock\"commo…

NVIDIA DeepStream插件之Gst-nvtracker

NVIDIA DeepStream插件之Gst-nvtracker 1. 源由2. 基礎知識3. Gst-nvtracker插件3.1 插件參數3.2 插件API接口 4. 分析問題5. 總結6. 參考資料 1. 源由 這篇的主要目的是稍微吐槽下NVIDIA的設計&#xff0c;當然其實他們做的還是不錯的&#xff08;從系統架構設計角度看&#…

進程內存轉儲工具|內存鏡像提取-取證工具

1.內存轉儲&#xff0c;內存轉儲&#xff08;Memory Dump&#xff09;是將計算機的物理內存&#xff08;RAM&#xff09;內容復制到一個文件中的過程&#xff0c;這個文件通常被稱為“內存轉儲文件”或“核心轉儲文件”&#xff08;Core Dump&#xff09;,內存轉儲的主要目的是…

Lua語言入門 - Lua 面向對象

Lua 面向對象 面向對象編程&#xff08;Object Oriented Programming&#xff0c;OOP&#xff09;是一種非常流行的計算機編程架構&#xff0c;通過創建和操作對象來設計應用程序。 以下幾種編程語言都支持面向對象編程&#xff1a; CJavaObjective-CSmalltalkC#Ruby Lua 是…

Pyqt6在lineEdit中輸入文件名稱并創建或刪除JSON文件

1、創建JSON文件 代碼 import osdef addModulekeyWordFile(self):if "" ! self.lineEdit_module.text():moduleFile self.lineEdit_module.text() .jsonelse:self.toolLogPrinting(請輸入模塊名稱)returnfilePath modulekeyWordFileDir moduleFileif os.path.e…

【Leetcode 熱題 100】236. 二叉樹的最近公共祖先

問題背景 給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。 最近公共祖先的定義為&#xff1a;對于有根樹 T T T 的兩個節點 p p p、 q q q&#xff0c;最近公共祖先表示為一個節點 x x x&#xff0c;滿足 x x x 是 p p p、 q q q 的祖先且 x x x 的深度盡可能大…

數據結構--堆的向上調整和向下調整

文章目錄 1.完全二叉樹2.堆向上調整3.堆向下調整4.測試代碼 1.完全二叉樹 下面的這個就是對于我們的完全二叉樹的這個邏輯結構和物理結構的說明&#xff1a; 邏輯結構就是我們自己認為的進行購想出來的&#xff1b; 但是這個物理結構卻是我們的這個數據結構在內存里面的真是…

智能掛號系統設計典范:SSM 結合 Vue 在醫院的應用實現

摘要 隨著信息技術在管理上越來越深入而廣泛的應用&#xff0c;管理信息系統的實施在技術上已逐步成熟。本文介紹了醫院預約掛號系統的開發全過程。通過分析醫院預約掛號系統管理的不足&#xff0c;創建了一個計算機管理醫院預約掛號系統的方案。文章介紹了醫院預約掛號系統的系…

“魔法糖果盒的秘密:用樸素貝葉斯算法猜糖果顏色”

想象一下&#xff0c;你有一個神奇的糖果盒&#xff0c;這個糖果盒里有兩種糖果&#xff1a;紅色的和藍色的。你閉上眼睛&#xff0c;從盒子里拿出一個糖果&#xff0c;然后嘗一嘗&#xff0c;你想知道這個糖果是紅色的還是藍色的。樸素貝葉斯算法就像是一個魔法規則&#xff0…