2010-05-11 4 views
0

Train Traffic Controller 소프트웨어 프로젝트에서 일하고 있습니다. 이 프로젝트의 책임은 시각적 철도 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

+0

차일드는 실제로 중첩되지 않습니다. 차일 즈가 같은 셀 안에있을 때 – onurozcelik

+0

클래스 선언을 할 수 있습니까? 그리고 같은 셀 안에 BlockSegmentItem과 SignalItem을 가진 예제를 만드는 데 사용한 코드의 샘플 (그리고 주로 복합 아이템을 어떻게 장면에 추가하는지). – Lohrun

답변

0

QGraphicsScene :: sendEvent()를 사용하여 이벤트를 자식에게 전달할 수 있습니다. 다음은 문제를 해결해야 할 예입니다.

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

복합 항목은 하나의 항목이 다른 항목 위에 그려지는 계층화 된 레이아웃으로 이해 될 수 있습니다. 이러한 레이아웃은 아직 존재하지 않지만 앞으로 나타날 경우 놀라지 않을 것입니다.

+0

조언으로 boundingRect 코드를 편집했습니다. 나는 아이의 경계를 단결시키는 것은 깔끔한 생각이라고 생각한다. 그러나 이번에는 contextmenuevent 및 mousepressevent와 같은 이벤트를 catch 할 수 없습니다. 그래서 제 이전 문제는 사건을 잡는 것입니다. 이 문제를 일으킬 수있는 아이디어가 있습니까? – onurozcelik

+0

CompositeItem은 QGraphicsItem에서 파생됩니까? 문제의 전체적인 모습을 볼 수있는 CompositeItem 클래스의 선언이 누락되었습니다. – Lohrun

+0

원본 게시물에 세부 정보를 추가했습니다. 희망은 충분하다. 더 많은 설명이 필요하면 그냥 물어보십시오.) – onurozcelik