Un control en un TPanel

Un control en un TPanel

Postby antolin » Thu May 23, 2013 11:47 am

Tengo un poblema que llevo tres dias intentando solucionar. Parece una tonteía pero a mi no me sale.

Tengo un Windows MDI con un MDICHILD. Desde éste último llamo a un dialogo y en ese dialogo he colocado un TPANEL para unas cosas mías de repintado que no vienen al caso. Resulta que no me deja colocar controles en el TPANEL. Primero me daba "Message Not found: TPANEL:DEFCONTROL". Así que le implementé un METHOD DefControl() AL TPANEL, tal que así:
Code: Select all  Expand view
METHOD DefControl( oCtrl )
   DEFAULT oCtrl:nId := oCtrl:GetNewId() // AUNQUE oCtrl YA TRAE UNO
   IF ::aControls = NIL
      ::aControls = {}
   ENDIF
   AADD( ::aControls, oCtrl )
   oCtrl:hWnd = 0  // TAMBIEN HE PROBADO oCtrl:hWnd = GetWindow(::hWnd,5) Y GetWindow(::oWnd:hWnd,5)
RETURN NIL

No se me cortaba, pero tamcpoco aparcía el control en pantalla. Tras algunas comprobaciones averigüë que el contol no se inicializaba. Así que modifique el METHOD INITIATE para que inicializara los controles:
Code: Select all  Expand view
IF ::aControls # NIL
   ASend(::aControls,"INICTIATE()",::hWnd)
ENDIF


Y ahora me da el error "NON DEFINED Id: No: 120"

El caso es que ya he utilizado paneles otras veces y no he tenido problemas, pero directamente sobre windows. Entiendo que en su método NEW() en vez de pasar el flujo del programa por AddControl() pasda por DefControl() y no le asigna el ::nId al TPANEL y eso que durante la definicion del control (un SAY por ejemplo) le digo OF oDlg, y su ::oWnd:hWnd da distinto de 0.

¿Alguien sabe como asignarle ese ::nId al TPANEL para que se inicialice adecuadamente?

Gracias de antemano.
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Un contrl en un TPanel

Postby antolin » Thu May 23, 2013 12:11 pm

Se me olvidaba. Mi FWH es bastante antiguo, del 2007. Lo mismo en vuestras versiones eso ya está solucionado. Si vuestro TPANEL tiene METHOD DefControl() me sería de gran ayuda que me posteeis dicho método (no la clase entera claro) a ver si con eso puedo solucionar mi problema.

Gracias
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Un contrl en un TPanel

Postby Antonio Linares » Thu May 23, 2013 2:49 pm

Antolin,

Creo que lo que te ha pasado es que has invertido el orden de los parámetros aqui:

oPnl = TPanel():Redefine( 120, oDlg )

Este ejemplo funciona bien aqui. Solo he modificado una línea en control.prg para que el Método Redefine() devuelva Self

Code: Select all  Expand view
#include "FiveWin.ch"

static oWnd

function Main()

   DEFINE WINDOW oWnd MDI MENU BuildMenu()

   ACTIVATE WINDOW oWnd

return nil

function BuildMenu()

   local oMenu

   MENU oMenu
      MENUITEM "Crear Child" ACTION CrearChild()
   ENDMENU

return oMenu

function CrearChild()

   local oWndChild, oDlg, oPnl

   DEFINE WINDOW oWndChild MDICHILD OF oWnd

   DEFINE DIALOG oDlg RESOURCE "test" OF oWndChild

   oPnl = TPanel():Redefine( 120, oDlg )

   oPnl:SetBrush( oDlg:oBrush )

   ACTIVATE DIALOG oDlg NOWAIT
   
   ACTIVATE WINDOW oWnd ;
      VALID oDlg:End()

return nil


rc:
Code: Select all  Expand view
test DIALOG 0, 0, 300, 300
STYLE WS_VISIBLE | WS_CHILD
FONT 8, "MS Sans Serif"
{  
   CONTROL "", 120, "TPanel", 0 | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL, 0, 0, 200, 200
}
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Un contrl en un TPanel

Postby Antonio Linares » Thu May 23, 2013 2:59 pm

Los controles que quieras situar en el Panel haz de crearlos desde la claúsula ON INIT del diálogo:

Code: Select all  Expand view
#include "FiveWin.ch"

static oWnd

function Main()

   DEFINE WINDOW oWnd MDI MENU BuildMenu()

   ACTIVATE WINDOW oWnd

return nil

function BuildMenu()

   local oMenu

   MENU oMenu
      MENUITEM "Crear Child" ACTION CrearChild()
   ENDMENU

return oMenu

function CrearChild()

   local oWndChild, oDlg, oPnl

   DEFINE WINDOW oWndChild MDICHILD OF oWnd

   DEFINE DIALOG oDlg RESOURCE "test" OF oWndChild

   oPnl = TPanel():Redefine( 120, oDlg )

   oPnl:SetBrush( oDlg:oBrush )

   ACTIVATE DIALOG oDlg NOWAIT ;
      ON INIT CreaControles( oDlg )
   
   ACTIVATE WINDOW oWnd ;
      VALID oDlg:End()

return nil

function CreaControles( oDlg )

   local oBtn

   @ 2, 2 BUTTON oBtn PROMPT "OK" SIZE 80, 20 ;
      ACTION ( MsgInfo( "Hello world!" ), oBtn:SetFocus() )
   
return nil  
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Un control en un TPanel

Postby Antonio Linares » Thu May 23, 2013 3:25 pm

Habia un error en mi ejemplo, ahora si:

Code: Select all  Expand view
#include "FiveWin.ch"

static oWnd

function Main()

   DEFINE WINDOW oWnd MDI MENU BuildMenu()

   ACTIVATE WINDOW oWnd

return nil

function BuildMenu()

   local oMenu

   MENU oMenu
      MENUITEM "Crear Child" ACTION CrearChild()
   ENDMENU

return oMenu

function CrearChild()

   local oWndChild, oDlg, oPnl

   DEFINE WINDOW oWndChild MDICHILD OF oWnd

   DEFINE DIALOG oDlg RESOURCE "test" OF oWndChild

   oPnl = TPanel():Redefine( 120, oDlg )

   oPnl:SetBrush( oDlg:oBrush )

   ACTIVATE DIALOG oDlg NOWAIT ;
      ON INIT CreaControles( oPnl )
   
   ACTIVATE WINDOW oWnd ;
      VALID oDlg:End()

return nil

function CreaControles( oPnl )

   local oBtn

   @ 2, 2 BUTTON oBtn PROMPT "OK" SIZE 80, 20 ;
      ACTION MsgInfo( "Hello world!" ) OF oPnl
   
return nil  


Code: Select all  Expand view
test DIALOG 0, 0, 300, 300
STYLE WS_CHILD
FONT 8, "MS Sans Serif"
{  
   CONTROL "", 120, "TPanel", 0 | WS_TABSTOP | WS_CHILD | WS_VISIBLE, 0, 0, 200, 200
}
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Un contrl en un TPanel

Postby antolin » Thu May 23, 2013 3:29 pm

Gracias Antonio por la respuesta, pero el problema no está ahí. El panel si me sale y puedo pintar en el con DrawText, Rectangle, etc. Pero no lo construyo desde recurso, sino a mano con @ 10,10 .... . Segundo lo que falla es el TSAY que no se asocia con el panel. La línea del INITiATE: IF( ( ::hWnd := GetDlgItem( hDlg,::nId ) ) # 0 ) me devuelve 0 y creo que es porque no reconoce ::nId como item del panel. Seguramente tendrá algo que ver que no viene de recurso pues ya he tenido algún que otro contratiempo por culpa de eso, pero esta vez no atino a resolverlo, pues no se como asociar el identificador del control con el panel, es decir cómo decirle a FiveWin que ese ::nId es un control del panel.

Este es el trozo de codigo:
Code: Select all  Expand view
FUNCTION ConsReg(oLb,cPath)
   LOCAL oDlC,oPan,oVScr
   LOCAL oFont[3],oBot,nAlto
   LOCAL aTama := {680,0}
   LOCAL aLins := {}
   LOCAL oCtrl := {}
   LOCAL oBmp  := {}
LOCAL oSay
   *
   nLin :=  0
   lArr := .T.
   lAbj := .F.
   *
   DEFINE FONT oFont[1] NAME "Serifa BT" SIZE 0,-15
   DEFINE FONT oFont[2] NAME "Arial" SIZE 0,-12 BOLD
   DEFINE FONT oFont[3] NAME "Arial" SIZE 0,-15 BOLD
   nAlto := (oFont[1]:nHeight*1.2)+8
   *
   DEFINE DIALOG oDlC OF oLb:oWnd STYLE nOr(WS_POPUP,WS_VISIBLE,WS_CAPTION,WS_SYSMENU,WS_DLGFRAME) ;
      TITLE "  Consultar Registro" SIZE aTama[1]+57,560 FONT oFont[1]
      oPan := TPANEL():New(0,0,100,100,oDlC)
@ 10,10 SAY oSay PROMPT "PRUEBA" OF oPan SIZE 100,10 PIXEL
         *
     ComponLin(oLb,aLins,oPan,oFont,aTama,oCtrl,oBmp,nAlto)
     *
      @ 0,0 BUTTONBMP oBot PROMPT "&Volver" SIZE 50,12 OF oDlC PIXEL FONT oFont[2] ACTION ( oDlC:End(),

oLb:SetFocus() )
      *
      oPan:bPainted := { |hDc| PintConst(hDc,oPan,aLins,oFont,aTama[1]-135,oCtrl,oBmp) }
      oPan:bMMoved  := { || IF(!oPan:lFocused,oPan:SetFocus(),NIL) }
      oDlC:bPainted := { |hDc| PintCReg(hDc,oDlC,oPan,aTama) }
   ACTIVATE DIALOG oDlC CENTER ON INIT PonCReg(oDlC,oPan,oBot,oVScr,aLins,aTama,nAlto,oFont,oCtrl,oBmp,oLb)
   AEVAL(oFont,{ |o| o:End()})
RETURN NIL
*
FUNCTION PonCReg(oDlg,oPn,oBt,oVS,aLin,aTam,nStep,oF,oCtrl,oBmp,oLb)
   LOCAL nAlto := (oF[1]:nHeight*1.2)+8
   *
   oBt:Move(oDlg:nHeight-67,oDlg:nWidth-oBt:nWidth-30)
   *
   nAlto := oDlg:nHeight-108-GetSysMetrics(32)
   IF aTam[2] > nAlto
      oPn:Move(15,18,aTam[1],nAlto)
      *
      @ oPn:nTop-1,oPn:nWidth+23 SCROLLBAR oVS OF oDlg SIZE 18,oPn:nHeight+2 VERTICAL PIXEL ;
           RANGE 0,Round((aTam[2]-nAlto)/4,0) PAGESTEP oPn:nHeight/4        // 4 PORQUE LAS

FLECHAS DEL SCROLL
       oVS:bGoDown   := { || PintDown(oVS,oPn,aLin,oF,aTam[1]-135,2,oCtrl,oBmp) }   // SUBEN O BAJAN 4

PIXELS CADA VEZ
       oVS:bGoUp     := { || PintUp(oPn,aLin,oF,aTam[1]-135,2,oCtrl,oBmp) }
       oVS:bPageDown := { || PintPageDown(oVS,oPn,aLin,oF,aTam[1]-135,2,oCtrl,oBmp) }
       oVS:bPageUp   := { || PintPageUp(oPn,aLin,oF,aTam[1]-135,2,oCtrl,oBmp) }
       oVS:bTrack    := { |nPos| PintDentro(oVS,oPn,aLin,oF,nPos,aTam[1]-135,2,oCtrl,oBmp) }
      oPn:bWheel := { |D,K| PinWheel(oVS,oPn,D,aLin,nStep,aTam[1]-135,oF,2,oCtrl,oBmp) }
   ELSE
      oPn:Move(15,29,aTam[1],nAlto)
   ENDIF
RETURN NIL
*
 

oLb es un listobox que cuando pincho en una linea me tiene que dar una serie de detalles. El panel es para hacer un scroll propio con doble buffer, va muy bien pero necesito scrolar tambien algunos controles, siempre y cuando me los admita. El caso es que sobre window no hay problema, el asunto es cn los dialogos.
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Un control en un TPanel

Postby Antonio Linares » Thu May 23, 2013 3:42 pm

No puedes modificar mi ejemplo, que es muy sencillo, para que se asemeje a lo que estas haciendo ?

Sin código fuente y un ejemplo que probar es dificil ser más preciso :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Un control en un TPanel

Postby antolin » Mon May 27, 2013 8:31 am

Hola Antonio.

Efectivamente, sería más práctico plantearme utilizar recursos, el problema es que no se qué o cuántos controles voy a tener que presentar cada ves, principalmente listbox's, una vez será uno, otra tres o ninguno, por lo que no tengo más remedio que utilizar oCtrl:New() en vez de oCtrl:Redefine().

Prueba este código:
Code: Select all  Expand view
#include "FiveWin.ch"

STATIC oWMain,oMenu

FUNCTION MAIN()
  DEFINE WINDOW  oWMain MDI TITLE "  PRUEBA PANEL" MENU PonMenu()
  ACTIVATE WINDOW oWMain MAXIMIZED
RETURN NIL
*
FUNCTION PonMenu()
   MENU oMenu
      MENUITEM "Crea Child" ACTION CrearChild()
   ENDMENU
RETURN NIL
*
FUNCTION CrearChild()
   LOCAL nHeight := GetSysMetrics(17)-GetSysMetrics(15) // ALTO AREA CLIENTE - ALTO MENU
   LOCAL nWidth  := GetSysMetrics(0)            // ANCHO PANTALLA
   LOCAL oWin,oDlO,oBot
   *
   DEFINE WINDOW oWin MDICHILD OF oWMain
      DEFINE DIALOG oDlO OF oWin STYLE nOr(WS_CHILD,WS_VISIBLE)
     @ 100,100 BUTTONBMP oBot PROMPT "Prueba" SIZE 50,12 OF oDlO PIXEL ACTION Dialogo(oDlO)
      ACTIVATE DIALOG oDlO NOWAIT ON INIT oDlO:Move(0,0,nWidth,nHeight)
   ACTIVATE WINDOW oWin MAXIMIZED
RETURN NIL
*
FUNCTION Dialogo(oDlg)
   LOCAL oDlC,oPan,oSay
   *
   DEFINE DIALOG oDlC OF oDlg STYLE nOr(WS_POPUP,WS_VISIBLE,WS_CAPTION,WS_SYSMENU,WS_DLGFRAME) SIZE 600,400
     oPan := TPanel():New(10,10,580,380,oDlC)
     @ 10,20 SAY oSay PROMPT "PRUEBA" OF oPan SIZE 60,15
   ACTIVATE DIALOG oDlC CENTER ON INIT oPan:Move(10,10,580,380)
RETURN NIL


La verdad es que no es necesaria tanta parafernalia, sólo bastan un Dialogo, un Panel y un SAY sobre el panel para que falle la compilación. El inconveniente es que cuando se crea el TSAY, al final de su método New() llama a ::oWnd:DefControl(), pero resulata que el ::oWnd es el TPANEL que es un control, no un Dialogo, y TCONTROL no tiene método DefControl() por lo que el TSAY no tiene más remedio que fallar.

Buscando una solución le definí un DefControl estándar al TAPNEL, tal que así:
Code: Select all  Expand view
METHOD DefControl( oCtrl ) CLASS TPanel

   DEFAULT oCtrl:nId := oCtrl:GetNewId()

      IF ::aControl = NIL
     ::aControls := {}
      ENDIF
      AAdd( ::aControls, oCtrl )
      oCtrl:hWnd = 0

RETURN NIL


Ya no falla la construcción del TSAY pero no se inicializa porque cuando el Dialogo recibe el mensaje "INITIATE" inicializa todos sus controles pero no ese TSAY porque no le pertenece, pertenece al TPANEL.

La solución pasaría por definirle un METHOD INITIATE( hDlg ) al uso al TPANEL añadiéndole al final:
Code: Select all  Expand view
IF ::aControls # NIL
  ASend( ::aControls, "INITIATE()", ::hWnd )
ENDIF


Pero aparece otro problema. El flujo del programa, efectivamente, intienta incializar el TSAY, pero cuando llega a:
Code: Select all  Expand view
IF( ( ::hWnd := GetDlgItem( hDlg, ::nId ) ) # 0 )

falla porque GetDlgItem( hDlg, ::nId ) devuelve 0 y se corta. Seguramente porque TPANEL no es un dialogo. El caso es que he probado con GetWindow( ::hWnd, GW_CHILD ), pero también devuelve 0, lo ponga donde lo ponga, en el INITITE del TPANEL o en el del TSAY y no lo comprendo por TCOMBO lo utiliza y funciona.

Por ahora he encontrado una solución provisional definiendo el DefControl() del TPANEL de esta manera:
Code: Select all  Expand view
METHOD DefControl( oCtrl ) CLASS TFondo
   ::oWnd:DefControl( oCtrl )
   SetParent(oCtrl:hWnd,::hWnd)
RETURN NIL

Y el TSAY se dibuja. El problema es que se pinta tanto sobre el TPANEL como sobre el DIALOG, porque en realidad, aunque le digo que su window padre es el TPANEL, en realidad es un ::aControls del DIALOG, por lo tanto cuando se pinta, lo hace a caballo entre los dos, es decir se ve entero pero parte sobre el DIALOG y parte sobre el TPANEL. Podría modificar el nLeft del TSAY para que sólo se dibujara sobre el TPANEL, pero no me sirve porque cuando presente los controles del TPANEL necesito que las paretes que no caben sobre el TPANEL no se pinten sobre el DIALOGO sino que aparezcan cortadas ( el dialogo tiene más cosas además del TPANEL). El TPANEL tiene que aprentar un folio sobre el que se escriben las cosas, y las que no caben no pueden pintarse sobre la mesa (el DIALOG).

La solución pasa por definirle al TSAY un ::hWnd dependiente del TPANEL durante la inicialización pero no atino a hacerlo. Pensé que GetWindow(::hWnd,GW_CHILD) serviría, pero no lo hace y no sé porqué.

Antonio, tu tienes mucha más esperiencia que yo en este campo, eres el maestro, si tu no encuentras la solución no la va a encontrar nadie y tendré que desistir de esta opción para mi programa. Claro que tampoco quiero que le dediques todo tu valioso tiempo en este asunto.

Si puedes hacer algo, muchas gracias, y si no, pues tampoco pasa nada.
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Un control en un TPanel

Postby cnavarro » Mon May 27, 2013 8:58 am

Antolin, puedes probar esta modificacion

Code: Select all  Expand view

#include "FiveWin.ch"

STATIC oWMain,oMenu

FUNCTION MAIN()
  DEFINE WINDOW  oWMain MDI TITLE "  PRUEBA PANEL" MENU PonMenu()
  ACTIVATE WINDOW oWMain MAXIMIZED
RETURN NIL
*
FUNCTION PonMenu()
   MENU oMenu
      MENUITEM "Crea Child" ACTION CrearChild()
   ENDMENU
RETURN oMenu
*
FUNCTION CrearChild()
   LOCAL nHeight := GetSysMetrics(17)-GetSysMetrics(15) // ALTO AREA CLIENTE - ALTO MENU
   LOCAL nWidth  := GetSysMetrics(0)            // ANCHO PANTALLA
   LOCAL oWin,oDlO,oBot
   *
   DEFINE WINDOW oWin MDICHILD OF oWMain
       
      DEFINE DIALOG oDlO OF oWin STYLE nOr(WS_CHILD,WS_VISIBLE)
     @ 100,100 BUTTONBMP oBot PROMPT "Prueba" SIZE 50,12 OF oDlO PIXEL ACTION Dialogo(oDlO)
      ACTIVATE DIALOG oDlO NOWAIT ON INIT oDlO:Move(0,0,nWidth,nHeight)
   ACTIVATE WINDOW oWin MAXIMIZED
RETURN NIL
*
FUNCTION Dialogo(oDlg)
   LOCAL oDlC,oPan,oSay
   *
   DEFINE DIALOG oDlC OF oDlg STYLE nOr(WS_POPUP,WS_VISIBLE,WS_CAPTION,WS_SYSMENU,WS_DLGFRAME) SIZE 600,400
   ACTIVATE DIALOG oDlC CENTER ON INIT ( oPan := HazPanel( oDlC ), oPan:Move(10,10,580,380) )
RETURN NIL

Function HazPanel( oDlC )
Local oPan,  oSay
Local oBrush
     DEFINE BRUSH oBrush COLOR RGB( 118, 148, 168 )
     oPan := TPanel():New(10,10,580,380,oDlC)
     oPan:oBrush := oBrush
     @ 10,20 SAY oSay PROMPT "PRUEBA" OF oPan SIZE 60,15

Return oPan
 


Saludos
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6500
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Un control en un TPanel

Postby antolin » Mon May 27, 2013 9:35 am

!!FUNCIONA!!

Muchas gracias, no sabes que favor me has hecho.

Entiendo que ahora, en lugar de pasar por DefControl() pasa por AddControl() que es de TWINDOW, común a todo y todos. Lo que no llego a entender es porque ahora si funciona GetDlgItem() y antes no, pues hDlg no venía como 0 y se refería al mismo TPANEL. Pero bueno, lo importante es que funciona y que me has sacado de un apuro.

Muchas gracias otra vez.
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Un control en un TPanel

Postby cnavarro » Mon May 27, 2013 9:45 am

Antolin, a mi tambien me paso lo mismo hace tiempo.

Antonio ya te lo había comentado en este mismo tema un poco más arriba
http://forums.fivetechsupport.com/viewtopic.php?f=6&t=26388#p145389

Saludos, y a mandar
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6500
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Un control en un TPanel

Postby antolin » Mon May 27, 2013 9:50 am

Ups! mea culpa, estaba obsecado en mi error y no veia más allá de mis narices. Mil perdones.

Un saludo.
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla


Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 75 guests