PDA

Ver la Versión Completa : Parent, ParentWindow, objetos y el error Control has no parent Window


dec
06-08-2007, 14:07:47
Hola,

Houston, we have a problem. O sea, vente con la caja-herramientas Pepe que la hemos liado. Rápido. Venga. Vamos. Dale. Ya tenías que estar aquí, Pepe. Pero, creo que me estoy yendo por las ramas... pido disculpas y sigo adelante a ver si soy capaz de centrar el asunto que me preocupa y me está causando problemas y alguna cana tal vez. La madre que lo parió.

La verdad es que no sé cómo explicarlo bien. Por eso he tratado de montar "algo" para reproducir el problema, de modo que vosotros mismos podáis ver dicho problema con vuestros propios ojos. El problema se da con otros componentes, y en otra situación, pero, al cabo creo que he conseguido el mismo error, es decir, reproducir este.

En el archivo adjunto (proyecto de pruebas) lo veréis más claro, pero, básicamente se trata de lo siguiente:

1º Es menester crear un objeto dentro de una determinada ventana cuyo "Handle" conocemos

2º No puede usarse su propiedad "Parent", sino que hay que recurrir a "ParentWindow"

3º El objeto que hay que crear contiene a su vez un objeto en su interior

4º Este segundo objeto (dentro del primero) está al tanto del ratón, y, cuando se hace clic sobre el objeto, se hace una llamada a "SetFocus"

5º Es esta llamada a "SetFocus" la que "levanta" el error, puesto que dicho objeto "embebido" en el otro "No has parent Window"...

Ayer estuve varias horas intentando dar con una solución. Busqué mucho por Internet, y encontré bastante información, pero, nada clara (para mí) y, todo lo que intenté fue un fracaso, no funcionó.

Hoy he conseguido montar esta especie de "escenario" para poder probar el asunto más claramente, puesto que creo que si se consigue una solución para el problema en este escenario (ver archivo adjunto) la misma será válida también para cualquier otro similar.

No sé. A ver si me podéis echar una mano. No corre prisa alguna, empero, agradecería cualquier comentario acerca de qué puede estar pasando. Seguro que hay gente aquí mucho más experimentada que yo en estos menesteres. En todo caso muchas gracias a todos por la atención. De verdad. De la buena. Muchas gracias de antemano.

eduarcol
06-08-2007, 14:42:12
Amigo no se si a los demas tambien, pero a mi no me deja descargar el adjunto

seoane
06-08-2007, 14:52:15
Y por que en vez de usar Create no usas CreateParented.

Es decir:

FEmbeddedPanel := TEmbeddedPanel.CreateParented(Self.Handle);

FObjectPanel := TObjectPanel.CreateParented(Self.Handle);

dec
06-08-2007, 14:53:13
Hola,

Vaya. Es cosa de los permisos de usuario. Sé que no es lo mismo, porque tendrás que hacer un esfuerzo más, pero, aquí está el código fuente del asunto. Tienes que incluirlo en el formulario principal de un proyecto nuevo de Delphi, creo que me entiendes.


unit UMainFrm;

interface

uses
Forms, StdCtrls, ExtCtrls, Classes, Controls;

type
TEmbeddedPanel = class(TPanel)
protected
procedure MouseDown(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); override;
end;

type
TObjectPanel = class(TPanel)
private
FEmbeddedPanel: TEmbeddedPanel;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy(); override;
end;

type
TmainFrm = class(TForm)
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FObjectPanel: TObjectPanel;
end;

var
mainFrm: TmainFrm;

implementation

{$R *.dfm}

{ TEmbeddedPanel }

procedure TEmbeddedPanel.MouseDown(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
inherited;
SetFocus();
end;

{ TObjectPanel }

constructor TObjectPanel.Create(AOwner: TComponent);
begin
inherited;
FEmbeddedPanel := TEmbeddedPanel.Create(self);
InsertControl(FEmbeddedPanel);
Self.Top := 10;
Self.Left := 10;
Self.Width := 100;
Self.Height := 100;
with FEmbeddedPanel do
begin
Top := 10;
Left := 10;
Width := 50;
Height := 50;
end;
end;

destructor TObjectPanel.Destroy();
begin
FEmbeddedPanel.Free();
inherited;
end;

{ TmainFrm }

procedure TmainFrm.FormCreate(Sender: TObject);
begin
FObjectPanel := TObjectPanel.Create(nil);
FObjectPanel.ParentWindow := self.Handle;
end;

procedure TmainFrm.FormDestroy(Sender: TObject);
begin
FObjectPanel.Free();
end;

end.

dec
06-08-2007, 14:54:25
Hola,

Gracias por tu respuesta Domingo. Juraría que he probado con "CreateParented", pero, como no estoy seguro de haberlo hecho con todos los componentes implicados, voy a hacerlo ahora mismo sobre el "escenario de pruebas" y, si funciona, lo haré en la aplicación real en que tiene que ir bien.

Ahora mismo cuento lo que sea. Gracias de nuevo. :)

dec
06-08-2007, 15:07:00
Hola,

Vale. No funciona del todo bien Domingo. De hecho creo que ya probé con ello, lo que pasa es que he probado ya tantas cosas que ni me acuerdo... lo digo en serio.

Ahora bien, en el ejemplo, efectivamente, puedes usar el "CreateParented" y el error no aparece. Sin embargo, si el panel de ejemplo "usara" tuviera que responder al teclado me temo que no lo haría.

¿Me temo? Bueno. No he podido hacer la prueba, pero, sí la he hecho en la aplicación real en que estoy teniendo el problema. Efectivamente, con el "CreateParent" no se da el error, pero, tampoco pueden manejarse el componente con el teclado.

Además, usando el CreateParented se produce una violación de acceso al cerrar la aplicación en una de cuyas ventanas "incrusto" el componente de marras. Bien. Tal vez esto pueda evitarse (tal vez no se prevén las consecuencias del CreateParented).

Pero, como digo, lo que más me "preocupa" de la solución es que aunque no aparece el error que menciono al principio, tampoco el componente es capaz de reaccionar al teclado, con lo que pierde parte de su funcionalidad.

De hecho, y como el problema se produce con sendas llamadas a "SetFocus", yo puedo no hacer estas, es decir, evitarlas, y de este modo todo va perfecto... salvo que el componente no actúa con el teclado... o sea que estaría en las mismas.

En fin. Gracias de todas formas Domingo. A lo mejor el ejemplo que he preparado no sirve muy bien, o habría que hacer algún cambio para comprobar que efectivamente el panel embebido puede actuar con el teclado.

dec
06-08-2007, 15:15:11
Hola,

Soy yo otra vez... qué pesado... Pues nada. Que probando si el panel embebido puede responder al teclado creándose mediante el "CreateParent"... así es. Es decir, que el asunto funciona Domingo, pero, funciona en el ejemplo, no en la aplicación real en que tengo los problemas.

Sigo liado haciendo pruebas. Me **** en la ****. :D :D :D :D

seoane
06-08-2007, 15:15:56
Caramba !!! que costumbre mas fea tienen los usuarios novatos de preguntar una cosa, cuando en realidad quieren saber otra :p :D

De que se trata en realidad, si hace falta podemos recurrir a la api :cool:

eduarcol
06-08-2007, 15:16:07
Dec, acabo de modificar tu codigo

TEmbeddedPanel = class(TEdit)

los create segun dijo seoane y si me funciona con el teclado, o sea pude escribir en el, no se que otra funcionalidad esperas con el teclado, al menos eso fue lo que te entendi


PD. Creo que respondimos los tres a la vez

dec
06-08-2007, 15:18:33
Hola,

... Se trata de que la ventana en que debo crear el objeto está en otra aplicación, hecha en Delphi también (Neobook (http://www.neosoftware.com/)), pero, de la que yo no tengo absoluto control. De hecho el control se crea desde una DLL, es decir, la aplicación real es un plugin, una DLL que Neobook carga para utilizarla.

Respecto de la API... yo he intentado con "FindControl" y "FinWindow", buscando proporcionar un "Parent" (no una "ParentWindow") válido, pero, no ha habido manera. Yo creo que los problemas pasan por el hecho de que el control se crea en y/o desde una DLL. Algo leí ayer mismo sobre esto, pero, chico, ya digo que leí tantas cosas que no me acuerdo de todas exactamente.

Eduardo: Tuvimos la misma idea... yo también usé un TEdit para probar, y, efectivamente, va bien. Y como arriba he dicho (que nos hemos cruzado) puedo también "controlar" el teclado desde el TPanel, con el mensaje de Windows correspondiente, empero,... aunque en el ejemplo todo va bien, en la aplicación "real" no...

Gracias a todos, ¿eh? Que se sepa. :)

seoane
06-08-2007, 15:26:16
Entonces, para que quede claro, tienes el handle de una ventana en la que quieres insertar un TPanel, y dentro de ese TPanel otras cosas (Edits, label, puede que botones, etc ...). ¿Es eso correcto?

dec
06-08-2007, 15:35:56
Hola,

Bueno. Es así y no es así. Verás. En realidad no se trata de paneles, sino de otros componentes. De hecho me dispongo ahora mismo a hacer una prueba con dichos componentes (pero en un proyecto de pruebas, no en la aplicación real), a ver si es que por ahí se averigua algo, puesto que con los paneles... todo parece ir bien.

El asunto es así:

Tengo el Handle de una ventana en que muestro (vía ParentWindow) un componente (no un Panel) que contiene a su vez dos controles más.

El componente en cuestión es el "TSLHColorPicker", que forma parte de la estupenda librería de componentes MXS Color Lib (http://mxs.bergsoft.net/index.php?p=3).

Ahora mismo voy a probar con el "CreateParented" en un proyecto nuevo de Delphi Domingo, de modo que pueda comprobar si dicho componente responde al teclado (como se espera) o qué pasa.

dec
06-08-2007, 15:39:31
Hola,

Comprobado. En un nuevo proyecto de Delphi, creando tanto el componente contenedor como los "subcomponentes" mediante "CreateParented" el asunto funciona, va como se espera, el componente hace caso al teclado y no se produce error alguno.

¿Habré hecho algo mal cuando lo he probado en la aplicación "real"? Voy a ver...

Edito: No; no olvidé nada... no funciona... y además al salir de la aplicación se produce una violación de acceso... ¡Ay!

Más información: La violación de acceso es aleatoria, no se produce siempre... y el control parece que puede tomar el Foco, mediante "SetFocus", empero, no parece responder al teclado... ¡Ay, ay, ay! :D

eduarcol
06-08-2007, 16:30:41
Perdoname por preguntarte esto, pero al mejor cazador se le va la liebre, tienes algun codigo en el keypress???

dec
06-08-2007, 16:34:31
Hola,

Sí; ambos componentes (los controles que "has no window parent") implementan un método "CNKeyDown", que, "captura" el teclado y lleva a cabo determinadas tareas dependiendo de la tecla que se hubiera pulsado. Gracias por tu interés Eduardo.

eduarcol
06-08-2007, 16:42:43
A ver y no has revisado no vaya a ser que en esos eventos estes bloqueando alguna funcionalidad o ejecutando procesos que se queden en memoria, eso explicaria el acces violation

dec
06-08-2007, 16:49:37
Hola,

Pues todo puede ser, porque lo cierto es que estos componentes "pintan" y "repintan" bastante y yo en esto no estoy muy puesto, así que, probablemente, algo raro hay por ahí que se me está escapando completamente.

Sin embargo, el "access violation" sucede cuando creamos los componentes mediante el "CreateParented", pero, si lo hacemos normalmente no se producen "access violation". Eso sí, no se producen "access violation" pero el componente no responde al teclado.

El caso es que el componente funciona y funciona muy bien en Delphi. Digo el componente tal cual "viene", sin retocarlo en absoluto. El problema reside cuando trato de crear dicho componente dentro de una ventana en otra aplicación... y desde una DLL...

Algo se me está escapando, eso está claro. Veremos a ver qué pasa al final. Gracias Eduardo otra vez. :)

dec
06-08-2007, 17:52:35
Hola,

- Y, entonces, dije yo, "podría ser por bla, bla, bla"...

- Y Domingo replicó, "(...) si hace falta podemos recurrir a la api"

- Y digo yo, coñe, pues venga, lo mismo podemos arreglarlo por ahí.

Y como el que no quiere la cosa, he dado un poco de vidilla a este Hilo. :eek: :D :p

dec
07-08-2007, 15:02:01
Hola,

Vale. Quería decir que una posible solución puede ser incluir el componente "problemático" en un formulario, de modo que este se convierta en el "Parent" de aquél, y que sea dicho formulario el que "embebo" en la ventana.

Sin embargo, el asunto no funciona tampoco como se espera, puesto que el componente sigue sin poder recibir el foco correctamente. Por otro lado otros problemas surgen a raíz de hacerlo como digo.

Pero, no quisiera seguir, puesto que este problema se da en un determinado plugin para una aplicación en concreto... y tal vez no existan fórmulas generales y sí haya que tener el tipo de componente con el que tratemos, entre otras cosas.

En fin. Que sepáis que no he encontrado una solución plenamente satisfactoria, pero, que, por el momento, no creo que vaya a continuar con el tema.