堆栈窗体QStackedWidget类以及布局QSplitter

Qt的布局方式主要有四种:
 
QGridLayout         栅格布局
QFormLayout       表格布局
QHBoxLayout       水平布局
QVBoxLayout       垂直布局
 
然而,只通过以上四种布局的组合似乎不太好用, 因此需要搭配分割器QSplitter, 在QSplitter中实现局部布局,最后再放进主布局中可以实现非常好的效果.
 
/*
 ******************************************************************
 * 函数名称 : initLayout
 * 函数功能 : 初始化窗口布局
 * 函数参数 : 无
 * 返回值 : 无
 ******************************************************************
 */
void QFriendManager::initLayout()
{
     //创建主布局VBoxLayout
     QVBoxLayout *mainLayout = new QVBoxLayout();
 
 
 
     //创建主Splitter
     QSplitter *splitterMain = new QSplitter(Qt::Vertical, this);
 
 
 
     //添加标题标签和表格部件到主Splitter
     tableWidget = new QTableWidget(splitterMain);
     tableWidget->setMinimumHeight(120);
 
 
 
     //创建底部工具栏Splitter,父亲为主Splitter
     QSplitter *splitterBottom = new QSplitter(Qt::Horizontal, splitterMain);
     check_selectAll = new QCheckBox(QObject::tr("全选"), splitterBottom);
     pb_delete = new QPushButton(QObject::tr("删除"), splitterBottom);
     pb_find = new QPushButton(QObject::tr("查找"), splitterBottom);
     le_find = new QLineEdit(splitterBottom);
     check_selectAll->setFixedSize(48, 32);
     pb_delete->setFixedSize(48, 32);
     pb_find ->setFixedSize(48, 32);
 
 
 
     //禁用Splitter拉伸效果
     splitterMain->handle(1)->setDisabled(true);
      splitterBottom->handle(1)->setDisabled(true);
     splitterBottom->handle(2)->setDisabled(true);
     splitterBottom->handle(3)->setDisabled(true);
 
 
     //设置窗口边沿宽度
     mainLayout->setContentsMargins(2,5,2,5);
 
 
     //添加主Splitter到主布局VBoxLayout
     mainLayout->addWidget(splitterMain, 0);
     this->setLayout(mainLayout);
}

 

堆栈窗体QStackedWidget类

2013-09-25   zwsj    阅 6015  转 15

这些窗体都比较类似,相对简单,就没什么可以深入研究的了。


下面用代码实现上面窗口的设计:

1.建立项目时基类选择QDialog,取消Gernerate form复选框的选中状态。

2.在头文件dialog.h中编写如下代码:

#include <QtGui/QDialog>
#include <QListWidget>
#include <QStackedWidget>
#include <QLabel>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
private:
    QListWidget *leftlist;
    QStackedWidget *stack;
    QLabel *label1;
    QLabel *label2;
    QLabel *label3;
};


3.在源文件dialog.cpp中编写如下代码:

#include "dialog.h"
#include <QHBoxLayout>
Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
     setWindowTitle(tr("StackedWidget"));
     //设置列表框
     leftlist=new QListWidget(this);
     leftlist->insertItem(0,tr("window1"));
     leftlist->insertItem(1,tr("window2"));
     leftlist->insertItem(2,tr("window3"));
     //设置堆栈窗体
     label1=new QLabel(tr("WindowTest1\n\tby liming"));
     label2=new QLabel(tr("WindowTest2\n\tby liming"));
     label3=new QLabel(tr("WindowTest3\n\tby liming"));

     stack=new QStackedWidget(this);
     stack->addWidget(label1);
     stack->addWidget(label2);
     stack->addWidget(label3);
     //设置主窗体布局
     QHBoxLayout *mainLayout=new QHBoxLayout(this);
     mainLayout->setMargin(5);
     mainLayout->setSpacing(5);
     mainLayout->addWidget(leftlist);
     mainLayout->addWidget(stack,0,Qt::AlignHCenter);
     mainLayout->setStretchFactor(leftlist,1);
     mainLayout->setStretchFactor(stack,3);
     connect(leftlist,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)));
}


解析:

1.这里的程序是,选中左边列表框内的内容,显示相应的窗体。


2.所以,第一步是初始化列表框QListWidget。


3.第二步新建堆栈窗体:

stack=new QStackedWidget(this);
然后将三个相应的label放入其中:

stack->addWidget(label1);
stack->addWidget(label2);
stack->addWidget(label3);


4.设置主窗体布局时,用到了布局管理器。这里用到的是水平排列窗体QHBoxLayout:

QHBoxLayout *mainLayout=new QHBoxLayout(this);

这个布局管理器用法为:

×对话框边距设为5

mainLayout->setMargin(5);

×内部控件间距为5

mainLayout->setSpacing(5);

×对于setStetchFactor函数,借用别的文章说明(http://blog.csdn.net/lin49940/article/details/6033727):

这里讲得是QSplitter的setStetchFactor函数:

程序为

 对于B 和 A 来说, 他们的本身的大小相对于整个窗口来说, 都是很小的. 这样就存在着一些多余的空间, 这些空间可以给B, 也可以给A, 或者两个平分. 对于B 和 A 各自空间大小的控制, 是通过 QSplitter 的 setStretchFactor 方法, 该方法的声明:

 

      void setStretchFactor(int index, int stretch);

 

      第一个参数index 是子微件的索引值, 从0 开始. 这里的话, B 是0, A 是1; 第二个参数 stretch 是拉伸系数, int 类型, 下面主要对stretch 的数值进行说明.

 

      1.  mainSplitter->setStretchFactor(0, -2);

      效果如下,

      

      B占据了所有多余的空间, 看来 stretch 的值如果为负整数, 那这个微件将占据最大的空间.

 

      2.     mainSplitter->setStretchFactor(0, -2);
              mainSplitter->setStretchFactor(1, -4);

      效果如下:

      

 

      B 和 A 平分了空间, 看来stretch 如果是负整数就会尽可能的占据空间, 而不看负整数的大小, 把 -2 改为 -12, 结果一样的.

 

      3.     mainSplitter->setStretchFactor(0, 0);
              mainSplitter->setStretchFactor(1, 0);

       效果同第二.

 

       4.       mainSplitter->setStretchFactor(0, 0);  //可以把这段注释掉, 效果一样
                 mainSplitter->setStretchFactor(1, 1);

       效果如下:

       

 

       5.     mainSplitter->setStretchFactor(0, 4);
               mainSplitter->setStretchFactor(1, 8);

       效果如下:

       

 

       6.     mainSplitter->setStretchFactor(0, -4);
               mainSplitter->setStretchFactor(1, 8);

      效果如下,

      

 

       从 1, 2 和 6 的测试效果可以看出, 拉伸系数为负整数的微件将占据最大的多余空间.

       从3, 4 和 5 的测试效果来看, 就算我们不设置 B 或 A 的拉伸系数stretch, 他们内部也应该存在着一个默认拉伸系数值0. stretch为 0 的微件, 将把最大多余空间让给stretch 为正整数的微件. 如果有多个stretch 为正整数的微件, 他们的多余空间的占有率由通过数字的比例来确定的.


注:因此,我的堆栈窗体程序中的

     mainLayout->setStretchFactor(leftlist,1);
     mainLayout->setStretchFactor(stack,3);
就是设定了list与stack比例为1:3。


5.设定消息相应的信号与槽:

connect(leftlist,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)));
都是控件自带的信号与槽,这里将其关联起来,就达到了程序的设计效果:

更改第几行就显示第几个Label。

最后编译运行:












QT之切分窗口

     QSplitter就是一个可以包含一些其他窗口部件的部件。在切分窗口QSplitter中的这些窗口部件会通过切分条Splitter handle而分割开来。用户可以通过拖动这些分割条改变切分条中子窗口的大小。QSplitter中的子窗口部件将会自动按照创建时的顺序一个挨着一个的放在一起,并且以切分窗口分割条来分割相邻的窗口。下面是代码实例

#include <QtGui>
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QTextEdit *editor1 = new QTextEdit;    //定于在splitter中的三个编辑框
    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();

}

效果如下:

可以随意改变各个窗口大小:

另外下面演示下使用多个splitter进行水平或者垂直方向上的嵌套。本代码适用于《C++ GUI QT4》

mailclient.cpp. 其界面布局部分代码如下

//窗口布局
    rightSplitter = new QSplitter(Qt::Vertical);
    rightSplitter->addWidget(messagesTreeWidget);  //在右窗口中添加一个邮件列表
    rightSplitter->addWidget(textEdit);                         //显示文本邮件
    rightSplitter->setStretchFactor(1, 1);                      //保证textEdit伸展到多余的空间

    mainSplitter = new QSplitter(Qt::Horizontal);
    mainSplitter->addWidget(foldersTreeWidget);
    mainSplitter->addWidget(rightSplitter);
    mainSplitter->setStretchFactor(1, 1);                     //使用两个setStretchFactor保证了把多余的额外空间都留给textEdit
    setCentralWidget(mainSplitter);
    setWindowTitle(tr("Mail Client"));

效果如下图:



(清悠我心:http://hi.baidu.com/%E6%B8%85%E6%82%A0%E6%88%91%E5%BF%83/home




分割窗口在应用程序中经常用到,比如在类似资源管理器的窗口设计中:



下面用代码实现上面窗口的设计:

1.建立项目时基类选择QMainWindow,取消Gernerate form复选框的选中状态。

2.在main.cpp中编写如下代码:

  1. #include <QtGui/QApplication>   
  2. #include "mainwindow.h"   
  3. #include <QSplitter>   
  4. #include <QTextCodec>   
  5. #include <QTextEdit>   
  6. int main(int argc, char *argv[])  
  7. {  
  8.     QApplication a(argc, argv);  
  9.     //设置字体   
  10.     QFont font("ZYSong18030",12);  
  11.     a.setFont(font);  
  12.     QTextCodec::setCodecForTr(QTextCodec::codecForLocale());  
  13.     //主splitter,以下填充text和子splitter  
  14.     QSplitter *splitterMain=new QSplitter(Qt::Horizontal,0);  
  15.     QTextEdit *textLeft=new QTextEdit(QObject::tr("Left Widget"),splitterMain);  
  16.     textLeft->setAlignment(Qt::AlignCenter);  
  17.     QSplitter *splitterRight=new QSplitter(Qt::Vertical,splitterMain);  
  18.     splitterRight->setOpaqueResize(false);  
  19.     //开始填充右边的splitter,放上两个text  
  20.     QTextEdit *textTop=new QTextEdit(QObject::tr("Right Top Widget"),splitterRight);  
  21.     textTop->setAlignment(Qt::AlignCenter);  
  22.     QTextEdit *textBottom=new QTextEdit(QObject::tr("Right Bottom Widget"),splitterRight);  
  23.     textBottom->setAlignment(Qt::AlignCenter);  
  24.     //设置主splitter   
  25.     splitterMain->setStretchFactor(1,1);  
  26.     splitterMain->setWindowTitle(QObject::tr("Splitter"));  
  27.     splitterMain->show();  
  28.     return a.exec();  
  29. }  
[cpp]  view plain copy
  1. #include <QtGui/QApplication>  
  2. #include "mainwindow.h"  
  3. #include <QSplitter>  
  4. #include <QTextCodec>  
  5. #include <QTextEdit>  
  6. int main(int argc, char *argv[])  
  7. {  
  8.     QApplication a(argc, argv);  
  9.     //设置字体  
  10.     QFont font("ZYSong18030",12);  
  11.     a.setFont(font);  
  12.     QTextCodec::setCodecForTr(QTextCodec::codecForLocale());  
  13.     //主splitter,以下填充text和子splitter  
  14.     QSplitter *splitterMain=new QSplitter(Qt::Horizontal,0);  
  15.     QTextEdit *textLeft=new QTextEdit(QObject::tr("Left Widget"),splitterMain);  
  16.     textLeft->setAlignment(Qt::AlignCenter);  
  17.     QSplitter *splitterRight=new QSplitter(Qt::Vertical,splitterMain);  
  18.     splitterRight->setOpaqueResize(false);  
  19.     //开始填充右边的splitter,放上两个text  
  20.     QTextEdit *textTop=new QTextEdit(QObject::tr("Right Top Widget"),splitterRight);  
  21.     textTop->setAlignment(Qt::AlignCenter);  
  22.     QTextEdit *textBottom=new QTextEdit(QObject::tr("Right Bottom Widget"),splitterRight);  
  23.     textBottom->setAlignment(Qt::AlignCenter);  
  24.     //设置主splitter  
  25.     splitterMain->setStretchFactor(1,1);  
  26.     splitterMain->setWindowTitle(QObject::tr("Splitter"));  
  27.     splitterMain->show();  
  28.     return a.exec();  
  29. }  


解析:

1.QSplitter的构造方法:

QSplitter *splitterMain=new QSplitter(Qt::Horizontal,0);

第一个参数通过Qt::Horizontal 和 Qt::Vertical来设定为水平分割或垂直分割。第二个设定0代表是主窗口,无父窗口。

不过子splitter设置的

new QSplitter(Qt::Vertical,splitterMain);
 
             

代表主窗口是splitterMain。则子splitter就被添加到splitterMain中。

添加时为从左至右(或从上至下)添加;

2.添加QTextEdit控件。

QTextEdit *textLeft=new QTextEdit(QObject::tr("Left Widget"),splitterMain);

第一个参数设置文本内容,第二个参数设置主窗体。


3.设置拖动时是否实时更新

splitterRight->setOpaqueResize(false);

false为不实时更新——在拖动时候只显示一条灰色的线条,在拖动到位并释放鼠标后再显示分割条。默认为true——实时更新。



4.设定可伸缩控件:

splitterMain->setStretchFactor(1,1);

第一个参数代表控件序号,第一个序号为0.后面参数0代表不可伸缩,非0代表可伸缩。

这里设置右边的可伸缩。当拉伸整个窗口时候,左边保持原来宽度。


拉伸后,我们发现左边的宽度不变。





当使用QSplitter时,如果是多个QSPlitter嵌套使用(如下图)


就很容易出现错误。通常是“内存不能为read” (如下图)

代码如下:(错误的用法)

  1. #include <QApplication>   
  2. #include <QFont>   
  3. #include <QPushButton>   
  4. #include <QSplitter>   
  5. #include <QTextEdit>   
  6. #include <QTableWidget>   
  7. #include <QTreeWidget>   
  8. #include <QSettings>   
  9.   
  10. int main(int argc, char* argv[])  
  11. {  
  12.     QApplication app(argc, argv);  
  13.   
  14.     QTextEdit *editor1 = new QTextEdit;  
  15.     QTableWidget *table = new QTableWidget;  
  16.     QTreeWidget *tree = new QTreeWidget;  
  17.   
  18.     //子splitter   
  19.     QSplitter vSplitter(Qt::Vertical);  
  20.     vSplitter.addWidget(table);  
  21.     vSplitter.addWidget(editor1);  
  22.     //父splitter   
  23.     QSplitter hSplitter(Qt::Horizontal);  
  24.     hSplitter.addWidget(tree);  
  25.     hSplitter.addWidget(&vSplitter);  
  26.   
  27.     hSplitter.show();  
  28.   
  29.     return app.exec();  
  30. }  


出现错误的原因为,如果先创建的是父QSplitter,然后创建的子QSplitter,则没有错误。

因为当关闭窗体是,调用析构函数的顺是:子,父。

但是如果是先创建的子QSplitter,然后创建的父QSplitter,那么在关闭窗体时,

先调用的是父QSplitter的析构函数,然后才调用的子QSplitter的析构函数。

这样就会出错。个人猜测试由于在父QSplitter的析构函数中已经自动调用了子QSplitter的析构函数,

当再次调用子QSplitter的析构函数时,就会找不到对象,导致出错。

这就要求我们一定要按顺序定义QSplitter,这很难做到。

相反,如果我们自己决定调用析构函数的顺序就不会出错了。

因此,正确的使用QSplitter的方法是在堆上建立对象,然后自行delete。

正确用法如下:

  1. include <QApplication>  
  2. #include <QFont>   
  3. #include <QPushButton>   
  4. #include <QSplitter>   
  5. #include <QTextEdit>   
  6. #include <QTableWidget>   
  7. #include <QTreeWidget>   
  8. #include <QSettings>   
  9.   
  10. int main(int argc, char* argv[])  
  11. {  
  12.     QApplication app(argc, argv);  
  13.   
  14.     QTextEdit *editor1 = new QTextEdit;  
  15.     QTableWidget *table = new QTableWidget;  
  16.     QTreeWidget *tree = new QTreeWidget;  
  17.   
  18.     //子splitter   
  19.     QSplitter *vSplitter = new QSplitter(Qt::Vertical);  
  20.     vSplitter->addWidget(table);  
  21.     vSplitter->addWidget(editor1);  
  22.     //父splitter   
  23.     QSplitter *hSplitter = new QSplitter(Qt::Horizontal);  
  24.     hSplitter->addWidget(tree);  
  25.     hSplitter->addWidget(vSplitter);  
  26.   
  27.     hSplitter->show();  
  28.   
  29.     app.exec();  
  30.   
  31.     delete vSplitter;   //先删除子   
  32.     delete hSplitter;   //后删除父   
  33.   
  34.     return 0;  
  35. }  

ps:

由于调用父splitter会自动删除其内部的所有控件,所以也可以直接delete父QSplitter。

这样连里面的其他控件也会删除了。但是切记,一定要用new。

ps:

类似的布局类控件如QScrollArea也要注意相同的问题。



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值