ATOUTFOX
COMMUNAUTÉ FRANCOPHONE DES PROFESSIONNELS FOXPRO
Visual FoxPro : le développement durable

GetDC versus GetWindowDC + Browser2.app corrigé   



L'auteur

Robert Plagnard
France France
Membre Simple
# 0000000031
enregistré le 15/10/2004

http://www.ingelog.fr
PLAGNARD Robert
75015 PARIS
de la société IngéLog
Fiche personnelle


Note des membres
pas de note

Contributions > 05 - API et appels systèmes

GetDC versus GetWindowDC + Browser2.app corrigé
# 0000000429
ajouté le 17/03/2007 12:24:43 et modifié le 17/03/2007
consulté 9823 fois
Niveau expert

Version(s) Foxpro :
VFP 9.0
VFP 8.0
VFP 7.0


Télécharger le ZIP (850.19 Ko)
Description
De quelles fenêtres parle t-on

De quelles fenêtres parle t-on ?

ou

Corrections et synthèse des articles antérieurs

Correction

Dans l’un de mes derniers articles « Dessiner un rectangle de sélection » Gregory Adams m’a fait remarquer que j’avais oublié de libérer le contexte de périphérique. C’est une faute grave que j’ai corrigée depuis. Mais cette faute je l’avais reproduite dans « Définir une sélection avec un rectangle de sélection », dans un « Un séparateur sympathique » et même dans la nouvelle version proposée du browser. J’ai modifié mes articles en conséquence, mais certains garderons peut-être ce bug. C’est la première raison qui me fait publier à nouveau ces différents codes. Mais il y a une raison plus profonde.

GetDC versus GetWindowDC

La deuxième raison concerne le commentaire de Frédéric Steczycki qui m’a fait remarquer que GetDC était beaucoup plus simple à utiliser que GetWindowDC surtout quand il s’agit de dessiner dans la partie cliente de la fenêtre. Ma première réaction a été « Mais c’est bien sur ! Pourquoi n’y ai-je pas pensé plus tôt ? ».

Sur ce, je modifie mon premier code « Dessiner un rectangle de sélection », je remplace les GetWindowDC par des GetDC plus simple. Ca marche, c’est impeccable.

Je passe au deuxième programme « Définir une sélection avec un rectangle de sélection », c’est impeccable. Et puis c’est beaucoup plus élégant.

J’arrive au troisième programme « Un séparateur sympathique ». Là, c’est pas sympa du tout car ça ne marche plus. Le rectangle de sélection ne se dessine pas. Je compare mon ancien code au nouveau, la seule chose importante qui change, c’est GetDC à la place de GetWindowDC. J’y passe finalement une bonne partie d’un WE pour m’apercevoir que j’avais, dans cet exemple, une fenêtre top-level (contrairement aux deux premiers exemples). Je constate alors qu’en mettant ShowWindow = 0 dans la définition de la form ça marche, alors qu’avec ShowWindow=2 (top-level) ça ne marche pas. Bon ! je me dis que si je ne dessine rien c’est que probablement je ne suis pas dans le bon contexte de périphérique. Je me penche sur la doc (et oui…) et je tombe sur 3 fonctions sys que je ne connaissais pas :

SYS(2325) Returns the hWnd of a client window from the parent window's WHANDLE.

SYS(2326) Returns a Visual FoxPro WHANDLE from a window’s hWnd.

SYS(2327) Returns a window's hWnd from a Visual FoxPro window’s WHANDLE.

(Je fais remarquer au passage que la doc pour 2325 est fausse. Cette fonction retourne une WHANDLE et non pas une hWnd).

 

En fait on a le schéma suivant :

 

Form frm

 

Windows handle

 

VFP window handle

Window’s Form

 

hw = frm.HWnd

==>

hf = sys( 2326, m.hw )

Client window

(Same window if standard different if top level)

Top-level

hwc=sys(2327,m.hfc)

<==

hfc = sys( 2325, m.hf ) et

hfc <> hf

Standard

<==

hfc = sys( 2325, m.hf ) et hfc==hf

 

Donc à la place de :

(1) hDC = GetDC( thisform.HWnd )

J’essaye :

(2) hDC = GetDC( Sys(2327,Sys( 2325, Sys(2326, thisform.HWnd))))

Fantastique! Ca marche.

C’est clair, il faut passer par les handles VFP pour atteindre la fenêtre cliente dans le cas des top-level. Mais quand on est en fenêtre normale, (1) et (2) donnent le même résultat. Donc, en prenant la formule (2) ça marche dans tous les cas. Je suis super content, mes trois premiers programmes marchent maintenant sur le même principe.

Je m’attaque alors au browser, je passe à GetDC, avec la formule (2). Et là encore, grosse déception, ça ne marche pas on ne voit plus le splitter. La principale différence maintenant, est qu’on a des objets descendants de OleControl.

Je refais donc profil bas, et je reprends mon tout premier programme tout simple en ajoutant un OleControl au milieu de la fenêtre. Et bien je constate qu’on n’arrive pas à dessiner au dessus des OleControls.

Moralité : pour dessiner un splitter au dessus de tout il faut absolument dessiner dans la fenêtre principale de la form en prenant le contexte de périphérique de la form avec GetWindowDC et non pas avec GetDC.

J’ai finalement découvert cela par erreur. Tient ! Cela me rappelle quelque chose.

 

 

 

Code source :
*/* FocusRect1.prg
*   Using DrawFocusRect API function
*   Using GetDC shows that we do not draw over OleControls
*   but GetWindowsDC allows it.
*   Run this prg
*   Robert Plagnard feb 25, 2007

#define SM_CYCAPTION            4
#define SM_CXSIZEFRAME         32
#define SM_CYSIZEFRAME         33
#define SM_CYMENU              15

   declare integer DrawFocusRect    in win32api integerstring @
   declare integer GetDC            in win32api integer
   declare integer GetWindowDC      in win32api integer
   declare integer ReleaseDC        in win32api integerinteger

   public gf1, gf2
   gf1 = CreateObject"CForm".F..F. )
   gf1.Caption = 'Click on form (use GetDC)'
   gf1.Move( 50, 120)
   gf1.Show

   gf2 = CreateObject"CForm".F..T. )
   gf2.Caption = 'Click on form (use GetWindowDC)'
   gf2.Move( 500, 120)
   gf2.Show

define class CForm as Form
   showwindow = 2
   lGetWindowDC = .F.
   active = .F.

   hidden nXClientOrigin   && X Origin of client zone in window
   hidden nYClientOrigin   && Y Origin of client zone in window

   add object bsr as "CBrowser" with ;
      left = 100, top = 100, width = 100, height = 100

   procedure Init( lMenu, lGetWindowDC )
      this.lGetWindowDC = m.lGetWindowDC
      if m.lGetWindowDC then
         this.nXClientOrigin = GetSystemMetrics( SM_CXSIZEFRAME )   && API calls
         this.nYClientOrigin = GetSystemMetrics( SM_CYSIZEFRAME )+;
                               GetSystemMetrics( SM_CYCAPTION   )
         if m.lMenu
            this.nYClientOrigin = this.nYClientOrigin + GetSystemMetrics( SM_CYMENU )
         endif
      else
         this.nXClientOrigin = 0
         this.nYClientOrigin = 0
      endif
   endproc

   procedure MouseDown( nButton, nShift, nXCoord, nYCoord )
      local R      && Rectangle
      local hDC    && handle of device context
      local hWnd2
      if thisform.Active then
         R = Rect( m.nXCoord + this.nXClientOrigin  ,;
                   m.nYCoord + this.nYClientOrigin  ,;
                   m.nXCoord + this.nXClientOrigin + 30 + Int( 150*rand() ),;
                   m.nYCoord + this.nYClientOrigin + 20 + Int(  80*rand() ) )
         if thisform.lGetWindowDC then
            hWnd2 = thisform.HWnd
            hDC = GetWindowDC( m.hWnd2 )
         else
            hWnd2 = hWndClient( thisform.HWnd )
            hDC = GetDC( m.hWnd2 )
         endif
         DrawFocusRect(m.hDC,@R)
         ReleaseDC( m.hWnd2, m.hDC )
      endif
   endproc

   procedure activate
      this.Active = .T.
   endproc

   procedure deactivate
      this.Active = .F.
   endproc

enddefine

function hWndTohVfp( hWnd as Integer ) as Integer
   return Sys( 2326, m.hWnd )
endfunc

function hVfpClient( hVfp as Integer ) as Integer
   return Sys( 2325, m.hVfp )
endfunc

function hVfpTohWnd( hVfp as Integer ) as Integer
   return Sys( 2327 , m.hVfp )
endfunc

function hWndClient( hWnd as Integer ) as Integer
   return hVfpTohWnd( hVfpClient( hWndTohVfp( m.hWnd )))
endfunc

function Rectlefttoprightbottom ) as String
   return BinToC(m.left,'4RS')+BinToC(m.top'4RS')+BinToC(m.right'4RS')+BinToC(m.bottom'4RS')
endfunc

*/=========================================================================
define class CBrowser as olecontrol
   oleclass = "Shell.Explorer.2"
   height   = 100
   width    = 100
   name     = "CBrowser"
enddefine

Commentaires
le 17/03/2007, Gregory Adam a écrit :
C'est bien Robert.
Une toute, toute petite remarque ...

Je vois qui tu m'a fait cadeau de la lettre S en ecrivant mon nom. (AdamS)
Ce n'est pas grave, cela arrive

Et quand cela arrive, je la prefere en postfix - comme tu as fait, plutot qu'en prefix ;)

le 20/03/2007, laurent.dellacherie2 a écrit :
Robert,

J'ai essayé ton code mais il s'arrete sur :
this.nXClientOrigin = GetSystemMetrics( SM_CXSIZEFRAME ) && API calls

car la fonction n'est pas défini, est-ce une fonction perso ou un appel à api non déclaré?

le 22/03/2007, Gregory Adam a écrit :
Laurent,

Essaye: declare integer GetSystemMetrics in user32.dll integer nIndex


Publicité

Les pubs en cours :

www.atoutfox.org - Site de la Communauté Francophone des Professionnels FoxPro - v3.4.0 - © 2004-2024.
Cette page est générée par un composant COM+ développé en Visual FoxPro 9.0-SP2-HF3