[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.

Ce tutoriel vous a t-il aidé à résoudre votre problème ?

Oui
6
55%
Non
4
36%
En partie
1
9%
Je ne sais pas
0
Aucun vote
 
Nombre total de votes : 11

Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
Messages : 11276
Inscription : 02 mai 2006 10:42

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

Message par Pierre-Yves Samyn »

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é 126922 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

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é 126926 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é 7294 fois
Dernière modification par Pierre-Yves Samyn le 15 déc. 2009 19:23, modifié 2 fois.
Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
Messages : 11276
Inscription : 02 mai 2006 10:42

Filtrer à l'aide de macros

Message par Pierre-Yves Samyn »

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

Elle est mise en œuvre dans ce fil : viewtopic.php?p=21224#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é 126894 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

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

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é 3968 fois
Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
Messages : 11276
Inscription : 02 mai 2006 10:42

Sélection multi-critères

Message par Pierre-Yves Samyn »

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

La plupart des données sont reprises du fil 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

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 :
    viewtopic.php?f=8&t=13423&hilit=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é 3439 fois
Dernière modification par Pierre-Yves Samyn le 01 févr. 2009 13:17, modifié 1 fois.
Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
Messages : 11276
Inscription : 02 mai 2006 10:42

Filtrer une liste en fonction d'une autre

Message par Pierre-Yves Samyn »

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 :
viewtopic.php?p=22525#p22525

voitures.png
voitures.png (4.36 Kio) Consulté 126876 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é 4784 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

'********************************************************************
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 modification par Pierre-Yves Samyn le 06 mai 2010 10:39, modifié 1 fois.
sebmdp
Membre hOOnoraire
Membre hOOnoraire
Messages : 125
Inscription : 08 juil. 2008 18:31
Localisation : Orleans / France

Recherche multi-critères par cases à cocher

Message par sebmdp »

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 :
viewtopic.php?f=8&t=15045

Salutations.
Open Office 3.2.1
Mac OS 10.5.8
Pierre-Yves Samyn
Grand Maître de l'OOffice
Grand Maître de l'OOffice
Messages : 11276
Inscription : 02 mai 2006 10:42

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

Message par Pierre-Yves Samyn »

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

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é 2120 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 
Piaf
GourOOu
GourOOu
Messages : 5622
Inscription : 25 nov. 2011 19:07
Localisation : Guyane

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

Message par Piaf »

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é 2420 fois
Toutes améliorations, corrections etc.. seront les bienvenues.
fContacts.png
ContactsForum.odb
La base exemple
(41.78 Kio) Téléchargé 1759 fois
****************************************************************************************

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).
Répondre