Difference between revisions of "FR/Documentation/Plus loin avec Composants et boites de dialogue"
B michaelsen (Talk | contribs) |
|||
Line 217: | Line 217: | ||
=Les boîtes de dialogue Multi-Page= | =Les boîtes de dialogue Multi-Page= | ||
Les boîtes de dialogues multi-pages avec [[FR/Documentation/BASIC_Guide/Properties|OOoBasic sont abordées]] sous le nom de "boîtes de dialogue à plusieurs onglets". Notre but est d'utiliser une boîte de dialogue multi-page encore et toujours avec notre compteur et ainsi de voir comment les choses fonctionnent. Notre seconde page sera très similaire à la boîte de dialogue toute simple du compteur tandis que la première page gérera les incréments. On passera d'une page à l'autre à l'aide des célèbres boutons "next>>" et "<<previous" (que je n'ai pas traduit). Et puis quant à faire on ajoutera pour la première fois les boutons "OK" et "Cancel" qui n'ont pas à être géré explicitement en fait. Puisque je n'ai jamais géré de dialogue multi-page avant d'écrire cette section, je commence par faire mes premières armes en OOoBasic. | Les boîtes de dialogues multi-pages avec [[FR/Documentation/BASIC_Guide/Properties|OOoBasic sont abordées]] sous le nom de "boîtes de dialogue à plusieurs onglets". Notre but est d'utiliser une boîte de dialogue multi-page encore et toujours avec notre compteur et ainsi de voir comment les choses fonctionnent. Notre seconde page sera très similaire à la boîte de dialogue toute simple du compteur tandis que la première page gérera les incréments. On passera d'une page à l'autre à l'aide des célèbres boutons "next>>" et "<<previous" (que je n'ai pas traduit). Et puis quant à faire on ajoutera pour la première fois les boutons "OK" et "Cancel" qui n'ont pas à être géré explicitement en fait. Puisque je n'ai jamais géré de dialogue multi-page avant d'écrire cette section, je commence par faire mes premières armes en OOoBasic. | ||
− | {{ | + | {{Note|Comme déjà expliqué, je pense que c'est une bonne pratique de commencer par écrire du OOoBasic avant de résoudre le problème en C++. Avant de commencer ce document en 2004, OOoBasic était déjà documenté dans [[FR/Documentation/BASIC_Guide|un guide OOoBASIC]] (et aussi dans des livres) mais vous n'aviez que quelques petits exemples en C++ dans le SDK. A ma connaissance il n'y a aucun livre C++/UNO. L'autre grande raison est que pour fabriquer les dialogues présentés dans ce chapitre (et le précédent) vous devez lancer l'environnement de développement du OOoBasic. Alors pour écrire un programme OOobasic, il n'y a plus qu'un pas.}} |
==Notre programme OOoBasic de départ== | ==Notre programme OOoBasic de départ== | ||
Nous commençons par donner notre programme OOoBasic. La première partie du main correspond à la gestion du compteur tandis que la deuxième partie correspond à la gestion du "next>>" et "<<previous" à l'aide de la propriété Step. Cette gestion est réalisée avec deux sous-programmes : | Nous commençons par donner notre programme OOoBasic. La première partie du main correspond à la gestion du compteur tandis que la deuxième partie correspond à la gestion du "next>>" et "<<previous" à l'aide de la propriété Step. Cette gestion est réalisée avec deux sous-programmes : |
Revision as of 07:44, 7 July 2018
Dans le chapitre précédent nous avons utilisé et programmé seulement deux types de contrôles dans nos boîtes de dialogue (bouton et zone de texte). Nous avons l'intention dans ce chapitre d'aller plus loin en utilisant des autres contrôles et voir comment ils fonctionnent. Vous ne pouvez pas aborder ce chapitre sans lire le chapitre précédent, particulièrement parce que seulement des extraits de code sont présentés.
Notre compteur sera encore le fil de ce chapitre même si nous finirons par l'abandonner à la fin.
Contents
- 1 Compteur avec des champs numériques
- 2 Utiliser les boutons radio
- 3 Utiliser une zone de liste dans une boîte de dialogue
- 4 Les boîtes de dialogue Multi-Page
- 5 Le nouveau contrôle pour les arborescences
- 6 Page d'accueil
- 7 See also
Compteur avec des champs numériques
Quand nous avons construit la boîte de dialogue fonctionnant avec notre compteur, nous avons choisi deux zones de texte pour nos données numériques : une pour la saisie, associée au bouton "setCount", et l'autre pour l'affichage du contenu du compteur associé au bouton "getCount". Parce que les zones de textes sont très souvent utilisées en pratique, notre exemple précédent reste fondamental, mais il est temps de l'améliorer en utilisant des champs numériques. Puisque l'aspect visuel de la boîte de dialogue est pratiquement inchangée nous ne fournissons pas de copie d'écran de cette boîte.
Vous pouvez aller voir l'interface com.sun.star.awt.XNumericField et découvrir ainsi ce qui peut être fait avec celle-ci : seules les méthodes getvalue
et setValue
seront utilisées dans cette section, mais vous pouvez vous amuser avec les autres méthodes.
Nous ne fournirons que le code de la fonction callHandlerMethod
dans le listing ci-après (voir le chapitre précédent et aussi l'interface correspondante com.sun.star.awt.XDialogEventHandler). La solution à notre problème d'utilisation des deux contrôles numériques est donnée par l'extrait de code suivant :
// Listing 1 // c++ sal_Bool SAL_CALL MyCounterImpl::callHandlerMethod(const Reference< XDialog >& xDialog,const Any& EventObject,const OUString & MethodName ) throw(WrappedTargetException, RuntimeException ){ if (MethodName.equalsAscii("foo1")){//increment increment(); return sal_True; } if (MethodName.equalsAscii("foo2")){//decrement decrement(); return sal_True; } if (MethodName.equalsAscii("foo3")){ //setCount Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("NumericField1")); Reference< XNumericField > xNumericField(xControl,UNO_QUERY); setCount((sal_Int32)xNumericField->getValue()); return sal_True; } if (MethodName.equalsAscii("foo4")){ //getCount Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("NumericField2")); Reference< XNumericField > xNumericField(xControl,UNO_QUERY); xNumericField->setValue(getCount()); return sal_True; } return sal_False; }
Nous n'avons pas besoin d'expliquer ce listing en détail, mais peut être faire une remarque : il serait bon de changer le nom des événements "foo1" ... "foo4". Ce sera fait un peu plus loin.
Nous allons maintenant nous intéresser à un autre exemple de contrôle : les boutons radio (ou cases de choix 1 parmi N).
Utiliser les boutons radio
Un bouton d'option com.sun.star.awt.UnoControlRadioButton est un simple commutateur avec deux états, qui sont sélectionnés par l'utilisateur. Les boutons d'option sont habituellement utilisés en groupe pour choisir une parmi plusieurs options. Bien que les boutons d'option et les cases à cocher semblent similaires, sélectionner un bouton radio se fait au détriment des autres du même groupe (mais on peut choisir plusieurs cases à cocher).
Dans notre exemple, on veut utiliser des boutons radio pour choisir la valeur de l'incrément/décrément du compteur (entre 1, 5 et 10). Voici une copie d'écran de notre boîte de dialogue :
où vous pouvez voir qu'une valeur de 5 pour l'incrément/décrément est choisie.
Pour cet exemple l'interface com.sun.star.awt.XRadioButton doit être consultée. Nous allons fournir deux solutions différentes à cet exemple. Nous commençons par examiner une méthode qui n'utilise que les quatre événements déjà utilisés correspondant aux quatre méthodes du compteur.
Une solution toute simple
Cette solution garde donc nos quatre méthodes gérées par callHandlerMethod()
encore nommées "foo1", "foo2", .. "foo4" de l'interface com.sun.star.awt.XDialogEventHandler. Pour dire les choses autrement aucun événement nouveau n'est généré par notre boîte de dialogue. Nous présentons maintenant le code correspondant, et encore une fois avec seulement le code de callHandlerMethod
. Regardez le chapitre précédent si vous voulez vous rappeler comment cela fonctionne.
// Listing 2 // C++ sal_Bool SAL_CALL MyCounterImpl::callHandlerMethod(const Reference< XDialog >& xDialog,const Any& EventObject,const OUString & MethodName ) throw(WrappedTargetException, RuntimeException ){ if (MethodName.equalsAscii("foo1")){//increment Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("OptionButton1")); Reference< XRadioButton > xRadioButton(xControl,UNO_QUERY); if (xRadioButton->getState()) m_nDelta=1; xControl=xControlContainer->getControl(OUString::createFromAscii("OptionButton2")); Reference< XRadioButton > xRadioButton2(xControl,UNO_QUERY); if (xRadioButton2->getState()) m_nDelta=5; xControl=xControlContainer->getControl(OUString::createFromAscii("OptionButton3")); Reference< XRadioButton > xRadioButton3(xControl,UNO_QUERY); if (xRadioButton3->getState()) m_nDelta=10; increment(); return sal_True; } if (MethodName.equalsAscii("foo2")){//decrement Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("OptionButton1")); Reference< XRadioButton > xRadioButton(xControl,UNO_QUERY); if (xRadioButton->getState()) m_nDelta=1; xControl=xControlContainer->getControl(OUString::createFromAscii("OptionButton2")); Reference< XRadioButton > xRadioButton2(xControl,UNO_QUERY); if (xRadioButton2->getState()) m_nDelta=5; xControl=xControlContainer->getControl(OUString::createFromAscii("OptionButton3")); Reference< XRadioButton > xRadioButton3(xControl,UNO_QUERY); if (xRadioButton3->getState()) m_nDelta=10; decrement(); return sal_True; } if (MethodName.equalsAscii("foo3")){ //setCount Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("NumericField1")); Reference< XNumericField > xNumericField(xControl,UNO_QUERY); setCount((sal_Int32)xNumericField->getValue()); return sal_True; } if (MethodName.equalsAscii("foo4")){ //getCount Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("NumericField2")); Reference< XNumericField > xNumericField(xControl,UNO_QUERY); xNumericField->setValue(getCount()); return sal_True; } return sal_False; }
Comme vous pouvez le constater, seules les méthodes increment()
et decrement()
cherchent à savoir quel est le bouton radio positionné. Le code de test correspondant est similaire dans les deux méthodes et gagnerait certainement en clareté s'il était mis dans une fonction. Aucun événement n'est déclenché quand on change l'état des boutons radio dans cet exemple. Mais il est possible d'appeler une méthode chaque fois que l'état d'un bouton radio est changé : notez que dans ce cas, il vous faut fournir une méthode par bouton. Examinons cette deuxième possibilité.
Gérer des événements des boutons Radio
Chaque fois qu'un utilisateur coche ou décoche un bouton radio un événement est émis, événement géré par une méthode : vous avez ainsi à éditer chacune des propriétés correspondantes des boutons et les associer à une méthode de composant (voir encore le Developer's Guide). Parceque vous avez trois boutons radio, il vous faudra ajouter trois méthodes. On voit que ce genre de solution peut devenir vite très compliquée quand le nombre de bouton radio croit.
Le code est ainsi le suivant :
// C++ // Listing 3 sal_Bool SAL_CALL MyCounterImpl::callHandlerMethod(const Reference< XDialog >& xDialog,const Any& EventObject,const OUString & MethodName ) throw(WrappedTargetException, RuntimeException ){ if (MethodName.equalsAscii("foo1")){//increment increment(); return sal_True; } if (MethodName.equalsAscii("foo2")){//decrement decrement(); return sal_True; } if (MethodName.equalsAscii("foo3")){ //setCount Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("NumericField1")); Reference< XNumericField > xNumericField(xControl,UNO_QUERY); setCount((sal_Int32)xNumericField->getValue()); return sal_True; } if (MethodName.equalsAscii("foo4")){ //getCount Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("NumericField2")); Reference< XNumericField > xNumericField(xControl,UNO_QUERY); xNumericField->setValue(getCount()); return sal_True; } if (MethodName.equalsAscii("foo5")){ //incr/decr +/-1 if (m_nDelta!=1) m_nDelta=1; return sal_True; } if (MethodName.equalsAscii("foo6")){ //incr/decr +/-5 if (m_nDelta!=5) m_nDelta=5; return sal_True; } if (MethodName.equalsAscii("foo7")){ //incr/decr +/-10 if (m_nDelta!=10) m_nDelta=10; return sal_True; } return sal_False; } Sequence< OUString > SAL_CALL MyCounterImpl::getSupportedMethodNames() throw (RuntimeException){ Sequence< OUString > SeqOUStr(7); SeqOUStr[0]=OUString::createFromAscii("foo1"); SeqOUStr[1]=OUString::createFromAscii("foo2"); SeqOUStr[2]=OUString::createFromAscii("foo3"); SeqOUStr[3]=OUString::createFromAscii("foo4"); SeqOUStr[4]=OUString::createFromAscii("foo5"); SeqOUStr[5]=OUString::createFromAscii("foo6"); SeqOUStr[6]=OUString::createFromAscii("foo7"); return SeqOUStr; }
Ce code fonctionne sans lire l'état des boutons radio (en ce qui concerne les méthodes associées "foo5" à "foo7"). Je ne peux pas vous certifier cependant que pour toutes les situations que vous rencontrerez dans votre vie de programmeur ce sera ainsi. Notez que l'on vous a déjà fourni le code pour accéder à l'état des boutons radio dans la section précédente. Notez aussi que m_nDelta
est une nouvelle donnée membre positionnée à 1 par le constructeur (ce qui correspond au bouton radio sélectionné par défaut).
Utiliser une zone de liste dans une boîte de dialogue
Dans cette section, nous remplaçons les boutons radio par une zone de liste. Jetez un oeil à l'interface com.sun.star.awt.XListBox. On utilisera seulement la méthode getSelectedItemPos()
dans le code ci-dessous.
// XDialogEventHandler implementation // C++ // Listing 4 sal_Bool SAL_CALL MyCounterImpl::callHandlerMethod(const Reference< XDialog >& xDialog,const Any& EventObject,const OUString & MethodName ) throw(WrappedTargetException, RuntimeException ){ if (MethodName.equalsAscii("foo1")){//increment Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("ListBox1")); Reference< XListBox > xListBox(xControl,UNO_QUERY); switch (xListBox->getSelectedItemPos()){ case 0: m_nDelta=1;break; case 1: m_nDelta=5;break; case 2: m_nDelta=10;break; } increment(); return sal_True; } if (MethodName.equalsAscii("foo2")){//decrement Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("ListBox1")); Reference< XListBox > xListBox(xControl,UNO_QUERY); switch (xListBox->getSelectedItemPos()){ case 0: m_nDelta=1;break; case 1: m_nDelta=5;break; case 2: m_nDelta=10;break; } decrement(); return sal_True; } if (MethodName.equalsAscii("foo3")){ //setCount Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("NumericField1")); Reference< XNumericField > xNumericField(xControl,UNO_QUERY); setCount((sal_Int32)xNumericField->getValue()); return sal_True; } if (MethodName.equalsAscii("foo4")){ //getCount Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("NumericField2")); Reference< XNumericField > xNumericField(xControl,UNO_QUERY); xNumericField->setValue(getCount()); return sal_True; } return sal_False; }
qui nous produit la boîte de dialogue ci-dessous :
Les boîtes de dialogue Multi-Page
Les boîtes de dialogues multi-pages avec OOoBasic sont abordées sous le nom de "boîtes de dialogue à plusieurs onglets". Notre but est d'utiliser une boîte de dialogue multi-page encore et toujours avec notre compteur et ainsi de voir comment les choses fonctionnent. Notre seconde page sera très similaire à la boîte de dialogue toute simple du compteur tandis que la première page gérera les incréments. On passera d'une page à l'autre à l'aide des célèbres boutons "next>>" et "<<previous" (que je n'ai pas traduit). Et puis quant à faire on ajoutera pour la première fois les boutons "OK" et "Cancel" qui n'ont pas à être géré explicitement en fait. Puisque je n'ai jamais géré de dialogue multi-page avant d'écrire cette section, je commence par faire mes premières armes en OOoBasic.
Comme déjà expliqué, je pense que c'est une bonne pratique de commencer par écrire du OOoBasic avant de résoudre le problème en C++. Avant de commencer ce document en 2004, OOoBasic était déjà documenté dans un guide OOoBASIC (et aussi dans des livres) mais vous n'aviez que quelques petits exemples en C++ dans le SDK. A ma connaissance il n'y a aucun livre C++/UNO. L'autre grande raison est que pour fabriquer les dialogues présentés dans ce chapitre (et le précédent) vous devez lancer l'environnement de développement du OOoBasic. Alors pour écrire un programme OOobasic, il n'y a plus qu'un pas. |
Notre programme OOoBasic de départ
Nous commençons par donner notre programme OOoBasic. La première partie du main correspond à la gestion du compteur tandis que la deuxième partie correspond à la gestion du "next>>" et "<<previous" à l'aide de la propriété Step. Cette gestion est réalisée avec deux sous-programmes :
- un sous-programme "cmdPrev_Initiated",
- un sous-programme "cmdNext_Initiated".
Quand nous sommes en Step=1 le bouton "<<previous" est inactif tandis qu'en Step=2 c'est au tour du bouton "next>>" d'être desactivé.
REM ***** BASIC ***** 'Listing 5 Dim Dlg As Object Dim Count As integer Dim IncrDecr As integer Sub Main DialogLibraries.LoadLibrary("Standard") Dlg = CreateUnoDialog(DialogLibraries.Standard.Dialog2) 'Because of Multi-page don't forget to manage Step : Dlg.Model.Step=1 Dlg.Execute() Dlg.dispose() End Sub 'Notre compteur commence ici <----------- Sub Increment Count = Count + IncrDecr End Sub Sub Decrement Count = Count - IncrDecr End Sub Sub getCount Dim oNumericField oNumericField = Dlg.getControl("NumericField2") oNumericField.Value = Count End Sub Sub setCount Dim oNumericField oNumericField = Dlg.getControl("NumericField1") Count = oNumericField.Value End Sub ' Notre compteur finit ici <------------ Sub cmdNext_Initiated Dim cmdNext As Object Dim cmdPrev As Object cmdPrev = Dlg.getControl("cmdPrev") 'inspect(cmdPrev) cmdNext = Dlg.getControl("cmdNext") cmdPrev.Model.Enabled = Not cmdPrev.Model.Enabled cmdNext.Model.Enabled = False 'if Next update IncrDecr If Dlg.Model.Step = 1 Then If Dlg.getControl("OptionButton1").State Then IncrDecr = 1 End If If Dlg.getControl("OptionButton2").State Then IncrDecr = 5 End If If Dlg.getControl("OptionButton3").State Then IncrDecr = 10 End If End If Dlg.Model.Step = Dlg.Model.Step + 1 End Sub Sub cmdPrev_Initiated Dim cmdNext As Object Dim cmdPrev As Object cmdPrev = Dlg.getControl("cmdPrev") cmdNext = Dlg.getControl("cmdNext") cmdPrev.Model.Enabled = False cmdNext.Model.Enabled = True Dlg.Model.Step = Dlg.Model.Step - 1 End Sub
Notez aussi que les états des boutons radio sont seulement testés quand on clique sur le bouton "Next>>" en Step 1. Les deux pages se présentent ainsi :
où vous pouvez voir que le bouton "<<Previous" est inactif
où c'est maintenant le bouton "Next>>" qui est inactif.
Programme C++
Notre but dans cette section est d'utiliser la même boîte de dialogue multi-page qu'en OOoBasic mais dans un composant C++. Si le travail a été simple en OOoBasic pour la gestion du "Next>>" et "<<Previous", j'ai passé plusieurs heures pour trouver la traduction de la toute simple ligne OOoBasic :
REM ***** BASIC ***** Dlg.Model.Step = Dlg.Model.Step + 1
Finalement, la génération automatique de code C++ par le Java Inspector a été mon salut. Le code est ainsi :
// C++ // Listing 6 // XDialogEventHandler implementation sal_Bool SAL_CALL MyCounterImpl::callHandlerMethod(const Reference< XDialog >& xDialog,const Any& EventObject,const OUString & MethodName ) throw(WrappedTargetException, RuntimeException ){ if (MethodName.equalsAscii("increment")){//increment increment(); return sal_True; } if (MethodName.equalsAscii("decrement")){//decrement decrement(); return sal_True; } if (MethodName.equalsAscii("setCount")){ //setCount Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("NumericField1")); Reference< XNumericField > xNumericField(xControl,UNO_QUERY); setCount((sal_Int32)xNumericField->getValue()); return sal_True; } if (MethodName.equalsAscii("getCount")){ //getCount Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("NumericField2")); Reference< XNumericField > xNumericField(xControl,UNO_QUERY); xNumericField->setValue(getCount()); return sal_True; } if (MethodName.equalsAscii("cmdPrev_Initiated")){ //<<Previous // xDialog is a parameter Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("cmdPrev")); //com.sun.star.awt.XConrolModel Reference< XControlModel> xControlModel= xControl->getModel(); Any any; sal_Bool Boolval; Reference< XPropertySet > xPropertySet( xControlModel,UNO_QUERY); any=xPropertySet->getPropertyValue(OUString::createFromAscii("Enabled")); any >>= Boolval; Boolval = !Boolval; any <<= Boolval; xPropertySet->setPropertyValue(OUString::createFromAscii("Enabled"),any); xControl=xControlContainer->getControl(OUString::createFromAscii("cmdNext")); xControlModel= xControl->getModel(); Reference< XPropertySet > xPropertySet2( xControlModel,UNO_QUERY); any=xPropertySet2->getPropertyValue(OUString::createFromAscii("Enabled")); any >>= Boolval; Boolval = !Boolval; any <<= Boolval; xPropertySet2->setPropertyValue(OUString::createFromAscii("Enabled"),any); // found with JavaInspector C++ code generation :Step property management sal_Int32 step; Reference< XControl > xControl2 (xDialog,UNO_QUERY_THROW); xControlModel= xControl2->getModel(); Reference< XPropertySet > xPropertySet3( xControlModel,UNO_QUERY); step = 1; any <<= step; xPropertySet3->setPropertyValue(OUString::createFromAscii("Step"),any); return sal_True; } if (MethodName.equalsAscii("cmdNext_Initiated")){ //Next>> // xDialog is a parameter Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl=xControlContainer->getControl(OUString::createFromAscii("cmdPrev")); //com.sun.star.awt.XConrolModel Reference< XControlModel> xControlModel= xControl->getModel(); Any any; sal_Bool Boolval; Reference< XPropertySet > xPropertySet( xControlModel,UNO_QUERY); any <<= sal_True; xPropertySet->setPropertyValue(OUString::createFromAscii("Enabled"),any); xControl=xControlContainer->getControl(OUString::createFromAscii("cmdNext")); xControlModel= xControl->getModel(); Reference< XPropertySet > xPropertySet2( xControlModel,UNO_QUERY); any <<= sal_False; xPropertySet2->setPropertyValue(OUString::createFromAscii("Enabled"),any); // RadioButton management : not great with such if ! xControl=xControlContainer->getControl(OUString::createFromAscii("OptionButton1")); Reference< XRadioButton > xRadioButton(xControl,UNO_QUERY); if (xRadioButton->getState()) m_nDelta=1; xControl=xControlContainer->getControl(OUString::createFromAscii("OptionButton2")); Reference< XRadioButton > xRadioButton2(xControl,UNO_QUERY); if (xRadioButton2->getState()) m_nDelta=5; xControl=xControlContainer->getControl(OUString::createFromAscii("OptionButton3")); Reference< XRadioButton > xRadioButton3(xControl,UNO_QUERY); if (xRadioButton3->getState()) m_nDelta=10; // Trouvé avec la génération automatique de C++ du JavaInspector sal_Int32 step; // L'astuce est ici : ne pas utiliser la ligne ci-après mais la suivante // Reference< XControl >xControl2=xControlContainer->getControl(OUString::createFromAscii("Dialog1")) Reference< XControl > xControl2 (xDialog,UNO_QUERY_THROW); xControlModel= xControl2->getModel(); Reference< XPropertySet > xPropertySet3( xControlModel,UNO_QUERY); step = 2; any <<= step; xPropertySet3->setPropertyValue(OUString::createFromAscii("Step"),any); return sal_True; } return sal_False; } Sequence< OUString > SAL_CALL MyCounterImpl::getSupportedMethodNames() throw (RuntimeException){ Sequence< OUString > SeqOUStr(6); SeqOUStr[0]=OUString::createFromAscii("increment"); SeqOUStr[1]=OUString::createFromAscii("decrement"); SeqOUStr[2]=OUString::createFromAscii("setCount"); SeqOUStr[3]=OUString::createFromAscii("getCount"); SeqOUStr[4]=OUString::createFromAscii("cmdNext_Initiated"); SeqOUStr[5]=OUString::createFromAscii("cmdPrev_Initiated"); return SeqOUStr; }
Voir aussi les interfaces com.sun.star.awt.XControl, com.sun.star.awt.XControlContainer, com.sun.star.awt.XControlModel et com.sun.star.beans.XPropertySet.
On va s'intéresser maintenant à un autre exemple qui va nous amener à laisser tomber notre compteur (enfin pas tout à fait) à cause de sa simplicité.
Le nouveau contrôle pour les arborescences
Le contrôle "Tree Contol" est abordé aussi ici mais l'article en question est en construction (depuis 2006). Comme je ne sais pas vraiment comment traduire "Tree Control", je le traduirai par contrôle pour arborescences. Pour parler franchement, je ne suis pas complètement satisfait avec ce contrôle pour le moment pour différentes raisons :
- le listener detectant l'expension de l'arbre est de mon point de vue incomplet. Si un noeud n'a pas d'enfant et que vous le déroulez, le listener ne sera pas appelé. Cela peut certainement poser des problèmes quand on veut gérer des arbres dynamiques (par exemple dans un outil d'introspection)
- La gestion de la propriété événement dans le dialogue OpenOffice.org est bien trop simple : pas assez d'événements gérés. Elle permettra donc parfois difficilement le remplacement d'un listener. Par exemple aucun événement de changement de sélection est géré.
Alors vous vous demandez certainement pourquoi je passe du temps à documenter ce contrôle. C'est seulement parce que je pense que s'il n'est pas documenté, il sera peu utilisé, et si les gens l'utilisent peu personne n'aura l'idée d'améliorer son code. Et puis, après un peu de temps passé avec ce contrôle, je me suis aperçu que l'on pouvait gérer les arbres dynamiques tel qu'il est en ajoutant simplement un bouton pour cela.
Le concept entourant tous ces contrôles est une complète séparation des données et du rendu à l'écran. C'est ce qui est connu sous le nom de Model/View/Controller-design (MVC)
- Les interfaces com.sun.star.awt.tree.XMutableTreeDataModel et com.sun.star.awt.tree.XMutableTreeNode sont relatives au model,
- L'interface com.sun.star.awt.tree.XTreeControl est relative au contrôle et à l'affichage.
Notre programme OOoBasic de départ
rvc44 a posté dans le OOOForum (Thu Dec 20, 2007) un exemple en OOoBasic qui me servira de point de départ. J'ai ajouté un "event listener" et obtenu le morceau de code suivant :
REM ***** BASIC ***** 'Listing 7 Option Explicit 'Most of this code belongs to rvc44 http://www.oooforum.org/forum/viewtopic.phtml?t=67005&highlight= Private oDlg as Object, oLbDescription as Object Private oTreeCtrl as Object, oTreeModel as Object Private oMutableTreeDataModel as Object Private oRootNode as Object, oChildNode as Object, ogNode as Object Sub mainTree '[Simple example: collapsing and expanding folders] DialogLibraries.loadLibrary("Standard") 'create the dialog oDlg = CreateUnoDialog(DialogLibraries.Standard.SimpleTreeDialog) If IsNull(oDlg) Then Exit Sub 'get a refrence to the control/s and its model/s oLbDescription = oDlg.getControl("lbDescription") oLbDescription.setText( "A very simple tree control with listeners." & _ chr(13) & chr(13) &_ "Expanding and collapsing happends automatically" ) oTreeCtrl = oDlg.getControl("TreeControl1") oTreeModel = oTreeCtrl.Model 'XRay oTreeModel 'instantiate the MutableTreeDataModel service oMutableTreeDataModel = createUnoService(_ "com.sun.star.awt.tree.MutableTreeDataModel") 'XRay oMutableTreeDataModel 'MutableTreeDataModel implemets XMutableTreeDataModel 'use XMutableTreeNode::createNode( ' [in] any DisplayValue, ' [in] boolean ChildsOnDemand ) 'to create the root node 'If you pass to the boolean parameter TRUE as a argument, 'the created node will be treated as a non-leaf (branch) node 'by the XTreeControl , even when it has no child nodes. 'If false, the node will be a leaf. 'The root should obviously be a non-leaf node. oRootNode = oMutableTreeDataModel.createNode( "Root", true ) 'use XMutableTreeNode::setRoot( [in] XMutableTreeNode RootNode ) 'to set this node as the root of the model oMutableTreeDataModel.setRoot(oRootNode) 'now create the children of the root Dim oChildNode1 oChildNode1 = oMutableTreeDataModel.createNode( "Parent 1", true ) oRootNode.appendChild(oChildNode1) 'Create this child's own children 'In two steps: Dim oSubChildNode oSubChildNode = oMutableTreeDataModel.createNode(_ "Child 1", true ) oChildNode1.appendChild(oSubChildNode) 'In only one: 'Go deeper in the hierarchical structure oSubChildNode.appendChild( _ oMutableTreeDataModel.createNode( _ "Grandson 1", false ) ) oSubChildNode.appendChild( _ oMutableTreeDataModel.createNode( _ "Grandson 2", false ) ) 'In only one: oChildNode1.appendChild( oMutableTreeDataModel.createNode( _ "Child 2", true ) ) '======================================================================= 'As you see, the Data Model always creates the nodes '(XMutableDataModel::createNode) 'and then you add it to the node you want, taking care that 'the node created and the parent node belong to the same data model Dim oChildNode2 oChildNode2 = oMutableTreeDataModel.createNode( "Parent 2", true ) oRootNode.appendChild(oChildNode2) Dim oChildNode3 oChildNode3 = oMutableTreeDataModel.createNode( "Parent 3", FALSE ) 'oChildNode3.setCollapsedGraphicURL( ANY_DOC ) 'oChildNode3.setExpandedGraphicURL( ANY_DOC ) 'oChildNode3.setNodeGraphicURL( BASIC_BRAKE ) oRootNode.appendChild(oChildNode3) Dim oChildNode4 oChildNode4 = oMutableTreeDataModel.createNode( "Parent 4", true ) oRootNode.appendChild(oChildNode4) Dim oChildNode5 oChildNode5 = oMutableTreeDataModel.createNode( "Parent 5", true ) oRootNode.appendChild(oChildNode5) Dim oChildNode6 oChildNode6 = oMutableTreeDataModel.createNode( "Parent 6", FALSE ) oRootNode.appendChild(oChildNode6) 'Although the API refrence states the following: ' "If you want to add child nodes to your tree on demand ' you can .[..] Make sure the parent node returns true ' for XTreeNode::hasChildsOnDemand() either by implementing ' XTreeNode yourself or, if you use the MutableTreeDataModel , ' use XMutableTreeNode::setHasChildsOnDemand() ." 'http://api.openoffice.org/docs/common/ref/com/sun/star/awt/tree/TreeControl.html Dim bHasChildernOnDemand as Boolean 'in this case hasChildsOnDemand returns FALSE 'bHasChildernOnDemand = oChildNode6.hasChildsOnDemand() Dim aChild : aChild = oMutableTreeDataModel.createNode( "Grandson", FALSE ) 'BUT the node is appended to this node that has no children on demand oChildNode6.appendChild(aChild) 'Should it throw an exception? 'set the data model at the TreeControlModel::DataModel property. oTreeModel.DataModel = oMutableTreeDataModel ' oTreeCtrl.DefaultExpandedGraphicURL = FOLDER_OPEN 'oTreeCtrl.DefaultCollapsedGraphicURL = FOLDER_CLOSED Dim oListener,oListener2 oListener = CreateUnoListener("Tree_","com.sun.star.awt.tree.XTreeExpansionListener") oListener2 = createUnoListener("Select_","com.sun.star.view.XSelectionChangeListener") 'Xray oListener2 oTreeCtrl.addTreeExpansionListener(oListener) oTreeCtrl.addSelectionChangeListener(oListener2) oDlg.execute() oTreeCtrl.removeSelectionChangeListener(oListener2) oTreeCtrl.removeTreeExpansionListener(oListener) oDlg.dispose() End Sub Sub Tree_treeExpanding(oEvt) 'oEvt.Node has methods : 'getChildAt Returns the child tree node at Index . 'getChildCount Returns the number of child nodes. 'getParent Returns the parent node of this node. 'getIndex Returns the index of Node in this instances children. 'hasChildsOnDemand Returns true if the childs of this node are created on demand. 'getDisplayValue If not empty, the textual representation of this any is used as the text part of this node. 'getNodeGraphicURL The URL for a graphic that is rendered before the text part of this node. 'getExpandedGraphicURL The URL for a graphic that is rendered to visualize expanded non leaf nodes. 'getCollapsedGraphicURL The URL for a graphic that is rendered to visualize collapsed non leaf nodes. MsgBox("Node : " & oEvt.Node.getDisplayValue &" expanding") ogNode = oEvt.Node end sub Sub Tree_treeExpanded(oEvt) ' MsgBox("Tree expanded") end sub Sub Tree_treeCollapsing(oEvt) 'MsgBox("Tree collapsing") end sub Sub Tree_treeCollapsed(oEvt) ' MsgBox("Tree collapsed") end sub Sub Tree_requestChildNodes(oEvt) 'print oEvt.Node.getIndex(oEvt.Node) 'XRay oEvt.Node ' Msgbox ("Tree_requestChildNodes") End Sub Sub Tree_disposing(oEvt) ' Msgbox ("Tree_disposing") End Sub Sub Select_selectionChanged(oEvt) MsgBox("Selection Changed") end sub
Voici une copie d'écran
qui montre le fonctionnement d'un listener déclenché par une expansion d'un noeud, et une deuxième avec un autre listener déclenché (changement de sélection).
Si vous voulez construire la même chose avec un autre langage de programmation, il vous faut vous investir dans les interfaces correspondantes :
- com.sun.star.awt.tree.XMutableTreeDataModel avec les méthodes
createNode
etsetRoot
, - com.sun.star.awt.tree.XMutableTreeNode avec la méthode
appendChild
, - com.sun.star.awt.tree.XTreeControl -|> com.sun.star.view.XMultiSelectionSupplier -|> com.sun.star.view.XSelectionSupplier avec la méthode
getSelection
(-|> est une notation simplifiée de l'héritage).
Il est grand temps d'examiner la traduction en C++ de cet exemple.
Code C++ sans Listener
Comme d'habitude nous voulons utiliser la boîte de dialogue OOoBasic précédente mais avec du C++. Parce que nous voulons seulement un exemple démonstratif, nous allons simplifier l'arbre (couper quelques branches). Notre but est de retrouver le noeud sélectionné, mais comme mentionné dans le titre, sans listener. Cela signifie donc que nous voulons gérer les événements du contrôle d'arborescence seulement avec des fonctions membres. Nous allons essayer d'abord en OOoBasic.
Gérer les événements du contrôle d'arborescence avec OOoBasic
Notre but est simple : retrouver le noeud sélectionné de l'arborescence. On commence par retirer tous les listener du code OOoBasic :
REM ***** BASIC ***** 'Listing 8 ' code retiré pour simplification ... Sub mainTree '[Simple example: collapsing and expanding folders] ' code retiré pour simplification ..... 'Dim oListener,oListener2 'oListener = CreateUnoListener("Tree_","com.sun.star.awt.tree.XTreeExpansionListener") 'oListener2 = createUnoListener("Select_","com.sun.star.view.XSelectionChangeListener") 'Xray oListener2 'oTreeCtrl.addTreeExpansionListener(oListener) 'oTreeCtrl.addSelectionChangeListener(oListener2) oDlg.execute() 'oTreeCtrl.removeSelectionChangeListener(oListener2) 'oTreeCtrl.removeTreeExpansionListener(oListener) oDlg.dispose() End Sub
Tout ce qui gère les listeners est mis en commentaire. Ensuite on choisit parmi les événements montrés ci-dessous :
où vous pouvez voir que j'ai choisi l'événement "perte de focus" avec le sous-programme :
REM ***** BASIC ***** 'Listing 9 Sub LosingFocus(Event As Object) 'inspect(oTreeCtrl) 'getSelection is member fuction of com.sun.star.awt.tree.XTreeControl interface 'getDisplayValue is member function of com.sun.star.awt.tree.XTreeNode interface MsgBox(oTreeCtrl.getSelection.getDisplayValue()) End Sub
Si vous déroulez l'arbre et sélectionnez un noeud, cliquez dans le contrôle d'édition de texte pour voir automatiquement le résultat
où vous voyez que le sous-programme "LosingFocus" ci-dessus a été déclenché.
Gérer les événements avec des fonctions membres C++
Nous décidons de changer le programme OOoBasic précédent en quatre points :
- On simplifie l'arbre affiché,
- nous affichons ce qui est sélectionné dans le contrôle texte déjà existant plutôt que dans une boîte de message,
- parceque nous traitons encore et toujours de composants (et non pas de addon) il nous faut encore partir d'un fichier IDL. J'ai gardé le fichier IDL du compteur même si ma nouvelle boîte de dialogue ne me permet plus de le faire fonctionner. J'ai fait cela par paresse parce que dans ce genre de situation je ne vois pas très bien quelle interface sortir.
- l'événement "losing focus" est lié à une méthode appelée "LosingFocus" (voir le Developper's Guide pour savoir comment faire).
Notre nouveau constructeur
Le constructeurr doit afficher un arbre dans le contrôle correspondant. Pour dire les choses différemment nous allons retrouver la plus grande partie du sous-programme OOoBasic "mainTree" dans notre constructeur. Le code est ainsi :
// cpp // Listing 10 inline MyCounterImpl( Reference< XComponentContext > const & xContext) throw () : m_xContext( xContext ) { m_xMCF=m_xContext->getServiceManager(); Reference< XDesktop > xDesktop( m_xMCF->createInstanceWithContext( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Desktop" ) ), xContext ), UNO_QUERY_THROW ); Reference< XComponent > xcomponent = xDesktop->getCurrentComponent(); Sequence< Any> Args(1); Args[0] <<= xcomponent; Reference< XDialogProvider2 > xDialog2(m_xMCF->createInstanceWithArgumentsAndContext( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DialogProvider2" ) ), Args, xContext), UNO_QUERY_THROW ); // Uncomment below and comment above if you want the OOoDesktop as parent of your dialog // Reference< XDialogProvider2 > xDialog2(m_xMCF->createInstanceWithContext( // OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DialogProvider2" ) ), // xContext), // UNO_QUERY_THROW ); Reference< XDialog > xDialog=xDialog2->createDialogWithHandler( OUString::createFromAscii( "vnd.sun.star.script:Standard.SimpleTreeDialog?location=application" ), (XCountable *)this); // Constructing the Tree (17th Jul 2009) Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl = xControlContainer->getControl(OUString::createFromAscii("TreeControl")); Reference< XMutableTreeDataModel > xTreeMutDatMod (m_xMCF->createInstanceWithContext( OUString::createFromAscii("com.sun.star.awt.tree.MutableTreeDataModel"),xContext),UNO_QUERY_THROW); // Reference< XMutableTreeDataModel > xTreeMutDatMod(xTreeControl,UNO_QUERY); //NO NO NO:hangs the office Any any; any <<= OUString::createFromAscii("root"); Reference< XMutableTreeNode > xMTN=xTreeMutDatMod->createNode(any,sal_True); xTreeMutDatMod->setRoot(xMTN); any <<= OUString::createFromAscii("Parent 1"); Reference< XMutableTreeNode > xChildNode = xTreeMutDatMod->createNode(any,sal_True); xMTN->appendChild(xChildNode); any <<= OUString::createFromAscii("Child 1"); Reference< XMutableTreeNode > xChildNode2 = xTreeMutDatMod->createNode(any,sal_True); xChildNode->appendChild(xChildNode2); any <<= OUString::createFromAscii("Grandson 1"); Reference< XMutableTreeNode > xChildNode3 = xTreeMutDatMod->createNode(any,sal_False); xChildNode2->appendChild(xChildNode3); any <<= OUString::createFromAscii("Grandson 2"); xChildNode3 = xTreeMutDatMod->createNode(any,sal_False); xChildNode2->appendChild(xChildNode3); any <<= OUString::createFromAscii("Child 2"); xChildNode2 = xTreeMutDatMod->createNode(any,sal_True); xChildNode->appendChild(xChildNode2); any <<= OUString::createFromAscii("Parent 2"); xChildNode=xTreeMutDatMod->createNode(any,sal_True); xMTN->appendChild(xChildNode); // positionner le model pour voir l'arbre control (deux heures pour trouver les 4 lignes qui suivent) // traduction de oTreeModel = oTreeCtrl.Model et oTreeModel.DataModel = oMutableTreeDataModel Reference< XControlModel > xControlModel=xControl->getModel(); Reference< XPropertySet > xPropertySet( xControlModel,UNO_QUERY); any <<= xTreeMutDatMod; xPropertySet->setPropertyValue(OUString::createFromAscii("DataModel"),any); // execute dialog xDialog->execute(); }
La méthode "LosingFocus"
Le sous-programme "LosingFocus" en OOoBasic était très simple. Je l'ai traduit à l'aide d'un outil d'Introspection et la documentation IDL comme com.sun.star.awt.tree.XTreeControl, com.sun.star.awt.tree.XTreeNode et com.sun.star.awt.XTextComponent.
// C++ // Listing 11 sal_Bool SAL_CALL MyCounterImpl::callHandlerMethod(const Reference< XDialog >& xDialog,const Any& EventObject,const OUString & MethodName ) throw(WrappedTargetException, RuntimeException ){ if (MethodName.equalsAscii("LosingFocus")){//When Losing Focus in Tree control Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl = xControlContainer->getControl(OUString::createFromAscii("TreeControl")); // com.sun.star.awt.tree.XTreeControl Reference< XTreeControl > xTreeControl(xControl,UNO_QUERY); Any any=xTreeControl->getSelection(); Reference< XTreeNode > xTreeNode; any >>= xTreeNode; // met le resultat de selection dans le control de texte xControl = xControlContainer->getControl(OUString::createFromAscii("lbDescription")); Reference< XTextComponent > xTextComponent(xControl,UNO_QUERY); any = xTreeNode->getDisplayValue(); OUString OUStr; any >>= OUStr; xTextComponent->setText(OUStr + OUString::createFromAscii(" -- DONE --")); return sal_True; } return sal_False; }
Cette méthode est appelée lors de la perte du focus : en cliquant dans le contrôle de texte par exemple.
Voici une copie d'écran de la boîte de dialogue :
Parceque vous ne gérez plus qu'un seul événement, il vous faut aussi changer la fonction getSupportedMethodNames()
comme suit :
// C++ // Listing 12 Sequence< OUString > SAL_CALL MyCounterImpl::getSupportedMethodNames() throw (RuntimeException){ Sequence< OUString > SeqOUStr(1); SeqOUStr[0]=OUString::createFromAscii("LosingFocus"); // SeqOUStr[1]=OUString::createFromAscii("foo2"); // SeqOUStr[2]=OUString::createFromAscii("foo3"); // SeqOUStr[3]=OUString::createFromAscii("foo4"); return SeqOUStr; }
Je ne suis pas sûr du fonctionnement correct de xml2cmp sensé travailler avec le fichier CppComponent.uno.xml pour un type comme :
<type>com.sun.star.awt.tree.XTreeControl</type> La profondeur des modules est-elle trop grande pour lui dans ce cas ? J'ai déplacé la création des fichier hpp dans le MakeFile pour que cela fonctionne. SergeMoutou 16:30, 17 July 2009 (UTC) |
C++ avec listener
Si j'adore utiliser les listeners avec OOoBasic je ne les porte pas dans mon coeur en C++ : ils sont faciles à utiliser en OOoBasic mais difficiles en C++. Je les ai déjà utilisés à plusieurs reprises mais bon ceci ne sera pas documenté avant un certain temps. Si quelqu'un veut s'y coller, c'est sans refus. SergeMoutou 12:54, 25 July 2009 (UTC)
A FAIRE
Les arbres dynamiques
Dans cette section, nous voulons examiner la possibilité de gérer des arbres dynamiques. Un arbre dynamique est un arbre qui est construit à la demande. C'est un sujet qui me tenait à coeur parce que je me suis toujours dit que l'on ne pouvait pas faire de choses sérieuses sans cela. Avant d'écrire les deux sections suvantes j'ignorai si cela pouvait être fait ou pas !
Commençons encore à l'aide du langage OOoBasic.
Arbres dynamiques en OOoBasic
En fait historiquement, j'ai commencé par d'abord écrire la section suivante. Mais suite aux nombreux problèmes rencontrés je suis revenu sur cette section. Après plusieurs heures passées je n'ai pas été capable de le faire fonctionner en C++ alors que cela m'a pris seulement 10 minutes en OOoBasic ! Pour votre information, j'ai fini par le faire fonctionner aussi en C++.
Je garde encore la boîte de dialogue initiale et ajoute deux boutons : un bouton "OK" et un bouton "add Child". Vous sélectionnez un noeud et quand vous cliquez sur "add Child", un enfant est ajouté. Son nom est le nom du noeud sélectionné suivi de ".n" où n est le nombre d'enfants (déjà créés). C'est un arbre dynamique parce que sa taille n'est pas fixée. Son code est le suivant :
REM ***** BASIC ***** 'Listing 14 Option Explicit Private oDlg as Object, oLbDescription as Object Private oTreeCtrl as Object, oTreeModel as Object Private oMutableTreeDataModel as Object Private oRootNode as Object, oChildNode as Object, ogNode as Object Sub mainTree '[Simple example: collapsing and expanding folders] DialogLibraries.loadLibrary("Standard") oDlg = CreateUnoDialog(DialogLibraries.Standard.SimpleTreeDialog) If IsNull(oDlg) Then Exit Sub oTreeCtrl = oDlg.getControl("TreeControl1") oTreeModel = oTreeCtrl.Model oMutableTreeDataModel = createUnoService(_ "com.sun.star.awt.tree.MutableTreeDataModel") oRootNode = oMutableTreeDataModel.createNode( "Root", true ) oMutableTreeDataModel.setRoot(oRootNode) Dim oChildNode1 oChildNode1 = oMutableTreeDataModel.createNode( "Parent 1", true ) oRootNode.appendChild(oChildNode1) 'Create this child's own children 'In two steps: Dim oSubChildNode oSubChildNode = oMutableTreeDataModel.createNode(_ "Child 1", true ) oChildNode1.appendChild(oSubChildNode) 'In only one: 'Go deeper in the hierarchical structure oSubChildNode.appendChild( _ oMutableTreeDataModel.createNode( _ "Grandson 1", false ) ) oSubChildNode.appendChild( _ oMutableTreeDataModel.createNode( _ "Grandson 2", false ) ) 'In only one: oChildNode1.appendChild( oMutableTreeDataModel.createNode( _ "Child 2", true ) ) Dim oChildNode2 oChildNode2 = oMutableTreeDataModel.createNode( "Parent 2", true ) oRootNode.appendChild(oChildNode2) Dim oChildNode3 oChildNode3 = oMutableTreeDataModel.createNode( "Parent 3", FALSE ) oRootNode.appendChild(oChildNode3) Dim oChildNode4 oChildNode4 = oMutableTreeDataModel.createNode( "Parent 4", true ) oRootNode.appendChild(oChildNode4) Dim oChildNode5 oChildNode5 = oMutableTreeDataModel.createNode( "Parent 5", true ) oRootNode.appendChild(oChildNode5) Dim oChildNode6 oChildNode6 = oMutableTreeDataModel.createNode( "Parent 6", FALSE ) oRootNode.appendChild(oChildNode6) Dim bHasChildernOnDemand as Boolean Dim aChild : aChild = oMutableTreeDataModel.createNode( "Grandson", FALSE ) oChildNode6.appendChild(aChild) oTreeModel.DataModel = oMutableTreeDataModel oDlg.execute() oDlg.dispose() End Sub Sub addChild(Event As Object) Dim oParentNode, oChildNode Dim nb as long Dim oChildName as String oParentNode = oTreeCtrl.getSelection() nb = oParentNode.getChildCount() nb=nb+1 'I want numerotation begins with 1 oChildName = oParentNode.getDisplayValue() + "." + nb oChildNode = oMutableTreeDataModel.createNode(oChildName , TRUE ) oParentNode.appendChild(oChildNode) oLbDescription = oDlg.getControl("lbDescription") oLbDescription.setText(oChildName) End Sub
Le sous-programme "addChild" est lié au bouton correspondant (pas difficile, ils ont même nom). Voici donc une copie d'écran du résultat :
Question : quel est le dernier noeud créé ? Réponse dans le contrôle de texte : "Root.7.1.2".
Voyons maintenant ce que cela donne en C++.
Arbres dynamiques en C++
Je parts de l'exemple déjà traité(C++) avec le même fonctionnement. Quand un noeud est sélectionné, le bouton "add Child" créé un noeud enfant avec nodename.i comme nom, où i est le nombre d'enfants et nodename le nom du noeud. Pour la mise au point, j'ai aussi mis le nom du noeud ajouté dans le contrôle de texte.
Notre nouveau constructeur
Le constructeur de la section précédente est légèrement modifié. Voici comment :
// c++ // Listing 15 // added this constructor 06/06/09 inline MyCounterImpl( Reference< XComponentContext > const & xContext) throw () : m_xContext( xContext ) { m_xMCF=m_xContext->getServiceManager(); // Reference< XMutableTreeDataModel > xTreeMutDatMod(xTreeControl,UNO_QUERY); //NO NO NO:hangs the office : see below Reference< XMutableTreeDataModel > xMutTreeDatMod(m_xMCF->createInstanceWithContext( OUString::createFromAscii("com.sun.star.awt.tree.MutableTreeDataModel"),m_xContext),UNO_QUERY_THROW); m_xMutTreeDatMod = xMutTreeDatMod; // If you want to use java Inspector Reference< XInstanceInspector > xInspector(m_xMCF->createInstanceWithContext( OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.InstanceInspector" ) ), m_xContext), UNO_QUERY_THROW ); m_xInspector = xInspector; Reference< XDesktop > xDesktop( m_xMCF->createInstanceWithContext( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Desktop" ) ), xContext ), UNO_QUERY_THROW ); Reference< XComponent > xcomponent = xDesktop->getCurrentComponent(); Sequence< Any> Args(1); Args[0] <<= xcomponent; Reference< XDialogProvider2 > xDialog2(m_xMCF->createInstanceWithArgumentsAndContext( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DialogProvider2" ) ), Args, xContext), UNO_QUERY_THROW ); // Reference< XDialogProvider2 > xDialog2(m_xMCF->createInstanceWithContext( // OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DialogProvider2" ) ), // xContext), // UNO_QUERY_THROW ); Reference< XDialog > xDialog=xDialog2->createDialogWithHandler( OUString::createFromAscii( "vnd.sun.star.script:Standard.SimpleTreeDialog?location=application" ), (XCountable *)this); // Constructing the Tree 21th Jul 2009 (dynamic Tree) Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl = xControlContainer->getControl(OUString::createFromAscii("TreeControl")); Any any; any <<= OUString::createFromAscii("root"); Reference< XMutableTreeNode > xMTN=m_xMutTreeDatMod->createNode(any,sal_True); m_xMutTreeDatMod->setRoot(xMTN); any <<= OUString::createFromAscii("Parent 1"); Reference< XMutableTreeNode > xChildNode = m_xMutTreeDatMod->createNode(any,sal_True); xMTN->appendChild(xChildNode); any <<= OUString::createFromAscii("Child 1"); Reference< XMutableTreeNode > xChildNode2 = m_xMutTreeDatMod->createNode(any,sal_True); xChildNode->appendChild(xChildNode2); any <<= OUString::createFromAscii("Grandson 1"); Reference< XMutableTreeNode > xChildNode3 = m_xMutTreeDatMod->createNode(any,sal_False); xChildNode2->appendChild(xChildNode3); any <<= OUString::createFromAscii("Grandson 2"); xChildNode3 = m_xMutTreeDatMod->createNode(any,sal_False); xChildNode2->appendChild(xChildNode3); any <<= OUString::createFromAscii("Child 2"); xChildNode2 = m_xMutTreeDatMod->createNode(any,sal_True); xChildNode->appendChild(xChildNode2); any <<= OUString::createFromAscii("Parent 2"); xChildNode=m_xMutTreeDatMod->createNode(any,sal_True); xMTN->appendChild(xChildNode); // set the model to see the tree in control (two hours to find four lines below) // translation of oTreeModel = oTreeCtrl.Model and oTreeModel.DataModel = oMutableTreeDataModel Reference< XControlModel > xControlModel=xControl->getModel(); Reference< XPropertySet > xPropertySet( xControlModel,UNO_QUERY); any <<= m_xMutTreeDatMod; xPropertySet->setPropertyValue(OUString::createFromAscii("DataModel"),any); // execute dialog xDialog->execute(); } // end of constructor
Le nouvau sous-programme "callHandlerMethod"
Comme cela peut être facilement vu, la seule méthode utilisée est "addChild" :
// C++ // Listing 16 // XDialogEventHandler implementation sal_Bool SAL_CALL MyCounterImpl::callHandlerMethod(const Reference< XDialog >& xDialog,const Any& EventObject,const OUString & MethodName ) throw(WrappedTargetException, RuntimeException ){ if (MethodName.equalsAscii("LosingFocus")){//When Losing Focus in Tree control // not used in this example return sal_True; } if (MethodName.equalsAscii("addChild")){//add a child to the selected node // First retrieve the selection Reference< XControlContainer > xControlContainer(xDialog,UNO_QUERY); Reference< XControl > xControl = xControlContainer->getControl(OUString::createFromAscii("TreeControl")); // com.sun.star.awt.tree.XTreeControl Reference< XTreeControl > xTreeControl(xControl,UNO_QUERY); Any any=xTreeControl->getSelection(); // Parent Reference< XMutableTreeNode > xParentNode; any >>= xParentNode; // adding sal_Int32 nb=xParentNode->getChildCount(); // Child OUString OUStr; any=xParentNode->getDisplayValue(); any >>= OUStr; OUStr = OUStr + OUString::createFromAscii(".") + OUString::valueOf((sal_Int32)++nb); // put the new node name in text control xControl = xControlContainer->getControl(OUString::createFromAscii("lbDescription")); Reference< XTextComponent > xTextComponent(xControl,UNO_QUERY); xTextComponent->setText(OUStr); any <<= OUStr; Reference< XMutableTreeNode > xChildMutTreeNode = m_xMutTreeDatMod->createNode(any ,sal_True); // Introspection // any <<= xChildMutTreeNode; // m_xInspector->inspect(any,OUString::createFromAscii("Inspector")); xParentNode->appendChild(xChildMutTreeNode); return sal_True; } return sal_False; } Sequence< OUString > SAL_CALL MyCounterImpl::getSupportedMethodNames() throw (RuntimeException){ Sequence< OUString > SeqOUStr(2); SeqOUStr[0]=OUString::createFromAscii("LosingFocus"); SeqOUStr[1]=OUString::createFromAscii("addChild"); return SeqOUStr; }
Voici une capture d'écran
où vous pouvez distinguer tous les nouveaux noeuds ajoutés.
Page d'accueil
Page d'accueil du développement C++ à l'aide du SDK
See also
- Version anglaise de ce chapitre.
- Construire des composants
- Gérer des boîtes de dialogues dans les composants.
- The New Tree Contol (in construction)
- The corresponding paragraph in Developer's Guide
- Generic UNO Interfaces for complex toolbar controls
- Popup Menu Controller and C++
- Statusbar Controler and C++
- C++ and UNO tutorial
- Service Declaration
- Registering properties
- UNO tutorial
- UNO IDL
- Extensions Packager (BasicAddonBuilder from Paolo Mantovani)
- BASIC UNO Object Browser : You can see the corresponding code as a complex component.
- Minimal Java Component
- Gérer les boîtes de Dialogues en OOoBasic.
- Guide OOoBasic (FR)