10.7.  Exercises: MainWindows

[ fromfile: ex-mainwindows.xml id: ex-mainwindows ]

  1. Write a text editor application, with a QTextEdit as its central widget.

    • Show the filename and whether there are changes to be saved in the window title.

    • File Menu: Add actions for Open, Save as, and Quit.

    • Help Menu: Add actions for About and About Qt

    • If there are changes to be saved, ask the user to confirm the quit.

  2. Write an application that lets the user select and Open a text (or rich text) file from the disk and view the contents by scrolling through it. The scrolling view should expose several lines at a time (at least ten).

    It should also permit the user to search for a string in that file. If the string is found, the line that contains it should appear in the scrolling view so that the user can see its context within the file. If it is not found, an appropriate message should appear in the status bar.

    The user should click a button to search for the Next occurrence or the Previous occurrence of the search string.

    There should also be a Close button that removes the file from the display and invites the user to select another file or Quit.

    Figure 10.11 is a screenshot of one possible solution. The two menus contain actions that duplicate all of the pushbuttons except for Clear Search (which just clears the search text).

    Figure 10.11.  Text File Browser

    Text File Browser

     

    Example 10.15. solution/textFileBrowser/main.cpp

    #include <QtGui/QApplication>
    #include "mainwindow.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    

    <include src="solution/textFileBrowser/main.cpp" href="solution/textFileBrowser/main.cpp" role="solution" mode="cpp"/>


    Example 10.16. solution/textFileBrowser/mainwindow.cpp

    #include <QFileDialog>
    #include <QFile>
    #include <QString>
    #include <QTextStream>
    #include <QCoreApplication>
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::on_openButton_clicked() {
        QString fileName = QFileDialog::getOpenFileName();
        QFile file(fileName);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
             return;
        QTextStream in(&file);
        m_Lines.clear();
        while (!in.atEnd()) {
            QString line = in.readLine();
            m_Lines << line;
        }
        file.close();
        ui->textEdit->clear();
        ui->textEdit->setHtml(m_Lines.join("\n"));
    }
    
    void MainWindow::on_closeButton_clicked()
    {
        ui->textEdit->clear();
        m_Lines.clear();
    }
    
    void MainWindow::on_quitButton_clicked()
    {
        QCoreApplication::quit();
    }
    
    void MainWindow::on_searchEdit_returnPressed()
    {
        QString searchstr = ui->searchEdit->text();
        if(ui->textEdit->find(searchstr))
            statusBar()->clearMessage();
        else
            statusBar()->showMessage(searchstr + " not found");
    }
    
    void MainWindow::on_nextButton_clicked()
    {
        on_searchEdit_returnPressed();
    }
    
    void MainWindow::on_previousButton_clicked()
    {
        QString searchstr = ui->searchEdit->text();
        if(ui->textEdit->find(searchstr, QTextDocument::FindBackward))
            statusBar()->clearMessage();
        else
            statusBar()->showMessage(searchstr + " not found");
    }
    
    void MainWindow::on_actionOpen_triggered()
    {
        on_openButton_clicked();
    }
    
    void MainWindow::on_action_Close_triggered()
    {
        on_closeButton_clicked();
    }
    
    void MainWindow::on_action_Quit_triggered()
    {
        on_quitButton_clicked();
    }
    
    void MainWindow::on_action_Previous_triggered()
    {
        on_previousButton_clicked();
    }
    
    void MainWindow::on_action_Next_triggered()
    {
        on_nextButton_clicked();
    }
    
    void MainWindow::on_clearSearchButton_clicked()
    {
        ui->searchEdit->clear();
        ui->searchEdit->setFocus();
    }
    

    <include src="solution/textFileBrowser/mainwindow.cpp" href="solution/textFileBrowser/mainwindow.cpp" role="solution" mode="cpp"/>


    Example 10.17. solution/textFileBrowser/mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QString>
    
    namespace Ui {
        class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
        QStringList m_Lines;
    
    private slots:
        void on_clearSearchButton_clicked();
        void on_closeButton_clicked();
        void on_action_Close_triggered();
        void on_action_Next_triggered();
        void on_action_Previous_triggered();
        void on_action_Quit_triggered();
        void on_actionOpen_triggered();
        void on_previousButton_clicked();
        void on_nextButton_clicked();
        void on_searchEdit_returnPressed();
        void on_quitButton_clicked();
        void on_openButton_clicked();
    };
    
    #endif // MAINWINDOW_H
    

    <include src="solution/textFileBrowser/mainwindow.h" href="solution/textFileBrowser/mainwindow.h" role="solution" mode="cpp"/>


    Example 10.18. solution/textFileBrowser/mainwindow.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>MainWindow</class>
     <widget class="QMainWindow" name="MainWindow">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>767</width>
        <height>473</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>Text File Browser</string>
      </property>
      <widget class="QWidget" name="centralWidget">
       <widget class="QWidget" name="">
        <property name="geometry">
         <rect>
          <x>10</x>
          <y>1</y>
          <width>751</width>
          <height>421</height>
         </rect>
        </property>
        <layout class="QHBoxLayout" name="horizontalLayout_3">
         <item>
          <layout class="QVBoxLayout" name="verticalLayout_2">
           <item>
            <widget class="QTextEdit" name="textEdit"/>
           </item>
           <item>
            <layout class="QHBoxLayout" name="horizontalLayout_2">
             <item>
              <widget class="QLabel" name="label">
               <property name="text">
                <string>Search text</string>
               </property>
              </widget>
             </item>
             <item>
              <widget class="QLineEdit" name="searchEdit"/>
             </item>
            </layout>
           </item>
           <item>
            <layout class="QHBoxLayout" name="horizontalLayout">
             <item>
              <widget class="QPushButton" name="previousButton">
               <property name="text">
                <string>Previous</string>
               </property>
              </widget>
             </item>
             <item>
              <widget class="QPushButton" name="nextButton">
               <property name="text">
                <string>Next</string>
               </property>
              </widget>
             </item>
             <item>
              <widget class="QPushButton" name="clearSearchButton">
               <property name="text">
                <string>ClearSearch</string>
               </property>
              </widget>
             </item>
             <item>
              <spacer name="horizontalSpacer">
               <property name="orientation">
                <enum>Qt::Horizontal</enum>
               </property>
               <property name="sizeHint" stdset="0">
                <size>
                 <width>40</width>
                 <height>20</height>
                </size>
               </property>
              </spacer>
             </item>
            </layout>
           </item>
          </layout>
         </item>
         <item>
          <layout class="QVBoxLayout" name="verticalLayout">
           <item>
            <spacer name="verticalSpacer_2">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>20</width>
               <height>40</height>
              </size>
             </property>
            </spacer>
           </item>
           <item>
            <widget class="QPushButton" name="openButton">
             <property name="text">
              <string>Open</string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QPushButton" name="closeButton">
             <property name="text">
              <string>Close</string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QPushButton" name="quitButton">
             <property name="text">
              <string>Quit</string>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="verticalSpacer">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>20</width>
               <height>40</height>
              </size>
             </property>
            </spacer>
           </item>
          </layout>
         </item>
        </layout>
       </widget>
      </widget>
      <widget class="QMenuBar" name="menuBar">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>767</width>
         <height>23</height>
        </rect>
       </property>
       <widget class="QMenu" name="menuFile">
        <property name="title">
         <string>File</string>
        </property>
        <addaction name="actionOpen"/>
        <addaction name="action_Close"/>
        <addaction name="action_Quit"/>
       </widget>
       <widget class="QMenu" name="menuSearch">
        <property name="title">
         <string>Search</string>
        </property>
        <addaction name="action_Previous"/>
        <addaction name="action_Next"/>
       </widget>
       <addaction name="menuFile"/>
       <addaction name="menuSearch"/>
      </widget>
      <widget class="QToolBar" name="mainToolBar">
       <attribute name="toolBarArea">
        <enum>TopToolBarArea</enum>
       </attribute>
       <attribute name="toolBarBreak">
        <bool>false</bool>
       </attribute>
      </widget>
      <widget class="QStatusBar" name="statusBar"/>
      <action name="actionOpen">
       <property name="text">
        <string>&amp;Open</string>
       </property>
      </action>
      <action name="action_Close">
       <property name="text">
        <string>&amp;Close</string>
       </property>
      </action>
      <action name="action_Quit">
       <property name="text">
        <string>&amp;Quit</string>
       </property>
      </action>
      <action name="action_Previous">
       <property name="text">
        <string>&amp;Previous</string>
       </property>
      </action>
      <action name="action_Next">
       <property name="text">
        <string>&amp;Next</string>
       </property>
      </action>
     </widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    </ui>

    <include src="solution/textFileBrowser/mainwindow.ui" href="solution/textFileBrowser/mainwindow.ui" role="solution" mode="txt"/>


    Example 10.19. solution/textFileBrowser/textBrowser.pro

    #-------------------------------------------------
    #
    # Project created by QtCreator 2011-04-11T18:29:14
    #
    #-------------------------------------------------
    
    QT       += core gui
    
    TARGET = textBrowser
    TEMPLATE = app
    
    
    SOURCES += main.cpp\
            mainwindow.cpp
    
    HEADERS  += mainwindow.h
    
    FORMS    += mainwindow.ui

    <include src="solution/textFileBrowser/textBrowser.pro" href="solution/textFileBrowser/textBrowser.pro" role="solution" mode="txt"/>


  3. QTextEdit provides methods for undo and redo. Investigate these features and discuss the operations that can be undone or redone.

  There is a nice solution (or starting point) to this in $QTDIR/examples/mainwindows/application.