Qt Dock Widgets 官方示例的翻譯

Qt Dock Widgets 官方示例的翻譯

Dock Widgets Example 介紹:

Dock Widgets 示例程序描述的有兩個技術要點:

  • 1、如何添加Dock 窗體到應用程序中。
  • 2、如何使用Qt的富文本引擎。

在這裏插入圖片描述

該示例應用程序描述的是一個簡單的處理商業郵件的模板程序。在兩個Dock 窗體中分別顯示了客戶的信息 和 常用語。通過單擊Dock中的列表,將自定添加選中的信息添加到郵件模板中。當然,撤銷按鈕可以撤去郵件模板中錯誤的或者不需要的信息。一旦郵件完成,可以直接答應或者保存爲HTML格式。

MainWindow Class 定義:

  class MainWindow : public QMainWindow
  {
      Q_OBJECT

  public:
      MainWindow();

  private slots:
      void newLetter();
      void save();
      void print();
      void undo();
      void about();
      void insertCustomer(const QString &customer);
      void addParagraph(const QString &paragraph);

  private:
      void createActions();
      void createStatusBar();
      void createDockWindows();

      QTextEdit *textEdit;
      QListWidget *customerList;
      QListWidget *paragraphsList;

      QMenu *viewMenu;
  };

接着,我們來一個個來了解每個函數的功能。

MainWindow Class 關聯的相關頭文件

#include
#if defined(QT_PRINTSUPPORT_LIB)
#include <QtPrintSupport/qtprintsupportglobal.h>
#if QT_CONFIG(printdialog)
#include
#endif
#endif

#include “mainwindow.h”

相關函數功能的介紹:

一開始我們包含了 ,QWidget類是所有用戶界面對象的基類。我們同樣需要包含mainwindow.h

  MainWindow::MainWindow()
      : textEdit(new QTextEdit)
  {
      setCentralWidget(textEdit);

      createActions();
      createStatusBar();
      createDockWindows();

      setWindowTitle(tr("Dock Widgets"));

      newLetter();
      setUnifiedTitleAndToolBarOnMac(true);
  }

在該構造函數中,我們一開始就創建了QTextEdit Widget。 然後我們調用QMainWindow::setCentralWidget()。 該函數會將 QTextEdit 的所有權傳遞給 MainWindow ,同時QTextEdit 會佔據MainWindow 的中央區域。

然後我們調用 createActions(), createMenus(), createToolBars(), createStatusBar(), and createDockWindows() 來初始化窗體.。
最後,我們調用 setWindowTitle() 來給用用程序設定一個名稱, newLetter() 來創建一個郵件模板。

我們 調用 createActions(), createMenus(), createToolBars(), and createStatusBar() 函數,是爲了保持和其他的Qt示例程序的風格保持一致。

  void MainWindow::createDockWindows()
  {
      QDockWidget *dock = new QDockWidget(tr("Customers"), this);
      dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
      customerList = new QListWidget(dock);
      customerList->addItems(QStringList()
              << "John Doe, Harmony Enterprises, 12 Lakeside, Ambleton"
              << "Jane Doe, Memorabilia, 23 Watersedge, Beaton"
              << "Tammy Shea, Tiblanka, 38 Sea Views, Carlton"
              << "Tim Sheen, Caraba Gifts, 48 Ocean Way, Deal"
              << "Sol Harvey, Chicos Coffee, 53 New Springs, Eccleston"
              << "Sally Hobart, Tiroli Tea, 67 Long River, Fedula");
      dock->setWidget(customerList);
      addDockWidget(Qt::RightDockWidgetArea, dock);
      viewMenu->addAction(dock->toggleViewAction());

      dock = new QDockWidget(tr("Paragraphs"), this);
      paragraphsList = new QListWidget(dock);
      paragraphsList->addItems(QStringList()
              << "Thank you for your payment which we have received today."
              << "Your order has been dispatched and should be with you "
                 "within 28 days."
              << "We have dispatched those items that were in stock. The "
                 "rest of your order will be dispatched once all the "
                 "remaining items have arrived at our warehouse. No "
                 "additional shipping charges will be made."
              << "You made a small overpayment (less than $5) which we "
                 "will keep on account for you, or return at your request."
              << "You made a small underpayment (less than $1), but we have "
                 "sent your order anyway. We'll add this underpayment to "
                 "your next bill."
              << "Unfortunately you did not send enough money. Please remit "
                 "an additional $. Your order will be dispatched as soon as "
                 "the complete amount has been received."
              << "You made an overpayment (more than $5). Do you wish to "
                 "buy more items, or should we return the excess to you?");
      dock->setWidget(paragraphsList);
      addDockWidget(Qt::RightDockWidgetArea, dock);
      viewMenu->addAction(dock->toggleViewAction());

      connect(customerList, &QListWidget::currentTextChanged,
              this, &MainWindow::insertCustomer);
      connect(paragraphsList, &QListWidget::currentTextChanged,
              this, &MainWindow::addParagraph);
  }

我們創建一個關於客戶信息的Dock 窗體,設定了該窗體的標題,我們同時傳遞“this”指針,這樣就指定了MainWindows爲父窗體。一般情況下,我們不需要傳遞,因爲當Widgets 陳列出時, 是自動繼承父窗體的,但是Dock 窗體是個例外,因爲它不是通過layouts 的方式來陳列的。

我們選擇限制這個客戶信息的Dock 窗體只能顯示在左邊和右邊的Dock區域。關於Dock區域的圖示,請看下圖:

在這裏插入圖片描述

用戶可以通過鼠標的拓展將Dock 移出,而變成一個自由窗體。通過QDockWidget::setFeatures()來設置Dock窗體是可移動的還是不可移動。

一旦我們創建好了Dock 窗體,創建好了list窗體,並指定list窗體的父窗體爲Dock窗體,那麼最後我們就可以調用addDockWidget()添加Dock 窗體到MainWindows 窗體中了。

我們依照同樣的過程可以創建另一個Dock 窗體,這次我們不限定該窗體的區域位置。

最後,我們通過信號槽事件。關聯信號currentTextChanged() ,到兩個槽 insertCustomer() ,addParagraph() 。

接着,我們來討論剩餘的其他一些函數的實現。

  void MainWindow::newLetter()
  {
      textEdit->clear();

      QTextCursor cursor(textEdit->textCursor());
      cursor.movePosition(QTextCursor::Start);
      QTextFrame *topFrame = cursor.currentFrame();
      QTextFrameFormat topFrameFormat = topFrame->frameFormat();
      topFrameFormat.setPadding(16);
      topFrame->setFrameFormat(topFrameFormat);

      QTextCharFormat textFormat;
      QTextCharFormat boldFormat;
      boldFormat.setFontWeight(QFont::Bold);
      QTextCharFormat italicFormat;
      italicFormat.setFontItalic(true);

      QTextTableFormat tableFormat;
      tableFormat.setBorder(1);
      tableFormat.setCellPadding(16);
      tableFormat.setAlignment(Qt::AlignRight);
      cursor.insertTable(1, 1, tableFormat);
      cursor.insertText("The Firm", boldFormat);
      cursor.insertBlock();
      cursor.insertText("321 City Street", textFormat);
      cursor.insertBlock();
      cursor.insertText("Industry Park");
      cursor.insertBlock();
      cursor.insertText("Some Country");
      cursor.setPosition(topFrame->lastPosition());
      cursor.insertText(QDate::currentDate().toString("d MMMM yyyy"), textFormat);
      cursor.insertBlock();
      cursor.insertBlock();
      cursor.insertText("Dear ", textFormat);
      cursor.insertText("NAME", italicFormat);
      cursor.insertText(",", textFormat);
      for (int i = 0; i < 3; ++i)
          cursor.insertBlock();
      cursor.insertText(tr("Yours sincerely,"), textFormat);
      for (int i = 0; i < 3; ++i)
          cursor.insertBlock();
      cursor.insertText("The Boss", textFormat);
      cursor.insertBlock();
      cursor.insertText("ADDRESS", italicFormat);
  }

在該函數中,我們清空了QTextEdit。接着我們創建了一個QTextCursor ,我們移動光標到文檔的開始處,創建並格式化一個frame。 我們創建一些字符格式和一個表格格式。我們插入一個表格到文檔中,並參照上滿的格式插入公司名和地址到表格中。接着我們插入包含標記NAME和ADDRESS的郵件“骨架”,我們用“Yours sincerely”,也作爲一個標記。

  void MainWindow::insertCustomer(const QString &customer)
  {
      if (customer.isEmpty())
          return;
      QStringList customerList = customer.split(", ");
      QTextDocument *document = textEdit->document();
      QTextCursor cursor = document->find("NAME");
      if (!cursor.isNull()) {
          cursor.beginEditBlock();
          cursor.insertText(customerList.at(0));
          QTextCursor oldcursor = cursor;
          cursor = document->find("ADDRESS");
          if (!cursor.isNull()) {
              for (int i = 1; i < customerList.size(); ++i) {
                  cursor.insertBlock();
                  cursor.insertText(customerList.at(i));
              }
              cursor.endEditBlock();
          }
          else
              oldcursor.endEditBlock();
      }
  }

如果用戶單擊了客戶信息的Dock, 會分割關於客戶的信息。然後我們查找標記“NAME”,在該標記中插入客戶的命名,同樣的,我們查找標記“ADDRESS”,並將此標記替代爲客戶的地址。
值得注意的是:我們將所有的插入放置在beginEditBlock() 和endEditBlock() 這兩個函數之間。

  void MainWindow::addParagraph(const QString &paragraph)
  {
      if (paragraph.isEmpty())
          return;
      QTextDocument *document = textEdit->document();
      QTextCursor cursor = document->find(tr("Yours sincerely,"));
      if (cursor.isNull())
          return;
      cursor.beginEditBlock();
      cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor, 2);
      cursor.insertBlock();
      cursor.insertText(paragraph);
      cursor.insertBlock();
      cursor.endEditBlock();

  }

該函數的功能類似於insertCustomer(). 首先我們尋找標記,這裏的標記是“Yours sincerely”,然後在在標記前,插入單擊選中的段落文本。同樣的這裏我們調用beginEditBlock() … endEditBlock()函數對,以便於我們撤銷時,把整段添加的都一併撤銷。

  void MainWindow::print()
  {
  #if QT_CONFIG(printdialog)
      QTextDocument *document = textEdit->document();
      QPrinter printer;

      QPrintDialog dlg(&printer, this);
      if (dlg.exec() != QDialog::Accepted) {
          return;
      }

      document->print(&printer);
      statusBar()->showMessage(tr("Ready"), 2000);
  #endif
  }

可以看到,Qt 的QTextDocument 類調用打印文檔也非常簡單。

  void MainWindow::save()
  {
      QMimeDatabase mimeDatabase;
      QString fileName = QFileDialog::getSaveFileName(this,
                          tr("Choose a file name"), ".",
                          mimeDatabase.mimeTypeForName("text/html").filterString());
      if (fileName.isEmpty())
          return;
      QFile file(fileName);
      if (!file.open(QFile::WriteOnly | QFile::Text)) {
          QMessageBox::warning(this, tr("Dock Widgets"),
                               tr("Cannot write file %1:\n%2.")
                               .arg(QDir::toNativeSeparators(fileName), file.errorString()));
          return;
      }

      QTextStream out(&file);
      QGuiApplication::setOverrideCursor(Qt::WaitCursor);
      out << textEdit->toHtml();
      QGuiApplication::restoreOverrideCursor();

      statusBar()->showMessage(tr("Saved '%1'").arg(fileName), 2000);
  }

QTextEdit 提供輸出HTML格式的文檔。

  void MainWindow::undo()
  {
      QTextDocument *document = textEdit->document();
      document->undo();
  }

如果窗體的焦點放置在QTextEdit,可以通過撤銷功能來撤銷刪除之前添加的文本。

總結:

  1、官方給定的示例對DockWidget 的使用做了簡單介紹。
  2、富文本的應用這裏也有涉及到。
  3、按照該示例程序的介紹可以很好的訓練程序思維。

總之,按部就班的學習示例程序是學好Qt的一項基本策略。

ps:翻譯有不當之處,請讀者們多多指點,本人純粹是爲了項目和學習的需要,才斗膽拙筆成文。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章