2010-05-11 88 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