我正在火車交通控制器軟件項目工作。 我在這個項目中的責任是開發視覺鐵路GUI。集裝箱項目實施
我們正在與Qt一起實施這個項目。 現在我正在使用QGraphicsLinearLayout來保存我的物品。 我正在使用佈局,因爲我不想計算每個項目的座標。 到目前爲止,我編寫了項目類來添加布局。例如SwitchItem類在現實世界中象徵着 鐵路開關。每個項目類都負責自己的繪畫和事件。 目前爲止這麼好。
現在我需要一個可以包含兩個或更多項目的組合項目。此課程將負責繪製包含在其中的項目。我需要這個類,因爲我必須在同一個佈局單元中放置兩個或多個項目。如果我不把它們放在同一個單元格中,我就不能使用佈局。看到下面的圖片。
Composite Item http://img169.imageshack.us/img169/9079/composite1.jpg BlockSegmentItem和SignalItem在同一個單元格內。
CompositeItem頭文件
#include <QtCore/QList>
#include <QtGui/QGraphicsLayoutItem>
#include <QtGui/QGraphicsItemGroup>
#include <QtGui/QGraphicsSceneMouseEvent>
#include <QtGui/QGraphicsSceneContextMenuEvent>
#include "fielditem.h"
class CompositeItem : public FieldItem
{
Q_OBJECT
public:
CompositeItem(QString id,QList<FieldItem *> _children);
~CompositeItem();
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF(-1,-1)) const;
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /* = 0 */);
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
private:
QList<FieldItem *> children;
};
//CompositeItem implementation
#include "compositeitem.h"
CompositeItem::CompositeItem(QString id,QList<FieldItem *> _children)
{
children = _children;
}
CompositeItem::~CompositeItem()
{
}
QRectF CompositeItem::boundingRect() const
{
FieldItem *child;
QRectF rect(0,0,0,0);
foreach(child,children)
{
rect = rect.united(child->boundingRect());
}
return rect;
}
void CompositeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
FieldItem *child;
foreach(child,children)
{
child->paint(painter,option,widget);
}
}
QSizeF CompositeItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
QSizeF itsSize(0,0);
FieldItem *child;
foreach(child,children)
{
// if its size empty set first child size to itsSize
if(itsSize.isEmpty())
itsSize = child->sizeHint(Qt::PreferredSize);
else
{
QSizeF childSize = child->sizeHint(Qt::PreferredSize);
if(itsSize.width() < childSize.width())
itsSize.setWidth(childSize.width());
itsSize.setHeight(itsSize.height() + childSize.height());
}
}
return itsSize;
}
void CompositeItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
qDebug()<<"Test";
}
//Code that add items to scene
//Subclass of QGraphicsWidget for future extension
FieldItemContainer *widget;
while(!itemGroupNode.isNull())
{
//Subclass of QGraphicsLinearLayout for future extension
FieldItemGroupLayout *layout = new FieldItemGroupLayout;
int layoutX = itemGroupNode.toElement().attribute("X").toInt();
int layoutY = itemGroupNode.toElement().attribute("Y").toInt();
layout->setSpacing(1);
QDomNode itemNode = itemGroupNode.toElement().namedItem("Item");
while (!itemNode.isNull() && itemNode.nodeType() == QDomNode::ElementNode)
{
FieldItem * item;
//Create proper item
item = FieldItemFactory::createFieldItem(itemNode);
//Add item to layout
layout->addItem(item);
itemNode = itemNode.nextSibling();
}
widget = new FieldItemContainer;
//Set layout to widget
widget->setLayout(layout);
widget->setPos(layoutX,layoutY);
//Add widget to scene
itsScene->addItem(widget);
itemGroupNode = itemGroupNode.nextSibling();
}
//FieldItemFactory implementation
FieldItem* FieldItemFactory::createFieldItem(QDomNode itemNode)
{
FieldItem *item;
//Common for all items
QString itemId = itemNode.toElement().attribute("id");
QString itemType = itemNode.toElement().attribute("type");
int x1 = itemNode.namedItem("X1").toElement().text().toInt();
int y1 = itemNode.namedItem("Y1").toElement().text().toInt();
//Only for Block part items
int x2 = 0;
int y2 = 0;
QString signalization = "";
////***********************
//Only for signal items
QString source = "";
int width = 0;
int height = 0;
///********************
//Only for switch items
QString normalPositionSource = "";
QString reversePositionSource = "";
///********************
///Labeling
QDomNode itemLabelNode = itemNode.namedItem("Label");
FieldItemLabel label;
label.x1 = itemLabelNode.namedItem("X1").toElement().text().toInt();
label.y1 = itemLabelNode.namedItem("Y1").toElement().text().toInt();
label.text = itemLabelNode.namedItem("Text").toElement().text().trimmed();
label.rotateAngle = itemLabelNode.namedItem("RotateAngle").toElement().text().toInt();
label.hideScale = itemLabelNode.namedItem("HideScale").toElement().text().toInt();
///*****************
if(itemType == FieldProperty::BLOCKSEGMENTITEM)
{
x2 = itemNode.namedItem("X2").toElement().text().toInt();
y2 = itemNode.namedItem("Y2").toElement().text().toInt();
signalization = itemNode.namedItem("Signalization").toElement().text().trimmed();
item = new BlockSegmentItem(itemId,x1,y1,x2,y2,
label,signalization);
}
else if(itemType == FieldProperty::SWITCHITEM)
{
normalPositionSource = itemNode.namedItem("Normal").toElement().text().trimmed();
reversePositionSource = itemNode.namedItem("Reverse").toElement().text().trimmed();
item = new SwitchItem(itemId,x1,y1,FieldProperty::SWITCH_WIDTH,
FieldProperty::SWITCH_HEIGHT,label,
normalPositionSource,reversePositionSource);
}
else if(itemType == FieldProperty::SIGNALITEM)
{
source = itemNode.namedItem("Source").toElement().text().trimmed();
width = itemNode.namedItem("Width").toElement().text().toInt();
height = itemNode.namedItem("Height").toElement().text().toInt();
item = new SignalItem(itemId,x1,y1,width,height,label,source);
}
else if(itemType == FieldProperty::TRAINIDBOXITEM)
{
item = new TrainIdBox(itemId,x1,y1);
}
else if(itemType == FieldProperty::COMPOSITEITEM)
{
QList<FieldItem *> children;
for (int i = 0; i < itemNode.childNodes().count(); i++)
{
children.push_back(createFieldItem(itemNode.childNodes().at(i)));
}
item = new CompositeItem(itemId,children);
}
return item;
}
//At last part of xml data that I used to create BlockSegmentItem and SignalItem in same cell
<Item id="[email protected]" type="COMPOSITE">
<Item id="[email protected]" type="BLOCKSEGMENT">
<Label>
<Text>001BT</Text>
<X1>70</X1>
<Y1>10</Y1>
</Label>
<X1>0</X1>
<Y1>15</Y1>
<X2>150</X2>
<Y2>15</Y2>
</Item>
<Item id="[email protected]" type="SIGNAL">
<Label>
<Text>B2D</Text>
<X1>15</X1>
<Y1>40</Y1>
</Label>
<X1>0</X1>
<Y1>20</Y1>
<Width>40</Width>
<Height>10</Height>
<Source>Resources/graphics/signals/sgt3lr.svg</Source>
</Item>
</Item>
此代碼的工作好與繪畫,但是當涉及到項目事件,它是有問題的。 QGraphicsScene將組合項目視爲適合佈局但不適合事件的單個項目。因爲每個項目都有自己的事件實現(例如SignalItem有其特定的上下文菜單事件)。
我必須單獨處理項目事件。另外我需要一個佈局的複合項目實現。我怎樣才能克服這種困境?
複合材料項目兒童疊加?或者他們在一個單元格內排列成垂直佈局? – Lohrun 2010-05-11 13:45:40
我覺得孩子並不是真的疊加在一起。孩子只在同一個單元內 – onurozcelik 2010-05-12 05:40:35
你可以給類聲明嗎?以及用於在同一單元格內生成帶有BlockSegmentItem和SignalItem的示例的代碼示例(主要是如何將複合項添加到場景中)。 – Lohrun 2010-05-12 09:08:25