Bienvenue sur le forum !

Si vous souhaitez rejoindre la communauté, cliquez sur l'un de ces boutons !

Qt 5 : 5.9.1 - Qt Creator : 4.4.0 - Qt Installer : 2.0.3 - JOM : 1.1.2 - Qt Build suite : 1.7.0 - VS Qt 5 : 2.0.0

Undo/Redo QPainter

Hello,

J'ai besoin d'utiliser le UndoFramework pour revenir en arrière/et en avant sur un tracé effectué avec la souris dans l'event Paint sur un widget. Pour l'instant la seule solution que je vois, mais qui n'est pas élégante, serait de stocker dans une list des QImage représentants l'état visuel du widget entre deux mousePressed et mouseReleased pour ensuite pouvoir revenir sur des anciens états.

Auriez vous une solution plus propre ?

Merci d'avance

Réponses

  • Bonsoir,
    que dessines-tu exactement dans ton widget ?
  • Des lignes entre l'ancienne position de la souris et la position courante. (pour faire un crayon)
  • December 2016 modifié
    Et bien je stockerai une liste de QLine, le undo dépille la liste et le redo empile. Ensuite plus qu'à appelé le repaint du widget.
    EDIT : l'utilisation des QGraphicsView/Scene/Items est plus adapté au dessin vectoriel.
  • Okay donc tu ferais une class héritant de QUndoCommand "TraceLine" par exemple ? Sinon j'ai décidé de le faire avec QPainter car prenons l'exemple d'un document de 1920 * 1080 avec donc le potentiel pour l'utilisateur de dessiner plus de 2000000 de petites lignes, je me suis dit qu'avec des QGraphicsLineItem ça serait un peu lourd à rendre :p
  • Alors, je verrai la liste de QLine dans le widget responsable du rendu.
    Ensuite à chaque création de ligne, plusieurs solution :
    1) passer le widget à la classe héritant de QUndoCommand, ainsi le constructeur garde un copie de la dernière QLine de la liste pour la rajouter lors du redo, et faire un widget->lines().removeLast() dans le undo.
    2) passer le widget + la QLine créée (ou 2 QPoint) et c'est la undoCommand qui l'ajoute ou l'enlève de la liste.

    Je verra une undoCommand par ligne créée ce qui permet de remplir une pile d'undo utile pour naviguer.
    Tu peux aussi utiliser de l'allocation dynamique pour les Qline.
  • December 2016 modifié
    Ne penses-tu pas que de stocker en mémoire tous les points coûterait plus cher que de stocker des QImages ? Car dans le cas des QImages j'ai besoin d'en stocker qu'une entre chaque mouseDown et mouseReleased (donc potentiellement beaucoup de lignes) fois le nombre d'undo/redo possible alors que dans le cas des lignes j'ai besoin de toutes les stocker pour pouvoir reconstruire l'image.
  • Combien veux-tu de niveau de undo ?
    car en théorie, tu auras autant d'images que de lignes non ?
    Si tu veux qu'un niveau, ne pas stocker une liste de lignes ou points, mais que les derniers.
  • Bah dans l'idée comme c'est un crayon j'ai une ligne entre chaque nouvelle position de souris lors d'un mouseMove. Et j'aimerais un nombre raisonnable d'undo, comme dans n'importe quel soft de dessin ~ 20/30
  • Salut,
    Et en passant par un QPainterPath, cela fait qu'un undo.
  • Hello,

    Stocker des points est beaucoup plus économe en mémoire que de stocker des images !
    Tu peux faire le calcul, le poids d'une image comparé au "poids" d'une ligne, à peu près. Une ligne c'est deux points, un point deux nombres, donc avec des doubles (QLineF/QPointF) qui font 8 octets chacun, cela fait 32 octets par ligne.
    Une image de 1024x768 en 32 bits fait 3145728 octets, soit l'équivalent de 98304 lignes... ;)
    Évidemment il y a d'autres éléments à prendre en compte comme la taille de chaque "undo command", mais cela reste faible.

    Un avis qui n'engage que moi, concernant le nombre limité d'undo/redo : je ne le limiterais pas (ou extrêmement grand). Aujourd'hui nos machines ont suffisamment de mémoire pour gérer cela, et je déteste ne pas pouvoir revenir sur qqch même si c'est 200 actions avant :-p
  • December 2016 modifié
    Merci pour les réponses, après personnellement j'imaginai un stockage de bouts d'images, pas du canvas entier. D'autre part en plus du stockage des points il faut que je prenne en compte la taille du trait (qui change en fonction de la pression sur la tablette graphique), du coup il me faudrait une petite structure qui contienne toutes les infos sur le tracé. Maintenant imaginons que je fasse évoluer mon crayon pour un système de brush qui utilisera donc des alphas pour le tracé. Dans ce cas, quoi qu'il arrive, les undo/redo coûterons cher.
  • December 2016 modifié
    Bonsoir !
    quoi qu'il arrive, les undo/redo coûteront cher.
    Non. Relis la comparaison de BBenj entre les lignes et les images pour t'en persuader. Et regarde la capacité mémoire de ton PC : tu ne vas pas abîmer ta mémoire en y empilant quelques structures...
    Pour l'anecdote, l'appli de dessin Gimp autorise 1.048.576 niveaux d'annulation maxi. En pratique, c'est équivalent à illimité : qui va faire Ctrl+Z plus que quelques dizaines de fois ?

    Ce que j'en dis c'est que si tu es plus à l'aise avec les images, utilise donc des images. Mais ne justifie pas ton choix par le coût en octets/Mo des opérations, la contrainte d'économiser une mémoire rare et chère a disparu à la fin du XXe siècle.
Connectez-vous ou Inscrivez-vous pour répondre.