第六章 布局管理

    在Qt Designer中使用会比代码中方便,但是代码中的布局会比较灵活。使用Qt布局类的一个重要原因是:他可以确保窗体能够自动适应不同的字体、语言、和系统平台。

    主要类有QHBoxLayout、QVBoxLayout、QGridLayout和QStackLayout。可执行布局管理的类还有QSplitterr、QScrollArea、QMainWindow和QMidArea。

一、在窗口中摆放窗口部件

    绝对位置法、人工布局法、布局管理器法。

    绝对位置法

FindFileDialog::FindFileDialog(QWidget *parent)
    : QDialog(parent)
{
    namedLabel->setGeometry(9, 9, 50, 25);
    namedLineEdit->setGeometry(65, 9, 200, 25);
    lookInLabel->setGeometry(9, 40, 50, 25);
    lookInLineEdit->setGeometry(65, 40, 200, 25);
    subfoldersCheckBox->setGeometry(9, 71, 256, 23);
    tableWidget->setGeometry(9, 100, 256, 100);
    messageLabel->setGeometry(9, 206, 256, 25);
    findButton->setGeometry(271, 9, 85, 32);
    stopButton->setGeometry(271, 47, 85, 32);
    closeButton->setGeometry(271, 84, 85, 32);
    helpButton->setGeometry(271, 199, 85, 32);

    setWindowTitle(tr("Find Files or Folders"));
    setFixedSize(365, 240);
}
像这种的直接设置控件的固定位置,缺点有很多,用户无法改变窗口的大小、容易出现文本截断现象、可能跨平台的时候布局出错、必须认为计算位置,否则极不好看。

    人工布局法:

尽管人工布局还是要放置绝对位置,但是可以设定和整个窗口的大小比例,币完全手写代码好很多哦。

FindFileDialog::FindFileDialog(QWidget *parent)
    : QDialog(parent)
{
    namedLabel = new QLabel(tr("&Named:"), this);
    namedLineEdit = new QLineEdit(this);
    namedLabel->setBuddy(namedLineEdit);

    lookInLabel = new QLabel(tr("&Look in:"), this);
    lookInLineEdit = new QLineEdit(this);
    lookInLabel->setBuddy(lookInLineEdit);

    subfoldersCheckBox = new QCheckBox(tr("Include subfolders"), this);

    QStringList labels;
    labels << tr("Name") << tr("In Folder") << tr("Size")
           << tr("Modified");

    tableWidget = new QTableWidget(this);
    tableWidget->setColumnCount(4);
    tableWidget->setHorizontalHeaderLabels(labels);

    messageLabel = new QLabel(tr("0 files found"), this);
    messageLabel->setFrameShape(QLabel::Panel);
    messageLabel->setFrameShadow(QLabel::Sunken);

    findButton = new QPushButton(tr("&Find"), this);
    stopButton = new QPushButton(tr("Stop"), this);
    closeButton = new QPushButton(tr("Close"), this);
    helpButton = new QPushButton(tr("Help"), this);

    connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));

    setWindowTitle(tr("Find Files or Folders"));
    setMinimumSize(265, 190);
    resize(365, 240);
}

void FindFileDialog::resizeEvent(QResizeEvent * /* event */)
{
    int extraWidth = width() - minimumWidth();
    int extraHeight = height() - minimumHeight();

    namedLabel->setGeometry(9, 9, 50, 25);
    namedLineEdit->setGeometry(65, 9, 100 + extraWidth, 25);
    lookInLabel->setGeometry(9, 40, 50, 25);
    lookInLineEdit->setGeometry(65, 40, 100 + extraWidth, 25);
    subfoldersCheckBox->setGeometry(9, 71, 156 + extraWidth, 23);
    tableWidget->setGeometry(9, 100, 156 + extraWidth,
                             50 + extraHeight);
    messageLabel->setGeometry(9, 156 + extraHeight, 156 + extraWidth,
                              25);
    findButton->setGeometry(171 + extraWidth, 9, 85, 32);
    stopButton->setGeometry(171 + extraWidth, 47, 85, 32);
    closeButton->setGeometry(171 + extraWidth, 84, 85, 32);
    helpButton->setGeometry(171 + extraWidth, 149 + extraHeight, 85,
                            32);
}
在resizeEvent()在处理器中,将多余的空间留给了哪些希望变长或者变高的窗口部件。

即使这样也存在需要编写大量代码和出现文本截断现象。


    布局管理器法:

最方便的方法就是使用布局管理器,布局管理器会充分考虑控件尺寸,也会自动改变空间大小以适应不同情况。

给出一个使用实例:

布局和效果如图:

第六章 布局管理第六章 布局管理

findfiledialog.h

#include <QtGui>

#include "findfiledialog.h"

FindFileDialog::FindFileDialog(QWidget *parent)
    : QDialog(parent)
{
    namedLabel = new QLabel(tr("&Named:"));
    namedLineEdit = new QLineEdit;
    namedLabel->setBuddy(namedLineEdit);

    lookInLabel = new QLabel(tr("&Look in:"));
    lookInLineEdit = new QLineEdit;
    lookInLabel->setBuddy(lookInLineEdit);

    subfoldersCheckBox = new QCheckBox(tr("Include subfolders"));

    QStringList labels;
    labels << tr("Name") << tr("In Folder") << tr("Size")
           << tr("Modified");

    tableWidget = new QTableWidget;
    tableWidget->setColumnCount(4);
    tableWidget->setHorizontalHeaderLabels(labels);

    messageLabel = new QLabel(tr("0 files found"));
    messageLabel->setFrameShape(QLabel::Panel);
    messageLabel->setFrameShadow(QLabel::Sunken);

    findButton = new QPushButton(tr("&Find"));
    stopButton = new QPushButton(tr("Stop"));
    closeButton = new QPushButton(tr("Close"));
    helpButton = new QPushButton(tr("Help"));

    connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));

    QGridLayout *leftLayout = new QGridLayout;
    leftLayout->addWidget(namedLabel, 0, 0);
    leftLayout->addWidget(namedLineEdit, 0, 1);
    leftLayout->addWidget(lookInLabel, 1, 0);
    leftLayout->addWidget(lookInLineEdit, 1, 1);
    leftLayout->addWidget(subfoldersCheckBox, 2, 0, 1, 2);
    leftLayout->addWidget(tableWidget, 3, 0, 1, 2);
    leftLayout->addWidget(messageLabel, 4, 0, 1, 2);

    QVBoxLayout *rightLayout = new QVBoxLayout;
    rightLayout->addWidget(findButton);
    rightLayout->addWidget(stopButton);
    rightLayout->addWidget(closeButton);
    rightLayout->addStretch();
    rightLayout->addWidget(helpButton);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addLayout(leftLayout);
    mainLayout->addLayout(rightLayout);
    setLayout(mainLayout);

    setWindowTitle(tr("Find Files or Folders"));
}

findfiledialog.cpp

#include <QtGui>

#include "findfiledialog.h"

FindFileDialog::FindFileDialog(QWidget *parent)
    : QDialog(parent)
{
    namedLabel = new QLabel(tr("&Named:"));
    namedLineEdit = new QLineEdit;
    namedLabel->setBuddy(namedLineEdit);

    lookInLabel = new QLabel(tr("&Look in:"));
    lookInLineEdit = new QLineEdit;
    lookInLabel->setBuddy(lookInLineEdit);

    subfoldersCheckBox = new QCheckBox(tr("Include subfolders"));

    QStringList labels;
    labels << tr("Name") << tr("In Folder") << tr("Size")
           << tr("Modified");

    tableWidget = new QTableWidget;
    tableWidget->setColumnCount(4);
    tableWidget->setHorizontalHeaderLabels(labels);

    messageLabel = new QLabel(tr("0 files found"));
    messageLabel->setFrameShape(QLabel::Panel);
    messageLabel->setFrameShadow(QLabel::Sunken);

    findButton = new QPushButton(tr("&Find"));
    stopButton = new QPushButton(tr("Stop"));
    closeButton = new QPushButton(tr("Close"));
    helpButton = new QPushButton(tr("Help"));

    connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));

    QGridLayout *leftLayout = new QGridLayout;
    leftLayout->addWidget(namedLabel, 0, 0);
    leftLayout->addWidget(namedLineEdit, 0, 1);
    leftLayout->addWidget(lookInLabel, 1, 0);
    leftLayout->addWidget(lookInLineEdit, 1, 1);
    leftLayout->addWidget(subfoldersCheckBox, 2, 0, 1, 2);
    leftLayout->addWidget(tableWidget, 3, 0, 1, 2);
    leftLayout->addWidget(messageLabel, 4, 0, 1, 2);

    QVBoxLayout *rightLayout = new QVBoxLayout;
    rightLayout->addWidget(findButton);
    rightLayout->addWidget(stopButton);
    rightLayout->addWidget(closeButton);
    rightLayout->addStretch();
    rightLayout->addWidget(helpButton);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addLayout(leftLayout);
    mainLayout->addLayout(rightLayout);
    setLayout(mainLayout);

    setWindowTitle(tr("Find Files or Folders"));
}

main.cpp

#include <QApplication>

#include "findfiledialog.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    FindFileDialog dialog;
    dialog.show();
    return app.exec();
}
布局管理器为我们提供很多额外的好处,添加或移除(即使是hide()或者show()也可以)窗口部件,布局都会自动适应这些布局。

一个窗口布局的大小策略(QSizePolicy)会告诉布局系统应该如何对部件进行拉伸或者压缩。

一个QSizePolicy既包含水平分量也包含垂直分量。最常用取值如下:

第六章 布局管理


二、分组布局

QStackedLayout类可以对一组子窗口部件进行摆放,或者对他们进行分页,并且一次显示一个。

这种东西和QTabWidget很像,替换一下也是可以的看你喜欢哪一种了

使用方法就是把你自己的QWidget放在你的QStackedLayout中就可以了;

 QWidget *appearancePage;

 stackedLayout = new QStackedLayout;

 stackedLayout->addWidget(appearancePage);


第六章 布局管理

preferencedialog.h

#ifndef PREFERENCEDIALOG_H
#define PREFERENCEDIALOG_H

#include <QDialog>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QRadioButton>
#include <QStackedLayout>

class PreferenceDialog : public QDialog
{
    Q_OBJECT

public:
    PreferenceDialog(QWidget *parent = 0);

private:
    void createAppearancePage();
    void createWebBrowserPage();
    void createMailAndNewsPage();
    void createAdvancedPage();

    QStackedLayout *stackedLayout;
    QListWidget *listWidget;
    QWidget *appearancePage;
    QWidget *webBrowserPage;
    QWidget *mailAndNewsPage;
    QWidget *advancedPage;
    QDialogButtonBox *buttonBox;

    QGroupBox *openGroupBox;
    QCheckBox *webBrowserCheckBox;
    QCheckBox *mailEditorCheckBox;
    QCheckBox *newsgroupCheckBox;
    QGroupBox *toolbarsGroupBox;
    QRadioButton *picturesAndTextRadioButton;
    QRadioButton *picturesOnlyRadioButton;
    QRadioButton *textOnlyRadioButton;
    QCheckBox *tooltipsCheckBox;
    QCheckBox *webSiteIconsCheckBox;
    QCheckBox *resizeImagesCheckBox;

    QGroupBox *displayGroupBox;
    QRadioButton *blankRadioButton;
    QRadioButton *homeRadioButton;
    QRadioButton *lastRadioButton;
    QGroupBox *homeGroupBox;
    QLabel *locationLabel;
    QLineEdit *locationLineEdit;
    QGroupBox *webButtonsGroupBox;
    QCheckBox *bookmarksCheckBox;
    QCheckBox *goCheckBox;
    QCheckBox *homeCheckBox;
    QCheckBox *searchCheckBox;
    QCheckBox *printCheckBox;

    QGroupBox *generalGroupBox;
    QCheckBox *confirmCheckBox;
    QCheckBox *rememberCheckBox;
    QGroupBox *mailButtonsGroupBox;
    QCheckBox *fileCheckBox;
    QCheckBox *nextCheckBox;
    QCheckBox *stopCheckBox;
    QCheckBox *junkCheckBox;

    QGroupBox *featuresGroupBox;
    QCheckBox *javaCheckBox;
    QCheckBox *ftpCheckBox;
    QLineEdit *ftpLineEdit;
};

#endif

preferencedialog.cpp

#include <QtGui>

#include "preferencedialog.h"

PreferenceDialog::PreferenceDialog(QWidget *parent)
    : QDialog(parent)
{
    createAppearancePage();
    createWebBrowserPage();
    createMailAndNewsPage();
    createAdvancedPage();

    buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
                                     | QDialogButtonBox::Cancel);

    listWidget = new QListWidget;
    listWidget->addItem(tr("Appearance"));
    listWidget->addItem(tr("Web Browser"));
    listWidget->addItem(tr("Mail & News"));
    listWidget->addItem(tr("Advanced"));

    stackedLayout = new QStackedLayout;
    stackedLayout->addWidget(appearancePage);
    stackedLayout->addWidget(webBrowserPage);
    stackedLayout->addWidget(mailAndNewsPage);
    stackedLayout->addWidget(advancedPage);
    connect(listWidget, SIGNAL(currentRowChanged(int)),
            stackedLayout, SLOT(setCurrentIndex(int)));

    QGridLayout *mainLayout = new QGridLayout;
    mainLayout->setColumnStretch(0, 1);
    mainLayout->setColumnStretch(1, 3);
    mainLayout->addWidget(listWidget, 0, 0);
    mainLayout->addLayout(stackedLayout, 0, 1);
    mainLayout->addWidget(buttonBox, 1, 0, 1, 2);
    setLayout(mainLayout);

    connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));

    setWindowTitle(tr("Preferences"));
    listWidget->setCurrentRow(0);
}

void PreferenceDialog::createAppearancePage()
{
    appearancePage = new QWidget;

    openGroupBox = new QGroupBox(tr("Open at startup"));
    webBrowserCheckBox = new QCheckBox(tr("Web browser"));
    mailEditorCheckBox = new QCheckBox(tr("Mail editor"));
    newsgroupCheckBox = new QCheckBox(tr("Newsgroups"));

    toolbarsGroupBox = new QGroupBox(tr("Show toolbars as"));
    picturesAndTextRadioButton = new QRadioButton(tr("Pictures and "
                                                     "text"));
    picturesOnlyRadioButton = new QRadioButton(tr("Pictures only"));
    textOnlyRadioButton = new QRadioButton(tr("Text only"));

    tooltipsCheckBox = new QCheckBox(tr("Show tooltips"));
    webSiteIconsCheckBox = new QCheckBox(tr("Show web site icons"));
    resizeImagesCheckBox = new QCheckBox(tr("Resize large images to "
                                            "fit in the window"));

    QVBoxLayout *openLayout = new QVBoxLayout;
    openLayout->addWidget(webBrowserCheckBox);
    openLayout->addWidget(mailEditorCheckBox);
    openLayout->addWidget(newsgroupCheckBox);
    openGroupBox->setLayout(openLayout);

    QVBoxLayout *toolbarsLayout = new QVBoxLayout;
    toolbarsLayout->addWidget(picturesAndTextRadioButton);
    toolbarsLayout->addWidget(picturesOnlyRadioButton);
    toolbarsLayout->addWidget(textOnlyRadioButton);
    toolbarsGroupBox->setLayout(toolbarsLayout);

    QVBoxLayout *pageLayout = new QVBoxLayout;
    pageLayout->setMargin(0);
    pageLayout->addWidget(openGroupBox);
    pageLayout->addWidget(toolbarsGroupBox);
    pageLayout->addWidget(tooltipsCheckBox);
    pageLayout->addWidget(webSiteIconsCheckBox);
    pageLayout->addWidget(resizeImagesCheckBox);
    pageLayout->addStretch();
    appearancePage->setLayout(pageLayout);

    webBrowserCheckBox->setChecked(true);
    mailEditorCheckBox->setChecked(true);
    picturesAndTextRadioButton->setChecked(true);
    tooltipsCheckBox->setChecked(true);
    webSiteIconsCheckBox->setChecked(true);
}

void PreferenceDialog::createWebBrowserPage()
{
    webBrowserPage = new QWidget;

    displayGroupBox = new QGroupBox(tr("Display on startup"));
    blankRadioButton = new QRadioButton(tr("Blank page"));
    homeRadioButton = new QRadioButton(tr("Blank page"));
    lastRadioButton = new QRadioButton(tr("Last page visited"));

    homeGroupBox = new QGroupBox(tr("Home Page"));
    locationLabel = new QLabel(tr("Location:"));
    locationLineEdit = new QLineEdit;

    webButtonsGroupBox = new QGroupBox(tr("Select the buttons you want "
                                          "in the toolbar"));
    bookmarksCheckBox = new QCheckBox(tr("Bookmarks"));
    goCheckBox = new QCheckBox(tr("Go"));
    homeCheckBox = new QCheckBox(tr("Home"));
    searchCheckBox = new QCheckBox(tr("Search"));
    printCheckBox = new QCheckBox(tr("Print"));

    QVBoxLayout *displayLayout = new QVBoxLayout;
    displayLayout->addWidget(blankRadioButton);
    displayLayout->addWidget(homeRadioButton);
    displayLayout->addWidget(lastRadioButton);
    displayGroupBox->setLayout(displayLayout);

    QHBoxLayout *homeLayout = new QHBoxLayout;
    homeLayout->addWidget(locationLabel);
    homeLayout->addWidget(locationLineEdit);
    homeGroupBox->setLayout(homeLayout);

    QGridLayout *webButtonsLayout = new QGridLayout;
    webButtonsLayout->addWidget(bookmarksCheckBox, 0, 0);
    webButtonsLayout->addWidget(goCheckBox, 1, 0);
    webButtonsLayout->addWidget(homeCheckBox, 2, 0);
    webButtonsLayout->addWidget(searchCheckBox, 0, 1);
    webButtonsLayout->addWidget(printCheckBox, 1, 1);
    webButtonsGroupBox->setLayout(webButtonsLayout);

    QVBoxLayout *pageLayout = new QVBoxLayout;
    pageLayout->setMargin(0);
    pageLayout->addWidget(displayGroupBox);
    pageLayout->addWidget(homeGroupBox);
    pageLayout->addWidget(webButtonsGroupBox);
    pageLayout->addStretch();
    webBrowserPage->setLayout(pageLayout);

    homeRadioButton->setChecked(true);
    locationLineEdit->setText("http://www.trolltech.com/");
    bookmarksCheckBox->setChecked(true);
    homeCheckBox->setChecked(true);
    searchCheckBox->setChecked(true);
    printCheckBox->setChecked(true);
}

void PreferenceDialog::createMailAndNewsPage()
{
    mailAndNewsPage = new QWidget;

    generalGroupBox = new QGroupBox(tr("General settings"));
    confirmCheckBox = new QCheckBox(tr("Warn when moving folders to "
                                       "the Trash"));
    rememberCheckBox = new QCheckBox(tr("Remember the last selected "
                                        "message"));

    mailButtonsGroupBox = new QGroupBox(tr("Select the buttons you "
                                           "want in the toolbar"));
    fileCheckBox = new QCheckBox(tr("File"));
    nextCheckBox = new QCheckBox(tr("Next"));
    stopCheckBox = new QCheckBox(tr("Stop"));
    junkCheckBox = new QCheckBox(tr("Junk"));

    QVBoxLayout *generalLayout = new QVBoxLayout;
    generalLayout->addWidget(confirmCheckBox);
    generalLayout->addWidget(rememberCheckBox);
    generalGroupBox->setLayout(generalLayout);

    QGridLayout *mailButtonsLayout = new QGridLayout;
    mailButtonsLayout->addWidget(fileCheckBox, 0, 0);
    mailButtonsLayout->addWidget(nextCheckBox, 1, 0);
    mailButtonsLayout->addWidget(stopCheckBox, 0, 1);
    mailButtonsLayout->addWidget(junkCheckBox, 1, 1);
    mailButtonsGroupBox->setLayout(mailButtonsLayout);

    QVBoxLayout *pageLayout = new QVBoxLayout;
    pageLayout->setMargin(0);
    pageLayout->addWidget(generalGroupBox);
    pageLayout->addWidget(mailButtonsGroupBox);
    pageLayout->addStretch();
    mailAndNewsPage->setLayout(pageLayout);

    confirmCheckBox->setChecked(true);
    rememberCheckBox->setChecked(true);
    nextCheckBox->setChecked(true);
    junkCheckBox->setChecked(true);
}

void PreferenceDialog::createAdvancedPage()
{
    advancedPage = new QWidget;

    featuresGroupBox = new QGroupBox(tr("Features that help "
                                        "interpret web pages"));
    javaCheckBox = new QCheckBox(tr("Enable Java"));
    ftpCheckBox = new QCheckBox(tr("Use this email address for "
                                   "anonymous FTP:"));
    ftpLineEdit = new QLineEdit;

    connect(ftpCheckBox, SIGNAL(toggled(bool)),
            ftpLineEdit, SLOT(setEnabled(bool)));

    QGridLayout *featuresLayout = new QGridLayout;
    featuresLayout->addWidget(javaCheckBox, 0, 0, 1, 2);
    featuresLayout->addWidget(ftpCheckBox, 1, 0, 1, 2);
    featuresLayout->addWidget(ftpLineEdit, 2, 1);
    featuresGroupBox->setLayout(featuresLayout);

    QVBoxLayout *pageLayout = new QVBoxLayout;
    pageLayout->setMargin(0);
    pageLayout->addWidget(featuresGroupBox);
    pageLayout->addStretch();
    advancedPage->setLayout(pageLayout);

    javaCheckBox->setChecked(true);
    ftpLineEdit->setEnabled(false);
}

main.cpp

#include <QApplication>

#include "preferencedialog.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    PreferenceDialog dialog;
    dialog.show();
    return app.exec();
}

三、切分窗口

    QSplitter就是一个可以包含一些其他窗口部件。在切分窗口中的这些窗口部件会通过切分条分隔开,用户可以改变切分窗口的大小,好处就是切分窗口可以作为布局管理器的替代品,用户可以有更多的控制权。

给出一个简单的例子:

main.cpp

#include <QApplication>
#include <QtGui>
#include <QTextEdit>
#include <QSplitter>
int main(int argc, char *argv[])
{
	QApplication app(argc, argv);

	QTextEdit *editor1 = new QTextEdit;
	QTextEdit *editor2 = new QTextEdit;
	QTextEdit *editor3 = new QTextEdit;

	QSplitter splitter(Qt::Horizontal);
	splitter.addWidget(editor1);
	splitter.addWidget(editor2);
	splitter.addWidget(editor3);
	editor1->setPlainText(QStringLiteral("我是窗口1"));
	editor2->setPlainText(QStringLiteral("我是窗口2"));
	editor3->setPlainText(QStringLiteral("我是窗口3"));
	splitter.setWindowTitle(QObject::tr("Splitter"));
	splitter.show();

	return app.exec();
}

在自己的QSplitter里面addWidget就行了,QStringLiteral("我是窗口1")是为了解决中文乱码问题。显示效果如下:

第六章 布局管理


再给一个复杂一点的例子,里面有一些QTreeWidget之类的使用方法,也就顺便学一下。

第六章 布局管理

mailclient.h

#ifndef MAILCLIENT_H
#define MAILCLIENT_H

#include <QMainWindow>
#include <QIcon>
#include <QSplitter>
#include <QTextEdit>
#include <QTreeWidget>
#include <QMenuBar>
#include <QStatusBar>


class MailClient : public QMainWindow
{
    Q_OBJECT

public:
    MailClient();

protected:
    void closeEvent(QCloseEvent *event);

private:
    void addFolder(const QIcon &icon, const QString &name);
    void addMessage(const QString &subject, const QString &from,
                    const QString &date);
    void readSettings();
    void writeSettings();

    QSplitter *mainSplitter;
    QSplitter *rightSplitter;
    QTreeWidget *foldersTreeWidget;
    QTreeWidget *messagesTreeWidget;
    QTextEdit *textEdit;
};

#endif

mailclient.cpp

#include <QtGui>

#include "mailclient.h"

MailClient::MailClient()
{
    QIcon folderIcon(style()->standardPixmap(QStyle::SP_DirClosedIcon));
    QIcon trashIcon(style()->standardPixmap(QStyle::SP_FileIcon));

    QStringList folderLabels;
    folderLabels << tr("Folders");

    foldersTreeWidget = new QTreeWidget;
    foldersTreeWidget->setHeaderLabels(folderLabels);
    addFolder(folderIcon, tr("Inbox"));
    addFolder(folderIcon, tr("Outbox"));
    addFolder(folderIcon, tr("Sent"));
    addFolder(trashIcon, tr("Trash"));

    QStringList messageLabels;
    messageLabels << tr("Subject") << tr("Sender") << tr("Date");

    messagesTreeWidget = new QTreeWidget;
    messagesTreeWidget->setHeaderLabels(messageLabels);
    addMessage(tr("Happy New Year!"),
               tr("Grace K. <[email protected]>"),
               tr("2006-12-31"));
    addMessage(tr("Radically new concept!"),
               tr("Grace K. <[email protected]>"),
               tr("2006-12-22"));
    addMessage(tr("Accounts"),
               tr("[email protected]"),
               tr("2006-12-31"));
    addMessage(tr("Expenses"),
               tr("Joe Bloggs <[email protected]>"),
               tr("2006-12-25"));
    addMessage(tr("Re: Expenses"),
               tr("Andy <[email protected]>"),
               tr("2007-01-02"));
    addMessage(tr("Re: Accounts"),
               tr("Joe Bloggs <[email protected]>"),
               tr("2007-01-03"));
    addMessage(tr("Re: Accounts"),
               tr("Andy <[email protected]>"),
               tr("2007-01-03"));
    messagesTreeWidget->resizeColumnToContents(0);
    messagesTreeWidget->resizeColumnToContents(1);

    textEdit = new QTextEdit;
    textEdit->setReadOnly(true);
    textEdit->setHtml("<table bolder=0>"
                      "<tr><td align=right><b>Subject:</b>"
                      "<td><p>Happy New Year!"
                      "<tr><td align=right><b>Date:</b>"
                      "<td><p>Sun, 31 Dec 2006"
                      "<tr><td align=right><b>From:</b>"
                      "<td><p>Grace K. <[email protected]>"
                      "<tr><td align=right><b>To:</b>"
                      "<td>[email protected]"
                      "</table>"
                      "<br>I want to seize this occasion to thank "
                      "everybody for the year that has gone, and want "
                      "to wish you the best for next year. It has been "
                      "a pleasure to work with you all on the Hawk "
                      "project, and I'm sure we'll get concrete "
                      "results shortly."
                      "<br><br>Happy New Year!"
                      "<br>--Grace");

    menuBar()->addMenu(tr("&File"));
    menuBar()->addMenu(tr("&Edit"));
    menuBar()->addMenu(tr("&View"));
    menuBar()->addMenu(tr("F&older"));
    menuBar()->addMenu(tr("&Message"));
    menuBar()->addMenu(tr("&Settings"));
    menuBar()->addMenu(tr("&Help"));
    statusBar()->showMessage(tr("No new messages on server"));

    rightSplitter = new QSplitter(Qt::Vertical);
    rightSplitter->addWidget(messagesTreeWidget);
    rightSplitter->addWidget(textEdit);
    rightSplitter->setStretchFactor(1, 1);

    mainSplitter = new QSplitter(Qt::Horizontal);
    mainSplitter->addWidget(foldersTreeWidget);
    mainSplitter->addWidget(rightSplitter);
    mainSplitter->setStretchFactor(1, 1);
    setCentralWidget(mainSplitter);

    setWindowTitle(tr("Mail Client"));
    readSettings();
}

void MailClient::closeEvent(QCloseEvent *event)
{
    writeSettings();
    event->accept();
}

void MailClient::addFolder(const QIcon &icon, const QString &name)
{
    QTreeWidgetItem *root;
    if (foldersTreeWidget->topLevelItemCount() == 0) {
        root = new QTreeWidgetItem(foldersTreeWidget);
        root->setText(0, tr("Mail"));
        foldersTreeWidget->setItemExpanded(root, true);
    } else {
        root = foldersTreeWidget->topLevelItem(0);
    }

    QTreeWidgetItem *newItem = new QTreeWidgetItem(root);
    newItem->setText(0, name);
    newItem->setIcon(0, icon);

    if (!foldersTreeWidget->currentItem())
        foldersTreeWidget->setCurrentItem(newItem);
}

void MailClient::addMessage(const QString &subject, const QString &from,
                            const QString &date)
{
    QTreeWidgetItem *newItem = new QTreeWidgetItem(messagesTreeWidget);
    newItem->setText(0, subject);
    newItem->setText(1, from);
    newItem->setText(2, date);

    if (!messagesTreeWidget->currentItem())
        messagesTreeWidget->setCurrentItem(newItem);
}

void MailClient::readSettings()
{
    QSettings settings("Software Inc.", "Mail Client");

    settings.beginGroup("mainWindow");
    restoreGeometry(settings.value("geometry").toByteArray());
    mainSplitter->restoreState(
            settings.value("mainSplitter").toByteArray());
    rightSplitter->restoreState(
            settings.value("rightSplitter").toByteArray());
    settings.endGroup();
}

void MailClient::writeSettings()
{
    QSettings settings("Software Inc.", "Mail Client");

    settings.beginGroup("mainWindow");
    settings.setValue("geometry", saveGeometry());
    settings.setValue("mainSplitter", mainSplitter->saveState());
    settings.setValue("rightSplitter", rightSplitter->saveState());
    settings.endGroup();
}


main.cpp

#include <QApplication>

#include "mailclient.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MailClient client;
    client.show();
    return app.exec();
}


四、滚动区域

QScrollArea类提供了一个可以滚动的视口和两个滚动条。这个比我们通过初始化QScrollBar滚动条然后再实现功能要简单得多。

QScrollArea使用方法就是对需要的设置滚动的窗口setWidget(),类把这个窗口自动重定义为该视口的父对象。

类的构建如下:

第六章 布局管理

代码如下:(利用之前实现过的IconEditor类)

链接:http://blog.csdn.net/hellozex/article/details/78315327

#include <QApplication>
#include <QHBoxLayout>
#include <QScrollArea>
#include "iconeditor.h"

int main(int argc, char *argv[])
{
	QApplication app(argc, argv);
	IconEditor *iconEditor = new IconEditor;
	iconEditor->setWindowTitle(QObject::tr("Icon Editor"));
	iconEditor->setIconImage(QImage("mouse.png"));

	QScrollArea scrollArea;
	scrollArea.setWidget(iconEditor);
	scrollArea.viewport()->setBackgroundRole(QPalette::Light);
	scrollArea.viewport()->setAutoFillBackground(true);
	scrollArea.setWindowTitle(QObject::tr("Icon Editor"));
	scrollArea.show();

	return app.exec();
}
修改main函数。这里遇到个问题:

如果不是new IconEditor出来,而是直接 IconEditor  iconEditor;在手动关闭窗口时会出现中断,初步估计是在它析构函数中出可问题。还未解决诶,可能用new会比较好吧。

scrollArea.setWidget(iconEditor);
使用方法就是把需要的添加滚动的窗口加到你的QScrollArea上即可,再设置相关属性就OK啦。

默认情况是窗口小于view时才会显示滚动条,也可以设置总是可见。

	scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
	scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);

第六章 布局管理



五、停靠窗口和工具栏

停靠窗口(dock window)是指一些可以停靠在QMainWindow中或是浮动为独立窗口的窗口。

QMainWindow具有四个停靠位置,知道win10的靠边停靠功能吧,例如把你的某窗口拖到某一边边上,鼠标触碰到电脑显示器边界就会被靠边布局了。

Qt各个停靠窗口都是QDockWidget的实例。


早期Qt版本工具栏的停靠和窗口停靠一样,并且共享统一停靠区域。但是Qt4开始就独自占用停靠区域了,如果需要一个浮动工具栏,把他放进QDockWidget就行了。

QMainWindow窗口部件构成如下:

第六章 布局管理

停靠区四个角可以设置成为相邻停靠区的一部分:

	QMainWindow::setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
就是把左上角的停靠区设置为左停靠区。



;