Qt4_切分窗口

本文详细介绍了如何在Qt中使用QSplitter实现窗口部件的灵活布局,包括创建嵌套切分窗口,以及如何调整子窗口大小以赋予用户自定义体验。通过MailClient实例,展示了如何利用QSplitter构建复杂的窗口结构。
摘要由CSDN通过智能技术生成

切分窗口

QSplitter就是一个可以包含一些其他窗口部件的窗口部件。在切分窗口(splitter)中的这些窗口部件会通过切分条( splitter handle) 而分隔开来。用户可以通过拖动这些切分条来改变切分窗口中子窗口部件的大小。切分窗口常常可以用作布局管理器的替代品,从而可以把更多的控制权交给用户。

QSplitter中的子窗口部件将会自动按照创建时的顺序一个挨一个地(或者一个在另外一个的下面)放在一起,并以切分窗口拖动条(splitter bar)来分隔相邻窗口部件。

main.cpp

#include <QtWidgets>

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("Mon enfant, ma soeur,\n"
                          "Songe  la douceur\n"
                          "D'aller l-bas vivre ensemble,\n"
                          "Aimer  loisir,\n"
                          "Aimer et mourir\n"
                          "Au pays qui te ressemble.");
    editor2->setPlainText("My child, my sister,\n"
                          "think of the sweetness\n"
                          "of going there to live together!\n"
                          "To love at leisure,\n"
                          "to love and to die\n"
                          "in a country that is the image of you!");
    editor3->setPlainText("Mein Kind, meine Schwester,\n"
                          "denke an den Traum\n"
                          "dort hin(unter) zu gehen um zusammen\n"
                          "zu leben und in aller Ruhe zu lieben,\n"
                          "Zu lieben und zu sterben\n"
                          "in dem Land, das dir gleicht.");

    splitter.setWindowTitle(QObject::tr("Splitter"));
    splitter.show();
    return app.exec();
}

在这里插入图片描述
这个例子由三个QTextEdit组成,通过一个Qpitter窗口部件水平地摆放它们,下图给出了它们的构成原理图。与布局管理器不同之处在于,布局管理器只是简单地摆放一个窗体中的子窗口部件并且也没有可见的外形,但QSplitter是从QWidget派生的;并且在使用的时候,它也可以像任何其他窗口部件一样使用。
在这里插入图片描述

嵌套的切分窗口

通过对多个QSpliter进行水平或者垂直方向的嵌套,就可以获得更为复杂的一些布局。例如,在如图所示的Mail Client(邮件客户端)应用程序中,就由一个水平的QSplitter构成,而在它的右侧又包含了一个垂直的QSplitter。
在这里插入图片描述

MailClient.h

#ifndef MAILCLIENT_H
#define MAILCLIENT_H

#include <QMainWindow>

class QIcon;
class QSplitter;
class QTextEdit;
class QTreeWidget;

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 <QtWidgets>

#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. <grace@software-inc.com>"),
               tr("2006-12-31"));
    addMessage(tr("Radically new concept!"),
               tr("Grace K. <grace@software-inc.com>"),
               tr("2006-12-22"));
    addMessage(tr("Accounts"),
               tr("pascale@nospam.com"),
               tr("2006-12-31"));
    addMessage(tr("Expenses"),
               tr("Joe Bloggs <joe@bloggs.com>"),
               tr("2006-12-25"));
    addMessage(tr("Re: Expenses"),
               tr("Andy <andy@nospam.com>"),
               tr("2007-01-02"));
    addMessage(tr("Re: Accounts"),
               tr("Joe Bloggs <joe@bloggs.com>"),
               tr("2007-01-03"));
    addMessage(tr("Re: Accounts"),
               tr("Andy <andy@nospam.com>"),
               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. &lt;grace@software-inc.com&gt;"
                      "<tr><td align=right><b>To:</b>"
                      "<td>all@software-inc.com"
                      "</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()
{
    //以下给出了Mail Client应用程序的witeSetings()函数,它可以保存Mail Client的各个状态设置值。
    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();
}

在创建了我们希望显示的三个窗口部件之后,再创建一个垂直切分窗口rightsplitter,并且把我们想要的两个窗口部件添加到它的右侧。然后,再创建一个水平切分窗口mainSplitter,并且把我们想要在左侧显示的窗口部件和想要在右侧显示的rightSlitter等这些窗口部件统统放进去。我们把mainSplitter作为QMainWindow的中央窗口部件。

当用户重新改变窗口的大小时,QSpliter通常会重新分配空间,以便能够使所有的子窗口部件的相对大小能够与先前一样保持相同的比例。

在Mail Client 例子中,我们想要的不是这种行为,相反,我们希望QTreeWidget和QTableWidget保持它们的大小不变,而把任何多余的额外空间都留给QTextEdit。这一点可以通过两次调用setStretchFactor()来实现。第一个参数是切分窗口子窗口部件的索引值,该值是一个从0开始的整数值。第二个参数是我们想要设置的伸展因子,伸展因子的默认值是0。

第一次是对rightSplitter调用setStretchFactor(),它会把位置1处的窗口部件(textEdit)的伸展因子设置为1。第二次则是对mainSitter调用setStretchFactor(),它会把位置1处的窗口部件(rightSplitter)的伸展因子设置为1。这样将可以确保textEdit总是可以获取那些任何多余的可用空间。

在启动应用程序时,QSplitter会根据子窗口部件的初始大小(或者在没有给定初始大小的时候根据它们的大小提示)给它们分配合适的大小。在程序中,可以通过调用QSplitter::setSizes()来移动切分条。QSplitter类也可以保存它的状态,并且可以在下次运行应用程序的时候直接恢复它的状态值。

main.cpp

#include <QApplication>

#include "mailclient.h"

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

在这里插入图片描述
Qt设计师完全支持QSplitter。要把多个窗口部件放到一个切分窗口中,可以先把这些子窗口部件放置在期望的大致位置,选中它们,然后再单击Form→Lay Out Horizontally in Splitter或者Form→Lay Out Vertically in Splitter即可。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阳光开朗男孩

你的鼓励是我最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值