IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Qt Discussion :

Comment tracer une ligne à la souris


Sujet :

Qt

  1. #1
    Membre du Club Avatar de sebmag
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2009
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Novembre 2009
    Messages : 52
    Points : 49
    Points
    49
    Par défaut Comment tracer une ligne à la souris
    Bonjour,

    Je me lance pour la première fois dans la conception d'un petit logiciel de dessin industriel ! Actuellement, j'en suis à l'étape où je souhaite tracer une ligne avec la souris.

    Voici ce que je souhaite faire :

    - Lors d'un premier clic, j'accroche la ligne à l'emplacement de la souris
    - j'étire la ligne jusqu'à un point de mon choix
    - je clic une seconde fois pour terminer la ligne.

    J'utilise une classe principale nommé "Dessin" qui hérite de QWidget, une qui hérite de QGraphicsView, une de QGraphicsScene et une de QGraphicsLineItem (pour la ligne à tracer).

    Le problème c'est que je ne sais pas du tout comment m'y prendre pour arriver au résultat souhaité !!!

    voici ma classe pour la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #include "ligne.h"
     
    Ligne::Ligne(QGraphicsItem *parent) :
            QGraphicsLineItem(parent)
    {
        acceptHoverEvents();
        setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
     
        m_pen.setWidth(1);
        m_pen.setColor(Qt::white);
        setPen(m_pen);
    }
    Ligne::Ligne(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem *parent)
    {
        acceptHoverEvents();
        setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
     
        m_pen.setWidth(1);
        m_pen.setColor(Qt::white);
        setPen(m_pen);
     
        QGraphicsLineItem::QGraphicsLineItem(x1,y1,x2,y2,parent,0);
    }
     
    Ligne::~Ligne()
    {
     
    }
    Cette classe vous parait-elle correct ?
    Pourriez-vous me donner une piste ? Merci par avance !!!

  2. #2
    Membre actif
    Avatar de GreatTux
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2009
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2009
    Messages : 77
    Points : 287
    Points
    287
    Par défaut
    Il faut que tu appelles le constructeur de la classe de base (QGraphicsLineItem) de la façon suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    Ligne::Ligne(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem *parent)
        QGraphicsLineItem(x1,y1,x2,y2,parent,0)
    {
        acceptHoverEvents();
        setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
     
        m_pen.setWidth(1);
        m_pen.setColor(Qt::white);
        setPen(m_pen);
    }

  3. #3
    Membre du Club Avatar de sebmag
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2009
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Novembre 2009
    Messages : 52
    Points : 49
    Points
    49
    Par défaut
    merci GreatTux,

    Je viens de modifier !

    Il me reste à savoir comment procéder pour tracer ma ligne ! Je sais que je dois utiliser les évènements de la souris MouseMoveEvent, mousePresseEvent etc... mais je ne sais pas lesquels utiliser (ceux de la scene je suppose ?) et comment procéder pour mettre tout ça en place étape par étape (pour tracer la ligne).

    merci d'avance.

  4. #4
    Membre actif
    Avatar de GreatTux
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2009
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2009
    Messages : 77
    Points : 287
    Points
    287
    Par défaut
    Si j'ai bien compris ton cas, il faudrait que tu dérives la classe QGraphicsView pour créer une classe perso. Dans cette classe, tu devras ensuite ré-implémenter la fonction suivante: http://qt.developpez.com/doc/4.6/qgr...ousepressevent afin de pouvoir gérer les clic de souris.

    Je pense que le plus simple est de gérer des états, pour la ligne tu en as deux. Un état "origine" et un état "ligne en cours de traçage". Deux états, donc tu peux utiliser un booléen. ça donnera qq chose comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    if(!m_bTracageEnCours)
    {
       //ici tu traiteras le premier clique, càd tu récupères la 1ere coordonnée de la ligne
     
       //code...
     
       m_bTracageEnCours = true;
    }else
    {
      //ici tu traiteras le second clique, càd tu récupères la 2nd coodonnée
     
       //code...
     
       m_bTracageEnCours = false;
    }

  5. #5
    Membre du Club Avatar de sebmag
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2009
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Novembre 2009
    Messages : 52
    Points : 49
    Points
    49
    Par défaut
    Merci beaucoup,

    tu me retires une épine de plus !

    J'ai déjà dérivé cette classe et réimplémenté mousePressEvent(). Je ne savais pas que c'était dans cette classe que je pouvais gérer les clics de souris car j'ai aussi une classe dérivé de QGraphicsScene !

    Donc si j'ai bien compris, cette classe qui hérite de QGraphicsView va permettre de stocker (en quelque sorte) les coordonnées de ma ligne et de les envoyer à ma classe qui hérite de QGraphicsLineItem ?

    Et concernant l'affichage de la ligne, comment faire pour que la ligne reste afficher lors du déplacement de la souris ? Je pense à mouseMoveEvent() mais dans quelle classe l'utiliser et comment ?

    En fait, j'aimerais comprendre un peu le fonctionnement de tout ça !

    Encore merci.

  6. #6
    Membre du Club Avatar de sebmag
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2009
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Novembre 2009
    Messages : 52
    Points : 49
    Points
    49
    Par défaut
    En suivant tes conseils, j'ai réussi à tracer des lignes mais pas vraiment comme je l'attendais ! C'est quand même encourageant !!!

    Je n'arrive pas encore à garder la ligne à l'écran lorsque je l'étire !

    Actuellement, je clic une première fois pour accrocher la ligne, je déplace ma souris (et là, la ligne ne s'affiche pas ) et j'effectue un second clic pour que la ligne apparaisse enfin !

    Ce que je souhaite, c'est afficher cette ligne entre le premier point d'accrochage et le second point final lorsque je déplace ma souris !

    Je ne sais pas comment m'y prendre ! As-tu une idée ? Merci.

    Voici ce que j'ai fait dans ma classe QGraphicsScene :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    Scene::Scene(QObject *parent) :
            QGraphicsScene(parent)
    {
        m_tracerEnCours = false;
    }
     
    Scene::~Scene()
    {
     
    }
     
    void Scene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
    {
        int x = event->scenePos().x();
        int y = event->scenePos().y();
     
        emit coordScene(x,y);
     
        update();
        QGraphicsScene::mouseMoveEvent(event);
    }
     
    void Scene::mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
     
        int x = event->scenePos().x();
        int y = event->scenePos().y();
     
        emit coordScenePress(x, y);
     
        if (!m_tracerEnCours)
        {
            m_coord1.setX(x);
            m_coord1.setY(y);
     
            m_tracerEnCours = true;
        }
        else
        {
            m_coord1.setX(x);
            m_coord1.setY(y);
     
            m_tracerEnCours = false;
        }
        update();
        QGraphicsScene::mousePressEvent(event);
    }
     
    QVector2D Scene::coordTrace1() const
    {
        QVector2D result = m_coord1;
     
        return result;
    }
     
    QVector2D Scene::coordTrace2() const
    {
        QVector2D result = m_coord2;
     
        return result;
    }
     
    bool Scene::clic() const
    {
        bool result = m_tracerEnCours;
     
        return result;
    }
    Puis la fonction dans la classe "Dessin" (hérite de QWidget) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // Code...
    connect(m_scene,SIGNAL(coordScenePress(int,int)),this, SLOT(dessiner(int,int)));
    }
     
    void Dessin::dessiner(int x, int y)
    {
        if(ui->pushButtonLigne->isChecked())// Pour tracer une ligne
        {
            int x1=0;
            int y1=0;
            int x2=0;
            int y2=0;
     
                if(!m_scene->clic())
                {
                   x1 = m_scene->coordTrace1().x();
                   y1 = m_scene->coordTrace1().y();
     
                   Ligne *line = new Ligne(x1,y1,x,y);
                   m_scene->addItem(line);
                }
                else
                {
                    x2 = m_scene->coordTrace2().x();
                    y2 = m_scene->coordTrace2().y();
                    Ligne *line = new Ligne(x1,y1,x2,y2);
                    m_scene->addItem(line);
                }
        }
    }

  7. #7
    Membre confirmé
    Avatar de haraelendil
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2004
    Messages
    283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2004
    Messages : 283
    Points : 533
    Points
    533
    Par défaut
    Bah la c'est plus compliqué.

    Une façon basique est que quand ton m_traceEnCours vaut vrai, tu redessine une ligne temporaire à chaque mouvement de souris (donc dans le QMouseMoveEvent)

  8. #8
    Membre du Club Avatar de sebmag
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2009
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Novembre 2009
    Messages : 52
    Points : 49
    Points
    49
    Par défaut
    Merci haraelendil,

    Voilà ce que j'ai fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    void Dessin::dessiner(int x, int y)
    {
        if(ui->pushButtonLigne->isChecked())// Pour tracer une ligne
        {
            int x1=0;
            int y1=0;
            int x2=0;
            int y2=0;
     
            Ligne *line = new Ligne;
            if(m_scene->clic())
            {  
                x1 = m_scene->coordTrace1().x();
                y1 = m_scene->coordTrace1().y();
     
                line->setLine(x1,y1,x,y);
            }
            else
            {
                x2 = m_scene->coordTrace2().x();
                y2 = m_scene->coordTrace2().y();
     
                line->setLine(x1,y1,x2,y2);
            }
            m_scene->addItem(line);
        }
    }
    Mais la fonction me trace une ligne à chaque déplacement de souris ! J'ai essayer avec removeItem() mais cela ne fonctionne pas mieux !

    Edit : voir le résultat en pièce jointe
    Images attachées Images attachées  

  9. #9
    Membre du Club Avatar de sebmag
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2009
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Novembre 2009
    Messages : 52
    Points : 49
    Points
    49
    Par défaut
    Bonjour,

    Est-ce qu'il faut obligatoirement mettre cette fonction dans le QMouseMoveEvent ? Si oui, je ne vois pas comment faire !

    Dois-je utiliser une partie de cette fonction dans le MouseMoveEvent de ma classe "Scene" puis envoyer un signal qui récupèrerais les coordonnées que j'utiliserais dans ma classe principale pour terminer la ligne ?

    Merci d'avance.

  10. #10
    Membre actif
    Avatar de GreatTux
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2009
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2009
    Messages : 77
    Points : 287
    Points
    287
    Par défaut
    Je ne pense pas qu'il fasse faire un new Ligne à chaque mouvement de la souris, mais simplement déplacer la ligne déjà existante (tu fais un new Ligne que si elle n'existe pas encore)

  11. #11
    Membre du Club Avatar de sebmag
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2009
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Novembre 2009
    Messages : 52
    Points : 49
    Points
    49
    Par défaut
    Oui effectivement ! Merci beaucoup. Je suis tellement perdu que je n'avais même pas vu que le fait de faire un new me recréait une nouvelle ligne à chaque déplacement !

    alors après quelques modifs, voilà ce que ça donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    void Dessin::dessiner(int x, int y)
    {
        m_vue->update();
        if(ui->pushButtonLigne->isChecked())// Pour tracer une ligne
        {
            int x1=0;
            int y1=0;
     
            if(m_scene->clic())
            {  
                x1 = m_scene->coordTrace1().x();
                y1 = m_scene->coordTrace1().y();
     
                m_line->setLine(x1,y1,x,y);
            }
            else
            {
                x = m_scene->coordTrace2().x();
                y = m_scene->coordTrace2().y();
            }
        }
    }
    Le souci avec cette méthode, c'est que je peux créer une seule et unique ligne à la fois. Lorsque je trace une seconde ligne à un endroit différent, ça efface la première et ainsi de suite... Logique puisque je ne fait qu'un seul new dans le constructeur. Comment puis-je procéder pour créer un nouvelle ligne à la fin de la première (c'est-à-dire à chaque clic) ?

    Merci.

  12. #12
    Membre actif
    Avatar de GreatTux
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2009
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2009
    Messages : 77
    Points : 287
    Points
    287
    Par défaut
    Je ne connais pas exactement la structure de ton programme, mais il faudrait que tu aies 2 fonctions:
    - une fonction qui déplace la ligne en cours de dessin (Mouse Move), ce que tu viens de réaliser
    - une fonction qui termine le dessin (Mouse Click), dans laquelle tu feras un new

    L'idée c'est que tu aies une ligne temporaire qui ne serve qu'à visualiser la ligne en cours de dessin, et que tu jètes ou caches après. Une fois que l'utilisateur a cliqué pour terminer le dessin de la ligne tu fais ton new, tu stockes éventuellement la nouvelle ligne qq part si besoin (container ou autre) et tu détruit ta ligne temporaire. Au début du tracer de la ligne suivante tu fais un new de ta ligne temporaire et ainsi de suite.

  13. #13
    Membre du Club Avatar de sebmag
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2009
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Novembre 2009
    Messages : 52
    Points : 49
    Points
    49
    Par défaut
    Désolé de cette réponse plus que tardive ! Vacances obliges !

    J'ai donc suivis les conseils de GreatTux que je remercie au passage.

    Il fallait simplement ajouter une petite variable qui sert de repère lorsqu'une ligne est terminée !

    Voici le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    void Dessin::dessiner(int x, int y)
    {
        m_vue->update();
        if(ui->pushButtonLigne->isChecked())// Pour tracer une ligne
        {
            int x1=0;
            int y1=0;
            int i=0;
     
            if(m_scene->clic())
            {  
                x1 = m_scene->coordTrace1().x();
                y1 = m_scene->coordTrace1().y();
     
                m_line->setLine(x1,y1,x,y);
            }
            else
            {
                x = m_scene->coordTrace2().x();
                y = m_scene->coordTrace2().y();
                i=1;
            }
     
            if (i==1)// Si la variable "i" vaut 1 à la fin d'une ligne : création d'une autre ligne etc...
            {
                m_line = new Ligne;
                m_scene->addItem(m_line);
            }
        }
    }
    Merci beaucoup de votre aide, ce sujet est résolu !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 22/07/2011, 19h46
  2. Réponses: 8
    Dernier message: 05/10/2009, 18h46
  3. [TASM] Comment tracer une ligne ?
    Par taze1 dans le forum x86 16-bits
    Réponses: 4
    Dernier message: 08/05/2009, 19h02
  4. Réponses: 11
    Dernier message: 26/08/2007, 14h07
  5. Comment tracer une ligne verticale dans un graphique
    Par developpeur82 dans le forum MATLAB
    Réponses: 3
    Dernier message: 03/04/2007, 14h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo