Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Windows Live Favorites 
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Classes principales  ·  Annotées  ·  Classes groupées  ·  Modules  ·  Fonctions  · 

Dock Widgets Example

Files:

The Dock Widgets example shows how to add dock windows to an application. It also shows how to use Qt's rich text engine.

Screenshot of the Dock Widgets example

The application presents a simple business letter template, and has a list of customer names and addresses and a list of standard phrases in two dock windows. The user can click a customer to have their name and address inserted into the template, and click one or more of the standard phrases. Errors can be corrected by clicking the Undo button. Once the letter has been prepared it can be printed or saved as HTML.

MainWindow Class Definition

Here's the class definition:

    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 createMenus();
        void createToolBars();
        void createStatusBar();
        void createDockWindows();

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

        QMenu *fileMenu;
        QMenu *editMenu;
        QMenu *viewMenu;
        QMenu *helpMenu;
        QToolBar *fileToolBar;
        QToolBar *editToolBar;
        QAction *newLetterAct;
        QAction *saveAct;
        QAction *printAct;
        QAction *undoAct;
        QAction *aboutAct;
        QAction *aboutQtAct;
        QAction *quitAct;
    };

We will now review each function in turn.

MainWindow Class Implementation

    #include <QtGui>

    #include "mainwindow.h"

We start by including <QtGui>, a header file that contains the definition of all classes in the QtCore and QtGui libraries. This saves us from having to include every class individually and is especially convenient if we add new widgets. We also include mainwindow.h.

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

        createActions();
        createMenus();
        createToolBars();
        createStatusBar();
        createDockWindows();

        setWindowTitle(tr("Dock Widgets"));

        newLetter();
    }

In the constructor, we start by creating a QTextEdit widget. Then we call QMainWindow::setCentralWidget(). This function passes ownership of the QTextEdit to the MainWindow and tells the MainWindow that the QTextEdit will occupy the MainWindow's central area.

Then we call createActions(), createMenus(), createToolBars(), createStatusBar(), and createDockWindows() to set up the user interface. Finally we call setWindowTitle() to give the application a title, and newLetter() to create a new letter template.

We won't quote the createActions(), createMenus(), createToolBars(), and createStatusBar() functions since they follow the same pattern as all the other Qt examples.

    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, SIGNAL(currentTextChanged(const QString &)),
                this, SLOT(insertCustomer(const QString &)));
        connect(paragraphsList, SIGNAL(currentTextChanged(const QString &)),
                this, SLOT(addParagraph(const QString &)));
    }

We create the customers dock window first, and in addition to a window title, we also pass it a this pointer so that it becomes a child of MainWindow. Normally we don't have to pass a parent because widgets are parented automatically when they are laid out: but dock windows aren't laid out using layouts.

We've chosen to restrict the customers dock window to the left and right dock areas. (So the user cannot drag the dock window to the top or bottom dock areas.) The user can drag the dock window out of the dock areas entirely so that it becomes a free floating window. We can change this (and whether the dock window is moveable or closable) using QDockWidget::setFeatures().

Once we've created the dock window we create a list widget with the dock window as parent, then we populate the list and make it the dock window's widget. Finally we add the dock widget to the MainWindow using addDockWidget(), choosing to put it in the right dock area.

We undertake a similar process for the paragraphs dock window, except that we don't restrict which dock areas it can be dragged to.

Finally we set up the signal-slot connections. If the user clicks a customer or a paragraph their currentTextChanged() signal will be emitted and we connect these to insertCustomer() and addParagraph() passing the text that was clicked.

We briefly discuss the rest of the implementation, but have now covered everything relating to dock windows.

    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);
    }

In this function we clear the QTextEdit so that it is empty. Next we create a QTextCursor on the QTextEdit. We move the cursor to the start of the document and create and format a frame. We then create some character formats and a table format. We insert a table into the document and insert the company's name and address into a table using the table and character formats we created earlier. Then we insert the skeleton of the letter including two markers NAME and ADDRESS. We will also use the Yours sincerely, text as a marker.

    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();
        }
    }

If the user clicks a customer we split the customer details into pieces. We then look for the NAME marker using the find() function. This function selects the text it finds, so when we call insertText() with the customer's name the name replaces the marker. We then look for the ADDRESS marker and replace it with each line of the customer's address. Notice that we wrapped all the insertions between a beginEditBlock() and endEditBlock() pair. This means that the entire name and address insertion is treated as a single operation by the QTextEdit, so a single undo will revert all the insertions.

    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();

    }

This function works in a similar way to insertCustomer(). First we look for the marker, in this case, Yours sincerely,, and then replace it with the standard paragraph that the user clicked. Again we use a beginEditBlock() ... endEditBlock() pair so that the insertion can be undone as a single operation.

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

        QPrintDialog *dlg = new QPrintDialog(&printer, this);
        if (dlg->exec() != QDialog::Accepted)
            return;

        document->print(&printer);

        statusBar()->showMessage(tr("Ready"), 2000);
    }

Qt's QTextDocument class makes printing documents easy. We simply take the QTextEdit's QTextDocument, set up the printer and print the document.

    void MainWindow::save()
    {
        QString fileName = QFileDialog::getSaveFileName(this,
                            tr("Choose a file name"), ".",
                            tr("HTML (*.html *.htm)"));
        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(fileName)
                                 .arg(file.errorString()));
            return;
        }

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

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

QTextEdit can output its contents in HTML format, so we prompt the user for the name of an HTML file and if they provide one we simply write the QTextEdit's contents in HTML format to the file.

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

If the focus is in the QTextEdit, pressing Ctrl+Z undoes as expected. But for the user's convenience we provide an application-wide undo function that simply calls the QTextEdit's undo: this means that the user can undo regardless of where the focus is in the application.

Publicité

Best Of

Actualités les plus lues

Semaine
Mois
Année
  1. « Quelque chose ne va vraiment pas avec les développeurs "modernes" », un développeur à "l'ancienne" critique la multiplication des bibliothèques 94
  2. Apercevoir la troisième dimension ou l'utilisation multithreadée d'OpenGL dans Qt, un article des Qt Quarterly traduit par Guillaume Belz 0
  3. Les développeurs ignorent-ils trop les failles découvertes dans leur code ? Prenez-vous en compte les remarques des autres ? 17
  4. Pourquoi les programmeurs sont-ils moins payés que les gestionnaires de programmes ? Manquent-ils de pouvoir de négociation ? 42
  5. Quelles nouveautés de C++11 Visual C++ doit-il rapidement intégrer ? Donnez-nous votre avis 10
  6. 2017 : un quinquennat pour une nouvelle version du C++ ? Possible, selon Herb Sutter 9
  7. Qt Commercial : Digia organise un webinar gratuit le 27 mars sur la conception d'interfaces utilisateur et d'applications avec le framework 0
Page suivante

Le Qt Developer Network au hasard

Logo

Une introduction à Qt Quick

Le Qt Developer Network est un réseau de développeurs Qt anglophone, où ils peuvent partager leur expérience sur le framework. Lire l'article.

Communauté

Ressources

Liens utiles

Contact

  • Vous souhaitez rejoindre la rédaction ou proposer un tutoriel, une traduction, une question... ? Postez dans le forum Contribuez ou contactez-nous par MP ou par email (voir en bas de page).

Qt dans le magazine

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 4.1
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
 
 
 
 
Partenaires

Hébergement Web