Forums : XPCom

Aller à la discussion :  Plus récente Plus ancienne

Aller à la page :  1 2

# [Partiellement résolu] Propriétés d'élements XUL et C++.

Envoyé par : Epeios

Date : 24/08/2006 16:53

J'ai une page XUL dans lequel j'ai un élément listbox. Je voudrais appeler la propriété selectItem() de cet élément en C++. Un coup d'oeuil à http://www.xulplanet.com/references/elem(..) m'indique qu'un listbox hérite de l'interface nsIDOMXULMultiSelectControlElement. J'ai donc, dans le fichier .idl de mon composant, crée une méthode qui prend comme paramètre un nsIDOMXULMultiSelectControlElement. Coté javascript, je donne comme valeur à ce paramètre ce qui m'est retourné par un getElementById() sur l'id de mon élément listbox. A noter qu'un getElementById() retourne toujours un objet de type Element que j'ai, jusqu'à présent, toujours pu récupèrer dans mon composant XPCOM sous forme de nsIDOMElement *.

En consultant le fichier d'entête correspondant à mon nsIDOMXULMultiSelectControlElement (nsIDOMXULMultSelectCntrlEl.h), je constate que la méthode SelectItem() nécessite un nsIDOMXULSelectControlItemElement *. Qu'à cela ne tienne, la page http://www.xulplanet.com/references/elem(..) m'indique qu'un élement listitem hérite justement (c'était prévisible) de l'interface nsIDOMXULSelectControlItemElement. Je crée donc, (toujours en C++), toutes les entrées de ma listbox à coup de CreateElement("listitem") (qui, soit dit en passant, retourne un nsIDOMElement *) et d'AppendChild(). Puis je passe l'entrée, qui doit apparaître comme sélectionnée dans ma listbox, à la méthode SelectItem() du nsIDOMXULMultiSelectControlElement * correspondant à ladite listbox. Comme j'ai obtenu l'entrée en question sous forme de nsIDOMElement * à l'aide de la méthode CreateElement("listitem"), je la caste d'autorité en nsIDOMXULSelectControlItemElement *, le type requis par la méthode SelectItem().

Je compile le tout, installe mon composant, essaye mon extension et ... ça fonctionne !

Bon, me dis-je, pour simplifier l'appel en javascript à la méthode de mon composant XPCOM, je vais, non pas passer l'élément correspondant à la listbox, mais son id, ce qui me permet de déporter la fonction getElementbyId() du javascript vers le C++. Et je caste le nsIDOMElement * obtenu par le GetElementById() en C++ en nsIDOMXULMultiSelectControlElement *, sur le même principe que précédemment où j'ai casté le nsIDOMElement * obtenu par le CreateElement("listitem") en nsIDOMXULSelectControlItemElement *.

Pareil. Je compile le tout, installe mon composant, essaye mon extension et ... ça plante !

Bon, me direz-vous, ce n'est pas grave, je n'ai qu'à utiliser la méthode qui fonctionne ! Sauf que, évidemment, ce plantage est probablement dû au castage de mon nsIDOMElement * en nsIDOMXULMultiSelectControlElement *, ce qui me fait penser que c'est à éviter. Or, comme dit plus haut, je caste sur le même principe de nsIDOMElement * en nsIDOMXULSelectControlItemElement *. Et si ce castage ne plante pas, c'est parce que, probablement, nsIDOMXULSelectControlItemElement hérite directement de nsIDOMXULElement (qui lui-même hérite directement nsIDOMElement), alors que nsIDOMXULMultiSelectControlElement n'hérite pas directement de nsIDOMXULElement, mais par l'intermédiaire de nsIDOMXULSelectControlElement.

Voilà donc mes questions :

  • Comment obtenir à partir d'un nsIDOMElement * d'une listbox, ou de l'id de cette même listbox, le nsIDOMXULMultiSelectControlElement * correspondant ?
  • Et existe-t'il une documentation expliquant comment procèder pour accèder, à partir d'un composant XPCOM écrit en C++, à toutes les propriétés (et pas seulement les attributs) d'un élément crée en javascript (ou à partir d'un fichier .xul) ?

Merci d'avance pour vos réponses ...

# Re: Propriétés d'élements XUL et C++.

Envoyé par : laurentj

Date : 25/08/2006 16:54

euh... tu "castes" comment ? Tu nous fais un caste c++ classique, ou tu passes bien par un queryInterface/nsCOMPtr ? On peut voir un bout de code sur tes casts ?

# Re: Propriétés d'élements XUL et C++.

Envoyé par : Epeios

Date : 25/08/2006 21:28

Je fais un bête cast C++. Mais, comme dit, bien que ça marche dans certaines situations, je me doute bien que ce n'est pas la bonne méthode ...

Pour fixer les idées, voilà la le contenu de mes différents fichiers, expurgé de tout ce qui ne concerne pas directement mon problème :

Fichier test.xul :

<window onload="MyComp.SetUI( document, document.getElementById('myListBox'), 'myListBox' );">
<listbox id="myListBox"/>
</window>

Fichier test.idl :

interface mycomp : nsISupports
{
	void SetUI(
		in nsIDOMDocument Document,
		in nsIDOMXULMultiSelectControlElement ListBoxAsElement,
		in string ListBoxId );
}

Fichier test.cpp

NS_IMETHODIMP mycomp::SetUI(
	nsIDOMDocument *Document,
	nsIDOMXULMultiSelectControlElement *ListBoxAsElement,
	const char *ListBoxId )
{
	nsIDOMXULMultiSelectControlElement *ListBox;
	nsIDOMXULSelectControlItemElement *ListItem, *SelectedListItem;
	nsIDOMElement *Element;
 	
#if 0	// Ne fonctionne pas (et j'aimerais savoir comment faire pour que cela fonctionne).
	Document->GetElementById( ListBoxId, &Element );
	ListBox = (nsIDOMXULMultiSelectControlElement *)Element;
#else	// Fonctionne !
	ListBox = ListBoxAsElement;
#endif

	Document->CreateElement( "listitem", &Element );		// Ca fonctionne, mais ça ne doit pas
	ListItem = (nsIDOMXULSelectControlItemElement *)Element;	// être la bonne manière de procèder !
	ListBox->AppendChild( ListItem );
	
	Document->CreateElement( "listitem", &Element );
	SelectedListItem = ListItem = (nsIDOMXULSelectControlItemElement *)Element;
	ListBox->AppendChild( ListItem );
	
	Document->CreateElement( "listitem", &Element );
	ListItem = (nsIDOMXULSelectControlItemElement *)Element;
	ListBox->AppendChild( ListItem );

	ListBox->SelectItem( SelectedListItem );
}

Par souci de simplification, j'ai omis certaines portions de codes, comme par exemple celui qui transforme un const char * en un type accepté par les méthodes CreateElement() et GetDocumentById().

# Re: Propriétés d'élements XUL et C++.

Envoyé par : Paul Rouget

Date : 26/08/2006 11:11

Je pense qu'il faut que tu passes par un QueryInterface pour faire ça proprement. Un truc dans le genre:

nsresult rv = Element->QueryInterface(IID_DOMXULMultiSelectControlElement, &ListBox);

# Re: Propriétés d'élements XUL et C++.

Envoyé par : Epeios

Date : 26/08/2006 17:49

Merci ! Le GetElementById fonctionne bien mieux maintenant, bien que j'ai dû remplacer IID_DOMXULMultiSelectControlElement par nsIDOMXULMultiSelectControlElement::GetIID(). Par contre, j'ai des difficultés avec CreateElement(). Quand j'essaye de récupèrer l'interface nsIDOMXULSelectControlItemElement sur un élement crée avec CreateElement("listitem"), j'obtiens une erreur comme quoi une telle interface n'existe pas ! Pourtant, un listitem implémente bien cette interface !

Je remets le code C++ de mon précédent message, mais modifié pour utliser QueryInterface, et dans lequel le QueryInterface qui accompagne le CreateElement() échoue.

Fichier test.cpp

NS_IMETHODIMP mycomp::SetUI(
	nsIDOMDocument *Document,
	nsIDOMXULMultiSelectControlElement *ListBoxAsElement,
	const char *ListBoxId )
{
	nsIDOMXULMultiSelectControlElement *ListBox;
	nsIDOMXULSelectControlItemElement *SelectedListItem;
	nsIDOMElement *Element;
 	
#if 1	// Version fonctionnelle utilisant l'id de la 'listbox'.
	Document->GetElementById( ListBoxId, &Element );
	Element->QueryInterface( nsIDOMXULMultiSelectControlElement::GetIID(), (void **)&Listbox );
#else	// Fonctionne aussi, mais moins intéressant !
	ListBox = ListBoxAsElement;
#endif

	Document->CreateElement( "listitem", &Element );
	ListBox->AppendChild( Element );
	
	Document->CreateElement( "listitem", &Element );
	ListBox->AppendChild( ListItem );

#if 0	// Ne fonctionne pas, à ma grande surprise !
	int ns_error = Element->QueryInterface( nsIDOMXULSelectControlItemElement::GetIID(), (void **)&SelectedListItem );	// On se retrouve avec 'NS_NOINTERFACE' dans 'ns_error' !!!
#else	// Fonctionne, mais vraiment pas propre est probablement pas généralisable !
	SelectedListItem = (nsIDOMXULSelectControlItemElement *)Element;
#endif
	
	Document->CreateElement( "listitem", &Element );
	ListBox->AppendChild( Element );

	ListBox->SelectItem( SelectedListItem );
}

# Re: Propriétés d'élements XUL et C++.

Envoyé par : laurentj

Date : 29/08/2006 11:15

Beurk ! il faut absolument utiliser les nsCOMPtr, pour éviter les leak, et pour faciliter l'ecriture. Et pas de cast c++ traditionnel avec les xpcom !

Et puis pas de const char *. Utilise les nsString. Consulte les interfaces IDL des objets que tu utilises :-p

Et donc c'est normal tout tes trucs qui fonctionnent pas.

Voici la bonne façon de faire :

/* void setUI(in nsIDOMDocument Document, in nsIDOMXULMultiSelectControlElement ListBoxAsElement, in AString ListBoxId) */
NS_IMETHODIMP mycomp::SetUI(
nsIDOMDocument *Document,
nsIDOMXULMultiSelectControlElement *ListBoxAsElement,
const nsAString & ListBoxId )
{
  nsCOMPtr<nsIDOMXULMultiSelectControlElement> ListBox;
  nsCOMPtr<nsIDOMXULSelectControlItemElement> SelectedListItem;
  nsCOMPtr<nsIDOMElement> Element;
  nsresult rv;

  Document->GetElementById( ListBoxId, getter_AddRefs(Element) );
  ListBox= do_QueryInterface(Element);

  Document->CreateElement( NS_LITERAL_STRING("listitem"), getter_AddRefs(Element));
  ListBox->AppendChild( Element );

  Document->CreateElement( NS_LITERAL_STRING("listitem"), getter_AddRefs(Element));
  ListBox->AppendChild( Element );

  SelectedListItem = do_QueryInterface(Element, &rv);
  NS_ENSURE_SUCCESS(rv,rv);

  Document->CreateElement( NS_LITERAL_STRING("listitem"), getter_AddRefs(Element) );
  ListBox->AppendChild( Element );

  ListBox->SelectItem( SelectedListItem );

  return NS_OK; // pas l'oublier celui là !!
}

Ahh tout de suite, c'est plus propre ;-)

La convention veut aussi que les paramètres commencent tous par "a", (et les propriétés de ta classe, par "m"). On devrait donc avoir :

NS_IMETHODIMP mycomp::SetUI(
nsIDOMDocument *aDocument,
nsIDOMXULMultiSelectControlElement *aListBoxAsElement,
const nsAString & aListBoxId )

Je te conseille de lire cette page et tous les liens qui y sont répertorier, pour apprendre à utiliser l'api XPCOM/gecko : http://www.mozilla.org/projects/xpcom/

# Re: Propriétés d'élements XUL et C++.

Envoyé par : Epeios

Date : 29/08/2006 17:18

laurentj a écrit:

Beurk ! il faut absolument utiliser les
[nsCOMPtr|http://www.mozilla.org/projects/xpcom/ns
COMPtr.html], pour éviter les leak, et pour
faciliter l'ecriture.

Je voulais éviter de surcharger le code d'exemple, pour me concentrer sur l'essentiel (comme je l'avais précisé dans mon message).

Et pas de cast c++
traditionnel avec les xpcom !

Euh .. traditionnel, c'est vite dit. Jamais je n'utilise ce genre de cast, puisque ça contourne le contrôle de typage du C++ (on peut caster n'importe quoi en n'importe quoi avec ce genre de cast). Mais ça me permettait d'avancer dans mon travail, tout en ayant conscience que ce n'était pas la solution, d'où l'initiation de cette discussion.

Et puis pas de const char *. Utilise les nsString.
Consulte les interfaces IDL des objets que tu
utilises :-p

J'ai volontairement supprimé toute référence aux nsString pour simplifier le code d'exemple.

Et donc c'est normal tout tes trucs qui
fonctionnent pas.

Pas le truc qui fait l'objet de mon précédent message.

Voici la bonne façon de faire :

...

Ahh tout de suite, c'est plus propre ;-)

C'est peut-être plus propre, mais ça ne fonctionne pas mieux ...

Voilà le code incriminé tel que je l'ai essayé, donc sans simplifications cette fois-ci :

NS_IMETHODIMP mycomp::SetUI(
nsIDOMDocument *Document,
	nsIDOMXULMultiSelectControlElement *ListBoxAsElement,
	const char *ListBoxId )
{
	nsCOMPtr<nsIDOMXULSelectControlItemElement> Item;
	nsCOMPtr<nsIDOMElement> Element;
	nsresult rv;

	rv = Document->CreateElement( NS_LITERAL_STRING("listitem"), getter_AddRefs(Element));
	NS_ENSURE_SUCCESS(rv,rv);	// Ca passe : 'Element' est != NULL.

	Item = do_QueryInterface(Element, &rv);
	NS_ENSURE_SUCCESS(rv,rv);	// Passe pas : 'rv' vaut 'NS_NOINTERFACE' et 'Item' est resté à NULL !

	return NS_OK;
}

Comme je l'ai indiqué dans les commentaires, le CreateElement() se passe bien, ce que l'on peut constater en remarquant que Element et différent de NULL, mais pas le do_QueryInterface, rv prenant la valeur NS_NOINTERFACE et Item restant à NULL.

# Re: Propriétés d'élements XUL et C++.

Envoyé par : laurentj

Date : 04/09/2006 16:25

peut être faut il que tu fasse plutôt un createElementNS. createElement, selon la spec DOM, créé un élement sans namespace...

En ce qui conçerne tes remarques sur la "simplification" : en montrant des lignes de code c++ sans utiliser tous ce qui est xpcom, ce n'est vraiment pas simplifier, car du coup, on ne sait pas trop d'où peut venir telle ou telle erreur.

XPCom est un tout.

# Re: Propriétés d'élements XUL et C++.

Envoyé par : Epeios

Date : 05/09/2006 10:07

laurentj a écrit:

peut être faut il que tu fasse plutôt un
createElementNS. createElement, selon la spec DOM,
créé un élement sans namespace...

Hélas, ça ne fonctionne toujours pas mieux. Voilà le code testé :

NS_IMETHODIMP mycomp::SetUI(
nsIDOMDocument *Document,
	nsIDOMXULMultiSelectControlElement *ListBoxAsElement,
	const char *ListBoxId )
{
	nsCOMPtr<nsIDOMXULSelectControlItemElement> Item;
	nsCOMPtr<nsIDOMElement> Element;
	nsresult rv;

	rv = Document->CreateElementNS( NS_LITERAL_STRING("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" ), NS_LITERAL_STRING("listitem"), getter_AddRefs(Element));
	NS_ENSURE_SUCCESS(rv,rv);	// Ca passe : 'Element' est != NULL.

	Item = do_QueryInterface(Element, &rv);
	NS_ENSURE_SUCCESS(rv,rv);	// Ne passe toujours pas : 'rv' vaut 'NS_NOINTERFACE' et 'Item' reste à NULL !

	return NS_OK;
}

En ce qui conçerne tes remarques sur la
"simplification" : en montrant des lignes de code
c++ sans utiliser tous ce qui est xpcom, ce n'est
vraiment pas simplifier, car du coup, on ne sait
pas trop d'où peut venir telle ou telle erreur.

Sauf que je ne connaissais pas NS_LITERAL_STRING, alors si j'avais mis le code qui transformait un const char * en un nsAString, je doute que le code aurait été trés lisible. Maintenant que je connais NS_LITERAL_STRING, je n'en ferais plus l'économie dorénavant.

J'ai pensé un moment qu'il y avait incompabilité entre Mozilla 1.8b, que j'utilise pour faire le test, et Xulrunner 1.8.0.4, des sources duquel j'ai génèré le SDK que j'utilise, mais le résultat est le même en utilisant le XULRunner obtenu en compilant ces mêmes sources ...

# Re: Propriétés d'élements XUL et C++.

Envoyé par : Epeios

Date : 05/09/2006 17:11

Aprés de laborieuses recherches sur le net, je suis parvenu à la conclusion que le problème viendrait du fait qu'un composant XBL n'est pas correctement initialisé tant qu'il n'a pas été mis en oeuvre. Dans le cas qui nous occupe, en rattachant, juste aprés sa création, le listitem à un listbox existant à l'aide d'un AppendChild, et bien le do_QueryInterface fonctionne. Le problème, c'est que l'AppendChild ne suffit pas en lui-même ; il faut qu'il s'applique à un listbox. Ce qui laisse supposer que, si cela fonctionne pour un listitem, cela ne fonctionnera probablement pas pour un textbox, par exemple, car un textbox n'a rien à voir avec un listbox. Or, j'aimerais disposer d'une procédure permettant de forcer l'initialisation de n'importe quel composant XBL fraîchement crée.

Quelqu'un aurait-il une piste ?

Aller à la page :  1 2

Il n'est plus possible de poster des messages dans ce forum.


Copyright © 2003-2013 association xulfr, 2013-2016 Laurent Jouanneau - Informations légales.

Mozilla® est une marque déposée de la fondation Mozilla.
Mozilla.org™, Firefox™, Thunderbird™, Mozilla Suite™ et XUL™ sont des marques de la fondation Mozilla.