Página 1 de 1

Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 25 Ago 2010, 08:57
por Ximorro
Buenas foreros, resulta que tengo un formulario con un control ActiveX incrustado (GUICtrlCreateObj), según pone en la ayuda los "Document Objects" sólos son visibles en el formulario si le pones el estilo WS_CLIPCHILDREN en GuiCreate.

Sin WS_CLIPCHILDREN efectivamente no va muy bien, el control normalmente se ve, pero ciertamente da problemas de parpadeo en otros controles y otras cosas raras...

El problema al poner el estilo es que hay controles que se hacen transparentes y se ve lo que hay detrás del formulario, o a veces se ve todo negro, según le parezca :smt010

Mirad por ejemplo el código simplificado que pongo abajo, si tenéis cosas en medio de la pantalla las veréis a través de él, si no ponedlo delante de algo, minimizad, y al restaurar sale la transparencia (o todo negro).

Casi lo soluciono poniendo una etiqueta que tapa todo el formulario, pero no va del todo bien. La he dejado comentada por si queréis probarlo. El caso es que entonces los recuadros de los ¡inputboxes no salen! Al pasar el ratón sobre ellos aparece, ¡es muy fastidioso!

He intentado también con un Picture... ¡también sale transparente! como si no estuviera...

¿Quizás alguna manera de obligar a que pinte el fondo del formulario aunque tenga el WS_CLIPCHILDREN, aunque si eso es como anular el flag entonces fallaría el ActiveX :smt013

Porfa a ver si alguien sabe algo porque es una faena, todo es funcional pero o va el ControlObject o se ve todo como un churro... :smt022

Este código es una tremenda simplificación del GUI original, pero aquí también se ve el "efecto". En este caso el control problemático es el grupo, si se pudiera hacer "no transparente"... De todas maneras pasa con otros controles, como digo los Picture tampoco van nada bien...

Código: Seleccionar todo

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Global $CoordGUI, $btnCerrar
$CoordGUI = GUICreate("Gui feo", 252, 230, -1,-1, BitOR($GUI_SS_DEFAULT_GUI, $WS_CLIPCHILDREN))

;~ GuiCtrlCreateLabel("", 0,0,252,230)
;~ GuiCtrlSetState(-1, $GUI_DISABLE)

GUICtrlCreateGroup("El título del grupo", 5, 9, 241, 180)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("UTM, huso 31:", 24, 39, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 59, 30, 17)
GUICtrlCreateInput("", 59, 55, 81, 21)
GUICtrlCreateInput("", 144, 55, 81, 21)
GUICtrlCreateLabel("UTM, huso 30:", 24, 103, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 123, 30, 17)
GUICtrlCreateInput("", 59, 119, 81, 21)
GUICtrlCreateInput("", 144, 119, 81, 21)
$btnCerrar = GUICtrlCreateButton("Cerrar", 190, 195, 50, 25)

GUISetState(@SW_SHOW)

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE, $btnCerrar
			ExitLoop
	EndSwitch
WEnd

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 26 Ago 2010, 17:52
por Chefito
Pufffffff......desconocía este fallo.
Después de mucho probar, apenas he conseguido nada :smt024 :smt021 .
He intentado darle los estilos con api, y el resultado era el mismo o peor. He refrescado la ventana y nada :smt013 . He hecho más cosas que ni me acuerdo jajajajaja. Al final he encontrado dos soluciones (creo).

La primera utilizando la api _WinAPI_SetLayeredWindowAttributes para controlar la transparencia de la ventana. He tenido que asignar los estilos a la ventana justo después de mostrarla para que no haga cosas raras (colorear el group de negro):

Código: Seleccionar todo

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WINAPI.au3>

Global $CoordGUI, $btnCerrar
$CoordGUI = GUICreate("Gui feo", 252, 230,-1,-1,-1,$WS_EX_LAYERED)

$group=GUICtrlCreateGroup("El título del grupo", 5, 9, 241, 180)
GUICtrlSetFont(-1, -1, 800)
$hgroup=GUICtrlGetHandle($group)
GUICtrlCreateLabel("UTM, huso 31:", 24, 39, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 59, 30, 17)
GUICtrlCreateInput("", 59, 55, 81, 21)
GUICtrlCreateInput("", 144, 55, 81, 21)
GUICtrlCreateLabel("UTM, huso 30:", 24, 103, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 123, 30, 17)
GUICtrlCreateInput("", 59, 119, 81, 21)
GUICtrlCreateInput("", 144, 119, 81, 21)
$btnCerrar = GUICtrlCreateButton("Cerrar", 190, 195, 50, 25)
_WinAPI_SetLayeredWindowAttributes($coordgui,0,255,2)
GUISetState(@SW_SHOW)
GUISetStyle(BitOR($GUI_SS_DEFAULT_GUI, $WS_CLIPCHILDREN))

While 1
   Switch GUIGetMsg()
   Case $GUI_EVENT_CLOSE, $btnCerrar
         ExitLoop
   EndSwitch
WEnd
Otra es cambiando los estilos siempre que se redibuje la ventana. Puede que parezca algo chapucera, pero parece que funciona perfectamente :smt005 :

Código: Seleccionar todo

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Global $CoordGUI, $btnCerrar
$CoordGUI = GUICreate("Gui feo", 252, 230)

GUIRegisterMsg($WM_PAINT, "MY_WM_PAINT")

$group=GUICtrlCreateGroup("El título del grupo", 5, 9, 241, 180)
$hgroup=GUICtrlGetHandle($group)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("UTM, huso 31:", 24, 39, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 59, 30, 17)
GUICtrlCreateInput("", 59, 55, 81, 21)
GUICtrlCreateInput("", 144, 55, 81, 21)
GUICtrlCreateLabel("UTM, huso 30:", 24, 103, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 123, 30, 17)
GUICtrlCreateInput("", 59, 119, 81, 21)
GUICtrlCreateInput("", 144, 119, 81, 21)
$btnCerrar = GUICtrlCreateButton("Cerrar", 190, 195, 50, 25)
GUISetState(@SW_SHOW)

While 1
   Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE, $btnCerrar
         ExitLoop
   EndSwitch
WEnd

Func MY_WM_PAINT($hWnd, $Msg, $wParam, $lParam)
  	GUISetStyle($GUI_SS_DEFAULT_GUI) 
	GUISetStyle($WS_CLIPCHILDREN+$GUI_SS_DEFAULT_GUI)
    Return $GUI_RUNDEFMSG
EndFunc
No se si funcionaran bien con el control ActiveX. Pruebalo y me cuentas.

Por cierto, a mi lo de el label desactivado me va bien. Lo único que cambia el aspecto de los labels, le quita los bordes de profundidad (los deja planos).

Saludos.

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 27 Ago 2010, 09:24
por Ximorro
¡Gracias por la ayuda, es un tema complicado!

Buf, yo también intenté a base de InvalidateRect, RedrawWindow y compañía, con varios tipos de estilos... Perdona no haberlo dicho, son cosas que he ido probando después, pero no me ha funcionado nada.
No se me ocurrió cambiar el estilo DESPUÉS de creado el formulario, como la ayuda decía "will only be visible if the Windows style $WS_CLIPCHILDREN has been used in GUICreate()" ni se me ocurrió. A ver...

¡CASI! ¡CASI!... En principio parece que funciona, aunque si minimizas, cuando restauras vuelve el fondo negro. Veo que registras WM_PAINT pero no hay función correspondiente, ¿es un resto de otra prueba o realmente falta la función? Quizás haciendo ahí que repinte... he puesto un invalidaterect por si lo fuerza y nada...
También he probado a poner el WS_CLIPCHILDREN antes del @SW_SHOW, pero tampoco.
Curiosidad: ¿qué hace ese SetLayeredWindowAttributes?

Y si pongo la etiqueta de fondo me sigue fallando igual (cosa que no hace sin el ClipChildren) No es sólo que quite el borde de los Input (no de los label), es que si pasas el cursor del ratón por encima de ellos esos bordes van apareciendo... hasta que minimizas y restauras...

Hummm, el segundo ejemplo es equivalente a no tener el WS_CLIPCHILDREN, aunque lo ponga después de pintar: no hace el fondo negro pero parpadea un montón por ejemplo cuando estoy escribiendo en los texboxes parpadean otros y el contenido del ControlObject se borra temporalmente, también manejando el ControlObject a veces desaparecen otros controles.
Vaya, que aunque ciertamente lo pones en cada repintado es como si no estuviera puesto el CLIPCHILDREN, igual es que ahí no tiene efecto cambiar el estilo... o realmente esto de cambiar ese estilo no se puede hacer donde te dé la gana, por eso decían en la ayuda lo de ponerlo en GuiCreate (aunque el primer ejemplo casi va, pero se pone al principio y no se vuelve a tocar...)

He probado a mezclar las dos opciones... ¡NO LO HAGÁIS!, no ha salido el GUI y se ha puesto a repintar TODAS las ventanas del todos los programas que tengo abiertos, ni el administrador de tareas funcionaba, he tenido que resetear...

Por ahora tendrá que quedarse lo del label (o un Picture, pero requiere una imagen y encima hace lo mismo que el label con los bordes de los Input). He intentado poner un fondo con un CreateGraphic, pero también sale negro. :smt010

Estoy probando otra opción que no soluciona realmente el problema de las transparencias: no poner controles transparentes. :smt013
Si no pongo los Group no pasan cosas feas, claro. Entonces para poner el marco pongo 4 labels, dos con SS_ETCHEDHORZ y otros dos con SS_ETCHEDVERT (¡sólo uno con SS_ETCHEDFRAME no vale porque por lo visto el centro es transparente y sale negro!), y luego un label normal para el título, tapando parte del SS_ETCHEDHORZ superior. Otra opción para el marco es usar sólo uno con SS_SUNKEN, el efecto no queda tan bonito pero no es trasparente y sí pinta bien.

Pero cualquier cosa que se quiera transparente, por ejemplo un simple label, saldrá negro...
En mi caso aún tiene pase, pues los GROUP son para hacer el marco bonito con su título y tal, así que puedo montarlo de otras maneras, como con los labels esos, pero los GROUP también se usan para argupar checkboxes y que sólo haya uno seleccionado, eso no se podría usar con WS_CLIPCHILDREN...

Buf, complicado, por ahora paso de los controles Group y lo simulo con lo de los labels "marco", pero el tema WS_CLIPCHILDREN y controles de fondo transparente realmente queda abierto...

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 27 Ago 2010, 16:01
por Chefito
Pufffff.....una pena. Ese estilo es muy follonero. Parece que desajusta todas las transparencias. No probaría lo de minimizarla en el primer ejemplo :smt012 .
Ximorro escribió:Veo que registras WM_PAINT pero no hay función correspondiente, ¿es un resto de otra prueba o realmente falta la función?
Un resto de hacer pruebas. No me dí cuenta de quitarlo :smt020 .
Ximorro escribió:¿qué hace ese SetLayeredWindowAttributes?
Maneja la transparencia de una ventana. Puede transparentar toda la ventana o condicionarla para que haga transparente un color de ésta. Los valores de transparencias van del 0 (transparente total) a 255 (opaca total).
Ximorro escribió:Por ahora tendrá que quedarse lo del label (o un Picture, pero requiere una imagen y encima hace lo mismo que el label con los bordes de los Input). He intentado poner un fondo con un CreateGraphic, pero también sale negro.
También sale negro? juer. Si no saliese negro se hubiese podido hacer el marco con esto :smt013 . Has probado a poner un rectangulo con el fondo rellenado de un color? ($GUI_GR_COLOR). Luego lo miraré yo a ver como va.
Piensa que también tienes las funciones gdi+ para hacer gráficos e imágenes. Intentalo con éstas. Puede que al hacerlo directamente con apis funcione de otra forma. Aunque visto lo visto, lo dudo :smt012 .

Se me ocurrió otra idea. No se si funcionaría. Es intentar mandarle un mensaje al control con la propiedad adecuada (si existe) para rellenar el fondo de un determinado color.

Si me pasas el código completo con lo que te pasa eso lo miraré mejor. Ya que dices que pasa con todos los controles activex, luego le meteré alguno a ver que tal.

Saludos.

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 27 Ago 2010, 18:16
por Chefito
Si es por intentar hacer un recuadro............te voy a dar una solución (creo) :smt005 .

He probado a recuadrar con gdi+ y parece que funciona :smt002 .
Le he puesto un recuadro sin rellenar y otro relleno comentado por si quieres ver el efecto. Si quieres cambiar colores y grosor de la línea, mira las funciones pen que son muy fáciles de cambiar.
He intentado hacer transparentes los labels y, como no!, he tenido problemas por culpa de ya sabes que estilo :smt005 .
Igualmente, si quieres dibujar texto, recuerda que también lo puedes hacer con gdi+ sin mucha dificultad :smt002 .

He tenido que poner un sleep(1) porque al minimizar y luego restaurar no se dibujaba el recuadro. Por lo visto no le daba tiempo o algo así tiene que ser. No creo que afecte casi nada al programa y al redibujado. Apenas es tiempo.

Lo que pasa que esto no soluciona el problema general con las transparencias, pero para este caso te puede servir como sustituto al group :smt001 .

Código: Seleccionar todo

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#Include <GDIPlus.au3>

Global $CoordGUI, $btnCerrar

$CoordGUI = GUICreate("Gui feo", 252, 230,-1,-1,BitOR($GUI_SS_DEFAULT_GUI, $WS_CLIPCHILDREN))

;Inicio el GDI+ y creo el pen o el brush 
_GDIPlus_Startup ()
$hGraphic = _GDIPlus_GraphicsCreateFromHWND ($coordGUI)

$hPen = _GDIPlus_PenCreate ()
_GDIPlus_PenSetWidth($hPen,2)
_GDIPlus_PenSetColor($hPen,0xffff0000)	;pen rojo

;~ $hbrush=_GDIPlus_BrushCreateSolid(0xffff0000)

GUICtrlCreateLabel(" El título del grupo", 20, 3,112,20)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("UTM, huso 31:", 24, 39, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 59, 30, 17)
GUICtrlCreateInput("", 59, 55, 81, 21)
GUICtrlCreateInput("", 144, 55, 81, 21)
GUICtrlCreateLabel("UTM, huso 30:", 24, 103, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 123, 30, 17)
GUICtrlCreateInput("", 59, 119, 81, 21)
GUICtrlCreateInput("", 144, 119, 81, 21)
$btnCerrar = GUICtrlCreateButton("Cerrar", 190, 195, 50, 25)
GUISetState(@SW_SHOW)

_GDIPlus_GraphicsDrawRect ($hGraphic, 5, 9, 241, 180, $hPen)
;~ _GDIPlus_GraphicsFillRect($hGraphic, 5, 9, 241, 180, $hbrush)	;si pones comentada la línea de arriba, la línea del evento paint y la parte del pen, descomenta esta, la del evento paint y la parte del brush

GUIRegisterMsg($WM_PAINT, "MY_WM_PAINT")

While 1
   Switch GUIGetMsg()
   Case $GUI_EVENT_CLOSE, $btnCerrar
         ExitLoop
   EndSwitch
WEnd

_GDIPlus_PenDispose($hPen)
;~ _GDIPlus_BrushDispose($Brush)
_GDIPlus_GraphicsDispose($hGraphic)
_GDIPlus_ShutDown ()

Func MY_WM_PAINT($hWnd, $Msg, $wParam, $lParam)
	Sleep(1)	;este retardo lo he tenido que poner porque había problemas para que se dibujase el rectángulo al minimizarse y restaurarse.
_GDIPlus_GraphicsDrawRect ($hGraphic, 5, 9, 241, 180, $hPen)
;~ _GDIPlus_GraphicsFillRect($hGraphic, 5, 9, 241, 180, $hbrush)
    Return $GUI_RUNDEFMSG
EndFunc
Saludos.

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 30 Ago 2010, 09:02
por Ximorro
Hombre, te puedo pasar el código completo, pero son más de 1200 líneas...

¡Mola lo de recuadrar con GDI!
La verdad es que ofrece bastantes posibilidades, aunque de GDI no tengo muchos conocimientos, y debo reconocer que no me meto mucho con ello porque le tengo un poco de manía :smt003
Eso de que para cambiar un color de algo tienes que hacer un objeto Pen cada vez y cosas así, me parece tan engorroso estar generando y destruyendo tantos objetos para cosas simples, en vez de funcionar con propiedades de objetos más complejos...

Pero vaya, volviendo a la solución me mola el recuadro, pintado no es tan interesante por lo de las etiquetas no transparentes, aunque es cierto que se podrían poner los textos también en GDI+

Lo que no me gusta mucho del GDI+ es que no puedes pintar en el fondo "y dejarlo ahí", eso de tener que estar repintando en cada WM_PAINT parece un gasto fuerte de recursos, y aquí sólo hay un recuadro pero si empiezas a poner más cositas como textos...

Por cierto, que a mí me va perfectamente sin el Sleep :smt017

Pero vaya, efectivamente soluciones alternativas se pueden encontrar, el problema será cuando realmente se necesiten transparencias, como un GROUP para agrupar checkboxes.
Creo que cuando no sea salvable la solución será tener dos formularios diferentes, el ActiveX podría estar en un formulario diferente pegado por software al padre. El problema es que se ve que son dos ventanas, pero bueno... se podría hacer una ventana sin barra de título y hacer una hija simulada WS_EX_MDICHILD, y "pegarla" dentro de un espacio vacío dentro del formulario inicial (que no tiene por qué tener el CLIPCHILDREN), parecido a lo que hice con la segunda imagen en el truco de la animación día-noche (http://www.emesn.com/autoitforum/viewto ... f=5&t=1847) pero en vez de mezclar con transparencias simplemente se pondría sobre un espacio vacío...
Vaya, creo que esto puede funcionar, lo probaré...

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 31 Ago 2010, 00:39
por Chefito
Ximorro escribió:Eso de que para cambiar un color de algo tienes que hacer un objeto Pen cada vez y cosas así, me parece tan engorroso estar generando y destruyendo tantos objetos para cosas simples, en vez de funcionar con propiedades de objetos más complejos...
Jejejeje....a mi tampoco me va mucho, pero no es para tanto. Al final te acabas acostumbrando. Y en este caso, solamente utilizas 2 objetos. No son muchos comparados con otros programa como los juegos :smt002 . Pero si te solucionan el problema merece la pena utilizarlo. Te aseguro es más profesional y menos engorroso que ir haciendo labels para intentar recuadrar u otros sistemas que a la larga se complican mucho más :smt003 .
Por cierto, me has recordado que no destruyo los objetos al finalizar....se me olvidó :smt005 . Voy a corregirlo :smt002 .
Ximorro escribió:Lo que no me gusta mucho del GDI+ es que no puedes pintar en el fondo "y dejarlo ahí", eso de tener que estar repintando en cada WM_PAINT parece un gasto fuerte de recursos, y aquí sólo hay un recuadro pero si empiezas a poner más cositas como textos...
No hay más remedio. Tienes que repintarlo para que no desaparezca. No lo trata internamente como otros objetos.
Nada nada. Aunque pongas textos y más recuadros no pasa nada. Mira los juegos que hacen en autoit. Esos tienen que estar refrescando gráficos y, peor aun, imágenes continuamente y van de lujo :smt003 .
Y lo de que gasta recursos.....no creo que gaste apenas nada. Unos recuadros y unos texto? Eso no es nada :smt005 . Esas funciones están ahí para eso y mucho mucho mucho mucho más :smt005 .
Ximorro escribió:Por cierto, que a mí me va perfectamente sin el Sleep
Pues si yo se lo quito, no me va en ninguno de mis dos ordenadores :smt017 . Será por que mis ordenadores son una antiguallas??? :smt005 . Lo he probado en un amd 1300 y en un p4 a 2400.
Ximorro escribió:Pero vaya, efectivamente soluciones alternativas se pueden encontrar, el problema será cuando realmente se necesiten transparencias, como un GROUP para agrupar checkboxes.
No hay ningún problema con esto. Si quieres agrupar controles, los agrupas con un group oculto y ya está. Luego si quieres recuadrar, lo haces con gdi y solucionado.
Ximorro escribió:Creo que cuando no sea salvable la solución será tener dos formularios diferentes, el ActiveX podría estar en un formulario diferente pegado por software al padre. El problema es que se ve que son dos ventanas, pero bueno... se podría hacer una ventana sin barra de título y hacer una hija simulada WS_EX_MDICHILD, y "pegarla" dentro de un espacio vacío dentro del formulario inicial (que no tiene por qué tener el CLIPCHILDREN), parecido a lo que hice con la segunda imagen en el truco de la animación día-noche (viewtopic.php?f=5&t=1847) pero en vez de mezclar con transparencias simplemente se pondría sobre un espacio vacío...Vaya, creo que esto puede funcionar, lo probaré...
Jejejeje......pues sí, pruebalo a ver que tal te sale :smt002 . Te recuerdo que en su día demostré que en autoit se podía hacer mdi de verdad utilizando alguna api que otra. La dirección es http://www.emesn.com/autoitforum/viewto ... =mdi#p6808.

Saludos.

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 31 Ago 2010, 08:35
por Ximorro
Hombre, lo de los labels queda en principio más bonito que lo que pueda hacer en GDI con un sólo recuadro, para simular el efecto 3D de los bordes pues hay que ir currándoselo a base de unas cuantas líneas (que no digo que no se pueda, sino que es un poco más rollo).
Pero si es muy complicado es que parece que tener un gestor de WM_PAINT larguísimo tiene que hacer las cosas bastante lentas. Y tú aún creas el PEN o el BRUSH al principio, pero si tienes que estar haciendo objetos de diferentes colores he visto que lo normal es ir creándolos al vuelo (y destruyéndolos al final de la función). ¡Luego nos quejamos de leaks y fragmentación de memoria! :smt003
Tengo que ver alguno de esos juegos...

Como es algo fijo... ¿se podría crear un bitmap con el fondo resultante, y al actualizar pegar el bitmap en vez de volver a dibujar las líneas, textos, etc...?
Bueno, la respuesta tengo bastante clara que es que sí, ahora la del millón... ¿se podría crear ese bitmap en memoria y asignarlo a un control? quizás un Picture, un botón no pinchable, un Icon o algo así. Lo ideal sería hacerlo todo en memoria, y vaya, si es necesario supongo que se puede guardar un archivo temporal, pero molaría hacerlo en memoria...
De esa manera el control no hay que estar repintándolo a mano, es como tener un Picture de fondo, lo creas al principio y te olvidas.

Sí, ya sé que se pueden hacer MDI reales (y por cierto tu ejemplo es impresionante al insertar ventanas de otros programas), pero dije lo de la simulada para que no dependa realmente de la otra, para que tenga sus estilos de ventana y que no colisionen con la "padre". Además no es una ventana flotante que mueves dentro del padre, el objetivo es que parezca un control como cualquier otro, pero realmente es una ventana sin título ni borde que se queda fija dentro de la principal, vaya, visualmente un control... ¡pero independiente! :smt002

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 31 Ago 2010, 12:34
por Chefito
Ximorro escribió:Como es algo fijo... ¿se podría crear un bitmap con el fondo resultante, y al actualizar pegar el bitmap en vez de volver a dibujar las líneas, textos, etc...?
Bueno, la respuesta tengo bastante clara que es que sí, ahora la del millón... ¿se podría crear ese bitmap en memoria y asignarlo a un control? quizás un Picture, un botón no pinchable, un Icon o algo así. Lo ideal sería hacerlo todo en memoria, y vaya, si es necesario supongo que se puede guardar un archivo temporal, pero molaría hacerlo en memoria...
De esa manera el control no hay que estar repintándolo a mano, es como tener un Picture de fondo, lo creas al principio y te olvidas.
Como tu bien te respondes a la primera pregunta, sí :smt002 .
La segunda es también que sí. Para empezar, gdi+ tiene funciones que transforman los gráficos en imágenes (_GDIPlus_BitmapCreateFromGraphics). Seguro que hay más métodos.
También puedes guardar la imagen en un archivo aparte y trabajar con ella con gdi+. Y recuerda que se puede meter el código binario de la imagen en el propio script para luego cargarla en memoria, y así poder trabajar con ella con gdi+.
Seguro que hay más posibilidades. Es cuestión de saberlas...claro :smt005 .

Te digo otra cosa. No puedes comparar en ningún momento las chapucillas que se pueden hacer con objetos, con todo lo que se puede hacer con gdi+. Yo hice solo un simple marco, pero puedes hacer verdaderos efectos :smt002 .
Todo es, como muchas veces, según te quieras complicar :smt003 .

Respecto a meter una imagen en un control...claro que se puede. Incluso puede que te interese poner una imagen directamente en el gui sin necesidad de utilizar un control. Yo por ejemplo, hace mucho tiempo introduje en un control listbox una imagen de fondo. Creo recordar que en su día lo hice enviando un mensaje con sendmessage a la propiedad (imagen de fondo) del control adecuado. Seguro que se puede hacer de más formas :smt003 .

Saludos.

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 01 Sep 2010, 08:17
por Ximorro
BUF, ¡Odio, odio a Peter Pan! digoooooooooo ¡a GDI!

Menudo cacao me he metido, he intentado dibujar en un GraphicsControl (sin WS_CLIPCHILDREN que si no sale negro), o un label o un Picture. La idea era que no hiciera falta hacer el repintado en el WM_PAINT, pero da igual, ni repintando en el WM_PAINT me sale.

Seguro que no es tan complicado, pero odio el sistema de GDI, que si handlers, que si contextos, que si imágenes... y luego hay que liberarlo todo, ¿para qué hay que liberar un handler a una imagen y también la imagen. Si uno fuera la propiedad del otro qué fácil sería todo...

Bueno, esto es lo que he hecho, pero no consigo dibujar, creo que no capto la filosofía GDI. Como digo la idea era incluso evitar el WM_PAINT, pero ni con esas...

Código: Seleccionar todo

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#Include <GDIPlus.au3>

Opt("MustDeclareVars", 1)

Global $CoordGUI, $btnCerrar

$CoordGUI = GUICreate("Gui feo", 252, 230,-1,-1, BitOR($GUI_SS_DEFAULT_GUI, $WS_CLIPCHILDREN))

_GDIPlus_StartUp()
Global $pic, $hBrush, $hGraphic, $hBmp, $hBmpGraphics, $hImage
;$pic = GUICtrlCreateGraphic(0,0, 252,230) ;No se puede usar con WS_CLIPCHILDREN porque tiene fondo transparente
$pic = GUICtrlCreateLabel("",0,0, 252,230) ;Con WS_CLIPCHILDREN usamos por ejemplo un Label o un Picture vacío
GuiCtrlSetState(-1, $GUI_DISABLE)
$hBrush =_GDIPlus_BrushCreateSolid(0xffff0000)
$hGraphic = _GDIPlus_GraphicsCreateFromHWND(GUICtrlGetHandle($pic))
$hBmp = _GDIPlus_BitmapCreateFromGraphics(220,200, $hGraphic) ;devuelve un handle al bitmap, no el bitmap
$hBmpGraphics = _GDIPlus_ImageGetGraphicsContext($hBmp) ;contexto para dibujar
_GDIPlus_GraphicsFillRect($hBmpGraphics, 5, 9, 241, 180, $hBrush)
$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBmp) ;creamos una imagen a partir del handle al bitmap

GUICtrlCreateLabel(" El título del grupo", 20, 3,112,20)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("UTM, huso 31:", 24, 39, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 59, 30, 17)
GUICtrlCreateInput("", 59, 55, 81, 21)
GUICtrlCreateInput("", 144, 55, 81, 21)
GUICtrlCreateLabel("UTM, huso 30:", 24, 103, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 123, 30, 17)
GUICtrlCreateInput("", 59, 119, 81, 21)
GUICtrlCreateInput("", 144, 119, 81, 21)
$btnCerrar = GUICtrlCreateButton("Cerrar", 190, 195, 50, 25)

GUISetState(@SW_SHOW)

GUIRegisterMsg($WM_PAINT, "MY_WM_PAINT")

While 1
	Switch GUIGetMsg()
	Case $GUI_EVENT_CLOSE, $btnCerrar
		ExitLoop
	EndSwitch
WEnd

_GDIPlus_ImageDispose($hImage)
; ¿Habrá que liberar de alguna manera el contexto del bitmap, $hBmpGraphics?
_WinAPI_DeleteObject($hBmp)
_GDIPlus_GraphicsDispose($hGraphic)
_GDIPlus_BrushDispose($hBrush)
_GDIPlus_ShutDown ()

Func MY_WM_PAINT($hWnd, $Msg, $wParam, $lParam)
	Sleep(1)
	_GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0)
	Return $GUI_RUNDEFMSG
EndFunc

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 02 Sep 2010, 01:15
por Chefito
Jejejeje....que lio el gdi+ eehhhh..... :smt005 .
He tocado un poco el código :smt024 . No se si es lo que te voy a poner lo que quieres (supongo que sí :smt002 ).
Te faltaba una función para dibujar la imagen (_GDIPlus_GraphicsDrawImageRect) :smt003 .
Ten cuidado y dibuja después de mostrar la ventana, si no lo haces así no se dibujará.

Por supuesto tendrás que redibujar. Eso es inevitable.
Con este código redibujas una imagen (en este caso contiene un gráfico) y no un gráfico.
He creado la imagen en el gui para que se mantenga en el fondo. Si lo haces en el label (y creo recordar que en cualquier otro control) se te irá para alante. No me preguntes porque, ya que lo desconozco. No se si habrá algún método para hacer que se queden en el fondo :smt017 . Aunque supongo que da igual crearla en el gui que en un control, no? :smt002 .

Código: Seleccionar todo

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#Include <GDIPlus.au3>

Opt("MustDeclareVars", 1)

Global $CoordGUI, $btnCerrar

$CoordGUI = GUICreate("Gui feo",252, 230,-1,-1, BitOR($GUI_SS_DEFAULT_GUI, $WS_CLIPCHILDREN))

Global $pic, $hBrush, $hGraphic, $hBmp, $hBmpGraphics, $hImage

;$pic = GUICtrlCreateGraphic(0,0, 252,230) ;No se puede usar con WS_CLIPCHILDREN porque tiene fondo transparente
;~ $pic = GUICtrlCreateLabel("",0,0, 200,200) ;Con WS_CLIPCHILDREN usamos por ejemplo un Label o un Picture vacío
;~ GuiCtrlSetState(-1, $GUI_DISABLE)
GUICtrlCreateLabel(" El título del grupo", 20, 3,112,20)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("UTM, huso 31:", 24, 39, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 59, 30, 17)
GUICtrlCreateInput("", 59, 55, 81, 21)
GUICtrlCreateInput("", 144, 55, 81, 21)
GUICtrlCreateLabel("UTM, huso 30:", 24, 103, 101, 14)
GUICtrlSetFont(-1, -1, 800)
GUICtrlCreateLabel("X,Y =", 26, 123, 30, 17)
GUICtrlCreateInput("", 59, 119, 81, 21)
GUICtrlCreateInput("", 144, 119, 81, 21)
$btnCerrar = GUICtrlCreateButton("Cerrar", 190, 195, 50, 25)

_GDIPlus_StartUp()
$hGraphic = _GDIPlus_GraphicsCreateFromHWND($coordgui);GUICtrlGetHandle($pic))
$hBmp = _GDIPlus_BitmapCreateFromGraphics(220,200, $hGraphic) ;devuelve un handle al bitmap, no el bitmap
$hBmpGraphics = _GDIPlus_ImageGetGraphicsContext($hBmp) ;contexto para dibujar
;_GDIPlus_GraphicsSetSmoothingMode($hBmpGraphics,  2)
$hBrush =_GDIPlus_BrushCreateSolid(0xffff0000)
_GDIPlus_GraphicsFillRect($hBmpGraphics, 5, 9, 241, 180, $hBrush)

GUISetState(@SW_SHOW)

_GDIPlus_GraphicsDrawImageRect($hGraphic,  $hBmp, 0, 0, 240, 200)

GUIRegisterMsg($WM_PAINT, "MY_WM_PAINT")

While 1
   Switch GUIGetMsg()
   Case $GUI_EVENT_CLOSE, $btnCerrar
      ExitLoop
   EndSwitch
WEnd

_GDIPlus_ImageDispose($hImage)
; ¿Habrá que liberar de alguna manera el contexto del bitmap, $hBmpGraphics?
_WinAPI_DeleteObject($hBmp)
_GDIPlus_GraphicsDispose($hGraphic)
_GDIPlus_BrushDispose($hBrush)
_GDIPlus_ShutDown ()

Func MY_WM_PAINT($hWnd, $Msg, $wParam, $lParam)
   Sleep(1)
	_GDIPlus_GraphicsDrawImageRect($hGraphic,  $hBmp, 0, 0, 240, 200)
   Return $GUI_RUNDEFMSG
EndFunc
Saludos.

Re: Problemas con WS_CLIPCHILDREN y pintado de formulario

Publicado: 02 Sep 2010, 09:49
por Ximorro
:smt013 ¿Y por qué se pone delante?
Sí, con ese problema me había encontrado al poner una imagen externa (al crearla con _GDIPlus_ImageLoadFromFile es todo mucho más fácil). Pues no había visto _GDIPlus_GraphicsDrawImageRect, pero sí _GDIPlus_GraphicsDrawImage (sin el "Rect") y con eso funcionaba.
¿Prefieres usar GraphicsDrawImageRect?, si se deja el tamaño original da lo mismo ¿no?... porque entiendo que eso escala la imagen, no hace clipping...

El lío fue al intentar crear un bitmap a partir del control para pintar en él, como veo no estaba tan lejos, me sobraba el _GDIPlus_BitmapCreateFromHBITMAP, y es que entendía que como $hBmp era un handler teníamos que extraer el bmp para pasárselo al GraphicsDrawImage, vi mal la función ¡menudo lío! :smt017

Pero mi gozo en un pozo, porque mi objetivo era tenerlo en un control que se refrescara "solo", al modificar su canvas, y no tener que estar actualizando en cada WM_PAINT, pero por lo visto es necesario siempre... ¡y encima no se puede poner en un control porque entonces sale delante!

¿Por qué si estoy dibujando en el control no respeta la posición de dicho control? Si ese control está detrás de todo, ¡detrás debería quedarse su dibujo!
Además, entiendo que WM_PAINT se envía cuando hay una petición de repintado, pero aún no se ha pintado, con lo que lo que pintemos ahí debería quedarse debajo, si al continuar el tratamiento de mensaje de Windows luego pinta lo demás... no entiendo...
Por cierto, que si registras WM_PAINT antes del GUISetState(@SW_SHOW) no hace falta hacer el primer dibujado, ya usa el del mensaje.

Se me ha ocurrido que quizás se pueda hacer con otro tipo de mensajes, en vez de usar el repintado general del formulario se podía mirar el del control, así guardará el orden con otros controles que pueda pintar encima... he encontrado un ejemplo en la ayuda de la función GUIRegisterMsg, donde crean un botón personalizado que dibujan manualmente... ¡¡¡¡pero es MUUUUUY complicado!!!! Además parece que sólo va con botones, porque ese flag BS_OWNERDRAW parece específico para botones...