<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          用Qt寫一個簡單的Markdown編輯器

          共 6156字,需瀏覽 13分鐘

           ·

          2021-06-17 21:43

          關(guān)注、星標公眾號,直達精彩內(nèi)容

          ID:技術(shù)讓夢想更偉大

          作者:李肖遙

          Markdown編輯器

          Markdown 是一種具有純文本格式語法的輕量級標記語言,Markdown Editor 演示了如何使用 QWebChannel 和 JavaScript 庫為自定義標記語言提供富文本預覽工具。

          Markdown 編輯器主窗口分為編輯器和預覽區(qū),編輯器支持 Markdown 語法,使用 QPlainTextEdit 實現(xiàn);文檔在預覽區(qū)渲染為富文本,通過QWebEngineView實現(xiàn)。

          為了呈現(xiàn)文本,Markdown 文本在 Web 引擎內(nèi)的 JavaScript 庫的幫助下轉(zhuǎn)換為 HTML 格式,預覽是通過 QWebChannel 從編輯器更新的。

          下圖演示如何將 Web 引擎集成到混合桌面應(yīng)用程序中。

          我們使用例子,左側(cè)輸入Markdown語法的文本,右側(cè)就是其預覽的樣式了。

          實現(xiàn)原理以及步驟

          公開文檔文本

          通過 QWebChannel 將要渲染的當前 Markdown 文本暴露給 Web 引擎,所以我們需要以某種方式通過 Qt 元類型系統(tǒng)使當前文本可用,這是通過使用將文檔文本公開為 Q_PROPERTY 的專用 Document 類來完成的:

          通過 QWebChannel 將要渲染的當前 Markdown 文本暴露給 Web 引擎,將文檔文本公開為 Q_PROPERTY 的專用 Document 類,然后通過 Qt 元類型系統(tǒng)使當前文本可用。

          Document 類使用setText()方法包裝要在C++ 端設(shè)置的 QString,并在運行時將其作為帶有 textChanged 信號的文本屬性公開。

          定義 setText 方法如下:

          void Document::setText(const QString &text)
          {
              if (text == m_text)
                  return;
              m_text = text;
              emit textChanged(m_text);
          }

          預覽文本

          實現(xiàn)自己的 PreviewPage 類,該類公開繼承自 QWebEnginePage。

          重新實現(xiàn)了虛擬的 acceptNavigationRequest 方法來阻止頁面導航離開當前文檔,從而將外部鏈接重定向到系統(tǒng)瀏覽器,代碼如下:

          bool PreviewPage::acceptNavigationRequest(const QUrl &url,
                                                    QWebEnginePage::NavigationType /*type*/,
                                                    bool /*isMainFrame*/)
          {
              // Only allow qrc:/index.html.
              if (url.scheme() == QString("qrc"))
                  return true;
              QDesktopServices::openUrl(url);
              return false;
          }

          創(chuàng)建主窗口

          MainWindow 類繼承了 QMainWindow 類,該類聲明了與菜單中的操作相匹配的私有槽,以及 isModified() 輔助方法。

          主窗口的實際布局在.ui文件中指定,小部件和操作在運行時在 ui 成員變量中可用。

          m_filePath 保存當前加載文檔的文件路徑, m_content 是 Document 類的一個實例。

          不同對象的實際設(shè)置是在 MainWindow 構(gòu)造函數(shù)中完成的,代碼如下:

          MainWindow::MainWindow(QWidget *parent) :
              QMainWindow(parent),
              ui(new Ui::MainWindow)
          {
              ui->setupUi(this);
              ui->editor->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
              ui->preview->setContextMenuPolicy(Qt::NoContextMenu);

          構(gòu)造函數(shù)首先調(diào)用 setupUi 來根據(jù) UI 文件構(gòu)造小部件和菜單操作,文本編輯器字體設(shè)置為具有固定字符寬度的字體,并且 QWebEngineView 小部件不顯示上下文菜單。

          PreviewPage *page = new PreviewPage(this);
          ui->preview->setPage(page);

          這里構(gòu)造函數(shù)確保我們的自定義 PreviewPage 被 ui->preview 中的 QWebEngineView 實例使用。

          connect(ui->editor, &QPlainTextEdit::textChanged,
                  [this]() { m_content.setText(ui->editor->toPlainText()); });

          QWebChannel *channel = new QWebChannel(this);
          channel->registerObject(QStringLiteral("content"), &m_content);
          page->setWebChannel(channel);

          這里編輯器的 textChanged 信號連接到更新 m_content 中的文本的 lambda, 然后這個對象被QWebChannel以content為名暴露給JS端。

          ui->preview->setUrl(QUrl("qrc:/index.html"));

          現(xiàn)在我們實際上可以從資源中加載 index.html 文件。有關(guān)該文件的更多信息,請參閱創(chuàng)建索引文件。

          connect(ui->actionNew, &QAction::triggered, this, &MainWindow::onFileNew);
          connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::onFileOpen);
          connect(ui->actionSave, &QAction::triggered, this, &MainWindow::onFileSave);
          connect(ui->actionSaveAs, &QAction::triggered, this, &MainWindow::onFileSaveAs);
          connect(ui->actionExit, &QAction::triggered, this, &MainWindow::onExit);
          connect(ui->editor->document(), &QTextDocument::modificationChanged,ui->actionSave, &QAction::setEnabled);

          菜單項連接到相應(yīng)的成員槽,保存項目的激活或停用取決于用戶是否已編輯內(nèi)容。

          QFile defaultTextFile(":/default.md");
          defaultTextFile.open(QIODevice::ReadOnly);
          ui->editor->setPlainText(defaultTextFile.readAll());
          }

          最后,我們從資源中加載一個默認文檔 default.md就可以了。

          創(chuàng)建索引文件

          <!doctype html>
          <html lang="en">
          <meta charset="utf-8">
          <head>
            <link rel="stylesheet" type="text/css" href="3rdparty/markdown.css">
            <script src="3rdparty/marked.js"></script>
            <script src="qrc:/qtwebchannel/qwebchannel.js"></script>
          </head>
          <body>
            <div id="placeholder"></div>
            <script>
            'use strict';

            var placeholder = document.getElementById('placeholder');

            var updateText = function(text) {
                placeholder.innerHTML = marked(text);
            }

            new QWebChannel(qt.webChannelTransport,
              function(channel) {
                var content = channel.objects.content;
                updateText(content.text);
                content.textChanged.connect(updateText);
              }
            );
            </script>
          </body>
          </html>

          index.html 中加載了一個自定義樣式表和兩個 JavaScript 庫。markdown.css 是一個 Markdown 友好樣式表;marked.js 是一個 Markdown 解析器和編譯器,旨在提高速度;qwebchannel.js 是 QWebChannel 模塊的一部分。

          在  元素中,首先定義一個占位符元素,并將其作為 JavaScript 變量使用,然后定義 updateText 輔助方法,最后設(shè)置 Web 通道來訪問內(nèi)容代理對象,并確保在 content.text 更改時調(diào)用 updateText()。

          最后

          • Qt安裝目錄找到源碼

          \Q{你的Qt版本}\Examples{你的Qt版本}\webenginewidgets\markdowneditor

          • 相關(guān)鏈接

          https://doc.qt.io/qt-5/qtwebengine-webenginewidgets-markdowneditor-example.html

          ????????????????  END  ????????????????

          推薦閱讀:


          嵌入式編程專輯
          Linux 學習專輯
          C/C++編程專輯
          Qt進階學習專輯

          關(guān)注我的微信公眾號,回復“加群”按規(guī)則加入技術(shù)交流群。


          點擊“閱讀原文”查看更多分享。

          瀏覽 78
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕亚洲在线 | langse精品 | 婷婷爱五月| 无码高清一卡二卡免费视频 | 伊人天堂视频 |