Russian Qt Forum
Май 17, 2024, 04:06 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Проясните с QUndoStack  (Прочитано 5112 раз)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« : Июнь 06, 2013, 11:46 »

Есть такая команда:

Код:
#include <QGraphicsItem>
#include "cscenecommand.h"
#include "cinterfacetag.h"

class CAppendItemCommand : public CSceneCommand
{
    CInterfaceTag       fitemTag;
    QPointF             fpos;
public:
    CAppendItemCommand(QUndoCommand * parent = 0);
    void    setTag(const CInterfaceTag & tag);
    void    setPos(const QPointF & pos);
    void    undo();
    void    redo();
};

Код:
#include "cappenditemcommand.h"

CAppendItemCommand::CAppendItemCommand(QUndoCommand *parent):
    CSceneCommand(parent)
{

}

void CAppendItemCommand::setTag(const CInterfaceTag &tag)
{
    fitemTag = tag;
}

void CAppendItemCommand::setPos(const QPointF &pos)
{
    fpos = pos;
}

void CAppendItemCommand::undo()
{
    if(scene())
    {
        scene()->remove_selected(items());
    }
}

void CAppendItemCommand::redo()
{
    if(scene())
    {
        scene()->addRailItem(fitemTag,fpos);
    }
}

Вызывается в этом месте:
Код:
void QExGraphicsScene::addRailItem(const CInterfaceTag &itemClass, const QPointF &position)
{
    QRailItemFactory   *   provider = frailItemProviderHash.value(itemClass,NULL);
    if(provider)
    {
        QRailItem   *   addedItem = provider->createRailItem(position);
        CAppendItemCommand  *   appendCommand = new CAppendItemCommand;
        appendCommand->setScene(this);
        appendCommand->setItem(addedItem);
        appendCommand->setPos(position);
        appendCommand->setTag(itemClass);
        fundoStack->push(appendCommand);
    }
}

Мне нужно добавить элемент на сцену, и запомнить действие отмены.
Почему при push вызывается сразу redo() и у меня прога падает в рекурсию... или я что то не понимаю.
Записан
mutineer
Гость
« Ответ #1 : Июнь 06, 2013, 11:54 »

Если fundoStack это QUndoStack, то
Цитировать
void QUndoStack::push ( QUndoCommand * cmd )
Pushes cmd on the stack or merges it with the most recently executed command. In either case, executes cmd by calling its redo() function.
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #2 : Июнь 06, 2013, 12:10 »

Хорошо, как мне к примеру сделать отмену перемещения элемента на сцене?
Код:
void    QExGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
fbeginPos = event->scenePos();
}

void    QExGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
     if(fbeginPos!=event->pos())
    {
        CMoveItemCommand    *   moveCommand = new CMoveItemCommand;
        moveCommand->setScene(this);
        moveCommand->setItems(selectedItems());
        moveCommand->setBeginPos(fbeginPos);
        moveCommand->setEndPos(event->pos());
        fundoStack->push(moveCommand);
    }
}

где команда отмены перемещения
Код:
void CMoveItemCommand::setBeginPos(const QPointF &pos)
{
    fbeginPos = pos;
}

void CMoveItemCommand::setEndPos(const QPointF &pos)
{
    fendPos = pos;
}

void CMoveItemCommand::undo()
{
    if(scene())
    {
        QPointF delta = fendPos-fbeginPos;
        foreach (QGraphicsItem * item, items())
        {
            item->moveBy(delta.x(),delta.y());
        }
    }
}

void CMoveItemCommand::redo()
{
    if(scene())
    {
        QPointF delta = fbeginPos-fendPos;
        foreach (QGraphicsItem * item, items())
        {
            item->moveBy(delta.x(),delta.y());
        }
    }
}

проблема в том, что вызывается  redo(), перемещение уже сделано мышью на сцене, и получается делается еще раз...
Записан
mutineer
Гость
« Ответ #3 : Июнь 06, 2013, 12:18 »

1) Не реагировать на первый вызов redo()
2) использовать setPos вместо moveBy
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #4 : Июнь 06, 2013, 12:19 »

пришлось вводить переменную, которая смотрит, было ли уже сделано redo().
блин, немного неудобный механизм Undo. почему он вызывает redo() при помещении в стек?
логично было бы сделать какие то действия на сцене, передать нужные параметры для отмены и поместить команду в стек.
а так получается в команде нужно реализовывать собственно изменения, которые раньше производились в самой сцене...
конечно решилось это дружестенными классами, тем немее туповато.
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #5 : Июнь 06, 2013, 12:20 »

т.е. создание и удаление элементов на моей сцене сложнее чем просто добавить/удалить.
а теперь нужно рыться в потрохах сцены из команды...
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3259


Просмотр профиля
« Ответ #6 : Июнь 07, 2013, 15:53 »

а так получается в команде нужно реализовывать собственно изменения, которые раньше производились в самой сцене...
конечно решилось это дружестенными классами, тем немее туповато.

Вы не поверите. Именно так и должен работать паттерн "команда".
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #7 : Июнь 14, 2013, 18:20 »

Сделал несколько  комманд, все работает, отменяет, восстанавливает.
Но при попытке очистить стэк изменений при загрузке нового документа у меня вылетает сегментация. причем, если команд в стеке нет, то сегментации тоже нет.
у меня несколько вкладок на табБаре, у каждой вкладки свой стек. эти стеки кидаю в группу QUndoGroup.
Не пойму причину сегментации. До внесения поддержки стков изменения сегментаций не было.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #8 : Июнь 14, 2013, 18:27 »

Вы главное код нам не показывайте. Что бы мы гадали подольше. Подмигивающий
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.065 секунд. Запросов: 23.