Page 1 of 1
Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 7:09 am
by triumvirato
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 _, 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 _ al resto de cláusulas.
Un ejemplo a ver si me sabe alguien ayudar, Gracias.
Code: Select all
#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
#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
}
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 7:43 am
by hmpaquito
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
//////////////////////////////////////////////////////////////////
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 _ 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
*
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 8:15 am
by triumvirato
hmpaquito,
he sustituido la línea donde llamo al Setfocus() por esta otra:
Code: Select all
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.
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 10:24 am
by hmpaquito
triumvirato,
1º 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.
2º Para ver qué está pasando pondría un msginfo("hola") a ver si al pulsar intro sobre el botón el mensaje aparece.
3º No se si con la funcion ForceFocus(), dentro, o en soledad, pon oBtnAnade:oJump:= oGetCodArt.
A ver si te vale algo de esto.
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 10:57 am
by triumvirato
hmpaquito wrote:
1º 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:
2º 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:
3º 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.
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 11:50 am
by hmpaquito
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.
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 2:46 pm
by triumvirato
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.
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 3:37 pm
by hmpaquito
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
#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
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 4:01 pm
by triumvirato
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.
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 5:05 pm
by Daniel Garcia-Gil
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
::PostMsg( FM_CLICK ) // fire the button's action
por esto
Code: Select all
::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
oBtnAnade:nDlgCode = DLGC_WANTALLKEYS
todo lo demas queda igual
te dejo el ejecutable...
http://www.sitasoft.net/fivewin/samples/testtri.zip
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 6:04 pm
by triumvirato
Daniel,
Muchas gracias por tu ayuda.
He recompilado con _ 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.
Re: Problema con Button y Setfocus()
Posted: Thu Aug 19, 2010 6:27 pm
by andresreyes_mzt
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
Esta Linea la Eliminas
Code: Select all
REDEFINE BUTTON oBtnAnade ID 4050 OF oDlg_GenAut UPDATE ACTION ( oGetCodArt:Enable(), oGetUdsPed:Enable(), oGetCodArt:SetFocus() )
Y la Cambias por esta ...
Code: Select all
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
Re: Problema con Button y Setfocus()
Posted: Fri Aug 20, 2010 6:09 am
by triumvirato
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.
Re: Problema con Button y Setfocus()
Posted: Sun Aug 07, 2011 11:46 pm
by carlos vargas
me has salvado, sos grande, aca mi codigo personalizado
Code: Select all
...
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
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