`
javasogo
  • 浏览: 1822105 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

QT(7)自定义Layout

阅读更多

我们进一步学习构建稍微复杂一点的布局。通过对抽象类QLayout的继承来进行自己的布局。在这个例子中,我们将重构QLayout类为BorderLayout,QLayout是一个用于布局管理的基础抽象类,而也是QBoxLayout,QGridLayout,QFormLayout和QStackedLayout的继承类。资料来源:

  1. http://doc.qt.nokia.com/latest/layouts-borderlayout.html
  2. 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月,在统一后的柏林法庭上,卫兵亨里奇受到审判。他的律师辩称,他们仅仅是执行命令的人,根本没有选择的权利,罪不在己。那么法官是怎么说怎么判的呢?法官当庭指出:“作为警察,不执行上级命令是有罪的,但是打不准是无罪的。作为一个心智健全的人,此时此刻,你有把枪口抬高一厘米的主权,这是你应主动承担的良心义务。这个世界,在法律之外还有‘良知’。当法律和良知冲突之时,良知是最高的行为准则,而不是法律。尊重生命,是一个放之四海而皆准的原则。”你有把枪口抬高一厘米的主权――在那个万不得已的情势下,打,但应该有意打不准 ――不把人家打死,这是最低限度的道德,这也是最高境界的良知。任何人都不能以“服从命令”为借口,去超越道德伦理的底线。这就是“一厘米主权”的道德义务,否则就必须承担罪责。柏林法庭最终的判决是:判处开枪射杀克利斯的卫兵亨里奇三年半徒刑,不予假释。

分享到:
评论

相关推荐

    Qt自定义控件代码Demo

    首先,理解Qt自定义控件的基本步骤: 1. **创建新类**:自定义控件通常继承自Qt提供的基类,如`QWidget`、`QGraphicsObject`等。在这个例子中,我们可能会创建一个名为`GEQButton`的新类,继承自`QPushButton`。...

    qt自定义界面样式

    在Qt框架中,自定义界面样式是一项重要的技能,它允许开发者根据个人或项目需求创建独特且吸引人的用户界面。Qt提供了丰富的API和工具,使得我们可以方便地改变窗口、控件的外观,实现“换肤”功能。下面我们将深入...

    qt自定义的messagebox

    在Qt框架中,开发者可以创建自定义的对话框来满足特定的用户界面需求。`QMessageBox`是Qt提供的一种预定义的对话框,用于显示简单的警告、询问或信息消息。然而,有时候系统的默认样式可能不符合应用程序的整体设计...

    Qt自定义无边框窗体demo

    让我们一步步地解析这个“Qt自定义无边框窗体demo”。 首先,要创建一个无边框窗体,我们需要使用`QMainWindow`或`QWidget`作为基础类,并禁用其默认的边框。在Qt中,我们可以通过调用`setWindowFlags()`函数并传入...

    多选项单选控件,自定义控件,基于Qt开发

    在本文中,我们将深入探讨如何使用Qt框架来创建一个自定义的多选项单选控件。这个控件允许用户从多个按钮中选择一个,并且在界面设计上比传统的下拉框或多个独立单选框更加简洁高效。我们将重点讨论两个核心文件:...

    QT如何编写和使用自定义控件例程

    以上就是QT自定义控件的基本流程。在提供的压缩包文件"udf"中,应该包含了两个QT工程,一个是制作自定义控件的工程,另一个是演示如何在实际项目中使用该自定义控件的工程。通过这两个实例,你可以更深入地理解...

    Qt自定义的MessageBox

    我们将以“Qt自定义的MessageBox”为例,讲解如何实现这一过程。 首先,我们需要理解QDialog类。QDialog是Qt中一个重要的窗口类,它提供了一个用于创建临时对话框的基类。与之相比,QMessageBox是一个预定义的...

    Qt自定义日历

    //自定义日历可看上篇文章 QCalendarTimeEdit::QCalendarTimeEdit(QWidget *parent) : QLineEdit(parent) , m_calendarWidget(nullptr) , m_widget(nullptr) { m_minDateTime = QDateTime::currentDateTime(); ...

    Qt实现自定义滚动日期选择部品(C++)

    在Qt框架下,开发人员经常需要创建自定义的UI组件以满足特定的界面设计需求。本教程将深入探讨如何利用C++语言在Qt环境中实现一个自定义的滚动日期选择部件。这个部件允许用户通过滚动来选取日期,为应用程序提供一...

    Qt 自定义进度条

    在Qt编程环境中,自定义控件是实现个性化界面设计的关键技术。本教程将重点讲解如何基于QProgressBar类创建一个自定义的进度条组件,通过加载图片来改变其默认样式,以满足不同应用场景的需求。 首先,我们需要了解...

    qt 自定义标签 窗口类创建

    在Qt框架中,自定义标签窗口类的创建是开发者经常遇到的需求,这允许我们实现更加个性化的用户界面。本文将详细讲解如何在Qt环境中创建一个自定义的标签窗口类,包括删除小标签、获取和设置数据以及实现随窗口变化...

    QtFlowlayout Qt流式布局器

    QtFlowlayout是一个专门为Qt开发的自定义布局器,它扩展了Qt的标准布局系统,使得在QWidget容器中可以灵活地自动布局子控件。这个库的主要目的是处理那些在大小和数量上变化不定的控件,例如在一个应用中,用户可能...

    自定义QFileDialog

    layout()-&gt;addWidget(previewButton); connect(previewButton, &QPushButton::clicked, this, &CustomFileDialog::showPreview); } ``` 3. **事件处理**:连接信号和槽以响应用户的操作。例如,当用户点击...

    简单便于集成的自定义ProgressDialog

    在res/layout目录下创建一个XML文件,例如`custom_progress_dialog.xml`,定义你的自定义布局。可以包含自定义的动画、文字、按钮等元素。例如: ```xml android:layout_width="wrap_content" android:layout_...

    QCalendarWidget时间日历自定义样式选择控件

    在Qt编程环境中,QCalendarWidget是一...总的来说,自定义QCalendarWidget的样式和集成时间选择控件是提升Qt应用界面美观性和用户体验的有效方法。通过深入学习和实践,开发者可以创建出更加个性化的日期时间选择组件。

    ros环境下qt导入rviz组件

    通过以上步骤,你已经成功地在QT环境中集成了RVIZ,并可以自定义加载各种显示。这个过程中的关键在于理解ROS与QT的交互方式,以及如何利用RVIZ的API来创建和配置显示。文件`rviz_qt`可能是该项目的源代码示例,你...

    QT widget控件自适应窗口大小,修改比例

    首先,我们需要了解QT中的布局管理器(Layout Manager),如QVBoxLayout、QHBoxLayout和QGridLayout等。这些布局管理器可以帮助我们自动调整控件的大小和位置,当窗口大小改变时,它们会按照预设规则重新排列和缩放...

    log4qt 日志管理 log4qt 日志管理log4qt 日志管理log4qt 日志管理log4qt 日志管理log4qt 日志管理

    Log4Qt的配置通常通过XML文件完成,包括设置日志级别、创建Appender、指定Layout和Filter等。例如,以下配置创建了一个写入文件的日志Appender: ```xml &lt;appender name="FileAppender" type="Log4Qt::FileAppender...

    Qt之log4Qt Demo

    同时,由于log4Qt的灵活性,你还可以根据需要自定义日志格式、过滤规则以及输出目的地,以满足不同项目的需求。总之,"Qt之log4Qt Demo"是一个值得学习和参考的优秀实践案例,对于提升你的Qt编程技能大有裨益。

    qt 最基础 最详细的 layout 基本布局 源代码

    此外,Qt还提供了`QBoxLayout::addSpacing()`, `QBoxLayout::addWidgetWithStretch()`, `QLayout::setMargin()`, `QLayout::setSpacing()`等方法,用于进一步自定义布局的外观和行为。学习这些高级用法可以帮助你...

Global site tag (gtag.js) - Google Analytics