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.3.1 - Qt Installer : 2.0.3 - JOM : 1.1.2 - Qt Build suite : 1.7.0 - VS Qt 5 : 2.0.0

[Qt4-Linux] Tracking sur QPainter

Bonjour,
Ayant chercher sur votre forum pendant pas mal de temps, je me résous à poster ...
J'explique le problème :

J'ai dessiné une sorte de grille avec des plages en X et Y modifiables.
Je voudrais avoir un effet de tracking sur les resultats qui sont dessiner dans des rectangles,
j'arrive à le dessiner mais le soucis se produit quand je "m'amuse" à bouger ma souris dans la zone de tracking comme un dingue.
En effet, le proc s'affole. En regardant de plus prêt, je redessine complètement le painter à chaque fois...
Si je fais un update() avec le rectangle à modifier, il m'efface le rectangle alors que je veux juste l'encadrer d'un trait noir.
J'ai aussi essayé en sauvegardant la zone dans une pixmap mais je n'y suis pas arriver et je pense que ca sera encore plus lourd.
J'ai utiliser un Qpainter pour palier au contraintes techniques, je gère tous les mouvements de la souris,
ce qui me permet d'interagir avec le Painter.
Ma question fondamental serait : existe-t-il une solution moins gourmande en ressources que celle proposer au dessus? si oui, laquelle ? :)

Merci d'avance

Cordialement

Réponses

  • Bonjour,

    up du matin :)
    Si y'a un soucis dans la compréhension du problème n'hésiter pas ;)

    Cordialement
  • As-tu regardé du côte des classes QGraphics* ?
  • Bonjour et merci de t'attarder sur mon problème,

    Avant de commencer ce que j'ai fait, j'avais testé QGraphicScene,QGraphicView ...
    mais le soucis c'est que j'ai besoin de quelquechose de très modulable d'où l'utilisation de QPainter.
    Ensuite, si quelquechose m'a échapper je suis preneur :)
    Pour etre plus explicite, dans la classe du Widget que je dessine :
    void MonWidget::paintEvent(QPaintEvent*)
    {
    QPainter p(this);

    DessineBackGround(&p);
    DessinePlage(&p);
    DessineGraph(&p);

    if(tracking) // le soucis c'est que la il m'oblige à tout dessiner
    DessineTracking(&p);

    }
    Voila

    Cordialement
  • Apparemment tu as déjà testé de ne rafraîchir qu'une portion de l'écran non ?

    Parce que, bien entendu, la solution pour accélérer tout ça est de ne modifier que ce qui a changé.
  • Yep,

    En faisant un update(Rect); // simplement le rect qui a changer

    QPainter supprime totalement le Rect alors que moi je veux simplement dessiner son contour...
    Si on devait le redessiner entierement(le Rect) les données que je dois y inscrire ne sont pas transporter jusque la et je ne pensais pas arriver jusque là ....
    Il doit y avoir une solution plus logique :) ... mais laquelle ^^ .

    Cordialement.
  • Si ton rectangle contient des données affichées et que tu souhaites faire bouger tout ensemble, il faudrait peut-être créer une sorte d'item qui serait fait à la fois de ton rectangle et des données. C'est alors cet item que tu bougerais.
  • Salut et merci de te joindre à nous pour trouver une réponse,

    alors, ce que tu me demande de faire n'est pas ce que je recherche en effet,
    il faut pas que je bouge l'ensemble du rectangle mais juste redessiner le contour du retangle sur lequel je suis avec la souris et aussi rafraichir l'ancien ....
    donc mettre les rectangles à rafraichir dans un objet QPixmap ? QImage?
    déjà tester, et sa devient vite le foutoir sachant qu'à chaque fois il faut les sauvegarder et les re-loader ...
    Sinon merci du coup de main quand même ;)

    Cordialement
  • Bonjour,

    up du vendredi :)

    Personne n'a de réponse à mon problème?!?

    Cordialement
  • Cess" said:
    Ma question fondamental serait : existe-t-il une solution moins gourmande en ressources que celle proposer au dessus? si oui, laquelle ?
    Si dessiner avec OpenGL est envisageable pour toi, le sujet [Qt4] Problèmes de lag avec QWidget::paintEvent peut êtres intéressant.

    Pour ça, dérives simplement ta classe MonWidget de QGLWidget et non pas de QWidget.
    C'est tout, rien à modifier au code :)


    Tu peux également active le dessin avec OpenGL en option de compilation:
    #ifdef USE_OPENGL_ENGINE
    #include <QGLWidget>
    #else
    #include <QWidget>
    #endif


    #ifdef USE_OPENGL_ENGINE
    class MonWidget : public QGLWidget {
    typedef QGLWidget Super;
    #else
    class MonWidget : public QWidget {
    typedef QWidget Super;
    #endif
    Q_OBJECT

    public:
    MonWidget(QWidget * = 0);

    protected:
    void paintEvent(QPaintEvent *);
    };
  • Merci beaucoup !
    Je connais pas mais je vais m'y intéresser de ce pas :)
    Je regarde ça de suite et je vous tiens au courant.

    Cordialement
  • Étant tout content à l'idée de tester ce que tu venais de me faire decouvrir,
    je viens de découvrir autre chose .... la machine ne gère pas l'OpenGL :(
    C'est sur que si je pouvais, en regardant plusieurs docs et le Thread que tu m'a donné, cela aurai été sympas
    mais malheureusement e noyau que mon collègue a crée ne le gère pas...
    Du coup retour à la case départ ....
    Merci quand même :)

    Cordialement
  • Cess said:
    je viens de découvrir autre chose .... la machine ne gère pas l'OpenGL :(
    Cela me parait vraiment bizarre.
    Même avec une très vielle machine avec une carte graphique on-board j'arrive à travailler avec OpenGL.

    Tu n'as pas besoin d'une carte graphique puissante. Tu veux juste faire du dessin 2D en passant par la carte graphique plutôt que de passer par le CPU.
  • Cess said:
    malheureusement le noyau que mon collègue a crée ne le gère pas...
    Du coup retour à la case départ ....
    C'est ça le soucis, pour faire simple, c'est pas un "ordinateur" :)
    mais plutôt une maquette que l'on développe entièrement.
    Donc pas d'OpenGL, à moins de tout revoir depuis le début...
    Sachant que je serai le seul à l'utiliser...

    Mais Merci de m'aider dans cette affaire, Sympa ;)

    Cordialement
  • December 2008 modifié
    Salut!
    up du lundi Matin .....

    pas d'autres idées ? :)

    Cordialement
  • Bonjour !

    Toujours pas d'idée :(

    Je vais déprimer pour les fêtes ^^
  • Alors, j'ai peut-être une idée.
    Il faudrait que tu dessines le contenu de ton widget dans un pixmap et que tu affiches ce pixmap dans ton widget.
    Cela permettrait d'éviter l'effacement du contenu de ton widget (et par extension dans ton cas du fond de tes rectangles).
  • ha..... ^^
    alors j'y est pensé mais es-ce que le faite de redessine a chaque fois dans la pixmap ne va pas aussi prendre un temps proc de folie....
    Car si je suis bien il faudra que je dessine la pixmap, que je l'affiche dans le widget et ensuite a chaque mouvement je ré-affiche le pixmap et dessine le rectangle ?

    ça va être pareil non?
  • Je ne suis pas sur d'avoir bien compris ce que fait ton application.
    Tu as une grille et quand la souris passe/clique sur une case de la grille, cette case change de couleur (ou la bordure change de couleur).
    C'est ça ?
        DessineBackGround(&p);
    DessinePlage(&p);
    DessineGraph(&p);

    if(tracking) // le soucis c'est que la il m'oblige à tout dessiner
    DessineTracking(&p);
    Je ne connais pas la complexité de tes méthodes Dessine* mais je pense que tu peux beaucoup optimiser ici (par exemple, as tu vraiment besoin de générer l'arrière plan à chaque fois ?)


    J'ai codé un petit exemple très simple.
    Le widget affiche une grille et quand l'utilisateur déplace la souris sur les cases de cette grille, la case sélectionnée devient jaune:
    MyWidget::MyWidget(QWidget *p_parent)
    : QWidget(p_parent) {

    // taille d'une case
    m_caseSize = 50;

    // taille du widget
    setFixedSize(50 +1, 50 +1);
    }

    void MyWidget::paintEvent(QPaintEvent *p_e) {
    QPainter p(this);

    /* position par défault */
    int x = 0;
    int y = 0;

    /* taille par défault */
    int width = rect().width();
    int height = rect().height();

    /* si le widget n'a pas besoin d'être totalement redessiné,
    * on change les valeurs par défault */
    if(p_e->rect() != rect()) {
    /* nouvelle position */
    x = (p_e->rect().x() / m_caseSize);
    y = (p_e->rect().y() / m_caseSize);

    /* nouvelle taille */
    width = p_e->rect().width();
    height = p_e->rect().height();
    }

    /* dessine la grille */
    for(; x <= width; ++x) {
    // dessine les lignes verticales
    p.drawLine(x * m_caseSize, 0, x * m_caseSize, height);
    for(; y <= height +1; ++y) {
    // dessine les lignes horizontales
    p.drawLine(0, y * m_caseSize, width, y * m_caseSize);
    }
    }

    // dessine la case selectionnée
    p.setBrush(Qt::yellow);
    p.drawRect(m_currentRect);
    }

    void MyWidget::mousePressEvent(QMouseEvent *p_e) {
    /* si l'utilisateur click sur la même case, on ignore l'evenement */
    if(m_lastRect.contains(p_e->pos())) {
    return QWidget::mousePressEvent(p_e);
    }

    // supprime l'ancienne case
    update(m_lastRect);

    // selection de la nouvelle case
    selectRect(p_e->pos());
    }

    void MyWidget::mouseMoveEvent(QMouseEvent *p_e) {
    /* si l'utilisateur se déplace sur la même case, on ignore l'evenement */
    if(m_lastRect.contains(p_e->pos())) {
    return QWidget::mouseMoveEvent(p_e);
    }

    // supprime l'ancienne case
    update(m_lastRect);

    // selection de la nouvelle case
    selectRect(p_e->pos());
    }

    void MyWidget::selectRect(const QPoint &p_pos) {
    int x = p_pos.x() / m_caseSize;
    int y = p_pos.y() / m_caseSize;

    /* mise à jour du rectangle */
    m_currentRect = QRect(x * m_caseSize, y * m_caseSize, m_caseSize, m_caseSize);
    update(m_currentRect);

    // pour la prochaine selection
    m_lastRect = m_currentRect;
    }
    J'ai essayer d'optimiser le plus possible (codé à la va-vite quand même):

    1) Limiter les appels à paintEvent
    J'utilise 2x la méthode update(Qrect) (pour l'ancienne case et la nouvelle) par click.
    Heureusement, Qt optimise mes appels et n'exécute qu'une seul fois paintEvent en combinant mes 2 cases (QRect::united).

    2) Ne pas dessiner la grille complète à chaque fois
    Qt ne dessine pas tout le widget mais seulement le rectangle indiqué.

    3) Ne pas générer la grille complète à chaque fois
    Imagines que ta grille fasses 50000x50000 cases, même si tu dessine uniquement la case sélectionnée, il est inutile de générer toute la grille.
    Dans ma méthode paintEvent, je génère ma grille uniquement pour le rectangle changé.


    PS: Le code n'est pas tout à fait au point, je n'ai pas eu le temps de prendre en compte les bordures des cases (les bordures de certaines ne sont pas redessinées) ...
  • Non, je parle de dessiner dans le pixmap uniquement les zones modifiées. Effectivement, si tu devais tout redessiner à chaque fois, ça serait une horreur. L'avantage de dessiner dans un pixmap est que tu peux conserver en mémoire des zones qui ne nécessitent pas d'être retracées.
  • December 2008 modifié
    Donc,au moment du tracking je save le rectangle que je vais update dans la pixmap.
    J'update, je recopie la pixmap ou on a update et je fais le rectangle ?

    Le souci étant qu'il faut mettre a jour le fond pour enlever le premier rectangle tracé quand on dessine le second rectangle...
    alors la il faudrait deux pixmaps et l'update ne marcherais pas ... ou mal.


    EDIT: j'ai pas vu tous les message dsl, je regarde ca ...

    EDIT 2 : merci Red Rabbit de t'y être penché plus précisément mais le point que tu a révélé, je les déjà testé, le soucis est que tu dessine un rectangle uni alors que moi il y a des chose a l'intérieur ..... sinon oui ton exemple est bon :) si je n'est rien à l'intérieur de mes rectangles mais si il y a des données..... c'est pour ça que redessiner UNIQUEMENT le contour m'aurai paru plus judicieux mais sans supprimer l'intérieur .... c'est vraiment le bord**^^
  • Salut !

    Aller dernier up et après je laisse tombé :/
    Petit cadeau de Noel ? :D
Connectez-vous ou Inscrivez-vous pour répondre.