当前位置:   article > 正文

Hello Qt(二十九)——NotePad实例开发_notepad是怎么开发的

notepad是怎么开发的

一、界面开发

 NotePad使用主窗口作为顶层窗口组件,使用QMainWindow作为基类,QMainWindow内部封装了菜单栏、工具栏、中央组件、停靠组件、状态栏等。QMainWindow内置了布局管理器,基本的组件布局如下:

 使用二阶构造模式构建NotePad界面。

  1. MainWindow::MainWindow()
  2. {
  3.     resize(800600);
  4. }
  5. MainWindow::~MainWindow()
  6. {
  7. }
  8. MainWindow* MainWindow::newInstance()
  9. {
  10.     MainWindow* ret = new MainWindow();
  11.     if((ret == NULL) || (!ret->construct()))
  12.     {
  13.         delete ret;
  14.         ret = NULL;
  15.     }
  16.     return ret;
  17. }
  18. bool MainWindow::construct()
  19. {
  20.     bool ret = true;
  21.     ret = ret && initMenuBar();//菜单栏构建
  22.     ret = ret && initToolBar();//工具栏构建
  23.     ret = ret && initStatusBar();//状态栏构建
  24.     ret = ret && initMainEditor();//中央组件构建
  25.     return ret;
  26. }

1、菜单栏

QT中提供了预定义的与菜单相关的类组件,菜单栏QMenuBar,下拉菜单QMenu,菜单项QAction。

  1.  QMenuBar* mb = menuBar();
  2. QMenu* menu = new QMenu("File(&F)");
  3. QAction *action = new QAction(text, NULL);
  4. menu->addAction(action);
  5. mb->addMenu(menu);

快捷键设置

 action->setShortcut(QKeySequence(KEY));

QKeySequence是QT中与快捷键相关的类,KEY是QT中代表键值的常量。

NotePad菜单栏共有文件、编辑、格式、查看、帮助五组下拉菜单,每组下拉菜单使用一个函数构建。

  1. bool MainWindow::initMenuBar()
  2. {
  3.     bool ret = true;
  4.     QMenuBar *mb = menuBar();
  5.     ret = ret && initFileMenu(mb);
  6.     ret = ret && initEditMenu(mb);
  7.     ret = ret && initFormatMenu(mb);
  8.     ret = ret && initViewMenu(mb);
  9.     ret = ret && initHelpMenu(mb);
  10.     return ret;
  11. }
  12. bool MainWindow::initFileMenu(QMenuBar *mb)
  13. {
  14.     QMenu *menu = new QMenu("File(&F)");
  15.     bool ret = (menu != NULL);
  16.     if(ret)
  17.     {
  18.         QAction *action = NULL;
  19.         ret = ret && makeAction(action, "New(&N)", Qt::CTRL + Qt::Key_N);
  20.         if(ret)
  21.         {
  22.             menu->addAction(action);
  23.         }
  24.         ret = ret && makeAction(action, "Open(&O)", Qt::CTRL + Qt::Key_O);
  25.         if(ret)
  26.         {
  27.             menu->addAction(action);
  28.         }
  29.         ret = ret && makeAction(action, "Save(&S)", Qt::CTRL + Qt::Key_S);
  30.         if(ret)
  31.         {
  32.             menu->addAction(action);
  33.         }
  34.         ret = ret && makeAction(action, "Save As(&A)"0);
  35.         if(ret)
  36.         {
  37.             menu->addAction(action);
  38.         }
  39.         menu->addSeparator();
  40.         ret = ret && makeAction(action, "Page Setting(&U)"0);
  41.         if(ret)
  42.         {
  43.             menu->addAction(action);
  44.         }
  45.         ret = ret && makeAction(action, "Print(&P)", Qt::CTRL + Qt::Key_P);
  46.         if(ret)
  47.         {
  48.             menu->addAction(action);
  49.         }
  50.         menu->addSeparator();
  51.         ret = ret && makeAction(action, "Exit(&X)"0);
  52.         if(ret)
  53.         {
  54.             menu->addAction(action);
  55.         }
  56.     }
  57.     if(ret)
  58.     {
  59.         mb->addMenu(menu);
  60.     }
  61.     else
  62.     {
  63.         delete menu;
  64.     }
  65.     return ret;
  66. }
  67. bool MainWindow::makeAction(QAction *&action, QString text, int key)
  68. {
  69.     bool ret = true;
  70.     action = new QAction(text, NULL);
  71.     if(action != NULL)
  72.     {
  73.         action->setShortcut(QKeySequence(key));
  74.     }
  75.     else
  76.     {
  77.         ret = false;
  78.     }
  79.     return ret;
  80. }
  81. bool MainWindow::initEditMenu(QMenuBar *mb)
  82. {
  83.     QMenu *menu = new QMenu("Edit(&E)"NULL);
  84.     bool ret = (menu != NULL);
  85.     if(ret)
  86.     {
  87.         QAction *action = NULL;
  88.         ret = ret && makeAction(action, "Undo(&U)", Qt::CTRL + Qt::Key_Z);
  89.         if(ret)
  90.         {
  91.             menu->addAction(action);
  92.         }
  93.         menu->addSeparator();
  94.         ret = ret && makeAction(action, "Cut(&T)", Qt::CTRL + Qt::Key_X);
  95.         if(ret)
  96.         {
  97.             menu->addAction(action);
  98.         }
  99.         ret = ret && makeAction(action, "Copy(&C)", Qt::CTRL + Qt::Key_C);
  100.         if(ret)
  101.         {
  102.             menu->addAction(action);
  103.         }
  104.         ret = ret && makeAction(action, "Paste(&P)", Qt::CTRL + Qt::Key_V);
  105.         if(ret)
  106.         {
  107.             menu->addAction(action);
  108.         }
  109.         ret = ret && makeAction(action, "Delete(&L)", Qt::Key_Delete);
  110.         if(ret)
  111.         {
  112.             menu->addAction(action);
  113.         }
  114.         menu->addSeparator();
  115.         ret = ret && makeAction(action, "Find(&F)", Qt::CTRL + Qt::Key_F);
  116.         if(ret)
  117.         {
  118.             menu->addAction(action);
  119.         }
  120.         ret = ret && makeAction(action, "Find Next(&N)", Qt::Key_F3);
  121.         if(ret)
  122.         {
  123.             menu->addAction(action);
  124.         }
  125.         ret = ret && makeAction(action, "Replace(&R)", Qt::CTRL + Qt::Key_H);
  126.         if(ret)
  127.         {
  128.             menu->addAction(action);
  129.         }
  130.         ret = ret && makeAction(action, "Goto(&G)", Qt::CTRL + Qt::Key_G);
  131.         if(ret)
  132.         {
  133.             menu->addAction(action);
  134.         }
  135.         menu->addSeparator();
  136.         ret = ret && makeAction(action, "All(&A)", Qt::CTRL + Qt::Key_A);
  137.         if(ret)
  138.         {
  139.             menu->addAction(action);
  140.         }
  141.         ret = ret && makeAction(action, "Time/Date(&D)", Qt::Key_F5);
  142.         if(ret)
  143.         {
  144.             menu->addAction(action);
  145.         }
  146.     }
  147.     if(ret)
  148.     {
  149.         mb->addMenu(menu);
  150.     }
  151.     else
  152.     {
  153.         delete menu;
  154.     }
  155.     return ret;
  156. }
  157. bool MainWindow::initFormatMenu(QMenuBar *mb)
  158. {
  159.     QMenu *menu = new QMenu("Format(&O)"NULL);
  160.     bool ret = (menu != NULL);
  161.     if(ret)
  162.     {
  163.         QAction *action = NULL;
  164.         ret = ret && makeAction(action, "Auto Wrap(&W)"0);
  165.         if(ret)
  166.         {
  167.             menu->addAction(action);
  168.         }
  169.         menu->addSeparator();
  170.         ret = ret && makeAction(action, "Font(&F)"0);
  171.         if(ret)
  172.         {
  173.             menu->addAction(action);
  174.         }
  175.     }
  176.     if(ret)
  177.     {
  178.         mb->addMenu(menu);
  179.     }
  180.     else
  181.     {
  182.         delete menu;
  183.     }
  184.     return ret;
  185. }
  186. bool MainWindow::initViewMenu(QMenuBar *mb)
  187. {
  188.     QMenu *menu = new QMenu("View(&V)"NULL);
  189.     bool ret = (menu != NULL);
  190.     if(ret)
  191.     {
  192.         QAction *action = NULL;
  193.         ret = ret && makeAction(action, "Status(&S)"0);
  194.         if(ret)
  195.         {
  196.             menu->addAction(action);
  197.         }
  198.     }
  199.     if(ret)
  200.     {
  201.         mb->addMenu(menu);
  202.     }
  203.     else
  204.     {
  205.         delete menu;
  206.     }
  207.     return ret;
  208. }
  209. bool MainWindow::initHelpMenu(QMenuBar *mb)
  210. {
  211.     QMenu *menu = new QMenu("Help(&H)"NULL);
  212.     bool ret = (menu != NULL);
  213.     if(ret)
  214.     {
  215.         QAction *action = NULL;
  216.         ret = ret && makeAction(action, "Help(&H)"0);
  217.         if(ret)
  218.         {
  219.             menu->addAction(action);
  220.         }
  221.         menu->addSeparator();
  222.         ret = ret && makeAction(action, "About NotePad(&A)"0);
  223.         if(ret)
  224.         {
  225.             menu->addAction(action);
  226.         }
  227.     }
  228.     if(ret)
  229.     {
  230.         mb->addMenu(menu);
  231.     }
  232.     else
  233.     {
  234.         delete menu;
  235.     }
  236.     return ret;
  237. }

2、工具栏

工具栏是应用程序中集成各种功能使用快捷方式的区域,不是应用程序必须存在的组件,工具栏的元素可以是各种窗口组件,但通常以图标按钮的方式存在。

QT中提供了预定义的工具栏相关组件,工具栏QToolBar和快捷项QAction。

  1. //创建工具栏
  2. QToolBar *tb = addToolBar("ToolBar");
  3. //创建工具栏选项
  4. QAction *action = new QAction("", NULL);
  5. action->setToolTip(“Open”);
  6. action->setIcon(QIcon(“/res/pic/open.png”));
  7. //将工具栏选项加入工具栏
  8. tb->addAction(action);
  1. void setFloatable(bool floatable) //设置工具栏为浮动
  2. void setMovable(bool movable) //设置工具栏为可移动
  3. void setIconSize(const QSize & iconSize) //设置工具栏的图标大小

QTollBar组件中可以加入QT中的任意QWidget组件。

 将菜单栏中的主要常用功能添加到工具栏中,按照功能所属的菜单栏进行分组创建。

  1. bool MainWindow::initToolBar()
  2. {
  3.     bool ret = true;
  4.     QToolBar *tb = addToolBar("ToolBar");
  5.     tb->setMovable(false);
  6.     tb->setIconSize(QSize(1616));
  7.     ret = ret && initFileToolItem(tb);//创建文件菜单栏的功能到工具栏
  8.     ret = ret && initEditToolItem(tb);//创建编辑菜单栏到工具栏
  9.     ret = ret && initFormatToolItem(tb);//创建格式菜单栏到工具栏
  10.     ret = ret && initViewToolItem(tb);//创建查看菜单栏到工具栏
  11.     return ret;
  12. }
  13. bool MainWindow::initFileToolItem(QToolBar *tb)
  14. {
  15.     bool ret = true;
  16.     QAction *action = NULL;
  17.     ret = ret && makeAction(action, "New"":/res/pic/new.png");
  18.     if( ret )
  19.     {
  20.         tb->addAction(action);
  21.     }
  22.     ret = ret && makeAction(action, "Open"":/res/pic/open.png");
  23.     if( ret )
  24.     {
  25.         tb->addAction(action);
  26.     }
  27.     ret = ret && makeAction(action, "Save"":/res/pic/save.png");
  28.     if( ret )
  29.     {
  30.         tb->addAction(action);
  31.     }
  32.     ret = ret && makeAction(action, "SaveAs"":/res/pic/saveas.png");
  33.     if( ret )
  34.     {
  35.         tb->addAction(action);
  36.     }
  37.     ret = ret && makeAction(action, "Print"":/res/pic/print.png");
  38.     if( ret )
  39.     {
  40.         tb->addAction(action);
  41.     }
  42.     tb->addSeparator();
  43.     return ret;
  44. }
  45. bool MainWindow::initEditToolItem(QToolBar* tb)
  46. {
  47.     bool ret = true;
  48.     QAction *action = NULL;
  49.     ret = ret && makeAction(action, "Undo"":/res/pic/undo.png");
  50.     if( ret )
  51.     {
  52.         tb->addAction(action);
  53.     }
  54.     ret = ret && makeAction(action, "Redo"":/res/pic/redo.png");
  55.     if( ret )
  56.     {
  57.         tb->addAction(action);
  58.     }
  59.     ret = ret && makeAction(action, "Cut"":/res/pic/cut.png");
  60.     if( ret )
  61.     {
  62.         tb->addAction(action);
  63.     }
  64.     ret = ret && makeAction(action, "Copy"":/res/pic/copy.png");
  65.     if( ret )
  66.     {
  67.         tb->addAction(action);
  68.     }
  69.     ret = ret && makeAction(action, "Paste"":/res/pic/paste.png");
  70.     if( ret )
  71.     {
  72.         tb->addAction(action);
  73.     }
  74.     ret = ret && makeAction(action, "Find"":/res/pic/find.png");
  75.     if( ret )
  76.     {
  77.         tb->addAction(action);
  78.     }
  79.     ret = ret && makeAction(action, "Replace"":/res/pic/replace.png");
  80.     if( ret )
  81.     {
  82.         tb->addAction(action);
  83.     }
  84.     ret = ret && makeAction(action, "Goto"":/res/pic/goto.png");
  85.     if( ret )
  86.     {
  87.         tb->addAction(action);
  88.     }
  89.     tb->addSeparator();
  90.     return ret;
  91. }
  92. bool MainWindow::initFormatToolItem(QToolBar* tb)
  93. {
  94.     bool ret = true;
  95.     QAction *action = NULL;
  96.     ret = ret && makeAction(action, "Auto Wrap"":/res/pic/wrap.png");
  97.     if( ret )
  98.     {
  99.         tb->addAction(action);
  100.     }
  101.     ret = ret && makeAction(action, "Font"":/res/pic/font.png");
  102.     if( ret )
  103.     {
  104.         tb->addAction(action);
  105.     }
  106.     tb->addSeparator();
  107.     return ret;
  108. }
  109. bool MainWindow::initViewToolItem(QToolBar* tb)
  110. {
  111.     bool ret = true;
  112.     QAction *action = NULL;
  113.     ret = ret && makeAction(action, "ToolBar"":/res/pic/tool.png");
  114.     if( ret )
  115.     {
  116.         tb->addAction(action);
  117.     }
  118.     ret = ret && makeAction(action, "Status"":/res/pic/status.png");
  119.     if( ret )
  120.     {
  121.         tb->addAction(action);
  122.     }
  123.     return ret;
  124. }
  125. bool MainWindow::makeAction(QAction*& action, QString tip, QString icon)
  126. {
  127.     bool ret = true;
  128.     action = new QAction(""NULL);
  129.     if( action != NULL )
  130.     {
  131.         action->setToolTip(tip);
  132.         action->setIcon(QIcon(icon));
  133.     }
  134.     else
  135.     {
  136.         ret = false;
  137.     }
  138.     return ret;
  139. }

3、状态栏

状态栏是应用程序中输出简要信息的区域,一般位于窗口的底部。状态栏显示的消息类型如下:

A、实时消息,如当前程序状态

B、永久消息,如程序版本,开发机构

C、进度消息,进度显示

QT中提供了预定义的状态栏相关组件状态栏QStatusBar,QStatusBar是容器型组件,可以是任意组件QWidget的父组件。

 QT状态栏的一般设计原则:

A、状态栏左边区域用于输出实时消息

B、状态栏右边区域用于输出永久消息

因此,addWidget函数用于在状态栏左边区域添加组件,addPermanentWidget函数用于在状态栏右边区域添加组件。

  1. bool MainWindow::initStatusBar()
  2. {
  3.     bool ret = true;
  4.     QStatusBar *sb = statusBar();
  5.     QLabel *label = new QLabel("CopyRight @Scorpio Studio");
  6.     if(label != NULL)
  7.     {
  8.         label->setMinimumWidth(150);
  9.         label->setAlignment(Qt::AlignCenter);
  10.         sb->addPermanentWidget(label);
  11.     }
  12.     else
  13.     {
  14.         ret = false;
  15.     }
  16.     return ret;
  17. }

4、中央组件

中央组件是多行文本编组件,使用QPlainTextEdit组件。

  1. bool MainWindow::initMainEditor()
  2. {
  3.     bool ret = true;
  4.     //设置mainEditor的父组件
  5.     mainEditor.setParent(this);
  6.     //设置中央组件为mainEditor
  7.     setCentralWidget(&mainEditor);
  8.     //设置mainEditor的背景色为豆沙绿
  9.     QPalette p = mainEditor.palette();
  10.     p.setColor(QPalette::Base, QColor(204, 232, 207));
  11.     mainEditor.setPalette(p);
  12.     return ret;
  13. }

二、核心功能开发

1、信号与槽函数

考虑到用户界面与业务逻辑代码的分离,槽函数实现需要与界面实现向分离,槽函数在新建MainwWindowSlots.cpp文件中实现,界面文件名称改为MainWindowUI.cpp。

菜单栏与工具栏中的QAction对象在鼠标点击后会发送triggered()信号,通过信号与槽机制可以实现对QAction对象的操作的处理。

connect(action, SIGNAL(triggered()), this, SLOT(slotfunction));

在QAction对象创建的时候连接信号与槽函数。

2、文件的存取操作

创建文件对话框:

  1. QString MainWindow::createFileDialog(QFileDialog::AcceptMode mode, QString title)
  2. {
  3.     QString ret = "";
  4.     QFileDialog filedialog(this);
  5.     QStringList filter;
  6.     filter.append("Text Files (*.txt)");
  7.     filter.append("All Files (*.*)");
  8.     filedialog.setWindowTitle(title);
  9.     filedialog.setAcceptMode(mode);
  10.     filedialog.setNameFilters(filter);
  11.     if(mode == QFileDialog::AcceptOpen)
  12.     {
  13.         filedialog.setFileMode(QFileDialog::ExistingFile);
  14.     }
  15.     if(filedialog.exec() == QFileDialog::Accepted)
  16.     {
  17.         ret = filedialog.selectedFiles()[0];
  18.     }
  19.     return ret;
  20. }

错误消息提示框:

  1. void MainWindow::showErrorMessage(const QString& title, const QString & text, 
  2. QMessageBox::StandardButtons buttons)
  3. {
  4.     QMessageBox::critical(this, title, text, buttons);
  5. }

打开文件:

  1. void MainWindow::onFileOpen()
  2. {
  3.     QString path = createFileDialog(QFileDialog::AcceptOpen, "Open");
  4.     if(path != "")
  5.     {
  6.         QFile file(path);
  7.         if(file.open(QIODevice::ReadOnly | QIODevice::Text))
  8.         {
  9.             mainEditor.setPlainText(QString(file.readAll()));
  10.             file.close();
  11.             m_filepath = path;
  12.             setWindowTitle("NotePad - [" + m_filepath + "]");
  13.         }
  14.         else
  15.         {
  16.             showErrorMessage(QString("Error"), QString("Open file error: " + m_filepath),
  17. QMessageBox::Ok);
  18.         }
  19.     }
  20. }

保存文件:

  1. void MainWindow::onFileSave()
  2. {
  3.     if(m_filepath == "")
  4.     {
  5.         m_filepath = createFileDialog(QFileDialog::AcceptSave, "Save");
  6.     }
  7.     if(m_filepath != "")
  8.     {
  9.         QFile file(m_filepath);
  10.         if(file.open(QIODevice::WriteOnly | QIODevice::Text))
  11.         {
  12.             QTextStream out(&file);
  13.             out << mainEditor.toPlainText();
  14.             file.close();
  15.             setWindowTitle("NotePad - [ " + m_filepath + " ]");
  16.         }
  17.         else
  18.         {
  19.             showErrorMessage(QString("Error"), QString("Save file error: " + m_filepath), 
  20. QMessageBox::Ok);
  21.             m_filepath = "";
  22.         }
  23.     }
  24. }

另存文件:

  1. void MainWindow::onFileSaveAs()
  2. {
  3.     QString path = createFileDialog(QFileDialog::AcceptSave, "Save As");
  4.     if(path != "")
  5.     {
  6.         QFile file(path);
  7.         if(file.open(QIODevice::WriteOnly | QIODevice::Text))
  8.         {
  9.             QTextStream out(&file);
  10.             out << mainEditor.toPlainText();
  11.             file.close();
  12.             m_filepath = path;
  13.             setWindowTitle("NotePad - [ " + m_filepath + " ]");
  14.         }
  15.         else
  16.         {
  17.             showErrorMessage(QString("Error"), QString("Save as error: " + m_filepath), 
  18. QMessageBox::Ok);
  19.         }
  20.     }
  21. }

创建新文件:

  1. void MainWindow::onFileNew()
  2. {
  3.     preTextChanged();
  4.     if(!m_isTextChanged)
  5.     {
  6.         mainEditor.clear();
  7.         setWindowTitle("NotePad - [New ]");
  8.         m_filepath = "";
  9.         m_isTextChanged = false;
  10.     }
  11. }

3、编辑区的数据交互

QPlainTextEdit编辑器组件提供了编辑交互功能接口。

QPlainTextEdit内置的信号如下:

  1. void textChanged()
  2. void copyAvailable(bool yes)
  3. void redoAvailable(bool available)
  4. void undoAvailable(bool available)
  5. void cursorPositionChanged()
  6. void modificationChanged(bool changed)

QPlainTextEdit内置的槽函数如下:

  1. void copy()
  2. void cut()
  3. void paste()
  4. void redo()
  5. void selectAll()
  6. void undo()

将菜单栏、工具栏中的copy、cut、paste、redo、undo等编辑操作QAction对象的triggered()信号连接到QPlainTextEdit对象的相应操作的槽函数,即可实现编辑操作。

  1. connect(action, SIGNAL(triggered(bool)), &mainEditor, SLOT(undo());
  2. connect(action, SIGNAL(triggered()), &mainEditor, SLOT(cut()));
  3. connect(action, SIGNAL(triggered()), &mainEditor, SLOT(copy()));
  4. connect(action, SIGNAL(triggered()), &mainEditor, SLOT(paste());

工具栏QAction对象的界面状态的设置

在创建Copy、Undo、Redo的QAction对象时设置为不可用状态。

将QPlainTextEdit对象的copyAvailable、undoAvailable、redoAvailable信号连接到自定义槽函数。

  1. connect(&mainEditor, SIGNAL(copyAvailable(bool)), this, SLOT(onCopyAvailable(bool)));
  2. connect(&mainEditor, SIGNAL(undoAvailable(bool)), this, SLOT(onUndoAvailable(bool)));
  3. connect(&mainEditor, SIGNAL(redoAvailable(bool)), this, SLOT(onRedoAvailable(bool)));

在自定义槽函数中根据信号的参数available设置QAction对象的状态

  1. void MainWindow::onCopyAvailable(bool available)
  2. {
  3.     findMenuBarItem("Copy")->setEnabled(available);
  4.     findMenuBarItem("Cut")->setEnabled(available);
  5.     findToolBarItem("Copy")->setEnabled(available);
  6.     findToolBarItem("Cut")->setEnabled(available);
  7. }
  8. void MainWindow::onUndoAvailable(bool available)
  9. {
  10.     findMenuBarItem("Undo")->setEnabled(available);
  11.     findToolBarItem("Undo")->setEnabled(available);
  12. }
  13. void MainWindow::onRedoAvailable(bool available)
  14. {
  15.     findToolBarItem("Redo")->setEnabled(available);
  16. }

4、拖放支持

拖放一个文件进入窗口时将触发拖放事件,QWidget对象都能处理拖放事件。

设置窗口支持拖放事件:

在构造函数调用setAcceptDrops(true);

重写拖放事件的处理函数:

  1. void dragEnterEvent(QDragEnterEvent *event);
  2. void dropEvent(QDropEvent *event);

默认情况下,QPlainTextEdit接受来自其他应用程序拖拽来的文本,把文件名显示出来。由于DropEvent是由子组件向父组件传播的,通过禁止QPlainTextEdit的DropEvent,主窗口可以获取DropEvent,MainWindow中就可以处理DropEvent。

在MainWwindow构造函数中需要禁止QPlainTextEdit接受DropEvent,允许MainWindow接受DropEvent。

  1.  mainEditor.setAcceptDrops(false);
  2. setAcceptDrops(true);

重写事件处理函数:

  1. void MainWindow::dragEnterEvent(QDragEnterEvent *event)
  2. {
  3.     if(event->mimeData()->hasFormat("text/uri-list"))
  4.     {
  5.         event->acceptProposedAction();
  6.     }
  7.     else
  8.     {
  9.         event->ignore();
  10.     }
  11. }
  12. void MainWindow::dropEvent(QDropEvent *event)
  13. {
  14.     if(event->mimeData()->hasUrls())
  15.     {
  16.         QList<QUrl> list = event->mimeData()->urls();
  17.         QString path = list[0].toLocalFile();
  18.         QFileInfo fi(path);
  19.         if( fi.isFile() )
  20.         {
  21.             preTextChanged();
  22.             if(!m_isTextChanged)
  23.             {
  24.                 loadFile(path);
  25.             }
  26.         }
  27.         else
  28.         {
  29.             showMessage(this, QMessageBox::Critical, "Error""Open file error"
  30. QMessageBox::Ok);
  31.         }
  32.     }
  33.     else
  34.     {
  35.         event->ignore();
  36.     }
  37. }

5、打印支持

QTextDocument是表示文本及文本属性的数据类。可以设置文本属性如:排版、字体、标题;获取文本参数如:行数、文本宽度、文本信息;实现标准操作如:撤销、重做、查找、打印。

打印功能实现如下:

A、连接打印功能的QAction对象到打印功能槽函数

B、在打印槽函数中定义打印对话框

C、根据用户选择获取QPrinter对象

D、使用QTextDocument对象进行打印

  1. void MainWindow::onPrint()
  2. {
  3.     QPrintDialog printdialog(this);
  4.     printdialog.setWindowTitle("Print");
  5.     if(printdialog.exec() == QPrintDialog::Accepted)
  6.     {
  7.         QPrinter *printer = printdialog.printer();
  8.         mainEditor.document()->print(printer);
  9.     }
  10. }

6、光标定位

QPlainTextEdit编辑框内部包含QTextCursor对象。

  1. [signal] void QPlainTextEdit::cursorPositionChanged()
  2. QTextCursor QPlainTextEdit::textCursor() const
  3. int QTextCursor::position() const
  1. void MainWindow::onCursorChanged()
  2. {
  3.     int pos = mainEditor.textCursor().position();
  4.     QString text = mainEditor.toPlainText();
  5.     int colum = 0;
  6.     int row = 0;
  7.     int flag = -1;
  8.     for(int i = 0; i < pos; i++)
  9.     {
  10.         if( text[i] == '\n' )
  11.         {
  12.             row++;
  13.             flag = i;
  14.         }
  15.     }
  16.     flag++;
  17.     colum = pos - flag;
  18.     m_status.setText("Line: " + QString::number(row + 1) + "   Colum: " +
  19. QString::number(colum + 1));
  20. }

7、查找功能

(1)查找对话框的功能:

A、可复用的组件

B、查找文本框中的指定字符串

C、能够指定查找方向

D、支持大小写敏感查找

(2)查找对话框架构设计如下:

 (3)查找对话框的界面布局:

 (4)查找功能的实现:

A、获取当前光标的位置作为起始点

B、查找目标第一次出现的位置

C、通过目标位置和目标长度在文本框内进行标记

QString类提供了字符串中查找子串的函数:

  1. int QString::indexOf(const QString &str, int from = 0,
  2. Qt::CaseSensitivity cs = Qt::CaseSensitive) const

从指定位置向后查找子串的下标位置

  1. int QString::lastIndexOf(const QString &str, int from = -1,
  2. Qt::CaseSensitivity cs = Qt::CaseSensitive) const

从指定位置向前查找子串的下标位置

QPlainTextEdit文本框中选中子串的标记

  1. QTextCursor cursor = m_textedit->textCursor();//获取当前光标
  2. cursor.setPosition(index);//设置光标到下标index
  3. //设置文本选择范围
  4. cursor.setPosition(index + target.length(), QTextCursor::KeepAnchor);
  5. m_textedit->setTextCursor(cursor);//设置光标信息到文本

(5)FindDailog类与MainWindow类的弱耦合关系

通过setPlainTextEdit(pText)设置FindDailog查找对话框指向的文本框,确立了FindDailog类与MainWindow类的弱耦合关系。

8、调色板设置

  1.   //设置mainEditor的背景色为豆沙绿
  2.     QPalette p = mainEditor.palette();
  3.     p.setColor(QPalette::Base, QColor(204, 232, 207));
  4.     p.setColor(QPalette::Inactive, QPalette::Highlight,
  5. p.color(QPalette::Active, QPalette::Highlight));
  6.     p.setColor(QPalette::Inactive, QPalette::HighlightedText,
  7. p.color(QPalette::Active, QPalette::HighlightedText));
  8.     mainEditor.setPalette(p);

9、替换功能

 替换对话框的功能:

A、可复用的组件

B、查找文本框中的字符串

C、替换当前查找到的字符串

D、替换所有的字符串

E、点击关闭按钮后隐藏

替换对话框的架构设计:

 考虑到FindDialog类代码复用,RepalceDialog类继承自FindDialog。

替换对话框界面设计:

  1.     m_replacelabel.setText("Replace To:");
  2.     m_replacebutton.setText("Replace");
  3.     m_replaceallbutton.setText("Replace All");
  4.     m_layout.removeWidget(&m_check);
  5.     m_layout.removeWidget(&m_radiogroup);
  6.     m_layout.removeWidget(&m_cancelbutton);
  7.     m_layout.addWidget(&m_replacelabel, 1, 0);
  8.     m_layout.addWidget(&m_replaceedit, 1, 1);
  9.     m_layout.addWidget(&m_replacebutton, 1, 2);
  10.     m_layout.addWidget(&m_check, 2, 0);
  11.     m_layout.addWidget(&m_radiogroup, 2, 1);
  12.     m_layout.addWidget(&m_replaceallbutton, 2, 2);
  13.     m_layout.addWidget(&m_cancelbutton, 3, 2);

替换功能的实现:

要实现替换操作,首先需要查找文本框中是否存在的字符串。如果存在字符串,则将鼠标标记的字符串替换。

  1. void ReplaceDialog::onReplace()
  2. {
  3.     QString target = m_edit.text();
  4.     QString to = m_replaceedit.text();
  5.     if((m_textedit != NULL) && (target != NULL) && (to != NULL))
  6.     {
  7.         QString select = m_textedit->textCursor().selectedText();
  8.         if(select == target)
  9.         {
  10.             m_textedit->insertPlainText(to);
  11.         }
  12.         onFind();
  13.     }
  14. }
  15. void ReplaceDialog::onRepalceAll()
  16. {
  17.     QString target = m_edit.text();
  18.     QString to = m_replaceedit.text();
  19.     if((m_textedit != NULL) && (target != NULL) && (to != NULL))
  20.     {
  21.         QString text = m_textedit->toPlainText();
  22.         text.replace(target, to, m_check.isChecked() ? 
  23. Qt::CaseSensitive : Qt::CaseInsensitive);
  24.         m_textedit->clear();
  25.         m_textedit->insertPlainText(text);
  26.     }
  27. }

10、工具栏、状态栏的显示隐藏

在构建菜单栏、工具栏中ToolBar、StatusBar的QAction对象时,设置QAction对象的属性。

  1.         action->setCheckable(true);
  2.         action->setChecked(true);
  3.         connect(action, SIGNAL(triggered()), this, SLOT(onViewToolBar()));

槽函数如下:

  1. void MainWindow::onViewStatusBar()
  2. {
  3.     QStatusBar *sb = statusBar();
  4.     bool visible = sb->isVisible();
  5.     sb->setVisible(!visible);
  6.     findToolBarItem("Status Bar")->setChecked(!visible);
  7.     findMenuBarItem("Status Bar")->setChecked(!visible);
  8. }
  9. void MainWindow::onViewToolBar()
  10. {
  11.     const QObjectList& list = children();
  12.     for(int i = 0; i < list.count(); i++)
  13.     {
  14.         QToolBar *tb = dynamic_cast<QToolBar*>(list[i]);
  15.         if(tb != NULL)
  16.         {
  17.             bool visible = tb->isVisible();
  18.             tb->setVisible(!visible);
  19.             findMenuBarItem("Tool Bar")->setChecked(!visible);
  20.             findToolBarItem("Tool Bar")->setChecked(!visible);
  21.             break;
  22.         }
  23.     }
  24. }

11、关于对话框

关于对话框用于标识软件的信息,如:Logo、版本号、开发者信息、版权、联系方式、项目信息等。

经典的关于对话框界面设计:

  1. AboutDialog::AboutDialog(QWidget* parent):QDialog(parent, 
  2. Qt::WindowCloseButtonHint), m_logo(this), m_info(this), m_close(this)
  3. {
  4.     QPixmap pm(":/res/pic/dt.png");
  5.     pm = pm.scaled(120,120, Qt::KeepAspectRatio);
  6.     m_logo.setPixmap(pm);
  7.     m_logo.move(2020);
  8.     m_logo.resize(120120);
  9.     QPalette p = m_info.palette();
  10.     p.setColor(QPalette::Active, QPalette::Base, palette().color(QPalette::Active, 
  11. QPalette::Background));
  12.     p.setColor(QPalette::Inactive, QPalette::Base, palette().color(QPalette::Inactive, 
  13. QPalette::Background));
  14.     m_info.setPalette(p);
  15.     m_info.move(20030);
  16.     m_info.resize(180130);
  17.     m_info.setFrameStyle(QPlainTextEdit::NoFrame);
  18.     m_info.setReadOnly(true);
  19.     m_info.insertPlainText("NotePad Project\n\nPlatform: Qt 5.6.2\n\nVersion: 1.0.0\n
  20. \nAuthor: Scorpio");
  21.     m_close.setText("Close");
  22.     m_close.move(273175);
  23.     m_close.resize(10030);
  24.     setWindowTitle("About NotePad");
  25.     setFixedSize(395230);
  26.     connect(&m_close, SIGNAL(clicked()), thisSLOT(onClose()));
  27. }

12、字体设置

设置文本框中的字体的属性。

字体设置通过QFontDialog对话框实现

槽函数如下:

  1. void MainWindow::onFormatFont()
  2. {
  3.     bool ok = false;
  4.     QFont font = QFontDialog::getFont(&ok, mainEditor.font(), this);
  5.     if(ok)
  6.     {
  7.         mainEditor.setFont(font);
  8.     }
  9. }

13、换行

QPlainTextEdit支持换行操作。在菜单栏、工具栏创建QAction对象时设置属性。

  1.        action->setCheckable(true);
  2.         action->setChecked(true);
  3.         connect(action, SIGNAL(triggered()), this, SLOT(onFormatWrap()));

槽函数如下:

  1. void MainWindow::onFormatWrap()
  2. {
  3.     QPlainTextEdit::LineWrapMode mode = mainEditor.lineWrapMode();
  4.     if(mode == QPlainTextEdit::NoWrap)
  5.     {
  6.         mainEditor.setLineWrapMode(QPlainTextEdit::WidgetWidth);
  7.         findMenuBarItem("Auto Wrap")->setChecked(true);
  8.         findToolBarItem("Auto Wrap")->setChecked(true);
  9.     }
  10.     else
  11.     {
  12.         mainEditor.setLineWrapMode(QPlainTextEdit::NoWrap);
  13.         findMenuBarItem("Auto Wrap")->setChecked(false);
  14.         findToolBarItem("Auto Wrap")->setChecked(false);
  15.     }
  16. }

14、帮助文档

QDesktopServices提供了一系列桌面开发的服务接口。

通过QDesktopServices的成员函数打开帮助文档。

[static] bool QDesktopServices::openUrl(const QUrl &url)

打开网页:

QDesktopServices::openUrl(QUrl("http://9291927.blog.51cto.com/"));

打开文档:

QDesktopServices::openUrl(QUrl("file:///C:/Documents and Settings/All Users/Desktop/help.pdf"));

15、程序配置文件

程序状态的保存可以通过在程序退出前保存程序状态参数到文件(数据库),程序启动时从配置文件读出状态参数并恢复。

程序状态参数的存储方式:

A、文本文件格式(XML、Json等)

B、轻量级数据库(Access、SQLite等)

C、二进制文件格式

通过二进制数据流将状态参数直接存储带文件中。

Appconfig.h文件:

  1. #ifndef APPCONFIG_H
  2. #define APPCONFIG_H
  3. #include <QObject>
  4. #include <QFont>
  5. #include <QFile>
  6. #include <QDataStream>
  7. #include <QApplication>
  8. class AppConfig : public QObject
  9. {
  10.     Q_OBJECT
  11. public:
  12.     explicit AppConfig(QObject *parent = 0);
  13.     explicit AppConfig(QFont editorfont, bool isautowrap, bool istoolbarvisible, 
  14. bool isstatusbarvisible, QObject *parent = 0);
  15.     bool store();
  16.     QFont editorFont();
  17.     bool isAutoWrap();
  18.     bool isToolBarVisible();
  19.     bool isStatusBarVisible();
  20.     bool isValid();
  21. private:
  22.     bool restore();
  23. private:
  24.     QFont m_editorFont;
  25.     bool m_isAutoWrap;
  26.     bool m_isToolBarVisible;
  27.     bool m_isStatusBarVisible;
  28.     bool m_isValid;
  29. };
  30. #endif // APPCONFIG_H

Appconfig.cpp文件:

  1. #include "AppConfig.h"
  2. AppConfig::AppConfig(QObject *parent) : QObject(parent)
  3. {
  4.     m_isValid = restore();
  5. }
  6. AppConfig::AppConfig(QFont editorfont, bool isautowrap, bool istoolbarvisible, 
  7. bool isstatusbarvisible, QObject *parent)
  8. {
  9.     m_editorFont = editorfont;
  10.     m_isAutoWrap = isautowrap;
  11.     m_isToolBarVisible = istoolbarvisible;
  12.     m_isStatusBarVisible = isstatusbarvisible;
  13.     m_isValid = true;
  14. }
  15. QFont AppConfig::editorFont()
  16. {
  17.     return m_editorFont;
  18. }
  19. bool AppConfig::isAutoWrap()
  20. {
  21.     return m_isAutoWrap;
  22. }
  23. bool AppConfig::isStatusBarVisible()
  24. {
  25.     return m_isStatusBarVisible;
  26. }
  27. bool AppConfig::isToolBarVisible()
  28. {
  29.     return m_isToolBarVisible;
  30. }
  31. bool AppConfig::isValid()
  32. {
  33.     return m_isValid;
  34. }
  35. bool AppConfig::store()
  36. {
  37.     bool ret = true;
  38.     QFile file(QApplication::applicationDirPath() + "/config.dat");
  39.     if(file.open(QIODevice::WriteOnly))
  40.     {
  41.         QDataStream out(&file);
  42.         out.setVersion(QDataStream::Qt_5_6);
  43.         out << m_editorFont;
  44.         out << m_isAutoWrap;
  45.         out << m_isToolBarVisible;
  46.         out << m_isStatusBarVisible;
  47.         file.close();
  48.     }
  49.     else
  50.     {
  51.         ret = false;
  52.     }
  53.     return ret;
  54. }
  55. bool AppConfig::restore()
  56. {
  57.     bool ret = true;
  58.     QFile file(QApplication::applicationDirPath() + "/config.dat");
  59.     if(file.open(QIODevice::ReadOnly))
  60.     {
  61.         QDataStream in(&file);
  62.         in.setVersion(QDataStream::Qt_5_6);
  63.         in >> m_editorFont;
  64.         in >> m_isAutoWrap;
  65.         in >> m_isToolBarVisible;
  66.         in >> m_isStatusBarVisible;
  67.         file.close();
  68.     }
  69.     else
  70.     {
  71.         ret = false;
  72.     }
  73.     return ret;
  74. }

从配置文件的读取状态参数恢复程序状态在构造函数中:

  1. bool MainWindow::construct()
  2. {
  3.     bool ret = true;
  4.     AppConfig config;
  5.     ret = ret && initMenuBar();
  6.     ret = ret && initToolBar();
  7.     ret = ret && initStatusBar();
  8.     ret = ret && initMainEditor();
  9.     if(config.isValid())
  10.     {
  11.         mainEditor.setFont(config.editorFont());
  12.         if(!config.isAutoWrap())
  13.         {
  14.             mainEditor.setLineWrapMode(QPlainTextEdit::NoWrap);
  15.             findToolBarItem("Auto Wrap")->setCheckable(false);
  16.             findMenuBarItem("Auto Wrap")->setChecked(false);
  17.         }
  18.         if(!config.isToolBarVisible())
  19.         {
  20.             toolBar()->setVisible(false);
  21.             findMenuBarItem("Tool Bar")->setChecked(false);
  22.             findToolBarItem("Tool Bar")->setChecked(false);
  23.         }
  24.         if(!config.isStatusBarVisible())
  25.         {
  26.             statusBar()->setVisible(false);
  27.             findMenuBarItem("Status Bar")->setChecked(false);
  28.             findToolBarItem("Status Bar")->setChecked(false);
  29.         }
  30.     }
  31.     return ret;
  32. }

状态参数保存到配置文件在析构函数中:

  1. MainWindow::~MainWindow()
  2. {
  3.     QFont font = mainEditor.font();
  4.     bool isautowrap = (mainEditor.lineWrapMode() == QPlainTextEdit::WidgetWidth);
  5.     bool istoolbarvisible = (findMenuBarItem("Tool Bar")->isChecked() 
  6. && findToolBarItem("Tool Bar")->isChecked());
  7.     bool isstatusbarvisible = (findMenuBarItem("Status Bar")->isChecked() 
  8. && findToolBarItem("Status Bar")->isChecked());
  9.     AppConfig config(font, isautowrap, istoolbarvisible, isstatusbarvisible);
  10.     config.store();
  11. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/700212
推荐阅读
相关标签
  

闽ICP备14008679号