Problema con Button y Setfocus()

Problema con Button y Setfocus()

Postby triumvirato » Thu Aug 19, 2010 7:09 am

El comportamiento de un boton es distinto cuando lo pulsas con ratón que cuando lo pulsas con la tecla Enter. El comportamiento que ha de hacer en ambos casos, incluye un SetFocus() en su cláusula ACTION que sí se respeta cuando pulsas con ratón sobre el boton, y se lo salta cuando oprimes sobre el la tecla Enter, pero si obedece en ambos casos al resto de cláusulas.
Un ejemplo a ver si me sabe alguien ayudar, Gracias.

Code: Select all  Expand view

#include "Fivewin.ch"


function Main()

   local oDlg_GenAut, oBtnAnade, oBrowPed,;
         aValues := { { "One", "Two", "Three" }, { "Four", "Five", "Six" } },;
         oGetCodArt, oGetUdsPed, cCod := Space( 14 ), nCan := 0, nRGBColor := nRGB( 0,255,255 )
         
   SetGetColorFocus( nRGBColor )

   DEFINE DIALOG oDlg_GenAut RESOURCE "DLG_GENAUT"

   REDEFINE BUTTON oBtnAnade ID 4050 OF oDlg_GenAut UPDATE ACTION ( oGetCodArt:Enable(), oGetUdsPed:Enable(), oGetCodArt:SetFocus() )
   
   REDEFINE LISTBOX oBrowPed;
      FIELDS aValues[ oBrowPed:nAt, 1 ], aValues[ oBrowPed:nAt, 2 ], aValues[ oBrowPed:nAt, 3 ];
       ID 90 OF oDlg_GenAut UPDATE
      oBrowPed:SetArray( aValues )    
     
   REDEFINE GET oGetCodArt VAR cCod ID 100 OF oDlg_GenAut PICTURE '@!S12' UPDATE;
            VALID ( MsgInfo( "Ejecutando Valid" ), .t. )

   REDEFINE GET oGetUdsPed VAR nCan ID 140 OF oDlg_GenAut PICTURE '@EZ 999,999' UPDATE;
            VALID ( oGetCodArt:Disable(), oGetUdsPed:Disable(), oBrowPed:Refresh(), .t. )

   ACTIVATE DIALOG oDlg_GenAut CENTERED ON INIT ( oGetCodArt:Disable(), oGetUdsPed:Disable() )

   DbCloseAll()

return nil


Fichero RC:

Code: Select all  Expand view

#include <windows.h>
#include <commctrl.h>
#include <richedit.h>

LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US

DLG_GENAUT DIALOG DISCARDABLE 65, 47, 231, 193
STYLE WS_POPUP|DS_MODALFRAME|WS_CAPTION|WS_SYSMENU|WS_VISIBLE
CAPTION "Prueba"
FONT 8, "MS Sans Serif"
{
  CONTROL "", 90, "TWBrowse", WS_DISABLED|WS_TABSTOP|0x00b00000, 4, 4, 224, 149
  CONTROL "Código:", -1, "Static", WS_GROUP, 4, 164, 28, 9
  CONTROL "", 100, "Edit", WS_BORDER|WS_TABSTOP, 36, 160, 63, 12
  CONTROL "Cantidad:", -1, "Static", WS_GROUP, 4, 180, 32, 8
  CONTROL "", 140, "Edit", WS_BORDER|WS_TABSTOP, 36, 176, 38, 12
  CONTROL "Añadir", 4050, "Button", WS_TABSTOP, 120, 160, 52, 12
}

 
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: Problema con Button y Setfocus()

Postby hmpaquito » Thu Aug 19, 2010 7:43 am

Triumvirato,

Algunas veces tuve problemas con el SetFocus(). Para ello hice esta funcion ForceFocus() para que sea "casi imposible" que un objeto NO reciba el foco cuando se le "pasa".

Saludos

Code: Select all  Expand view

//////////////////////////////////////////////////////////////////
FUNCTION ForceFocus(oJump)
Local oFocus:= oWndFromHwnd(GetFocus())  // Indocumentada (Window.Prg)
Local bValid, bWhen
*
IF If(oFocus != NIL, oFocus:hWnd != oJump:hWnd, .t.)  // No sea el mismo objeto el
                                                      // actual y el que se salta
   *
   IF oFocus != NIL
      bWhen:=         oFocus:bWhen
      bValid:=        oFocus:bValid
      oFocus:bWhen:=  {|| .f. }
      oFocus:bValid:= {|| .t.}  // Este no se si necesario, pero por si acaso.
   ENDIF
   *
   *
   IF __ObjHasMethod(oJump, "FORWHEN")  // en algunos casos oJump es de la clase TWindow
      oJump:ForWhen()
   ENDIF
   *
   *
   oJump:SetFocus()
   *
   IF oFocus != NIL
      IF !(oFocus:ClassName() $ "TWINDOW,TDIALOG")
         IF bWhen == NIL
            // Necesarisimo, pq si es NIL, entonces en el ForWhen()
            // no se entera pq en window en aEval() se lo salta
            // si bWhen es NIL y entonces no lo Enable()
            oFocus:bWhen:=  {|| .t. }
            *
         ELSE
            oFocus:bWhen := bWhen
         ENDIF

         // Solo si deriva de TControl
         oFocus:ForWhen()
      ENDIF
      *
      oFocus:bWhen := bWhen
      oFocus:bValid:= bValid
   ENDIF

   *
ENDIF
*
RETURN NIL
*
 
Last edited by hmpaquito on Thu Aug 19, 2010 10:18 am, edited 1 time in total.
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Problema con Button y Setfocus()

Postby triumvirato » Thu Aug 19, 2010 8:15 am

hmpaquito,

he sustituido la línea donde llamo al Setfocus() por esta otra:
Code: Select all  Expand view
  REDEFINE BUTTON oBtnAnade ID 4050 OF oDlg_GenAut UPDATE ACTION ( oGetCodArt:Enable(), oGetUdsPed:Enable(), ForceFocus( oGetCodArt ) )
 


Pero no funciona. No sé si es correcta su sintaxis.

Muchas gracias.
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: Problema con Button y Setfocus()

Postby hmpaquito » Thu Aug 19, 2010 10:24 am

triumvirato,

En general no me gusta mucho la idea de ir habilitando cosas con el obj:Enable(). Lo que suelo hacer yo es especificar la condicion en la clausula WHEN. Al menos y a mi modo de ver el codigo es mas legible y mantenible.
Para ver qué está pasando pondría un msginfo("hola") a ver si al pulsar intro sobre el botón el mensaje aparece.
No se si con la funcion ForceFocus(), dentro, o en soledad, pon oBtnAnade:oJump:= oGetCodArt.

A ver si te vale algo de esto.
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Problema con Button y Setfocus()

Postby triumvirato » Thu Aug 19, 2010 10:57 am

hmpaquito wrote: En general no me gusta mucho la idea de ir habilitando cosas con el obj:Enable(). Lo que suelo hacer yo es especificar la condicion en la clausula WHEN. Al menos y a mi modo de ver el codigo es mas legible y mantenible.


Correcto, tampoco soy partidario, pero busco un comportamiento un tanto especial que no soy capaz de hacer con la cláusula WHEN.

hmpaquito wrote: Para ver qué está pasando pondría un msginfo("hola") a ver si al pulsar intro sobre el botón el mensaje aparece.


Todas las funtiones, etc. que pongo en la cláusula ACTION del botón se cumplen incluido un MsgInfo() si lo colocamos, excepto el SetFocus() si se hace con la tecla Enter. Presionando el boton con el raton lo hace perfecto. Es sólamente si se pulsa el Enter.

hmpaquito wrote: No se si con la funcion ForceFocus(), dentro, o en soledad, pon oBtnAnade:oJump:= oGetCodArt.


Tampoco me ha funcionado en las formas que comentas.

Muchas gracias... a ver si alguien arroja un poco más de luz, porque me parece bastante extraño que con el raton funcione siempre bien y pulsando el enter tenga un comportamiento distinto.
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: Problema con Button y Setfocus()

Postby hmpaquito » Thu Aug 19, 2010 11:50 am

Se me ocurre:

1º SysRefresh()

... ACTION (oBtn:oJump:= oGetArt, SysRefresh() )

2º PostMsg()

... ACTION (oGetArt:PostMsg(WM_SETFOCUS))

A ver si alguno de estos funciona.

PD. Por todas estas cosas es por las que tengo todos los COMANDOS de Fwh redefinidos, para abstraer todos estos problemas.
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Problema con Button y Setfocus()

Postby triumvirato » Thu Aug 19, 2010 2:46 pm

hmpaquito,

Gracias por tu tiempo, de verdad. A ver si damos con ello.

hmpaquito wrote:1º SysRefresh()
... ACTION (oBtn:oJump:= oGetArt, SysRefresh() )


No funciona. Es curioso, con esta forma tiene la misma reacción si pulsas enter, como si lo haces con el raton, fallan las dos. Y ya de paso he probado más combinaciones con sysrefresh() sin éxito.

hmpaquito wrote:2º PostMsg()
... ACTION (oGetArt:PostMsg(WM_SETFOCUS))


Esta segunda forma parece que va mas encaminada. El problema está en que una vez ejecutada (con raton o teclado), no puedo escribir en el get que ha tomado el foco, no aparece tampoco el cursor, pero si respeta el tema del foco.

Cómo es eso que dices que tienes redefinidos todos los comandos de FWH para evitar estos problemas?.

Muchas gracias por tu tiempo. Te estoy muy agradecido.
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: Problema con Button y Setfocus()

Postby hmpaquito » Thu Aug 19, 2010 3:37 pm

Cómo es eso que dices que tienes redefinidos todos los comandos de FWH para evitar estos problemas?.

Un ejemplo al vuelo:
Code: Select all  Expand view

#Translate @ <nRow>, <nCol> MIGET <oGet> ;
                  [PREVALID <bPreValid>] ;                         // Action PreValid
                  [VALID <bValid> ;                                    // Exclusivamente condicion de validacion: luego es facil preguntar solo por las condiciones de validacion de todos los gets
                 [ POSTVALID <bPostValid>]                        // Action PostValid
                 [JUMPTO <oJump> ];
                 => ;
                @ <nRow>, <nCol> GET <oGet> ;
                       VALID (;
                                   If(<.bPreValid.>, Eval(<bPreValid>), NIL),;
                                   l:= Eval(<bValid>),;
                                   If(<.bPostValid.>, Eval(<bPostValid>), NIL),;
                                   If(l .AND. <.oJump.>, ForceFocus(<oJump>), NIL);
                                  )
 

Con esto se consigue:
1º Aislar los malfuncionamientos o funcionamientos incomodos. Por ejemplo utilizando la clausula JUMPTO para saltar a otro control. Si en futuras modificaciones de FWH no funcionara pues se cambia en un solo punto y ya esta.
2º Aislar el VALID para lo que realmente es: Evaluar una expresion que devuelva .f. o .t.. El prevalid o postvalid sirven para otra cosa.
3º Poder cambiar desde el comando diversos aspectos de funcionamiento sin tocar los comandos o fuentes originales de fwh.

Es solo una idea que nada tiene que ver con el tema que llevamos entre manos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Problema con Button y Setfocus()

Postby triumvirato » Thu Aug 19, 2010 4:01 pm

hmpaquito,

Ahí ya si me pierdo del todo. Más o menos he entendido para qué lo usas, pero mis conocimientos no dan para tanto, aunque veo ya cómo usas tu función ForceFocus. Efectivamente cualquier cambio o problema es más sencillo de solucionar.

Lo de mi problema a ver si hay alguien que arroje más luz al tema porque llevo dos dias probando casi de todo (para lo que mis conocimientos dan).

Gracias, un saludo.
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: Problema con Button y Setfocus()

Postby Daniel Garcia-Gil » Thu Aug 19, 2010 5:05 pm

triumvirato...

habria que cambiar la clase para hacer una mejor simulacion del click... actualmente se envia el mensaje FM_CLICK pero habria que hacerle un mejor "engaño"

abre el archivo button.prg

y cambia la linea
Code: Select all  Expand view

              ::PostMsg( FM_CLICK )    // fire the button's action
 

por esto
Code: Select all  Expand view

            ::PostMsg( WM_LBUTTONDOWN, 1, 1 )
            ::PostMsg( WM_LBUTTONUP, 1, 1 )
 


por tratarse de un dialogo debes asignarle DLGC_WANTALLKEYS a la data nDlgCode, sino esas pulsaciones no llegaran al control

Code: Select all  Expand view
oBtnAnade:nDlgCode = DLGC_WANTALLKEYS


todo lo demas queda igual

te dejo el ejecutable...

http://www.sitasoft.net/fivewin/samples/testtri.zip
User avatar
Daniel Garcia-Gil
 
Posts: 2365
Joined: Wed Nov 02, 2005 11:46 pm
Location: Isla de Margarita

Re: Problema con Button y Setfocus()

Postby triumvirato » Thu Aug 19, 2010 6:04 pm

Daniel,

Muchas gracias por tu ayuda.

He recompilado con los cambios que me indicas, pero sigue ocurriendo el mismo comportamiento, con el raton hace el SetFocus(), con la tecla enter encima del boton lo ignora.
Uso FWH/FWHX 10.1 26/January/2010
Por otro lado, efectivamente, el exe que me envías lo hace correctamente.

¿Esa modificación que me indicas en button.prg quedará en próximas versiones de FiveWin, o por el contrario debo hacer la modificación (en caso de que consiga que funcione) en las actualizaciones sucesivas de Fivewin?

Muchas gracias, Saludos.
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: Problema con Button y Setfocus()

Postby andresreyes_mzt » Thu Aug 19, 2010 6:27 pm

Triumvirato,

Desgraciadamente Windows maneja de forma muy diferente Ventanas Normales y Dialogos, en la mayoria de las ocasiones la llamada a la Funciona SetFocus no Funciona dentro de los dialogos.

La forma que establece windows para cambiar el foco dentro de dialogos es por medio del mensaje WM_NEXTDLGCTL

Incluye esto al principio de tu PRG
Code: Select all  Expand view

#define WM_NEXTDLGCTL                   0x0028
 


Esta Linea la Eliminas
Code: Select all  Expand view

REDEFINE BUTTON oBtnAnade ID 4050 OF oDlg_GenAut UPDATE ACTION ( oGetCodArt:Enable(), oGetUdsPed:Enable(), oGetCodArt:SetFocus() )
 


Y la Cambias por esta ...
Code: Select all  Expand view

REDEFINE BUTTON oBtnAnade ID 4050 OF oDlg_GenAut UPDATE ACTION ( oGetCodArt:Enable(), oGetUdsPed:Enable(), oDlg_GenAut:PostMsg( WM_NEXTDLGCTL, oGetCodArt:hWnd, 1 ) )
 


The WM_NEXTDLGCTL message is sent to a dialog box procedure to set the keyboard focus to a different control in the dialog box.

WM_NEXTDLGCTL
wCtlFocus = wParam; // identifies control for focus
fHandle = (BOOL) LOWORD(lParam); // wParam handle flag


Parameters

wCtlFocus

Value of wParam. If the fHandle parameter is TRUE, the wCtlFocus parameter identifies the control that receives the focus. If fHandle is FALSE, wCtlFocus is a flag that indicates whether the next or previous control with the WS_TABSTOP style receives the focus. If wCtlFocus is zero, the next control receives the focus; otherwise, the previous control with the WS_TABSTOP style receives the focus.

fHandle

Value of lParam. Contains a flag that indicates how Windows uses the wCtlFocus parameter. If the fHandle parameter is TRUE, wCtlFocus is a handle associated with the control that receives the focus; otherwise, wCtlFocus is a flag that indicates whether the next or previous control with the WS_TABSTOP style receives the focus.



Return Values

An application should return zero if it processes this message.

Remarks

The effect of this message differs from that of the SetFocus function because WM_NEXTDLGCTL modifies the border around the control.
Do not use the SendMessage function to send a WM_NEXTDLGCTL message if your application will concurrently process other messages that set the focus. Use the PostMessage function instead.


Es solo un cambio pequeño lo que necesitas hacer y con eso solucionas tu problema ... sin tanto codigo ...

Saludos,
Andres Reyes
{{{ ---- xharbour + Borland C --- }}}
User avatar
andresreyes_mzt
 
Posts: 71
Joined: Fri Jan 11, 2008 6:55 am
Location: Mexico

Re: Problema con Button y Setfocus()

Postby triumvirato » Fri Aug 20, 2010 6:09 am

Andrés,

Simplemente, perfecto.

Se me escapa bastante todo este tipo de soluciones, sinceramente, por lo que quedo maravillado del nivel de muchos de los que por aquí ayudáis.

Mcuhas gracias, Saludos.
triumvirato
 
Posts: 199
Joined: Tue Apr 22, 2008 9:54 am
Location: Valladolid, Spain.

Re: Problema con Button y Setfocus()

Postby carlos vargas » Sun Aug 07, 2011 11:46 pm

me has salvado, sos grande, aca mi codigo personalizado

Code: Select all  Expand view

...
EXTEND CLASS TDIALOG    WITH METHOD MySetFocus
...

FUNCTION MySetFocus( xData )
   LOCAL Self := HB_QSelf()

   DO CASE
   CASE ValType( xData )=="O"
      ::PostMsg( WM_NEXTDLGCTL, xData:hWnd, 1 )
   CASE ValType( xData )=="N"
      IF Len( ::aControls ) >= xData
         ::PostMsg( WM_NEXTDLGCTL, ::aControls[ xData ]:hWnd, 1 )
      ENDIF
   ENDCASE

RETURN NIL
...
 


y aca como lo uso
Code: Select all  Expand view

PROCEDURE FlujoRuta_SeleccionarRuta()
   LOCAL oDBSearch := TDBSearch():new( "Lista de ruta de cobro" )

   WITH OBJECT oDBSearch
      :cAlias   := "RUTA"
      :bFields  := { || { RUTA->NUM_RUTA, RUTA->NOMBRE } }
      :aHeaders := { "Número", "Nombre de gestor" }
      :aJustify := { 2, 0 }
      :aOrders  := { { "NUM_RUTA" }, { "Numero de ruta" } }
      :cCurOrd  := "NUM_RUTA"
      :nCurOrd  := 1
      IF :open()
         cNumRuta := RUTA->NUM_RUTA
         cNomRuta := RUTA->NOMBRE
         cNomCobr := COBR->NOMBRE
         oDlgE:update()
         oDlgE:MySetFocus( 9 )  //aca puedo usar la posicion del objeto en aControls
         //oDlgE:MySetFocus( oGet )   //aca puedo usar un objeto
      ENDIF
   END

RETURN
 


salu2
carlos vargas
Salu2
Carlos Vargas
Desde Managua, Nicaragua (CA)
User avatar
carlos vargas
 
Posts: 1688
Joined: Tue Oct 11, 2005 5:01 pm
Location: Nicaragua


Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 9 guests