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

MFC Discussion :

Cadre de sélection sur contrôle dynamique


Sujet :

MFC

  1. #1
    Nouveau membre du Club
    Inscrit en
    Février 2007
    Messages
    38
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Février 2007
    Messages : 38
    Points : 26
    Points
    26
    Par défaut Cadre de sélection sur contrôle dynamique
    Bonjour à tous et une fois encore merci de vous intéresser à mon problème.

    Je cherche à réaliser un cadre de sélection standard sur des contrôles créés dynamiquement. Le cadre me permet de redimensionner et déplacer le contrôle auquel il est affecté. Typiquement la même chose que l'on a lorsque l'on utilise l'interface graphique de Visual pour poser nos contrôles (button, textedit, ...) de manière statique.

    Plutôt que de m'amuser à recréer ce cadre et de réécrire les événements qui lui sont propres, je me demandais s'il n'existait pas déjà un contrôle en MFC qui me soulagerait de cette opération???

    Comptant sur vous pour m'aider sur ce problème

    Merci d'avance.

  2. #2
    Rédacteur
    Avatar de farscape
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    9 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 9 055
    Points : 17 323
    Points
    17 323
    Par défaut
    salut, voir la classe CRectTracker sur MSDN il y a un exemple d'utilisation (TRACKER).

  3. #3
    Nouveau membre du Club
    Inscrit en
    Février 2007
    Messages
    38
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Février 2007
    Messages : 38
    Points : 26
    Points
    26
    Par défaut
    Super !

    Tu m'épateras toujours!
    Je regarde çà de suite !

    Merci encore!

  4. #4
    Nouveau membre du Club
    Inscrit en
    Février 2007
    Messages
    38
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Février 2007
    Messages : 38
    Points : 26
    Points
    26
    Par défaut
    J'ai pas mal bossé sur la classe CRectTracker. Et comme j'ai pas trouvé énormément d'exemples dessus sur le web. Je me permet de poster le code que j'ai écris afin d'en faire profiter tout le monde ...

    J'ai deux pointeurs déclarés en protected dans la classe et initialisés à NULL dans le constructeur de la classe. La classe "CRectTrackerEx" hérite de "CRectTracker", j'explique après pourquoi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    CRectTrackerEx	*co_rect_tracker;	/*!< Tracker of the selected control */
    CWnd			*co_ctrl_wnd;		/*!< Selected control */
    Pour la compréhension de la suite, le constructeur de CRectTrackerEx est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    CRectTrackerEx::CRectTrackerEx( CWnd *parent )
    {
    	co_parent = parent;
    }
    co_parent est déclaré en protected, ainsi :

    Tout démarre avec la méthode suivante, qui identifie le contrôle sélectionné à la souris et trace le rectangle du tracker sur celui-ci :


    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
     
    void CWindowApplication::OnRangeClickButton(UINT nID)
    {
    	// Display selected control
    	if ( co_ctrl_wnd == this->GetDlgItem(nID) )
    		return;
     
    	co_ctrl_wnd = this->GetDlgItem(nID);
     
    	if ( !co_ctrl_wnd )
    		return;
     
    	if ( co_rect_tracker )
    		delete co_rect_tracker;
     
    	CRect rect_for_tracker;
     
    	co_ctrl_wnd->GetWindowRect(rect_for_tracker);
    	ScreenToClient(rect_for_tracker);
     
    	co_rect_tracker = new CRectTrackerEx(this);
    	co_rect_tracker->m_rect = rect_for_tracker;
    	co_rect_tracker->m_nStyle = CRectTracker::resizeOutside|CRectTracker::hatchedBorder|CRectTracker::solidLine;
     
    	RedrawWindow();
    }

    On surcharge aussi "OnSetCursor" de la boîte de dialogue afin de modifier l'état du curseur. Ce que je trouve d'ailleurs très étonnant, car la classe CRectTracker aurait peut-être pu le faire elle même... (Y manque quelque chose là je trouve ... :s)

    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
     
    BOOL CWindowApplication::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
    {
    	// TODO: Add your message handler code here and/or call default
    	if ( co_rect_tracker )
    	{
    		CPoint point;
    		GetCursorPos(&point);
    		ScreenToClient(&point);
     
    		// Test if the mouse is over the rect tracker
    		if ( co_rect_tracker->SetCursor(pWnd, nHitTest ) )
    		{			
    			// Test where is the mouse on this rect tracker (dot or border?)
    			switch( co_rect_tracker->HitTest(point) )
    			{
    				case CRectTracker::hitLeft  :	
    				case CRectTracker::hitRight :	
    							SetClassLong(this->GetSafeHwnd(), GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_SIZEWE));
    							break;
    				case CRectTracker::hitTop :	
    				case CRectTracker::hitBottom  :	
    							SetClassLong(this->GetSafeHwnd(), GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_SIZENS));
    							break;
    				case CRectTracker::hitTopLeft  :
    				case CRectTracker::hitBottomRight :	
    							SetClassLong(this->GetSafeHwnd(), GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_SIZENWSE));
    							break;
    				case CRectTracker::hitBottomLeft :	
    				case CRectTracker::hitTopRight :	
    							SetClassLong(this->GetSafeHwnd(), GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_SIZENESW));
    							break;
    				default :	// Mouse is over the rect borber
    							SetClassLong(this->GetSafeHwnd(), GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_SIZEALL));
    							break;
    			}
    		}
    		else
    		{
    			// Test if the mouse is inside the rect tracker
    			if ( co_rect_tracker->m_rect.PtInRect(point) )
    				SetClassLong(co_ctrl_wnd->GetSafeHwnd(), GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_SIZEALL));
    			else
    				SetClassLong(this->GetSafeHwnd(), GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
    		}
    	}
     
    	return CDialog::OnSetCursor(pWnd, nHitTest, message);
    }
    La méthode suivante commence le tracé du rectangle de sélection (si j'ai bien compris) dès que le bouton gauche de la souris est pressé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    void CWindowApplication::OnLButtonDown(UINT nFlags, CPoint point) 
    {
    	// TODO: Add your message handler code here and/or call default
    	if ( co_rect_tracker )
    	{
    		int hit = co_rect_tracker->HitTest(point);
    		// Test if the mouse is over a resizing point of the rect tracker and start the tracker
    		if ( hit >= 0 && hit <=8 )
    			co_rect_tracker->Track(this, point, FALSE, NULL);
    	}
     
    	CDialog::OnLButtonDown(nFlags, point);
    }

    La dernière méthode redimensionne et replace le contrôle sélectionné en fonction de la nouvelle position du rectangle. Elle est appelée dès l'instant que le bouton gauche de la souris est relâché et que le rectangle du tracker à été déplacé et/ou redimensionné :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void CWindowApplication::UpdateCtrl()
    {
    	if ( co_rect_tracker && co_ctrl_wnd )
    	{
    		co_ctrl_wnd->SetWindowPos(NULL, co_rect_tracker->m_rect.left, co_rect_tracker->m_rect.top, co_rect_tracker->m_rect.Width(), co_rect_tracker->m_rect.Height(), SWP_SHOWWINDOW);
    		RedrawWindow();
    	}
    }

    Bien entendu cette méthode n'est pas appelée toute seule. Pour cela j'ai surchargé la méthode "OnChangedRect" de CRectTracker afin d'appeler la méthode ci-dessus, d'où la classe "CRectTrackerEx" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    void CRectTrackerEx::OnChangedRect(const CRect &rectOld)
    {
    	if ( GetAsyncKeyState(VK_LBUTTON) == 0 )
    	{
    		LV_DISPINFO dispinfo;
    		dispinfo.hdr.hwndFrom	= co_parent->GetSafeHwnd();
    		dispinfo.hdr.code		= END_TRACKER;
     
    		co_parent->SendMessage( WM_NOTIFY, 0, (LPARAM)&dispinfo );
    	}
     
    	CRectTracker::OnChangedRect(rectOld);
    }

    "END_TRACKER" est une macro définie dans la classe CRectTrackerEx.


    A noter qu'il faut déclarer la notification liée à END_TRACKER de la manière suivante dans la classe "CWindowApplication" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    BEGIN_MESSAGE_MAP(CWindowApplication, CDialog)
    	//{{AFX_MSG_MAP(CWindowApplication)
    	ON_WM_LBUTTONDOWN()
    	ON_WM_SETCURSOR()
    	ON_WM_PAINT()
    	//}}AFX_MSG_MAP
     
    	ON_CONTROL_RANGE(BN_CLICKED, 0, 999999, OnRangeClickButton)
    	ON_NOTIFY(END_TRACKER, 0, UpdateCtrl)
     
    END_MESSAGE_MAP()

    Pour terminer, il faut rafraîchir le rectangle de sélection dans la fenêtre, j'ai donc complété la méthode OnPaint() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void CWindowApplication::OnPaint() 
    {
    	CPaintDC dc(this); // device context for painting
     
    	// TODO: Add your message handler code here
    	if ( co_rect_tracker )
    		co_rect_tracker->Draw(&dc);
    }



    Il reste toutefois une amélioration à faire. Je n'ai pas encore pu trouver une bonne solution à ce problème. Actuellement je ne peux déplacer le contrôle sélectionné qu'en cliquant sur le rectangle de sélection et en le déplaçant avec la souris. Cela ne fonctionne pas en cliquant à l'intérieur du contrôle à modifier et en le déplaçant à la souris. :s
    Le problème est que la méthode "CWindowApplication::OnLButtonDown" n'est pas appelée lors de l'appui sur le bouton gauche de la souris. C'est bien dommage mais c'est comme çà et puis c'est normal aussi...


    Mis à part ce défaut, j'espère que cet exemple pourra aider un peu.
    N'hésitez surtout pas si vous avez des optimisations à faire, je suis preneur!

    Une fois encore, merci Farscape de m'avoir fait découvrir cette classe. Cà m'a énormément aidé !

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

Discussions similaires

  1. [CS3] Retirer le cadre de sélection sur une image-lien
    Par psykam dans le forum Dreamweaver
    Réponses: 6
    Dernier message: 22/03/2011, 22h47
  2. Contrôle dynamique disparaît sur le chargement
    Par Hujii dans le forum ASP.NET
    Réponses: 3
    Dernier message: 23/03/2010, 02h42
  3. [WD10] Dessiner un cadre de sélection sur un champ image
    Par mnssylvain dans le forum WinDev
    Réponses: 4
    Dernier message: 11/03/2009, 15h48
  4. Evenements sur contrôles dynamiques
    Par BATCHOS CON TEQUILA dans le forum ASP.NET
    Réponses: 5
    Dernier message: 23/01/2009, 14h03
  5. Postback sur des contrôles dynamiques
    Par luimême dans le forum ASP.NET
    Réponses: 5
    Dernier message: 27/11/2007, 14h57

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