| auteur : Farscape |
On utilisera les radios chaque fois que l'on doit faire un choix unique parmi des options.
Exemple imaginons le traitement du régime TVA d'un client on aura par exemple France / Corse / Export / CEE .
1) étape :
Dans l'éditeur de ressources sur la dialogue concernée on placera le premier radio en spécifiant son nom :
Dans mon exemple je le nommerai IDC_RADIOTVA son label France
Ensuite ne pas oublier de cocher l'option Tab Stop et surtout l'option Group permettant de spécifier que l'on commence un nouveau groupe et donc que les contrôles suivants de même nature en font partie.
On place ensuite les autres radios et on laissera l'éditeur donner l'ID du radio qu'il incrémentera de manière automatique par rapport au premier radio.
Si je dois placer un autre groupe de radios derrière il faudra juste spécifier sur le premier radio l'option groupe pour distinguer les deux groupes.
2) étape :
Pour connaître la valeur de la sélection il faut attacher une variable uniquement sur le premier bouton radio du groupe.
Pour cela il faut lancer « ClassWizard » ,onglet « member variables » ,sélectionner dans la liste l'id du bouton radio ici IDC_RADIOTVA
Cliquer sur le bouton « Add Variable » spécifier le nom de la variable de type « int »
Exemple « m_nRegimeTVA ».
Et valider le choix par le bouton « Ok »
« ClassWizard » génère automatiquement :
- Le code de déclaration dans la classe.
- Initialise la valeur dans le constructeur - 1.
- Place le code d'échange des informations entre la variable et le contrôle dans la fonction membre de la classe dialogue : DoDataExchange(CDataExchange* pDX).
3)étape :
Pour donner une valeur de départ à l'affichage de la fenêtre il suffira d'initialiser la variable dans la fonction InitDialog pour une boite de dialogue modale (CDialog) et OnInitialUpdate pour une classe CFormView :
Ceci sélectionnera le deuxième radio de la liste,l'indexation commençant à zéro et finissant au nombre de bouton radio du groupe ? 1 dans mon exemple : 3.
La valeur à « -1 » voulant dire aucune valeur sélectionnée.
Pour signifier sa valeur au contrôle on utilisera la fonction
pour la mise à jour du contrôle et
Pour récupérer la valeur dans la variable.
Autre cas: si la variable ne suffit pas et que l'on désire par exemple récupérer le label du radio sélectionné on peut procéder comme suit.
Toujours par rapport à mon exemple :
CString CMyDialog:: GetRadioLabelForValue (UINT nId,int & rnValue)
{
CWnd * pRadio= NULL ;
UpdateData (TRUE);
if (rnValue >= 0 )
{
pRadio= GetDlgItem (nId);
for (int n= 0 ;pRadio & & n< rnValue;n+ + )
pRadio= pRadio- > GetWindow (GW_HWNDNEXT);
}
CString str;
if (pRadio) pRadio- > GetWindowText (str);
return str;
}
CString str= GetRadioLabelForValue (IDC_RADIOTVA , m_nRegimeTVA);
|
|
| auteur : Farscape | Exemple je traite le message OnKeyUp dans une fenêtre
et je veux savoir si la touche contrôle ou majuscule est enfoncée :
# define IsShiftDown ( ) ( ( GetKeyState ( VK_SHIFT ) & ( 1 < < ( sizeof ( SHORT ) * 8 - 1 ) ) ) ! = 0 )
# define IsCtrlDown ( ) ( ( GetKeyState ( VK_CONTROL ) & ( 1 < < ( sizeof ( SHORT ) * 8 - 1 ) ) ) ! = 0 )
# define IsAltDown ( ) ( ( GetKeyState ( VK_LMENU ) & ( 1 < < ( sizeof ( SHORT ) * 8 - 1 ) ) ) ! = 0 )
void CMyEdit:: OnKeyUp (UINT nChar,
UINT nRepCnt, UINT nFlags)
{
if (IsCtrlDown ())
{
switch (nChar)
{
case VK_INSERT:
case ' c ' :
case ' C ' :Copy ();
return ;
case ' z ' :
case ' Z ' :Undo ();
return ;
case ' x ' :
case ' X ' :Cut ();
return ;
}
}
if (IsShiftDown ())
{
if (nChar= = VK_INSERT)
{
Paste ();
return ;
}
}
CEdit:: OnKeyUp (nChar, nRepCnt, nFlags);
}
void CMyEdit:: OnSysKeyDown (UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (IsAltDown ())
{
TRACE (" \nAlt " );
}
CEdit:: OnSysKeyDown (nChar, nRepCnt, nFlags);
}
|
|
| auteur : Farscape | Exemple :
Je voudrais avoir un message m'indiquant que l'on a relâché le bouton gauche sur un CButton et avoir ce genre de message directement au niveau de la fenêtre de traitement.
Pour réaliser cette opération nous disposons du message WM_NOTIFY, permettant à un contrôle de communiquer avec son parent.
Méthode:
Avec l'aide de ClassWizard:
On générera une classe dérivée de la classe CButton.
Ensuite on interceptera le message WM_LBUTTONUP.
Enfin on enverra le message WM_NOTIFY au parent comme suit :
# define BN_LBUTTONUP 1 / / evenement custom LBUTTONUP
CMyButton:: CMyButton (){ }
CMyButton:: ~ CMyButton (){ }
BEGIN_MESSAGE_MAP (CMyButton, CButton)
ON_WM_LBUTTONUP ()
END_MESSAGE_MAP ()
void CMyButton:: OnLButtonUp (UINT nFlags, CPoint point)
{
NMHDR hdr;
hdr.hwndFrom = GetSafeHwnd ();
hdr.idFrom = GetDlgCtrlID ();
hdr.code = BN_LBUTTONUP;
GetParent ()- > SendMessage (WM_NOTIFY, GetDlgCtrlID (), (LPARAM)& hdr);
CButton:: OnLButtonUp (nFlags, point);
}
BEGIN_MESSAGE_MAP (CSdisamplesView, CFormView)
ON_BN_CLICKED (IDC_BUTTON1, OnButton1)
ON_NOTIFY (BN_LBUTTONUP,IDC_BUTTON1,OnButtonUp)
END_MESSAGE_MAP ()
void CSdisamplesView:: OnButtonUp (NMHDR* pNMHDR, LRESULT* pResult)
{
TRACE (" \nId:%u mess:%d " ,pNMHDR- > idFrom,pNMHDR- > code);
}
|
La macro ON_NOTIFY est à rajouter manuellement dans BEGIN_MESSAGE_MAP.
Ainsi que la fonction en réponse au message OnButtonUp(NMHDR* pNMHDR, LRESULT* pResult)
Note :L'exemple ci-dessus utilise directement la structure NMHDR pour support du message, il est tout à fait possible de construire votre structure personnelle comme suit:
struct TREE_NOTIFY Notify;
Notify.hdr.hwndFrom = GetSafeHwnd ();
Notify.hdr.idFrom = GetDlgCtrlID ();
Notify.hdr.code = TREE_INSERTITEM;
Notify.hItem= hNewItem;
GetParent ()- > SendMessage (WM_NOTIFY, GetDlgCtrlID (), (LPARAM)& Notify);
|
|
| auteur : Farscape | La technique :
On récupère les coordonnées du contrôle avec la fonction membre GetWindowRect.
Les coordonnées sont données en rapport à l'écran.
Pour déplacer un contrôle dans sa fenêtre on utilisera la fonction MoveWindow ou SetWindowPos, mais les coordonnées doivent être fournis en rapport à la fenêtre de placement (la view ou la dialogue) .
On utilisera pour la conversion la fonction ScreenToClient à partir de la fenêtre parent :
C'est-à-dire on demande de convertir des coordonnées écrans en coordonnées en rapport avec l'objet qui appel ScreenToClient .
Ensuite on applique la fonction de déplacement.
Note : dans le cas où on veut changer la taille on utilisera de préférence SetWindowPos à MoveWindow.
Dans l'exemple en dessus j'ai mis this->ScreenToClient pour bien montrer que c'est l'objet sur lequel on se trouve qui sert de référence pour la conversion.
CRect Rect;
MyStatic.GetWindowRect (& Rect);
this - > ScreenToClient (& Rect);
Rect.InflateRect (Rect.Width (),Rect.Height ());
MyStatic.SetWindowPos ( NULL ,0 ,0 ,Rect.Width (),Rect.Height (),SWP_NOMOVE | SWP_NOZORDER);
MyStatic.MoveWindow (& Rect) ;
|
|
| auteur : Farscape | Il n'existe pas de mécanismes standard de gestion des positions (layout) sur les contrôles.
La classe Template suivante se propose de remédier à ce problème.
# if ! defined ( AFX_TPLLAYOUT_H__59DC7C67_79D6_4082_A38B_4CD17E8257C1__INCLUDED_ )
# define AFX_TPLLAYOUT_H__59DC7C67_79D6_4082_A38B_4CD17E8257C1__INCLUDED_
# if _MSC_VER > 1000
# pragma once
# endif / / _MSC_VER > 1000
# include <algorithm>
# include <vector>
# ifndef OBM_SIZE
# define OBM_SIZE 32766
# endif
template < class GENERIC_LAYOUT>
class CTplLayout : public GENERIC_LAYOUT
{
public :
CTplLayout ( UINT nIDTemplate ):GENERIC_LAYOUT (nIDTemplate)
{
Init ();
}
CTplLayout ()
{
Init ();
}
void Init ()
{
m_bModeReSizing= false ;
m_xAllow= sizeResize;
m_yAllow= sizeResize;
m_bInited= false ;
}
public :
CSize GetSizeDialog (UINT id);
void SetModeResizeCtrl (bool bEnable= true ){ m_bModeReSizing= bEnable;}
boolm_bModeReSizing;
enum eSizeType
{
sizeNone,
sizeResize,
sizeRepos,
sizeRelative
} ;
protected :
class CItem
{
public :
UINT m_resID;
UINT m_resIDChain;
eSizeType m_xSize;
eSizeType m_ySize;
CRect m_rcControl;
CRect m_rcInitial;
CRect m_rcInitialChain;
bool m_bFlickerFree;
double m_xRatio;
double m_yRatio;
double m_xPercen;
double m_yPercen;
bool m_bPercen;
CSize m_Space;
protected :
void Assign (const CItem& src)
{
m_rcControl= src.m_rcControl;
m_rcInitial= src.m_rcControl;
m_rcInitialChain= src.m_rcInitialChain;
m_resID= src.m_resID;
m_resIDChain= src.m_resIDChain;
m_xSize= src.m_xSize;
m_ySize= src.m_ySize;
m_bFlickerFree= src.m_bFlickerFree;
m_xRatio= src.m_xRatio;
m_yRatio= src.m_yRatio;
m_bPercen= src.m_bPercen;
m_xPercen= src.m_xPercen;
m_yPercen= src.m_yPercen;
m_Space = src.m_Space;
}
public :
CItem (){ m_bPercen= false ;}
CItem (const CItem& src){ Assign (src);}
void OnSize (HDWP hdwp,
const CRect& rcParentOld,
const CRect& rcParentNew,CWnd * pDlg)
{
CSize diff;
CRect rcControl;
CWnd * pWnd;
int newpos,newsize;
double x;
bool bx= false ,by= false ;
pWnd= pDlg- > GetDlgItem (m_resID);
diff.cx= rcParentNew.Width ()- rcParentOld.Width ();
diff.cy= rcParentNew.Height ()- rcParentOld.Height ();
rcControl= m_rcControl;
switch (m_xSize)
{
case sizeResize:
if (m_resIDChain)
{
diff.cx/ = 2 ;
bx= true ;
}
rcControl.right+ = diff.cx;
if (m_bPercen)
{
x= m_rcInitial.Width ()+ (m_rcInitial.Width ()* (m_xPercen/ 100 .));
if (static_cast < double > (rcControl.Width ())> x)
rcControl.right= rcControl.left+ static_cast < long > (x);
if (rcControl.Width ()< m_rcInitial.Width ())
rcControl.right= m_rcInitial.right;
}
break ;
case sizeRepos:
rcControl.left+ = diff.cx;
rcControl.right+ = diff.cx;
break ;
case sizeRelative:
newpos= static_cast < int > ((m_xRatio* (double )rcParentNew.Width ())/ (1 .0 + m_xRatio));
newsize= rcControl.Width ();
rcControl.left= newpos;
rcControl.right= newpos+ newsize;
break ;
}
switch (m_ySize)
{
case sizeResize:
if (m_resIDChain)
{
by= true ;
diff.cy/ = 2 ;
}
rcControl.bottom+ = diff.cy;
if (m_bPercen)
{
x= m_rcInitial.Height ()+ (m_rcInitial.Height ()* (m_yPercen/ 100 .));
if (rcControl.Height ()> static_cast < long > (x))
rcControl.bottom= rcControl.top+ static_cast < long > (x);
if (rcControl.Height ()< m_rcInitial.Height ())
rcControl.bottom= m_rcInitial.bottom;
}
break ;
case sizeRepos:
rcControl.top+ = diff.cy;
rcControl.bottom+ = diff.cy;
break ;
case sizeRelative:
newpos= static_cast < int > ((m_yRatio* (double )rcParentNew.Height ())/ (1 .0 + m_yRatio));
newsize= rcControl.Height ();
rcControl.top= newpos;
rcControl.bottom= newpos+ newsize;
break ;
}
if ((rcControl! = m_rcControl) | | (m_xSize! = m_ySize))
{
if (m_resID<= 2 )
{
pWnd- > MoveWindow (& rcControl);
}
else
DeferWindowPos (hdwp,* pWnd,
NULL ,
rcControl.left,
rcControl.top,
rcControl.Width (),
rcControl.Height (),
SWP_NOZORDER);
m_rcControl= rcControl;
if (m_resIDChain & & (bx | | by))
{
CRect rect;
pWnd= pDlg- > GetDlgItem (m_resIDChain);
pWnd- > GetWindowRect (rect);
pDlg- > ScreenToClient (rect);
if (bx)
{
x= rect.Width ();
rect.left= rcControl.right+ m_Space.cx;
rect.right= rect.left+ static_cast < int > (x)+ diff.cx;
}
if (by)
{
x= rect.Height ();
rect.top= rcControl.bottom+ m_Space.cy;
rect.bottom= rect.top+ static_cast < int > (x)+ diff.cy;
}
DeferWindowPos (hdwp,* pWnd,
NULL ,
rect.left,
rect.top,
rect.Width (),
rect.Height (),
SWP_NOZORDER);
}
}
}
CItem& operator = (const CItem& src)
{
Assign (src);
return * this ;
}
} ;
enum { m_idSizeIcon= 0x4545 } ;
std:: vector< CItem> m_Items;
CRect m_rcDialog;
CPoint m_MinSize;
eSizeType m_xAllow;
eSizeType m_yAllow;
CBitmap m_bmSizeIcon;
CStatic m_wndSizeIcon;
bool m_bInited;
public :
void InitDialog (CRect & Rect,BOOL bSetIcon= TRUE);
void InitDialogBar (UINT uResId);
void SetPercenMaxSize (const UINT resID,double dysize,double dxsize);
void AddChainControl (const UINT resIDSrc,const UINT resIDChain);
void AddControl (const UINT resID,
const eSizeType xsize,
const eSizeType ysize,
const bool bFlickerFree= true );
void AllowSizing (const eSizeType xsize,const eSizeType ysize);
void HideSizeIcon (void );
void _OnSize (UINT nType, int cx, int cy);
BOOL _OnGetMinMaxInfo (MINMAXINFO * lpMMI);
virtual LRESULT DefWindowProc (UINT nMsg, WPARAM wParam, LPARAM lParam)
{
if (nMsg= = WM_SIZE )
{
_OnSize (wParam,LOWORD (lParam),HIWORD (lParam));
}
if (nMsg= = WM_GETMINMAXINFO)
{
_OnGetMinMaxInfo (reinterpret_cast < MINMAXINFO * > (lParam));
}
return GENERIC_LAYOUT:: DefWindowProc ( nMsg, wParam,lParam);
}
} ;
template < class GENERIC_LAYOUT>
void CTplLayout< GENERIC_LAYOUT> :: SetPercenMaxSize (const UINT resID,double dysize,double dxsize)
{
std:: vector< CItem> :: iterator it;
if (m_Items.size ())
{
for (it= m_Items.begin ();it! = m_Items.end ();it+ + )
{
if (it- > m_resID= = resID)
{
it- > m_bPercen= true ;
it- > m_xPercen= dxsize;
it- > m_yPercen= dysize;
return ;
}
}
}
}
template < class GENERIC_LAYOUT>
void CTplLayout< GENERIC_LAYOUT> :: AddChainControl (const UINT resIDSrc,const UINT resIDChain)
{
std:: vector< CItem> :: iterator it;
if (m_Items.size ())
{
for (it= m_Items.begin ();it! = m_Items.end ();it+ + )
{
if (it- > m_resID= = resIDSrc)
{
it- > m_resIDChain= resIDChain;
GetDlgItem (resIDChain)- > GetWindowRect (it- > m_rcInitialChain);
ScreenToClient (it- > m_rcInitialChain);
it- > m_Space.cx= it- > m_rcInitialChain.left- it- > m_rcControl.right;
it- > m_Space.cy= it- > m_rcInitialChain.top- it- > m_rcControl.bottom;
return ;
}
}
}
}
template < class GENERIC_LAYOUT>
CSize CTplLayout< GENERIC_LAYOUT> :: GetSizeDialog (UINT id)
{
int cy= 0 ,cx= 0 ;
LPCTSTR lpszTemplateName;
lpszTemplateName = MAKEINTRESOURCE (id);
LPDLGTEMPLATE lpDialogTemplate = 0 ;
HGLOBAL hDialogTemplate = 0 ;
HINSTANCE hInst = AfxGetResourceHandle ();
if (lpszTemplateName ! = NULL )
{
hInst = AfxFindResourceHandle (lpszTemplateName, RT_DIALOG);
HRSRC hResource = :: FindResource (hInst, lpszTemplateName, RT_DIALOG);
hDialogTemplate = LoadResource (hInst, hResource);
}
if (hDialogTemplate ! = NULL )
lpDialogTemplate = (LPDLGTEMPLATE)LockResource (hDialogTemplate);
if (hDialogTemplate ! = NULL )
{
LOGFONT lf;
CFont Font;
memset (& lf,0 ,sizeof (lf));
lf.lfHeight= - 11 ;
lf.lfWeight= 400 ;
strcpy (lf.lfFaceName," MS Sans Serif " );
Font.CreateFontIndirect ( & lf );
CWnd * pWnd= AfxGetMainWnd ();
CDC* pDC = pWnd- > GetDC ();
CFont* oldFont = pDC- > SelectObject (& Font);
TEXTMETRIC tm;
pDC- > GetTextMetrics ( & tm );
int baseUnitY = tm.tmHeight;
CSize size;
size = pDC- > GetTextExtent (
" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz " , 52 );
int baseUnitX = (size.cx / 26 + 1 ) / 2 ;
pDC- > SelectObject (oldFont);
Font.DeleteObject ();
cy= (lpDialogTemplate- > cy* baseUnitY)/ 8 ;
cx= (lpDialogTemplate- > cx* baseUnitX)/ 4 ;
}
if (lpszTemplateName ! = NULL | | hDialogTemplate ! = NULL )
UnlockResource (hDialogTemplate);
if (lpszTemplateName ! = NULL )
FreeResource (hDialogTemplate);
return CSize (cx,cy);
}
template < class GENERIC_LAYOUT>
void CTplLayout< GENERIC_LAYOUT> :: AddControl (const UINT resID,
const eSizeType xsize,
const eSizeType ysize,
const bool bFlickerFree)
{
CItem item;
CWnd * pWnd= GetDlgItem (resID);
pWnd- > GetWindowRect (item.m_rcControl);
ScreenToClient (item.m_rcControl);
item.m_rcInitial= item.m_rcControl;
item.m_bFlickerFree= bFlickerFree;
item.m_resID= resID;
item.m_resIDChain= 0 ;
item.m_xSize= xsize;
item.m_ySize= ysize;
item.m_bPercen= false ;
item.m_rcInitialChain= CRect (0 ,0 ,0 ,0 );
if (xsize= = sizeRelative)
item.m_xRatio= (double )item.m_rcControl.left/ ((double )m_rcDialog.Width ()- (double )item.m_rcControl.left);
if (ysize= = sizeRelative)
item.m_yRatio= (double )item.m_rcControl.top/ ((double )m_rcDialog.Height ()- (double )item.m_rcControl.top);
m_Items.push_back (item);
}
template < class GENERIC_LAYOUT>
void CTplLayout< GENERIC_LAYOUT> :: AllowSizing (const eSizeType xsize,const eSizeType ysize)
{
m_xAllow= xsize;
m_yAllow= ysize;
}
template < class GENERIC_LAYOUT>
void CTplLayout< GENERIC_LAYOUT> :: HideSizeIcon (void )
{
m_wndSizeIcon.ShowWindow (SW_HIDE);
}
template < class GENERIC_LAYOUT>
void CTplLayout< GENERIC_LAYOUT> :: _OnSize (UINT nType,int cx,int cy)
{
if (! m_bModeReSizing) return ;
CRect rect;
HDWP hdwp;
std:: vector< CItem> :: iterator it;
if (m_Items.size ())
{
if (IsKindOf (RUNTIME_CLASS (CFormView)))
{
if (m_MinSize.x & & m_MinSize.y)
{
if (cx< m_MinSize.x | | cy< m_MinSize.y) return ;
}
}
GetWindowRect (rect);
hdwp= BeginDeferWindowPos (20 );
for (it= m_Items.begin ();it! = m_Items.end ();it+ + )
it- > OnSize (hdwp,m_rcDialog,rect,this );
EndDeferWindowPos (hdwp);
}
m_rcDialog= rect;
}
template < class GENERIC_LAYOUT>
BOOL CTplLayout< GENERIC_LAYOUT> :: _OnGetMinMaxInfo (MINMAXINFO * lpMMI)
{
if (! m_bModeReSizing) return FALSE;
if (m_bInited)
{
lpMMI- > ptMinTrackSize= m_MinSize;
if (m_xAllow= = sizeNone)
lpMMI- > ptMaxTrackSize.x= lpMMI- > ptMaxSize.x= m_MinSize.x;
if (m_yAllow= = sizeNone)
lpMMI- > ptMaxTrackSize.y= lpMMI- > ptMaxSize.y= m_MinSize.y;
return TRUE;
}
return FALSE;
}
template < class GENERIC_LAYOUT>
void CTplLayout< GENERIC_LAYOUT> :: InitDialogBar (UINT uResId)
{
CSize size= GetSizeDialog (uResId);
InitDialog (CRect (0 ,0 ,size.cx,size.cy),FALSE);
}
template < class GENERIC_LAYOUT>
void CTplLayout< GENERIC_LAYOUT> :: InitDialog (CRect & Rect,BOOL bSetIcon)
{
SetModeResizeCtrl ();
CRect rcIcon,rcDialogClient,rcCurrent;
m_rcDialog= Rect;
if (! Rect.left & &
! Rect.top & &
! Rect.bottom & &
! Rect.right)
{
GetWindowRect (m_rcDialog);
Rect= m_rcDialog;
}
GetWindowRect (rcCurrent);
m_MinSize.x= m_rcDialog.Width ();
m_MinSize.y= m_rcDialog.Height ();
if (bSetIcon)
{
m_bmSizeIcon.LoadOEMBitmap (OBM_SIZE);
m_wndSizeIcon.Create (NULL ,
WS_CHILD | WS_VISIBLE | SS_BITMAP,CRect (0 ,0 ,10 ,10 ),
this ,m_idSizeIcon);
m_wndSizeIcon.SetBitmap (m_bmSizeIcon);
GetClientRect (rcDialogClient);
m_wndSizeIcon.GetWindowRect (rcIcon);
ScreenToClient (rcIcon);
m_wndSizeIcon.SetWindowPos (NULL ,rcDialogClient.right- rcIcon.Width (),
rcDialogClient.bottom- rcIcon.Height (),
0 ,0 ,SWP_NOZORDER | SWP_NOSIZE);
AddControl (m_idSizeIcon,sizeRepos,sizeRepos);
}
m_bInited= true ;
if (Rect! = rcCurrent) _OnSize (0 ,rcCurrent.Width (),rcCurrent.Height ());
}
# endif / / ! defined ( AFX_TPLLAYOUT_H__59DC7C67_79D6_4082_A38B_4CD17E8257C1__INCLUDED_ )
|
utilisation avec une CFormView :
# include "TplLayout.hpp"
class CTestMdILayoutView : public CTplLayout< CFormView>
{
....
|
CTestMdILayoutView:: CTestMdILayoutView ()
: CTplLayout< CFormView> (CTestMdILayoutView:: IDD)
{
}
void CTestMdILayoutView:: OnInitialUpdate ()
{
CFormView:: OnInitialUpdate ();
CChildFrame * pChild= static_cast < CChildFrame * > (GetParentFrame ());
if (pChild- > GetInitialRectFrame ().IsRectNull ())
{
ResizeParentToFit ();
}
AddControl (IDC_STATICLIB,eSizeType:: sizeResize,eSizeType:: sizeRepos);
AddControl (IDOK,eSizeType:: sizeRepos,eSizeType:: sizeNone);
AddControl (IDCANCEL,eSizeType:: sizeRepos,eSizeType:: sizeNone);
InitDialog (pChild- > GetInitialRectFrame (),FALSE);
}
|
pour une boîte de Dialogue (CDialog)
Déclaration:
class CAboutDlg : public CTplLayout< CDialog>
{
public :
CAboutDlg ();
|
code:
CAboutDlg:: CAboutDlg () : CTplLayout< CDialog> (CAboutDlg:: IDD)
{
}
BOOL CAboutDlg:: OnInitDialog ()
{
CDialog:: OnInitDialog ();
AddControl (IDOK,eSizeType:: sizeRepos,eSizeType:: sizeNone);
CRect Rect (0 ,0 ,0 ,0 );
InitDialog (Rect,TRUE);
return TRUE;
}
|
Note: le style resizing doit être activé sur la dialogue dans l'éditeur de ressources.
pour une CDialogBar :
la déclaration :
# include "TplLayout.hpp"
class CMyDlgBar : public CTplLayout< CDialogBar>
{
public :
CMyDlgBar ();
void InitDialog ();
|
le code :
CMyDlgBar:: CMyDlgBar (): CTplLayout< CDialogBar> ()
{
}
void CMyDlgBar:: InitDialog ()
{
AddControl (IDC_BUTTON,eSizeType:: sizeRepos,eSizeType:: sizeNone);
AddControl (IDC_STATIC1,eSizeType:: sizeRepos,eSizeType:: sizeNone);
AddControl (IDC_EDIT1,eSizeType:: sizeResize,eSizeType:: sizeNone);
InitDialogBar (IDD_DIALOGBAR);
}
|
Initialisation de la CDialogBar à partir de la view:
void CTestMdILayoutView:: OnInitialUpdate ()
{
CFormView:: OnInitialUpdate ();
CChildFrame * pChild= static_cast < CChildFrame * > (GetParentFrame ());
if (pChild- > GetInitialRectFrame ().IsRectNull ())
{
ResizeParentToFit ();
}
AddControl (IDC_STATICLIB,eSizeType:: sizeResize,eSizeType:: sizeRepos);
AddControl (IDOK,eSizeType:: sizeRepos,eSizeType:: sizeNone);
AddControl (IDCANCEL,eSizeType:: sizeRepos,eSizeType:: sizeNone);
InitDialog (pChild- > GetInitialRectFrame (),FALSE);
pChild- > m_DlgBar.InitDialog ();
}
|
le positionnement est géré sur l'axe des X et Y :
sizeNone : ne fait rien
sizeResize : dimensionnement du contrôle proportionel
sizeRepos : maintient la distance en fonction du point haut /gauche
sizeRelative : distance proportionelle en fonction des côtés
Les Fonctions:
void SetPercenMaxSize(const UINT resID,double dysize,double dxsize):
Permet de spécifier la taille maximum de d'étirement sur la largeur et hauteur du contrôle identifié par resID
void AddChainControl(const UINT resIDSrc,const UINT resIDChain);
Permet de lier au déplacement d'un contrôle resIDSrc un contrôle secondaire resIDChain
L'espace initial entre les deux est maintenu.
void AddControl(const UINT resID,const eSizeType xsize,const eSizeType
ysize,const bool bFlickerFree=true);
Fixe les modalités d'étirements du contrôle sur la largeur et ou hauteur .
void InitDialog(CRect &Rect,BOOL bSetIcon=TRUE);
Initialisation pour une classe CFormView et CDialog.
mettre bSetIcon=FALSE pour une CFormView et TRUE pour une CDialog
permettant d'afficher l'icone d'étirement en bas à droite.
void InitDialogBar(UINT uResId);
Initialisation d'une CDialogBar.
uResId et l'identifiant de la CDialogBar permettant de calculer sa taille initiale de référence
Un exemple complet:
http://farscape.developpez.com/Samples/TestMdiLayout.zip
|
| auteur : Farscape | Il y a deux manières de travailler avec des contrôles placés sur une fenêtre :
La première méthode consiste à récupérer un pointeur sur la fenêtre du contrôle
Exemple :
CListBox * pListBox = static_cast < CListBox * > (GetDlgItem (IDC_LISTBOX)) ;
pListBox- > AddString (" coucou " ) ;
CEdit * pEdit= static_cast < CEdit * > (GetDlgItem (IDC_EDIT)) ;
pEdit- > SetWindowText (" essai " ) ;
|
La deuxième consiste à associer une variable au contrôle, à ce niveau on dispose encore de deux possibilités,
La variable associée peut être le contrôle lui-même un CEdit une CListBox etc, ou une variable pour manipuler le contenu du contrôle exemple :
Dans le cas d'un contrôle CEdit il sera pratique de travailler avec une variable CString pour changer ou récupérer le contenu du CEdit .
Cette association peut se faire directement à partir de l'éditeur de ressources :
Dans l'éditeur de ressources sur le contrôle en question faire clic droit
Avec Visual 6.0 :
Sélectionner l'option ClassWizard ,puis l'onglet member variables et enfin le bouton Add Variable.
Il ne reste plus qu'a renseigner le nom de la variable, indiquer le type de variable : contrôle ou valeur.
Dans le cas de valeur le type de variable CString ,int ,long c'est suivant le type de contrôle .
Avec Visual .net :
Sélectionner l'option ajouter une variable.
L'assistant d'ajout de variables apparaît, il ne reste plus qu'à sélectionner les différentes options : contrôle ou valeur .
Examinons le code généré par Visual :
Une variable est rajoutée dans la classe fenêtre ou est situé le contrôle :
Exemple avec une variable de type CEdit et une variable CString attachée à ce même contrôle :
Dans le .h de la classe :
protected :
protected :
DECLARE_MESSAGE_MAP ()
public :
CEdit m_EditCtrl;
CString m_strForEdit;
} ;
|
dans le code :
CsamplenetView:: CsamplenetView ()
: CFormView (CsamplenetView:: IDD)
, m_strForEdit (_T (" " ))
{
}
|
La variable CString est initialisée dans le constructeur.
void CsamplenetView:: DoDataExchange (CDataExchange* pDX)
{
CFormView:: DoDataExchange (pDX);
DDX_Control (pDX, IDC_EDITTEST, m_EditCtrl);
DDX_Text (pDX, IDC_EDITTEST, m_strForEdit);
}
|
C'est la fonction DodaExchange qui établit le lien entre le contrôle Windows et les variables.
Cette fonction est appelée par la fonction UpdateData et le premier appel initialise les liens notamment pour la variable contrôle (m_EditCtrl) qui va subclasser le contrôle windows.
Voir: Comment mettre à jour les contrôles depuis leurs variables et vice-versa ?
Note : j'insiste ,le contrôle sera graphiquement prêt après le premier UpdateData(FALSE) et pas avant,
celui étant fait par les MFC dans la fonction CFormView::OnInitialUpdate pour une CFormView ou CDialog::OnInitDialog pour une CDialog.
void CFormView:: OnInitialUpdate ()
{
ASSERT_VALID (this );
if (! UpdateData (FALSE))
TRACE (traceAppMsg, 0 , " UpdateData failed during formview initial update.\n " );
CScrollView:: OnInitialUpdate ();
}
BOOL CDialog:: OnInitDialog ()
{
if (! UpdateData (FALSE))
{
TRACE (traceAppMsg, 0 , " Warning: UpdateData failed during dialog init.\n " );
EndDialog (- 1 );
return FALSE;
}
}
|
Conséquences :
Toutes tentatives d'utilisations d'un contrôle avant l'exécution de ces fonctions se solderont par une assertion d'erreur.
Exemple : faire m_EditCtrl.SetWindowText("coucou") ; dans le constructeur.
Liste des erreurs communes en relation avec la fonction DodataExchange :
Utiliser une variable dont le lien n'existe pas dans la fonction provoquera l'erreur.
ASSERT ( IsWindow (m_hWnd) );
|
Signifiant que le handle de fenêtre n'est pas initialisé.
Changer par mégarde l'identifiant d'un contrôle sans faire de même dans la fonction provoquera aussi une erreur.
Supprimer un contrôle dans les ressources et garder le lien dans la fonction provoquera aussi une erreur.
Une fois ces initialisations faites on peut utiliser les deux formes de mise à jour et récupération de valeurs dans un contrôle .
Récupération d'une valeur sur un CEdit :
Directement avec la fonction GetWindowText .
CString str ;
m_EditCtrl.GetWindowText (str) ;
GetDlgItem (IDC_EDITTEST)- > GetWindowText (str) ;
|
Par la variable :
Affectation d'une valeur à un CEdit :
Directement avec la fonction SetWindowText :
CString str = " coucou " ;
m_EditCtrl.SetWindowText (str) ;
GetDlgItem (IDC_EDITTEST)- > SetWindowText (str) ;
|
Par la variable :
m_strForEdit= " coucou " ;
UpdateData (FALSE) ;
|
|
| auteur : matazz | J'ai vérifié pour les classes suivantes CListCtrl, CListBox, CTreeCtrl, et CComboBox, et cette astuce marche.
Il se peut qu'il y ait d'autres contrôles qui le gèrent, à voir...
En fait lors de la construction de la Liste (ou du Tree, ou du Combo), il est possible d'associer l'adresse d'un pointeur d'un objet personnalisé à chaque Item ajouté.
Soit par exemple une de vos classes ClsMyData, avec des variables et des méthodes, un pointeur de cette classe sera stocké sur 32 bits soit un DWORD.
Il suffit de créer une nouvelle instance de votre classe et de la stocker dans le Contrôle grâce à la méthode SetItemData
ClsMyData * MyObj = new ClsMyData ();
...
CTreeControl:: SetItemData (HTREEITEM hItem, DWORD dwItemData );
CListBox:: SetItemData (int nIndex, DWORD dwItemData );
CListCtrl:: SetItemData ( int nItem, DWORD dwData );
CComboBox:: SetItemData ( int nIndex, DWORD dwItemData );
|
Ensuite sur les évènement de clic (CTreeCtrl) ou de sélection (List et Combo) vous pouvez récupérer l'objet de votre classe tout simplement en utilisant GetItemData(...) :
ClsMyData * MyObj = (ClsMyData * )MyList.GetItemData (MyList.GetCurSel ());
MyObj- > AfficheCaractéristiques ();
....
ClsMyData * MyObj = (ClsMyData * )MyTree.GetItemData (MyTree.GetSelectedItem ( ));
MyObj- > AfficheCaractéristiques ();
....
|
|
| auteur : Farscape | L'idée de base est d'utiliser le composant graphique groupbox pour définir l'ensemble des composants à grouper.
Ensuite ce composant par l'intermédiaire d'une classe spécialisée permettrait des manipulations sur l'ensemble des composants inclus dans sa surface.
Exemple d'implémentation:
l'include :
# if ! defined ( AFX_GROUP_H__AD9C45E9_1C19_44A4_B708_698ED49E178B__INCLUDED_ )
# define AFX_GROUP_H__AD9C45E9_1C19_44A4_B708_698ED49E178B__INCLUDED_
# if _MSC_VER > 1000
# pragma once
# endif / / _MSC_VER > 1000
class CGroup : public CButton
{
public :
CGroup ();
public :
public :
boolShowGroup (int nCmdShow= SW_SHOW);
boolEnableGroup (BOOL bEnable= TRUE);
boolIsHide ();
boolIsEnable ();
public :
virtual ~ CGroup ();
protected :
DECLARE_MESSAGE_MAP ()
private :
boolGetCtrlOnGroup ();
private :
CArray< int ,int > m_arIdCtrl;
CArray< CRect,CRect> m_arRectCtrl;
} ;
# endif / / ! defined ( AFX_GROUP_H__AD9C45E9_1C19_44A4_B708_698ED49E178B__INCLUDED_ )
|
le .cpp
# ifdef _DEBUG
# define new DEBUG_NEW
# undef THIS_FILE
static char THIS_FILE[] = __FILE__;
# endif
CGroup:: CGroup ()
{
}
CGroup:: ~ CGroup ()
{
}
bool CGroup:: ShowGroup (int nCmdShow)
{
if (! GetCtrlOnGroup ()) return false ;
CWnd * pDialog= GetParent ();
for (int i= 0 ;i< m_arIdCtrl.GetSize ();i+ + ) pDialog- > GetDlgItem (m_arIdCtrl[i])- > ShowWindow (nCmdShow);
return true ;
}
bool CGroup:: EnableGroup (BOOL bEnable)
{
if (! GetCtrlOnGroup ()) return false ;
CWnd * pDialog= GetParent ();
for (int i= 0 ;i< m_arIdCtrl.GetSize ();i+ + ) pDialog- > GetDlgItem (m_arIdCtrl[i])- > EnableWindow (bEnable);
return true ;
}
bool CGroup:: GetCtrlOnGroup ()
{
ASSERT (m_hWnd);
if (m_arIdCtrl.GetSize ()) return true ;
CWnd * pDialog= GetParent ();
CRect rectGrp;
GetWindowRect (& rectGrp);
CWnd * pCtrl= pDialog- > GetNextDlgTabItem (this );
CRect rectCtrl,rectUnion;
if (! pCtrl) return false ;
do
{
pCtrl- > GetWindowRect (& rectCtrl);
if (rectGrp.PtInRect (CPoint (rectCtrl.left,rectCtrl.top)) & &
rectGrp.PtInRect (CPoint (rectCtrl.right,rectCtrl.top)) & &
rectGrp.PtInRect (CPoint (rectCtrl.left,rectCtrl.bottom)) & &
rectGrp.PtInRect (CPoint (rectCtrl.right,rectCtrl.bottom)))
{
m_arIdCtrl.Add (pCtrl- > GetDlgCtrlID ());
m_arRectCtrl.Add (rectCtrl);
}
else break ;
pCtrl= pDialog- > GetNextDlgTabItem (pCtrl);
}
while (pCtrl );
return (m_arIdCtrl.GetSize ()> 0 );
}
bool CGroup:: IsHide ()
{
if (! GetCtrlOnGroup ()) return false ;
int nct= 0 ;
CWnd * pDialog= GetParent ();
for (int i= 0 ;i< m_arIdCtrl.GetSize ();i+ + )
nct+ = ! (pDialog- > GetDlgItem (m_arIdCtrl[i])- > IsWindowVisible ());
return (nct= = m_arIdCtrl.GetSize ());
}
bool CGroup:: IsEnable ()
{
if (! GetCtrlOnGroup ()) return false ;
int nct= 0 ;
CWnd * pDialog= GetParent ();
for (int i= 0 ;i< m_arIdCtrl.GetSize ();i+ + )
nct+ = pDialog- > GetDlgItem (m_arIdCtrl[i])- > IsWindowEnabled ();
return (nct= = m_arIdCtrl.GetSize ());
}
BEGIN_MESSAGE_MAP (CGroup, CButton)
END_MESSAGE_MAP ()
|
l'utilisation dans une CFormView:
void CSampleSDIView:: OnButton1 ()
{
m_group.EnableGroup (! m_group.IsEnable ());
}
|
Il suffit de mettre un groupbox dans la ressource, d'enlever la propriété visible et de déclarer une variable contrôle dessus en choisissant la classe CGroup.
Attention aux conditions pour qu'un contrôle fasse partie d'un groupe :
Le premier contrôle possède le style group et tab stop.
L'ordre des tab stop doit être réglé au niveau des ressources (tab order).
A adapter selon vos besoins..
|
| auteur : Farscape | En utilisant la fonction SetWindowPos qui permet de spécifier l'ordre des fenêtres (Z order)
Le contrôle dynamique devra néanmoins disposer du style WS_TAB.
Exemple avec un CEdit:
CEdit* pEdit = new CEdit;
pEdit- > Create (ES_MULTILINE | WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER,
CRect (10 , 10 , 100 , 100 ), this , 1 );
pEdit- > SetWindowPos (pWndAfter,0 ,0 ,0 ,0 ,SWP_NOMOVE | SWP_NOSIZE);
|
pWndAfter représente la fenêtre d'insertion dans l'ordre des fenêtres.
On dispose d'autres modes voir MSDN, parmi les plus utiles:
wndBottom: Place la fenêtre en bas du Z-order
wndTop: Place la fenêtre au sommet du Z-order.
|
| auteur : Farscape | Lors de la création dynamique d'un contrôle disposant du style WS_TABSTOP, il devient nécessaire de spécifier son placement dans l'ordre de tabulation (tab order) de la fenêtre.
On Utilisera la méthode SetWindowPos comme suit :
CWnd * pWndAfter= GetNextDlgTabItem (NULL );
pWndDynCtrl- > SetWindowPos (pWndAfter,0 ,0 ,0 ,0 ,SWP_NOMOVE | SWP_NOSIZE);
|
dans mon exemple pWndDynCtrl sera placé dans l'ordre de tabulation aprés pWndAfter, qui est ici le premier contrôle dans l'ordre de tabulation.
|
| auteur : Farscape | Parmi les nouveaux contrôles ajoutés aux MFC on trouve le "Command bouton control"
L'éditeur de ressources de Visual 2008 permet l'ajout de ce composant directement dans la form .
En fait un "command button control" est un bouton avec le style BS_COMMANDLINK ou BS_DEFCOMMANDLINK.
L'association du contrôle à une variable contrôle sera donc du type CButton qui est la classe MFC de base pour gérer les boutons.
Comment procéder :
On spécifie le libellé du bouton dans l'éditeur de ressources ou par un classique SetWindowText dans le code.
Une nouvelle méthode SetNote permet de définir le libellé de description.
Enfin la méthode SetShield permet de changer l'icône pour celle du bouclier utilisée par Vista pour l'elévation des droits.
CString str= _T (" ceci est un commentaire\nsur deux lignes " );
m_Btn.SetNote (str);
m_BtnAcces.SetShield (TRUE);
|
l'exemple en image:
|
| auteur : Farscape | Dans la Faq on trouve un post permettant d'implémenter un message privé Comment implémenter un message supplémentaire à partir d'un contrôle ?
sur un contrôle à destination du parent.
Un message ON_CONTROL appelle une fonction dans la classe parent sans argument particulier
Pour illustrer le sujet je vais rajouter une notification double clic sur un contrôle Edit.
On commencera par créer avec l'assistant une classe héritée de CEdit , puis on implémentera le message à intercepter et à relayer à la fenêtre parent.
# define EDIT_LBUTTONDBLCLK 1 / / evenement custom
void CTestEdit:: OnLButtonDblClk (UINT nFlags, CPoint point)
{
GetParent ()- > SendMessage (WM_COMMAND,MAKEWPARAM ( GetDlgCtrlID (), EDIT_LBUTTONDBLCLK),(LPARAM)GetSafeHwnd ());
CEdit:: OnLButtonDblClk (nFlags, point);
}
|
L'utilisation dans la classe parent :
BEGIN_MESSAGE_MAP (CTESTONCONTROLDlg, CDialog)
ON_WM_SYSCOMMAND ()
ON_WM_PAINT ()
ON_WM_QUERYDRAGICON ()
ON_CONTROL (EDIT_LBUTTONDBLCLK,IDC_EDITTEST,OnDblClickEdit)
END_MESSAGE_MAP ()
void CTESTONCONTROLDlg:: OnDblClickEdit ()
{
AfxMessageBox (" coucou " );
}
|
|
lien : Comment implémenter un message supplémentaire à partir d'un contrôle ?
|
| auteur : Farscape | Après lecture de l'aide sur MSDN on pourrait penser que le style TBS_DOWNISLEFT puisse faire l'affaire, il n'en est rien.
Le moyen le plus simple à ce jour est de faire un appel spécifique à la méthode SetPos comme suit.
MySlider.SetPos (MySlider.GetRangeMax ()- x);
|
Où X représente la valeur initiale du déplacement souhaité.
|
Consultez les autres F.A.Q.
|
|