2010-05-11 82 views
0

我正在火车交通控制器软件项目工作。 我在这个项目中的责任是开发视觉铁路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有其特定的上下文菜单事件)。

我必须单独处理项目事件。另外我需要一个布局的复合项目实现。我怎样才能克服这种困境?

+0

复合材料项目儿童叠加?或者他们在一个单元格内排列成垂直布局? – Lohrun 2010-05-11 13:45:40

+0

我觉得孩子并不是真的叠加在一起。孩子只在同一个单元内 – onurozcelik 2010-05-12 05:40:35

+0

你可以给类声明吗?以及用于在同一单元格内生成带有BlockSegmentItem和SignalItem的示例的代码示例(主要是如何将复合项添加到场景中)。 – Lohrun 2010-05-12 09:08:25

回答

0

您可以使用QGraphicsScene :: sendEvent()将事件传递给子节点。这是一个应该解决您的问题的例子。

void CompositeItem::sceneEvent(QEvent * event) 
{ 
    if (scene()) { 
    FieldItem *child; 
    foreach(child, children) { 
     scene()->sendEvent(child, event); 
    } 
    } 
} 

在我看来是复合项目可以理解为分层布局,一个项目在另一个顶部绘制。这种布局尚不存在,但如果他们将来出现,我不会感到惊讶。

+0

由于我编辑了boundingRect代码的建议。我想联合孩子们的界限是一个很好的想法。但是这个时间项目不能捕获contextmenuevent和mousepressevent等事件。所以我之前的问题是要捕捉事件。你有什么想法可能会导致这种情况? – onurozcelik 2010-05-12 08:28:59

+0

您的CompositeItem是否从QGraphicsItem派生?我错过了CompositeItem类的声明以获得完整的问题视图。 – Lohrun 2010-05-12 09:04:35

+0

我将详细信息添加到原始帖子。希望就够了。如果你需要更多的解释,请问;) – onurozcelik 2010-05-12 11:43:52