您的位置:首页 > 其它

堆栈窗体QStackedWidget类以及布局QSplitter

2017-12-21 15:28 375 查看
Qt的布局方式主要有四种:

 

QGridLayout    栅格布局

QFormLayout   表格布局

QHBoxLayout   水平布局

QVBoxLayout   垂直布局

 

然而,只通过以上四种布局的组合似乎不太好用,因此需要搭配分割器QSplitter,在QSplitter中实现局部布局,最后再放进主布局中可以实现非常好的效果.

 

/*

******************************************************************

*函数名称:initLayout

*函数功能:初始化窗口布局

*函数参数:无

*返回值:无

******************************************************************

*/

voidQFriendManager::initLayout()

{

    //创建主布局VBoxLayout

    QVBoxLayout*mainLayout=newQVBoxLayout();




    //创建主Splitter

    QSplitter*splitterMain=newQSplitter(Qt::Vertical,this);




    //添加标题标签和表格部件到主Splitter

    tableWidget=newQTableWidget(splitterMain);

    tableWidget->setMinimumHeight(120);




    //创建底部工具栏Splitter,父亲为主Splitter

    QSplitter*splitterBottom=newQSplitter(Qt::Horizontal,splitterMain);

    check_selectAll=newQCheckBox(QObject::tr("全选"),splitterBottom);

    pb_delete=newQPushButton(QObject::tr("删除"),splitterBottom);

    pb_find=newQPushButton(QObject::tr("查找"),splitterBottom);

    le_find=newQLineEdit(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,取消Gernerateform复选框的选中状态。
2.在头文件dialog.h中编写如下代码:

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

classDialog:publicQDialog
{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=newQListWidget(this);
leftlist->insertItem(0,tr("window1"));
leftlist->insertItem(1,tr("window2"));
leftlist->insertItem(2,tr("window3"));
//设置堆栈窗体
label1=newQLabel(tr("WindowTest1\n\tbyliming"));
label2=newQLabel(tr("WindowTest2\n\tbyliming"));
label3=newQLabel(tr("WindowTest3\n\tbyliming"));

stack=newQStackedWidget(this);
stack->addWidget(label1);
stack->addWidget(label2);
stack->addWidget(label3);
//设置主窗体布局
QHBoxLayout*mainLayout=newQHBoxLayout(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=newQStackedWidget(this);

然后将三个相应的label放入其中:

stack->addWidget(label1);

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


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

QHBoxLayout*mainLayout=newQHBoxLayout(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(intindex,intstretch);
 
     第一个参数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中的这些窗口部件会通过切分条Splitterhandle而分割开来。用户可以通过拖动这些分割条改变切分条中子窗口的大小。QSplitter中的子窗口部件将会自动按照创建时的顺序一个挨着一个的放在一起,并且以切分窗口分割条来分割相邻的窗口。下面是代码实例
#include<QtGui>

intmain(intargc,char*argv[])

{
   QApplicationapp(argc,argv);

   QTextEdit*editor1=newQTextEdit;   //定于在splitter中的三个编辑框

   QTextEdit*editor2=newQTextEdit;

   QTextEdit*editor3=newQTextEdit;

   QSplittersplitter(Qt::Horizontal);      //定义一个切分窗口

   splitter.addWidget(editor1);              //将文件控件加入到切分框

   splitter.addWidget(editor2);

   splitter.addWidget(editor3);        

   editor1->setPlainText("Monenfant,masoeur,\n"

                         "Songe ladouceur\n"

                         "D'allerl-basvivreensemble,\n"

                         "Aimer loisir,\n"

                         "Aimeretmourir\n"

                         "Aupaysquiteressemble.");

   editor2->setPlainText("Mychild,mysister,\n"

                         "thinkofthesweetness\n"

                         "ofgoingtheretolivetogether!\n"

                         "Toloveatleisure,\n"

                         "toloveandtodie\n"

                         "inacountrythatistheimageofyou!");

   editor3->setPlainText("MeinKind,meineSchwester,\n"

                         "denkeandenTraum\n"

                         "dorthin(unter)zugehenumzusammen\n"

                         "zulebenundinallerRuhezulieben,\n"

                         "Zuliebenundzusterben\n"

                         "indemLand,dasdirgleicht.");

   splitter.setWindowTitle(QObject::tr("Splitter"));         //设置标题

   splitter.show();

   returnapp.exec();
}效果如下:



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



另外下面演示下使用多个splitter进行水平或者垂直方向上的嵌套。本代码适用于《C++GUI QT4》
mailclient.cpp.其界面布局部分代码如下
//窗口布局

   rightSplitter=newQSplitter(Qt::Vertical);

   rightSplitter->addWidget(messagesTreeWidget); //在右窗口中添加一个邮件列表

   rightSplitter->addWidget(textEdit);                        //显示文本邮件

   rightSplitter->setStretchFactor(1,1);                     //保证textEdit伸展到多余的空间

   mainSplitter=newQSplitter(Qt::Horizontal);

   mainSplitter->addWidget(foldersTreeWidget);

   mainSplitter->addWidget(rightSplitter);

   mainSplitter->setStretchFactor(1,1);                    //使用两个setStretchFactor保证了把多余的额外空间都留给textEdit

   setCentralWidget(mainSplitter);

   setWindowTitle(tr("MailClient"));
效果如下图:



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

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



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

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

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

view
plaincopy
toclipboard

#include <QtGui/QApplication>
  

#include "mainwindow.h"
  

#include <QSplitter>
  

#include <QTextCodec>
  

#include <QTextEdit>
  

int main(int argc, char *argv[])  

{  

    QApplication a(argc, argv);  

    //设置字体
  

    QFont font("ZYSong18030",12);  

    a.setFont(font);  

    QTextCodec::setCodecForTr(QTextCodec::codecForLocale());  

    //主splitter,以下填充text和子splitter  

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

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

    textLeft->setAlignment(Qt::AlignCenter);  

    QSplitter *splitterRight=new QSplitter(Qt::Vertical,splitterMain);  

    splitterRight->setOpaqueResize(false);  

    //开始填充右边的splitter,放上两个text  

    QTextEdit *textTop=new QTextEdit(QObject::tr("Right Top Widget"),splitterRight);  

    textTop->setAlignment(Qt::AlignCenter);  

    QTextEdit *textBottom=new QTextEdit(QObject::tr("Right Bottom Widget"),splitterRight);  

    textBottom->setAlignment(Qt::AlignCenter);  

    //设置主splitter
  

    splitterMain->setStretchFactor(1,1);  

    splitterMain->setWindowTitle(QObject::tr("Splitter"));  

    splitterMain->show();  

    return a.exec();  

}  

[cpp] view
plaincopy

#include <QtGui/QApplication>  

#include "mainwindow.h"  

#include <QSplitter>  

#include <QTextCodec>  

#include <QTextEdit>  

int main(int argc, char *argv[])  

{  

    QApplication a(argc, argv);  

    //设置字体  

    QFont font("ZYSong18030",12);  

    a.setFont(font);  

    QTextCodec::setCodecForTr(QTextCodec::codecForLocale());  

    //主splitter,以下填充text和子splitter  

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

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

    textLeft->setAlignment(Qt::AlignCenter);  

    QSplitter *splitterRight=new QSplitter(Qt::Vertical,splitterMain);  

    splitterRight->setOpaqueResize(false);  

    //开始填充右边的splitter,放上两个text  

    QTextEdit *textTop=new QTextEdit(QObject::tr("Right Top Widget"),splitterRight);  

    textTop->setAlignment(Qt::AlignCenter);  

    QTextEdit *textBottom=new QTextEdit(QObject::tr("Right Bottom Widget"),splitterRight);  

    textBottom->setAlignment(Qt::AlignCenter);  

    //设置主splitter  

    splitterMain->setStretchFactor(1,1);  

    splitterMain->setWindowTitle(QObject::tr("Splitter"));  

    splitterMain->show();  

    return a.exec();  

}  

解析:

1.QSplitter的构造方法:

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


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

不过子splitter设置的
newQSplitter(Qt::Vertical,splitterMain);



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

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

2.添加QTextEdit控件。
QTextEdit*textLeft=newQTextEdit(QObject::tr("LeftWidget"),splitterMain);


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

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

splitterRight->setOpaqueResize(false);


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



4.设定可伸缩控件:

splitterMain->setStretchFactor(1,1);


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

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



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



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



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



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

[cpp] view
plaincopyprint?

#include <QApplication>   
#include <QFont>   
#include <QPushButton>   
#include <QSplitter>   
#include <QTextEdit>   
#include <QTableWidget>   
#include <QTreeWidget>   
#include <QSettings>   
  
int main(int argc, char* argv[])  
{  
    QApplication app(argc, argv);  
  
    QTextEdit *editor1 = new QTextEdit;  
    QTableWidget *table = new QTableWidget;  
    QTreeWidget *tree = new QTreeWidget;  
  
    //子splitter   
    QSplitter vSplitter(Qt::Vertical);  
    vSplitter.addWidget(table);  
    vSplitter.addWidget(editor1);  
    //父splitter   
    QSplitter hSplitter(Qt::Horizontal);  
    hSplitter.addWidget(tree);  
    hSplitter.addWidget(&vSplitter);  
  
    hSplitter.show();  
  
    return app.exec();  
}  

出现错误的原因为,如果先创建的是父QSplitter,然后创建的子QSplitter,则没有错误。
因为当关闭窗体是,调用析构函数的顺是:子,父。
但是如果是先创建的子QSplitter,然后创建的父QSplitter,那么在关闭窗体时,
先调用的是父QSplitter的析构函数,然后才调用的子QSplitter的析构函数。
这样就会出错。个人猜测试由于在父QSplitter的析构函数中已经自动调用了子QSplitter的析构函数,
当再次调用子QSplitter的析构函数时,就会找不到对象,导致出错。
这就要求我们一定要按顺序定义QSplitter,这很难做到。
相反,如果我们自己决定调用析构函数的顺序就不会出错了。
因此,正确的使用QSplitter的方法是在堆上建立对象,然后自行delete。
正确用法如下:

[cpp] view
plaincopyprint?

include <QApplication>  
#include <QFont>   
#include <QPushButton>   
#include <QSplitter>   
#include <QTextEdit>   
#include <QTableWidget>   
#include <QTreeWidget>   
#include <QSettings>   
  
int main(int argc, char* argv[])  
{  
    QApplication app(argc, argv);  
  
    QTextEdit *editor1 = new QTextEdit;  
    QTableWidget *table = new QTableWidget;  
    QTreeWidget *tree = new QTreeWidget;  
  
    //子splitter   
    QSplitter *vSplitter = new QSplitter(Qt::Vertical);  
    vSplitter->addWidget(table);  
    vSplitter->addWidget(editor1);  
    //父splitter   
    QSplitter *hSplitter = new QSplitter(Qt::Horizontal);  
    hSplitter->addWidget(tree);  
    hSplitter->addWidget(vSplitter);  
  
    hSplitter->show();  
  
    app.exec();  
  
    delete vSplitter;   //先删除子   
    delete hSplitter;   //后删除父   
  
    return 0;  
}  

ps:
由于调用父splitter会自动删除其内部的所有控件,所以也可以直接delete父QSplitter。
这样连里面的其他控件也会删除了。但是切记,一定要用new。

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



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: