[Base] Sélection d'enregistrement avec une liste déroulante

Venez découvrir tous les tutoriels, modèles et autres foires aux questions afin de maîtriser rapidement votre suite bureautique favorite.

Modérateur: Vilains modOOs

Règles du forum
Aucune question dans cette section !
Cette section est faite pour présenter les tutoriels. Si vous avez une question sur l'installation, le fonctionnement ou l'utilisation, vous devez poster dans la section du module où se produit le problème.

[Base] Sélection d'enregistrement avec une liste déroulante

Messagepar Pierre-Yves Samyn » 01 Fév 2009 12:08

En préambule une précision...

Il ne faut pas confondre deux choses :

  • Quand un enregistrement est sélectionné, disposer de listes pour modifier la valeur d'un des champs. Par exemple, pour une facture, pouvoir choisir dans la liste des clients. Il va de soi que ce faisant on ne souhaite pas changer de facture...
  • Rechercher, choisir, sélectionner un enregistrement (une facture, un client, un contrebassiste, etc.), par exemple d'après son nom. Après cette opération l'enregistrement courant change : ce n'est plus systématiquement le premier saisi mais celui trouvé qui est affiché, prêt pour la consultation ou la modification.

Nous n'allons traiter ici que de ce deuxième cas de figure : la sélection d'un ou plusieurs enregistrements.

La plupart du temps on utilise pour cela une requête paramétrée. Or l'utilisation de paramètres dans une requête est assez frustrante car on ne maîtrise pas la présentation de leur saisie : OOo affiche une simple zone de saisie dans un dialogue.

L'objet de ce fil est de présenter quelques techniques permettant de recourir à des listes déroulantes affichant les valeurs possibles pour les paramètres.

OOoBase ne permet pas, à ce jour, de faire référence dans une requête à un contrôle de formulaire (comme le permet Access notamment).

En revanche il est bien sûr possible de faire l'inverse : fonder un formulaire sur une requête. Le problème est alors de "lier" la sélection faite dans une liste avec l'affichage du formulaire.

La première technique abordée est la plus simple en ce qu'elle n'utilise aucune macro : elle est fondée sur la mise en oeuvre d'un sous-formulaire.

Nous désirons obtenir :


cequonveut.png
cequonveut.png (3.1 Kio) Consulté 106410 fois



Dans cet exemple la liste affiche la liste des prénoms figurant dans la table. Après sélection de l'un d'entre eux, le clic sur le bouton doit rafraîchir le contrôle Table de manière à n'afficher que les enregistrements concernés.

Le "truc" est d'utiliser une table "supplémentaire" qui ne servira que pour la sélection. Dans l'exemple je l'ai donc nommée... Sélection.
Elle ne contient que deux champs :
  • ID_Sélection (Integer - clé primaire)
  • Sélection (Texte VARCHAR_IGNORECASE)

Saisir un seul enregistrement dans cette table (le champ Sélection peut rester à vide).

Fonder le formulaire principal (MainForm dans l'exemple) sur cette table Sélection
La liste déroulante sera liée au champ Sélection ; Type de contenu : SQL ; Contenu :

Code : Tout sélectionner   AgrandirRéduire
SELECT  DISTINCT "Prénom" FROM "Personnes" AS "Personnes"


Nota :
  • Le mot clé DISTINCT signifie que la liste n'affichera qu'une seule occurrence par prénom (i.e. elle n'affichera qu'une seule fois Raoul même si plusieurs enregistrements ont ce prénom).
  • Nous ne souhaitons pas saisir dans la table "Sélection", qui n'est là que pour pouvoir lier les données du sous-formulaire sur le critère de sélection. Le formulaire principal limite donc la saisie :
    • Autoriser les ajouts : non
    • Autoriser les modifications : oui
    • Autoriser les suppressions : non
    • N'ajouter que des données : non

Créer un sous-formulaire fondé sur la requête ou la table "à afficher filtrée" (RPersonnes dans l'exemple : cette requête permet de relier la table Personne avec la table Civilité pour afficher le libellé de cette dernière).

prenom.png
prenom.png (7.25 Kio) Consulté 106414 fois


Le sous-formulaire Standard est lié au formulaire principal sur les champs Sélection (du formulaire principal, autrement dit la liste déroulante) et Prénom (du sous-formulaire).

Le bouton Actualiser a comme propriété Action : Rafraîchir le formulaire

RequêteListe.odb
La base jointe comprend un autre exemple dans le formulaire "Civilité". Il montre que la même table "Sélection" peut être utilisée pour une recherche sur un autre champ.
(22.62 Kio) Téléchargé 5849 fois
Dernière édition par Pierre-Yves Samyn le 15 Déc 2009 19:23, édité 2 fois.
Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
 
Message(s) : 11276
Inscrit le : 02 Mai 2006 09:42

Filtrer à l'aide de macros

Messagepar Pierre-Yves Samyn » 01 Fév 2009 12:14

La deuxième technique abordée utilise des macros.

Elle est mise en œuvre dans ce fil : https://forum.openoffice.org/fr/forum/v ... 224#p21224

La base exemple de ce fil permet à la fois de sélectionner dans une liste déroulante et de saisir un critère "libre" dans la zone Rechercher :


macros.png
macros.png (5.43 Kio) Consulté 106382 fois



Dans les deux cas (liste ou zone de saisie), le principe est de modifier par macro la source du formulaire après que l'utilisateur ait fait son choix (soit modification de la liste, soit clic sur le bouton).

Lors du clic sur le bouton la procédure suivante est déclenchée :

Code : Tout sélectionner   AgrandirRéduire
Sub PysRechercher()
dim PysTexte as string, PysForm as object
dim PysSQL as string

PysForm = thisComponent.DrawPage.Forms.getByName("Standard")      'Accès au formulaire
PysTexte = PysForm.getByName("TextBox").Text                  'Accès au texte de la zone

'SELECT * FROM "T_FILM" WHERE "film_nom" LIKE '%Ram%'
'Concaténation avec le choix fait dans la liste
PysSQL = "SELECT * FROM T_FILM WHERE film_nom LIKE '%" + PysTexte + "%'"
PysForm.command = PysSQL            'Redéfinition de la source du formulaire
PysForm.reload                     'Recharge le formulaire

End Sub


Comme on le voit, l'instruction SQL source du formulaire est modifiée : on ajoute le mot clé LIKE ainsi que le caractère % (comme on le ferait dans une requête paramétrée) de part et d'autre du texte saisi dans la zone de recherche.

Le formulaire est ensuite "rechargé" de manière à prendre en compte la modification.

Lors de la modification de la liste déroulante, la procédure suivante est déclenchée :

Code : Tout sélectionner   AgrandirRéduire
Sub PysActualiser(PysEvt as object)
dim PysList as object, PysForm as object
dim PysSQL as string, PysChoix as string

PysList = PysEvt.source               'La liste déroulante

PysChoix = PysList.SelectedItem         'Choix fait dans la liste
PysForm = PysList.model.Parent         'On "remonte" au parent (le formulaire)

'SELECT T_FILM.*, T_GENRE.* FROM T_FILM, T_GENRE WHERE T_FILM.id_genre = T_GENRE.id_genre AND T_GENRE.genre = 'comique'
'Concaténation avec le choix fait dans la liste
PysSQL = "SELECT T_FILM.*, T_GENRE.* FROM T_FILM, T_GENRE WHERE T_FILM.id_genre = T_GENRE.id_genre AND T_GENRE.genre ='" + PysChoix + "'"
PysForm.command = PysSQL            'Redéfinition de la source du formulaire
PysForm.reload                     'Recharge le formulaire

End Sub


La procédure est un peu plus complexe...

On indique en paramètre un nom de variable (PysEvt dans l'exemple). Cette variable "recevra" en quelque sorte l'événement déclencheur. A partir de cet événement on peut remonter à la source c'est-à-dire à la liste qui nous donne l'élément choisi et, à un niveau supérieur le "parent" de la liste, c'est-à-dire le formulaire lui-même, ce qui nous donne enfin accès à la propriété SQL du formulaire.

Il ne reste plus qu'à modifier cette instruction pour ajouter le choix fait dans la liste puis recharger le formulaire pour appliquer la modification.

Nota : la recherche ou sélection se fait dans cet exemple sur des chaînes de caractères. Il est de ce fait nécessaire d'ajouter des quotes avant et après le texte recherché. Ceci ne serait pas à faire dans le cas d'une recherche "numérique".


RequêteListeEtZone.odb
(12.61 Kio) Téléchargé 3115 fois
Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
 
Message(s) : 11276
Inscrit le : 02 Mai 2006 09:42

Sélection multi-critères

Messagepar Pierre-Yves Samyn » 01 Fév 2009 12:19

L'exemple suivant va plus loin qui permet une sélection multi-critères.

La plupart des données sont reprises du fil https://forum.openoffice.org/fr/forum/ftopic7003.html

La solution est ici enrichie de la gestion d'un opérateur ET / OU entre les critères. Cet ajout est la seule différence, le principe restant le même : reconstruction de l'instruction SQL source du formulaire par concaténation avec les choix faits dans les listes.

Nous désirons gérer un formulaire du type :


plusieurs.png


Ci-dessous le code mis en œuvre :

Code : Tout sélectionner   AgrandirRéduire
option explicit

sub PysActualiser(PysEvt as object)

dim PysForm as object, PysRadio as object
dim PysSQL as string, PysChoix() as string, PysOper as string
dim PysNb as integer

PysForm = PysEvt.source.model.Parent            'On "remonte" au parent (le formulaire)
PysRadio = PysForm.getByName("RadioGroup1")         'Les boutons radio soit ET (1), soit OU (2)

PysOper = iif(PysRadio.state = 0, " OR " , " AND ")

PysSQL = "SELECT * FROM T_Reg_App_Cave_List WHERE "

with PysForm.getByName("ListMillesime")
   if .currentValue <> "" then 'Si la liste n'est pas vide (chargement du formulaire)
      redim PysChoix(0)
      if .currentValue = "Tout"  then
         PysChoix(0) = " Millesime LIKE '*'"
      else
         PysChoix(0) = " Millesime = '" & .currentValue & "'"
      end if   
   end if
end with

with PysForm.getByName("ListCouleur")
   if .currentValue <> "" then
      PysNb = ubound(PysChoix())+1
      redim preserve PysChoix(PysNb)
      if .currentValue = "Tout"  then
         PysChoix(PysNb) = " Couleur LIKE '*'"
      else
         PysChoix(PysNb) = " Couleur = '" & .currentValue & "'"
      end if
   end if
end with

with PysForm.getByName("ListAppellation")
   if .currentValue <> "" then
      PysNb = ubound(PysChoix())+1
      redim preserve PysChoix(PysNb)
      if .currentValue = "Tout"  then
         PysChoix(PysNb) = " Appellation LIKE '*'"
      else
         PysChoix(PysNb) = " Appellation = '" & .currentValue & "'"
      end if
   end if
end with

with PysForm.getByName("ListRegion")
   if .currentValue <> "" then
      PysNb = ubound(PysChoix())+1
      redim preserve PysChoix(PysNb)
      if .currentValue = "Tout"  then
         PysChoix(PysNb) = " Region LIKE '*'"
      else
         PysChoix(PysNb) = " Region = '"  & .currentValue & "'"
      end if
   end if
end with

PysSQL = PysSQL & join(PysChoix, PysOper)

PysForm.command = PysSQL            'Redéfinition de la source du formulaire
PysForm.reload                     'Recharge le formulaire

End sub


Explications :
  • Les boutons radio se limitant à une alternative nous pouvons tester simplement l'état (propriété State). Pour une gestion plus complexe se rapporter à ce fil :
    https://forum.openoffice.org/fr/forum/v ... ilit=radio
  • Comme il y a plusieurs listes, il faut gérer le cas où certaines ne sont pas utilisées et restent donc "vides"

RequêtePlusieursCritères.odb
(24.59 Kio) Téléchargé 2768 fois
Dernière édition par Pierre-Yves Samyn le 01 Fév 2009 13:17, édité 1 fois.
Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
 
Message(s) : 11276
Inscrit le : 02 Mai 2006 09:42

Filtrer une liste en fonction d'une autre

Messagepar Pierre-Yves Samyn » 01 Fév 2009 12:26

L'exemple précédent met en oeuvre plusieurs listes mais elles sont indépendantes l'une de l'autre. Une utilisation fréquente des listes a pour objet de réduire successivement la sélection des données (choisir une région, puis un département, puis un canton, etc.). C'est ce dont nous allons traiter maintenant.

On s'inspire ici du fil :
https://forum.openoffice.org/fr/forum/v ... 525#p22525


voitures.png
voitures.png (4.36 Kio) Consulté 106364 fois



La sélection d'une marque de voiture limite l'affichage de la liste Voitures à celles du constructeur choisi.

ListesLiées.odb
(19.89 Kio) Téléchargé 3712 fois



La procédure PysOpen est lancée par clic sur le bouton. Elle permet d'ouvrir le formulaire Marque pour en ajouter de nouvelles (il serait possible de faire la même chose pour les modèles de voiture).
La procédure PysMajListe est lancée sur modification de la liste des marques. Elle utilise toujours le même principe (reconstruction de l'instruction SQL source de la liste voiture).
La procédure PysRefresh est lancée sur réception du focus de la liste des marques. Ceci est utile notamment si on a ouvert le formulaire d'ajout afin de prendre en compte les nouvelles données.
La procédure PysActualisation est lancée après le changement d'enregistrement (événement "formulaire") pour sélectionner dans la liste Voiture la valeur contenue dans le champ.

Code : Tout sélectionner   AgrandirRéduire
'********************************************************************
option explicit

dim PysLstMarque as Object , PysLstVoiture AS Object

Sub PysOpen(PysEvent)

dim PysContainer  as object, PysConnection as object
dim PysProp(1) as New com.sun.star.beans.PropertyValue

PysContainer =  PysEvent.Source.Model.Parent.ActiveConnection.Parent.DatabaseDocument.FormDocuments
PysConnection = PysEvent.Source.Model.Parent.ActiveConnection
PysProp(0).Name = "ActiveConnection"
PysProp(0).Value = PysConnection
PysProp(1).Name = "OpenMode"
PysProp(1).Value = "open"
PysContainer.loadComponentFromURL("Marque","_blank",0,PysProp())

end sub

sub PysRefresh
ThisComponent.DrawPage.Forms.getByName("Standard").getByName("lbox_marque").refresh
end sub

'************************************************************************************************
sub PysMajListe
'************************************************************************************************
'Lancée sur modification de la liste des marques pour mettre à jour la liste des modèles
'************************************************************************************************

DIM var_id_marque as integer

'Recupere les composants liste

PysLstMarque = ThisComponent.DrawPage.Forms.getByName("Standard").getByName("lbox_marque")
PysLstVoiture = ThisComponent.DrawPage.Forms.getByName("Standard").getByName("lbox_voiture")

'Recupere l'id de la marque selectionnée

'Syntaxe si le champ n'est pas lié à un champ de la base
'var_id_marque = PysLstMarque.SelectedItems(0)

'Syntaxe si le champ est lié à un champ de la base
var_id_marque = PysLstMarque.valueItemList(PysLstMarque.SelectedItems(0))

'Modifie la requete SQL de la liste des voitures :

PysLstVoiture.ListSource() = array("SELECT nom_voiture, id_voiture FROM T_Voiture WHERE id_marque =" & var_id_marque)
PysLstVoiture.refresh

end sub


'************************************************************************************************
sub PysActualisation
'************************************************************************************************
'Lancée après changement d'enregistrement pour sélectionner dans la liste la valeur contenue
'dans le champ
'************************************************************************************************

dim ExoTrav

PysMajListe 

ExoTrav= ExoRechercheDansTableau(PysLstVoiture.ValueItemList, PysLstVoiture.boundField.Value)

if ExoTrav <> "#N/A" then
   PysLstVoiture.SelectedItems = array(ExoTrav)
else
   PysLstVoiture.SelectedItems = array(0)
end if

end sub


'******************************************************************************************************
Function ExoRechercheDansTableau(ExoTablo, ExoRech)
'******************************************************************************************************
dim i as integer

ExoRechercheDansTableau = "#N/A"

for i = lbound(ExoTablo) to ubound(ExoTablo)
   if ExoTablo(i)= ExoRech then
      ExoRechercheDansTableau = i
      exit for
   end if
next i

end function



Merci de ne poser aucune question à la suite de ce tutoriel.


Les poser soit dans la rubrique Base de données (questions relatives à la première technique) ou dans la section Macros (si la question porte sur ces dernières).
Dernière édition par Pierre-Yves Samyn le 06 Mai 2010 09:39, édité 1 fois.
Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
 
Message(s) : 11276
Inscrit le : 02 Mai 2006 09:42

Re: [Base]Filtrer une requête avec une liste déroulante

Messagepar sebmdp » 23 Fév 2009 18:29

Bonjour,

Le titre étant très précis je ne posterais que le lien pour faciliter les recherches des utilisateurs qui veulent à partir de ce fil construire une recherche multi-critères non pas par liste déroulante mais par case à cocher :
https://forum.openoffice.org/fr/forum/viewtopic.php?f=8&t=15045&p=83649#p83649

Salutations.
Open Office 3.2.1
Mac OS 10.5.8
sebmdp
Membre hOOnoraire
Membre hOOnoraire
 
Message(s) : 125
Inscrit le : 08 Juil 2008 17:31
Localisation : Orleans / France

Re: [Base]Sélectionner un enreg. avec une liste déroulante

Messagepar Pierre-Yves Samyn » 15 Nov 2010 17:50

Atteindre un enregistrement sans filtrer

Les techniques précédentes (sous-formulaire ou application d'un filtre par macro) réduisent la sélection dans le formulaire de consultation, de manière à n'afficher que l'enregistrement correspondant à la sélection.

Il peut arriver qu'on souhaite afficher un enregistrement particulier sans pour autant réduire la sélection à cet enregistrement.

Cette partie du tutoriel explique comment procéder, de deux manières différentes, selon que les données sont ou non dans un ordre croissant sur l'identifiant recherché.

Comme dans les exemples précédents, la macro est associée à l'événement "Modifiée" de la liste.

Enregistrements non ordonnées

Cet exemple est mis en oeuvre dans le formulaire "Clients" de la base exemple.

La procédure associée à la modification de la liste est PysRechercher

Le principe est simple : le programme va "boucler" sur tous les enregistrements en comparant pour chacun la valeur recherchée avec le champ correspondant (la référence client dans l'exemple).

Pour optimiser le traitement on ne travaille pas directement sur le jeu d'enregistrements affiché mais sur un "clone" (afin de ne pas provoquer de changement d'affichage écran consommateur de ressources).

Lorsque l'enregistrement est trouvé on "synchronise" par la propriété Bookmark (en quelque sorte l'équivalent d'un signet représentant l'enregistrement dans ce jeu) l'enregistrement affiché avec celui trouvé .

On voit tout de suite la limite de cette procédure : plus le jeu d'enregistrements sera grand et plus la valeur cherchée sera "loin" du début, plus la recherche sera longue (raison principale pour laquelle les méthodes évoquées dans les parties précédentes sont à privilégier).

On peut toutefois réduire le temps de recherche lorsque les données sont ordonnées sur la valeur recherchée (la référence client, dans notre exemple, est justement dans ce cas puisqu'il s'agit d'un champ numérique en auto-valeur).

Enregistrements ordonnées

Cet exemple est mis en oeuvre dans le formulaire "ClientsDichotomie" de la base exemple.

La procédure associée à la modification de la liste est PysRechercherDicho

Le principe est d'utiliser une recherche dichotomique qui consiste à comparer l'élément recherché à l'élément du milieu de la zone de recherche (les enregistrements). Cela permet de savoir dans quelle moitié se situe l'élément recherché. De nouveau on compare à l'élément recherché à l'élément du milieu de la bonne moitié...jusqu'à trouver.


Code : Tout sélectionner   AgrandirRéduire
option explicit

Sub PysRechercherDicho(PysEvent)

const PysNomForm = "Clients", PysColID = "RéfClient"

dim PysForm as object
dim PysEnregs as object
dim PysEnCours as object
dim PysTrouve
dim PysInf as Long
dim PysSup as Long
dim PysMilieu as Long
dim PysCherche as integer

with PysEvent.Source.Model
   PysCherche = .ValueItemList(.SelectedItems(0))
end with

PysForm = thiscomponent.drawPage.forms.getByName(PysNomForm)
PysEnregs = PysForm.createResultSet()

PysInf = 0
PysSup = PysEnregs.rowCount
PysTrouve = false

PysEnregs.absolute(1)

PysEnCours = PysEnregs.columns.getByName(PysColID)

if PysCherche = PysEnCours.Int then
   PysTrouve = true
else
   Do while PysInf <= PysSup
      PysMilieu = INT((PysInf + PysSup) / 2)
      PysEnregs.absolute(PysMilieu)
      PysEnCours = PysEnregs.columns.getByName(PysColID)
       if PysCherche = PysEnCours.Int then PysTrouve = true:Exit Do
       If PysCherche < PysEnCours.Int then PysSup = PysMilieu - 1
       If PysCherche > PysEnCours.Int then PysInf = PysMilieu + 1
   Loop
end if

if PysTrouve = true then
   PysForm.moveToBookmark(PysEnregs.Bookmark)
   thiscomponent.currentcontroller.getControl(PysForm.getByName("fmtRéfClient")).setFocus
else
   msgbox "Enregistrement non trouvé", 64, "Rechercher"
end if
End Sub


Sub PysRechercher(PysEvent)

const PysNomForm = "Clients", PysColID = "RéfClient"

dim PysForm as object
dim PysEnregs as object
dim PysEnCours as object
dim PysCherche as integer
dim PysTrouve as boolean

with PysEvent.Source.Model
   PysCherche = .ValueItemList(.SelectedItems(0))
end with

PysForm = thiscomponent.drawPage.forms.getByName(PysNomForm)
PysEnregs = PysForm.createResultSet()
PysEnregs.beforeFirst

PysTrouve = false
do while PysEnregs.next() and PysTrouve = false
   PysEnCours = PysEnregs.columns.getByName(PysColID)
   if PysEnCours.Int = PysCherche then
      PysTrouve = true
      exit do
   end if
loop

if PysTrouve = true then
   PysForm.moveToBookmark(PysEnregs.Bookmark)
else
   msgbox "Enregistrement non trouvé", 64, "Rechercher"
end if
End Sub


sub PysActualiserListe(PysEvent)
PysEvent.source.model.refresh
end sub


RechercheParZoneDeListe.odb
(22.82 Kio) Téléchargé 1533 fois


 Ajout : 18/11/2010

Procédure PysRechercherDicho corrigée (oubli du traitement quand recherche du premier enregistrement)
Et ajout de la procédure PysActualiserListe permettant de rafraîchir la liste quand elle reçoit le focus. Ceci permet d'inclure les enregistrements ajoutés et sauvegardés dans le formulaire principal (mis en oeuvre dans le formulaire "ClientsDichotomie" : associée à l'événement Sur focus de la liste 



Merci de ne poser aucune question à la suite de ce tutoriel.


Les poser soit dans la rubrique Base de données (questions relatives à la première technique) ou dans la section Macros (si la question porte sur ces dernières).
Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
 
Message(s) : 11276
Inscrit le : 02 Mai 2006 09:42

Tutoriel sur la sélection par liste code postal / ville

Messagepar Piaf » 04 Mars 2013 13:57

Bonjour
Une proposition de tutoriel, niveau débutant, sur la sélection du code ou de l'intitulé dans une liste déroulante.
Liste Code ou Libellé.odt
Le tutoriel
(134.72 Kio) Téléchargé 1669 fois
Toutes améliorations, corrections etc.. seront les bienvenues.
fContacts.png
Pièces jointes
ContactsForum.odb
La base exemple
(41.78 Kio) Téléchargé 1117 fois
Piaf
GourOOu
GourOOu
 
Message(s) : 5380
Inscrit le : 25 Nov 2011 19:07
Localisation : Guyane


Retour vers Tutoriels

Qui est en ligne ?

Utilisateur(s) parcourant ce forum : Aucun utilisateur inscrit et 1 invité