FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour Problema con Button y Setfocus()
Posts: 199
Joined: Tue Apr 22, 2008 09:54 AM
Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 07: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 (fw): Select all Collapse
#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 (fw): Select all Collapse
#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
}
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 07: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 (fw): Select all Collapse
//////////////////////////////////////////////////////////////////
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
*
Posts: 199
Joined: Tue Apr 22, 2008 09:54 AM
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 08:15 AM
hmpaquito,

he sustituido la línea donde llamo al Setfocus() por esta otra:
Code (fw): Select all Collapse
   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.
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Problema con Button y Setfocus()
Posted: 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:= oGetCodArt.

A ver si te vale algo de esto.
Posts: 199
Joined: Tue Apr 22, 2008 09:54 AM
Re: Problema con Button y Setfocus()
Posted: 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:= 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.
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 11:50 AM

Se me ocurre:

[u:1rje53i2]1º SysRefresh()[/u:1rje53i2]

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

[u:1rje53i2]2º PostMsg()[/u:1rje53i2]

... 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.

Posts: 199
Joined: Tue Apr 22, 2008 09:54 AM
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 02:46 PM
hmpaquito,

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

hmpaquito wrote:1º SysRefresh()
... ACTION (oBtn:= 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.
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 03: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 (fw): Select all Collapse
#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
Posts: 199
Joined: Tue Apr 22, 2008 09:54 AM
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 04: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.

Posts: 2365
Joined: Wed Nov 02, 2005 11:46 PM
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 05: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 (fw): Select all Collapse
              ::PostMsg( FM_CLICK )    // fire the button's action

por esto
Code (fw): Select all Collapse
            ::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 (fw): Select all Collapse
oBtnAnade:nDlgCode = DLGC_WANTALLKEYS


todo lo demas queda igual

te dejo el ejecutable...

http://www.sitasoft.net/fivewin/samples/testtri.zip
Posts: 199
Joined: Tue Apr 22, 2008 09:54 AM
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 06: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.

Posts: 71
Joined: Fri Jan 11, 2008 06:55 AM
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 06: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 (fw): Select all Collapse
#define WM_NEXTDLGCTL                   0x0028


Esta Linea la Eliminas
Code (fw): Select all Collapse
REDEFINE BUTTON oBtnAnade ID 4050 OF oDlg_GenAut UPDATE ACTION ( oGetCodArt:Enable(), oGetUdsPed:Enable(), oGetCodArt:SetFocus() )


Y la Cambias por esta ...
Code (fw): Select all Collapse
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 --- }}}
Posts: 199
Joined: Tue Apr 22, 2008 09:54 AM
Re: Problema con Button y Setfocus()
Posted: Fri Aug 20, 2010 06: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.

Posts: 1789
Joined: Tue Oct 11, 2005 05:01 PM
Re: Problema con Button y Setfocus()
Posted: Sun Aug 07, 2011 11:46 PM
me has salvado, sos grande, aca mi codigo personalizado

Code (fw): Select all Collapse
...
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 (fw): Select all Collapse
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)

Continue the discussion