我们进一步学习构建稍微复杂一点的布局。通过对抽象类QLayout的继承来进行自己的布局。在这个例子中,我们将重构QLayout类为BorderLayout,QLayout是一个用于布局管理的基础抽象类,而也是QBoxLayout,QGridLayout,QFormLayout和QStackedLayout的继承类。资料来源:
-
http://doc.qt.nokia.com/latest/layouts-borderlayout.html
-
http://www.kuqin.com/qtdocument/customlayout.html
。
一、搭建project的主题框架
我们创建自己的布局类为BorderLayout,使用borderlayout.cpp和borderlayout.h,构造我们的窗口mywindow.h和mywindow.cpp,以及主程序qtmain.cpp。下面是mywindows.cpp的内容,执行后如图所示。
MyWindow:: MyWindow()
{
QTextBrowser * centralWidget = new QTextBrowser;
centralWidget->setPlainText(tr("Central widget"));
BorderLayout * layout = new BorderLayout;
layout -> addWidget (centralWidget,BorderLayout::Center);
layout -> addWidget (createLabel("North"),BorderLayout::North);
layout -> addWidget (createLabel("West"),BorderLayout::West);
layout -> addWidget (createLabel("East 1"),BorderLayout::East);
layout -> addWidget (createLabel("East 2"),BorderLayout::East);
layout -> addWidget (createLabel("South"),BorderLayout::South);
setLayout(layout);
setWindowTitle(tr("Border Layout"));
}
QLabel * MyWindow::createLabel(const QString &text)
{
QLabel * label = new QLabel(text);
label->setFrameStyle(QFrame::Box |QFrame::Raised);
return label;
}
二、重点在建立我们的类BorderLayout,我们先建立一个用来存放被布局处理的项目的数据结构QList,每个entry为ItemWrapper,存放组件和位置信息。QLayout的抽象组件为QLayoutItem,实际可以是QLabel等等具体的组件。我们在borderlayout.h中定义:
private:
struct ItemWrapper
{
ItemWrapper(QLayoutItem * i,Position p){
item = i;
position = p;
}
QLayoutItem * item;
Position postion;
};
enum SizeType {MinumumSize, SizeHint};
QSize calculateSize(SizeType sizeType) const; //用于后面
QList list;
三、建立我们自己的布局管理器,需要实现QLayout中的几个virtual的函数。addItem(), sizeHint(), setGeometry(), itemAt() and takeAt(),此外还需要实现minimumSize()用于确保我们的布局没有因为space太小而重置为0。我们去查QLayout的参考(
http://doc.qt.nokia.com/latest/qlayout.html
),其中pure
virtual的有:addItem(),intemAt(),takeAt(),count(),这些都是用于处理item的,分别是增加(存储),查找,删除,总数。我们同时在destory函数中清除所有item。
/********** borderlayout.h PART 2 ***********/
public:
void addItem
(QLayoutItem * item);
QLayoutItem * itemAt
(int index) const;
QLayoutItem * takeAt
(int index);
int count
() const;
//在我们实际应用中,我们通常不使用addItem,而是使用addWidget,由于我们增加了一个方位因子,所以需要补充一个addWidget的方法。
void addWidget
(QWidget * w, Position p);
/********** borderlayout.cpp PART 2 ***********/
BorderLayout::~BorderLayout()
{
QLayoutItem *l;
while((l = takeAt(0)) != NULL)
delete l;
}
//在我们存储的数据中加入元素,addItem在实际上是很少调用的,一般都会使用addWidget,它将使用addItem。
void BorderLayout :: addItem(QLayoutItem * item)
{
list.append(new ItemWrapper(item,West));
}
//takeAt表示从list中删除index的item,并返回它,而index必须是有效的数值,因此需要先行检查:0 <= i < size()).
QLayoutItem * BorderLayout :: takeAt(int index)
{
if(index >= 0 && index < list.size()){
ItemWrapper * layoutStruct = list.takeAt(index);
return layoutStruct -> item;
}
return 0;
}
QLayoutItem * BorderLayout :: itemAt(int index) const
{
ItemWrapper * wrapper = list.value(index);
if(wrapper)
return wrapper->item;
else
return 0;
}
int BorderLayout::count() const
{
return list.size();
}
void BorderLayout :: addWidget(QWidget * item, Position position)
{
list.append(new ItemWrapper(new QWidgetItem (item),position));
}
四、编译:undefined reference to `BorderLayout::sizeHint() const
QLayoutItem是QLayout操作的一个抽闲的item,有一些方法从QLayoutItem中继承,例如sizeHint表示implemented in subclasses to return the preferred size of this item,那么对于layout则表示整个layout的大小。而在QLayout中说明: sizeHint
(), 此外通常还需要实现minimumSize
(),我们一起补上,此外,我们还加上了expandingDirections
(用于表明这个layout可以使用比sizeHint()更多的空间,并允许向那个维度扩展)
/************* borderlayout.cpp PART 3 ***************/
Qt::Orientations BorderLayout::expandingDirections() const
{
return Qt::Vertical | Qt::Horizontal; //两个方向均允许扩展。
}
QSize BorderLayout :: sizeHint() const
{
return calculateSize(MinimumSize);
}
QSize BorderLayout :: minimumSize() const
{
return calculateSize(SizeHint);
}
//将各item的大小进行统计获得layout的大小
QSize BorderLayout::calculateSize(SizeType sizeType) const
{
QSize totalSize;
for(int i = 0 ; i < list.size(); i++){
ItemWrapper * wrapper = list.at(i);
Position position = wrapper -> position;
QSize itemSize;
if(sizeType == MinimumSize)
itemSize = wrapper->item->minimumSize();
else // SizeHint
itemSize = wrapper->item->sizeHint();
if(position == North || position == South || position == Center)
totalSize.rheight() += itemSize.height();
if(position == West || position == East || position == Center)
totalSize.rwidth() += itemSize.width();
}
return totalSize;
}
五、setGeometry()是最重要的一个,用于描述这个布局,我们重造该方法:
void BorderLayout::setGeometry(const QRect &rect)
{
QLayout::setGeometry(rect);
/* Add you code here*/
}
在这里,我们向描述一下我们Layout的情况。
在这个图的基础上我们来布局。我们从QList中读出我们的组件,根据组件的位置属性,我们先完成南北向的组件布局,在完成东西向的组件布局,布局使用QRect来确定每个组件的大小,每个组件都有一个缺省的大小item->sizeHint().width()和item->sizeHint().height(),对于南北,宽度等同于整个layout,而东西,高度修正为同center的大小。明确了正阳的布局,我们编写下面的代码:
void BorderLayout::setGeometry(const QRect &rect)
{
ItemWrapper * center = NULL;
int eastWidth = 0,westWidth = 0,northHeight = 0 ,southHeight = 0, centerHeight = 0;
for(int i = 0; i < list.size(); i ++){
ItemWrapper * wrapper = list.at(i);
QLayoutItem * item = wrapper -> item;
Position position = wrapper->position;
if(position == North){
item->setGeometry(QRect(rect.x(),northHeight, rect.width(),item->sizeHint().height()));
northHeight += item->sizeHint().height() +spacing();
}else if(position == South){
item->setGeometry(QRect(rect.x(), rect.height()-southHeight-item->sizeHint().height(),
rect.width(),
item->sizeHint().height()));
southHeight += item->sizeHint().height() + spacing();
}else if(position == Center){
center = wrapper;
}
}
centerHeight = rect.height()- northHeight-southHeight;
for(int i = 0; i < list.size(); i ++){
ItemWrapper * wrapper = list.at(i);
QLayoutItem * item = wrapper -> item;
Position position = wrapper->position;
if(position == West){
item->setGeometry(QRect(rect.x() + westWidth,northHeight,item->sizeHint().width(),centerHeight));
westWidth += item->sizeHint().width()+spacing();
}else if(position == East){
item->setGeometry(QRect(rect.width()-eastWidth-item->sizeHint().width(),northHeight,
item->sizeHint().width(),centerHeight));
eastWidth += item->sizeHint().width() + spacing();
}
}
if(center)
center->item->setGeometry(QRect(westWidth,northHeight,
rect.width()-eastWidth-westWidth,centerHeight));
}
相关链接:我的MeeGo/Moblin相关文章
此外,看到这么一则小故事也copy下来:
倒墙的前两年,东德一个名叫亨里奇的守墙卫兵,开枪射杀了攀爬柏林墙企图逃向西德的青年克利斯。1992年2月,在统一后的柏林法庭上,卫兵亨里奇受到审判。他的律师辩称,他们仅仅是执行命令的人,根本没有选择的权利,罪不在己。那么法官是怎么说怎么判的呢?法官当庭指出:“作为警察,不执行上级命令是有罪的,但是打不准是无罪的。作为一个心智健全的人,此时此刻,你有把枪口抬高一厘米的主权,这是你应主动承担的良心义务。这个世界,在法律之外还有‘良知’。当法律和良知冲突之时,良知是最高的行为准则,而不是法律。尊重生命,是一个放之四海而皆准的原则。”你有把枪口抬高一厘米的主权――在那个万不得已的情势下,打,但应该有意打不准
――不把人家打死,这是最低限度的道德,这也是最高境界的良知。任何人都不能以“服从命令”为借口,去超越道德伦理的底线。这就是“一厘米主权”的道德义务,否则就必须承担罪责。柏林法庭最终的判决是:判处开枪射杀克利斯的卫兵亨里奇三年半徒刑,不予假释。
分享到:
相关推荐
//自定义日历可看上篇文章 QCalendarTimeEdit::QCalendarTimeEdit(QWidget *parent) : QLineEdit(parent) , m_calendarWidget(nullptr) , m_widget(nullptr) { m_minDateTime = QDateTime::currentDateTime(); ...
• 使用现有的和用户自定义的组件 • 使用Graphics view 组件 • 学会如何在各平台上(Symbian,Meego etc)上使用Qt • 同时使用Qt和Symbian • 样式(Styling)基础知识 课程内容 • 介绍 • 什么是Qt?什么是Qt for ...
2.、自定义的进度条不起作用,不知为什么百分比槽连接不成功 connect(wmp, SIGNAL(PositionChange(double, double)),this, SLOT(Slot_onPositionChange(double, double))); 3、我用的是QAxWidget控件,这个是不是...
这份资料详细的讲解了如何应用Qt开发应用程序;包含以下内容: 1 Qt程序设计基础 2 Qt Designer应用 3 QMainWindow、QDialog、Layout ...7 Qt事件处理 8 Qt网络编程 9 QSS样式设计 10 QGraphics View应用 11 自定义控件
WaveDemo waveDemo; @Override protected void onCreate(@Nullable Bundle ... setContentView(R.layout.shape_class); waveDemo = findViewById(R.id.wave_demo); waveDemo.startAnimation(); }
一、Qt Creator 的安装和hello world 程序的编写(原创) 1.首先到Qt 的官方网站上下载Qt Creator,这里我们下载windows 版的。 下载地址:http://qt.nokia.com/downloads 如下图我们下载:Download Qt SDK for ...
用Qt写的扫雷,比较简单,可以实现 #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { this->setWindowIcon(QIcon(tr(":/images/ico.png"))); menuBar=new QMenuBar(this)...
在 `QMainWindow` 中,中心部件(Central Widget)是主窗口的中间区域,通常用于显示应用程序的主要内容,例如绘图区域、文本编辑... QVBoxLayout *layout = new QVBoxLayout(centralWidget); QLabel *label = new QL
一个基于thinkphp5的cms框架,前端采用swiper+bootstrap+自定义layout,外观相当美观。考虑到目前市场成熟的基于php的cms都商业收费,具有一定的使用成本,而且比较难定制开发,故本人收集到该代码时首先考虑到免费...
Flow Layout。完成一个自定义布局类型FlowLayout,该类型的布局可分为水平布局和垂直 布局两种。水平布局在顶级部件中从左到右,从上到下排列子部件。当布局中的每一行空间不足时, 首先将这些项水平放置,然后垂直...
13.8. 自定义Feed和条目类 14. Zend_Filter 14.1. 简介 14.1.1. 什么是过滤器(filter)? 14.1.2. 过滤器的基本用法 14.1.3. 使用静态 get() 方法 14.2. 标准过滤器类 14.2.1. Alnum 14.2.2. Alpha 14.2.3. ...