• 9352阅读
  • 8回复

[提问]求助关于QGraphicsItem的坐标问题 [复制链接]

上一主题 下一主题
离线阿拉克尼
 

只看楼主 正序阅读 楼主  发表于: 2016-06-26
想保存QGraphicsScene里的item,我用了items();函数,但是这个函数应该保存不了坐标,有哪位做过这方面的功能,应该怎么获取这些item的坐标呢?谢谢了!
离线firebolt

只看该作者 8楼 发表于: 2016-06-29
回 firebolt 的帖子
firebolt:1、保存到xml文件:
    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text)) {
        QMessageBox::warning(this, tr("Qt Drawing"),
   & .. (2016-06-29 19:04) 

还忘了一个方法
bool GraphicsItem::readBaseAttributes(QXmlStreamReader *xml)
{
    qreal x = xml->attributes().value(tr("x")).toDouble();
    qreal y = xml->attributes().value(tr("y")).toDouble();
    m_width = xml->attributes().value("width").toDouble();
    m_height = xml->attributes().value("height").toDouble();
    setZValue(xml->attributes().value("z").toDouble());
    setRotation(xml->attributes().value("rotate").toDouble());
    setPos(x,y);
    return true;
}
离线firebolt

只看该作者 7楼 发表于: 2016-06-29
1、保存到xml文件:
    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text)) {
        QMessageBox::warning(this, tr("Qt Drawing"),
                             tr("Cannot write file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
        return false;
    }

    QXmlStreamWriter xml(&file);
    xml.setAutoFormatting(true);
    xml.writeStartDocument();
    xml.writeDTD("<!DOCTYPE qdraw>");
    xml.writeStartElement("canvas");
    xml.writeAttribute("width",QString("%1").arg(scene()->width()));
    xml.writeAttribute("height",QString("%1").arg(scene()->height()));

    foreach (QGraphicsItem *item , scene()->items()) {
        AbstractShape * ab = qgraphicsitem_cast<AbstractShape*>(item);
        QGraphicsItemGroup *g = dynamic_cast<QGraphicsItemGroup*>(item->parentItem());
        if ( ab &&!qgraphicsitem_cast<SizeHandleRect*>(ab) && !g ){
            ab->saveToXml(&xml);
        }
    }
    xml.writeEndElement();
    xml.writeEndDocument();

2从文件中读取
   QFile file(fileName);
    if (!file.open(QFile::ReadOnly | QFile::Text)) {
        QMessageBox::warning(this, tr("Qt Drawing"),
                             tr("Cannot read file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
        return false;
    }

    QXmlStreamReader xml(&file);
    if (xml.readNextStartElement()) {
        if ( xml.name() == tr("canvas"))
        {
            int width = xml.attributes().value(tr("width")).toInt();
            int height = xml.attributes().value(tr("height")).toInt();
            scene()->setSceneRect(0,0,width,height);
            loadCanvas(&xml);
        }
    }

    setCurrentFile(fileName);
    qDebug()<<xml.errorString();
    return !xml.error();
3、item对象存为xml对象
bool GraphicsItemGroup::saveToXml(QXmlStreamWriter *xml)
{
    xml->writeStartElement("group");
    xml->writeAttribute(tr("x"),QString("%1").arg(pos().x()));
    xml->writeAttribute(tr("y"),QString("%1").arg(pos().y()));
    xml->writeAttribute(tr("rotate"),QString("%1").arg(rotation()));

    foreach (QGraphicsItem * item , childItems()) {
        removeFromGroup(item);
        AbstractShape * ab = qgraphicsitem_cast<AbstractShape*>(item);
        if ( ab &&!qgraphicsitem_cast<SizeHandleRect*>(ab)){
            ab->updateCoordinate();
            ab->saveToXml(xml);
        }
        addToGroup(item);
    }
    xml->writeEndElement();
    return true;
}

4、item对象从xml中读取属性
bool GraphicsRectItem::loadFromXml(QXmlStreamReader * xml )
{
    m_isRound = (xml->name() == tr("roundrect"));
    if ( m_isRound ){
        m_fRatioX = xml->attributes().value(tr("rx")).toDouble();
        m_fRatioY = xml->attributes().value(tr("ry")).toDouble();
    }
    readBaseAttributes(xml);
    updateCoordinate();
    xml->skipCurrentElement();
    return true;
}

5、从xml对象中读取item对象并加入scene中。
void DrawView::loadCanvas( QXmlStreamReader *xml)
{
    Q_ASSERT(xml->isStartElement() && xml->name() == "canvas");

    while (xml->readNextStartElement()) {
        AbstractShape * item = NULL;
        if (xml->name() == tr("rect")){
            item = new GraphicsRectItem(QRect(0,0,1,1));
        }else if (xml->name() == tr("roundrect")){
            item = new GraphicsRectItem(QRect(0,0,1,1),true);
        }else if (xml->name() == tr("ellipse"))
            item = new GraphicsEllipseItem(QRect(0,0,1,1));
        else if (xml->name()==tr("polygon"))
            item = new GraphicsPolygonItem();
        else if ( xml->name()==tr("bezier"))
            item = new GraphicsBezier();
        else if ( xml->name() == tr("polyline"))
            item = new GraphicsBezier(false);
        else if ( xml->name() == tr("line"))
            item = new GraphicsLineItem();
        else if ( xml->name() == tr("group"))
            item =qgraphicsitem_cast<AbstractShape*>(loadGroupFromXML(xml));
        else
            xml->skipCurrentElement();

        if (item && item->loadFromXml(xml))
            scene()->addItem(item);
        else if ( item )
            delete item;
    }
}

大概就这么个过程吧。
离线阿拉克尼

只看该作者 6楼 发表于: 2016-06-27
回 kimtaikee 的帖子
kimtaikee:你添加每个item到scene中都是需要调用setPos设置它的位置的,这时候scenePos返回的是正确的结果。如果你没有调用setPos的话返回的都是(0,0),我上一个回复中提到的左上角是item在scene中的左上角不是整个scene的左上角。你先把创建这些item的代码贴上来。 (2016-06-27 21:19) 

嗯,setPos设置位置是在另一个cpp里面
void DiagramScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    if (mouseEvent->button() != Qt::LeftButton)
        return;

    DiagramItem *item;
    switch (myMode) {
        case InsertItem:
            item = new DiagramItem(myItemType, myItemMenu);
            item->setBrush(myItemColor);
            addItem(item);
            item->scenePos()=mouseEvent->scenePos();
            item->setPos(mouseEvent->scenePos());
            emit itemInserted(item);
            break;
default:
        ;
    }
    QGraphicsScene::mousePressEvent(mouseEvent);
}
我现在开始怀疑我是否用对了那个items()函数,这个函数有好几种重载形式
离线kimtaikee

只看该作者 5楼 发表于: 2016-06-27
你添加每个item到scene中都是需要调用setPos设置它的位置的,这时候scenePos返回的是正确的结果。如果你没有调用setPos的话返回的都是(0,0),我上一个回复中提到的左上角是item在scene中的左上角不是整个scene的左上角。你先把创建这些item的代码贴上来。

离线阿拉克尼

只看该作者 4楼 发表于: 2016-06-27
回 kimtaikee 的帖子
kimtaikee:这个scenePos是你在把这个item加入到scene时设置的,如果你没有设置的话那就是(0,0), 那你再试试item->sceneBoundingRect().topLeft()这个能获得左上角的坐标位置。 (2016-06-27 13:17) 

嗯,说下我的思路吧,有两个按钮,一个保存按钮,一个恢复按钮。
先拖item到QGraphicsscene里边,然后点击保存按钮,我用的是
QList<QGraphicsItem *> list;
void MainWindow::save()
{
list = scene ->items();
}
这个items()函数来实现保存所有item的功能的,然后点击恢复按钮,
void MainWindow::restore()
{
    foreach (QGraphicsItem *my, list)
    {
       scene->addItem(my);
       my->setPos(my->scenePos());
}
我换成my->setPos(my->sceneBoundingRect().topLeft());是可以定位到左上角的位置的,现在没有头绪,麻烦大哥看下问题出在哪,为我指点下迷津,谢谢!
离线kimtaikee

只看该作者 3楼 发表于: 2016-06-27
回 阿拉克尼 的帖子
阿拉克尼:嗯,我用了这个函数
foreach (QGraphicsItem *my, list)    {        scene->addItem(my);        my->setPos(my->scenePos());     &n .. (2016-06-26 23:40) 

这个scenePos是你在把这个item加入到scene时设置的,如果你没有设置的话那就是(0,0), 那你再试试item->sceneBoundingRect().topLeft()这个能获得左上角的坐标位置。

离线阿拉克尼

只看该作者 2楼 发表于: 2016-06-26
嗯,我用了这个函数
foreach (QGraphicsItem *my, list)    {        scene->addItem(my);        my->setPos(my->scenePos());        }
这个foreach是保存完QGraphicsscene里所有的item,然后恢复item位置的一个语句,my遍历了QGraphicsscene里所有的item,                                    my->setPos(my->scenePos());这句感觉有点问题,实际也是执行的时候没有结果,提示my->scenePos()没有有效值。不知道哪里出了问题。
离线kimtaikee

只看该作者 1楼 发表于: 2016-06-26
有个scenePos()函数

快速回复
限100 字节
 
上一个 下一个