Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 2021
-
29 avril 2008 à 14:57
cs_asimengo
Messages postés280Date d'inscriptionjeudi 24 mars 2005StatutMembreDernière intervention18 mars 2009
-
7 mai 2008 à 18:53
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.
Bien que j'ai pas fait de mise a jour en ligne, j'utilise en gros cet objet pour tous mes contrôles de liste et je prefere un datagrid rattache a un recordset local qu'un listview, je vais d'aileurs regarder à quoi ressemble le scgrid de PLUPLU
cs_drissou
Messages postés160Date d'inscriptiondimanche 7 décembre 2003StatutMembreDernière intervention14 janvier 2009 7 mai 2008 à 14:30
LIBRE_MAX:
Effectivement je ne pense pas assez à ce tag..
Je vais aller consulter l'article de Renfield..
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 5 mai 2008 à 15:11
Merci en tout cas f' avoir pris la peine de le faire.
C' est vraiment enrichissant, et ça permet de rappeler rout à chacun qu' on peut toujours faire autrement et surtout mieux.
C' est d' ailleurs ma devise.
A+
Bonne continuation.
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 5 mai 2008 à 15:03
tout a fait, je ne fais qu'exposer, comme vous avez pu le faire, ma vision de la chose.
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 5 mai 2008 à 14:56
beh je savais bien que j' ai loupé quelque chose :-)
Inconsciement peut être...du fait que je tenais beaucoup à ma méthode.
Maintenant que j' ai tout compris, ou presque, j' essayerais de mettre en application cette nouvelle approche..et voir.
A+
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 5 mai 2008 à 14:44
voir la source, elle est commentée.
on renvoie un Boolean qui indique uniquement si la Form a été validée ou non (ou Annulée, quoi).
le parametre ClientID est passé par référence. on le modifie directement.
comme énoncé dans l'article on pourrait utiliser une propriété publique de la Form
genre:
Public property get ClientID As Long
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 5 mai 2008 à 14:41
Pour le Change, je parlais de txtId (mon control masqué) et pas de CcTxtClient
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 5 mai 2008 à 14:34
Salut,
Pas si indépendant que ça !
Corrigez-moi si j' ai mal compris mais Lauch ne me renvoie qu' une Boolean.
Ou est donc passer l' Id et surtout vers quelle control il va être dirrigé ?
If Launch Then
'# Pour cette Form, on renvoie l'ID
[...]
End If
Tout la question est dans [...] !
A vouloir contourner le Select Case on retombe dans pire !
Toutefois, je suis d' accord sur le fait que seul l' iD compte.
C ' est après qu' on s'occupera du reste, lorsque mon control dédié
à le recevoir change.
txtId_Change ==> Rechercher le reste.
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 5 mai 2008 à 13:14
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 5 mai 2008 à 10:41
on touche un concept interressant, asimengo, des "objets indépendants"...
cs_asimengo
Messages postés280Date d'inscriptionjeudi 24 mars 2005StatutMembreDernière intervention18 mars 2009 2 mai 2008 à 02:12
Je prends le train en marche, j'ai dû copier/coller le code du premier commentaire de Renf pour essayer de comprendre la problématique.
Ci-dessous ma proposition pour cette problématique.
FORM1
-----
Option Explicit
Private WithEvents Frm As Form2
Private lID As Long
Private Sub CcTxtClient_Validate(Cancel As Boolean)
lID = 0
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set Frm = Nothing
End Sub
Private Sub Frm_Annuler()
CcTxtClient = vbNullString
End Sub
Private Sub Frm_Valider(ByVal TbValeurs As Variant)
lID = TbValeurs(0)
CcTxtClient = lID & " - " & TbValeurs(1)
End Sub
Private Sub CcBtnClient_Click()
Set Frm = New Form2
With Frm
.Init App.Path & "\Bd1.mdb", "SELECT * From `Clients` ORDER BY `Nom`", lID, CcTxtClient.Text
.Show vbModal
End With
End Sub
FORM2
-----
Option Explicit
Public Event Valider(ByVal TbValeurs As Variant)
Public Event Annuler()
Private m_ID As Long, m_CheminBD As String, m_CmdText As String
Public Function Init(ByVal sCheminBD As String, ByVal sCmdText As String, ByVal lID As Long, Optional sValeur As String) As Boolean
m_ID = lID
m_CheminBD = sCheminBD
m_CmdText = sCmdText
End Function
Private Sub CcBtnOk_Click()
CcLst_DblClick
End Sub
Private Sub CcLst_DblClick()
On Error GoTo Handler
Dim i As Long, sValeurs As String
With CcLst
sValeurs = Mid(.SelectedItem.Key, 2) & Chr(0) & .SelectedItem.Text
For i = 2 To .ColumnHeaders.Count
sValeurs = sValeurs & Chr(0) & .SelectedItem.ListSubItems(i - 1)
Next i
End With
RaiseEvent Valider(Split(sValeurs, Chr(0)))
Unload Me
Exit Sub
Handler:
MsgBox Err.Description
End Sub
Private Sub CcBtnCancel_Click()
RaiseEvent Annuler
Unload Me
End Sub
Private Sub Form_Load()
Dim oDb As Database
Dim oRs As Recordset
Dim lIndex As Long, lID As Long, i As Long
Set oDb = OpenDatabase(m_CheminBD)
Set oRs = oDb.OpenRecordset(m_CmdText)
lIndex = 1
Do Until oRs.EOF
lID = oRs.Fields(0).Value
With CcLst.ListItems.Add(Key:="#" & lID)
.Text = oRs.Fields(1).Value
For i = 3 To oRs.Fields.Count
.SubItems(i - 2) = oRs.Fields(i - 1).Value
Next i
End With
If lID <> m_ID Then
lIndex = lIndex + 1
Else
CcLst.ListItems(lIndex).Selected = True
End If
oRs.MoveNext
Loop
oRs.Close
oDb.Close
End Sub
Je préfère des objets independants avec propriétés et méthodes et évènements en laissant le soin à l'appelant de jouer avec les évènements.
A+
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 1 mai 2008 à 16:37
Bonjour,
Il m' est arrivé d' utiliser ta technique PLUPLU, avec une variante cependant.
Je ne rafraichissais pas ma liste à chaque frappe mais je me contentais
de faire un appel à ma fonction RECHERCHER_PART selon que je suis sur la
zone code ou la zone nom.Sitôt l' occurence trouvée je plaçais ma ligne au top
de la liste.
Autre façon de faire aussi, c' est d' utiliser une ListBox, et selon que le focus est
sur la zone code ou la zone nom la remplir ou avec les Codes ou les Noms.
Et dans l' evenement Change des deux zones, utiliser l' Api SendMessage qui permettera
de trouver la première occurence.
On voit bien ici que les techniques sont multiples, et je crois que le but recherché par
Renfield est justement d' en faire la synthèse.
A+
@DRISSOU.
Pas la peine d' avoir recours à une procèdure pour avoir la feuille appelante,
il suffit de palcer son Nom dans le Tag de ta form2 au chargement de celle-ci.
Faire ensuite:
select case Me.Tag
case "feuille1"
form1.MiseAjour (NumClient)
case else
end select
cs_pluplu
Messages postés615Date d'inscriptionmercredi 18 décembre 2002StatutMembreDernière intervention 4 juillet 2012 30 avril 2008 à 22:06
Bonjour Renfield,
Je prend la cogitation en cours de route, perso j'utilise rarement le contrôle listview je préfère de loin le datagrid ou quelque chose de similaire comme le SCGrid http://www.scgrid.com/ sûrement plus souple que tous les autres. Le problème lorsqu'on utilise une form séparée pour rechercher un client c'est pour que se soit synchro avec la feuille appelante. J'ai retrouvé un exemple qui correspond à ce que tu veux faire, Dans la form de saisie de facture, j'ai un comboboxe avec la liste des clients par nom, ce qui convient pour quelques clients, mais si la liste s'allonge plus de 50 cela n'est pas top, alors avec un double clic sur le comboboxe, on ouvre une seconde fenêtre qui est composée d'une grid avec les informations complètes de tous les clients, au bas de cette grid j’ai deux texte boxes un pour le No de client et l'autre pour le nom, dès que je rentre dans l'un de ces texte boxes un début d'information automatiquement ma grid est rafraîchit par une requête qui pointe sur les éléments commençant par l'information que j'ai rentré. Un petit exemple, lorsque ma fenêtre apparaît en premier ma grid contient l'ensemble des clients, je rentre dans ma textboxe un début de nom "Pa" et ma grid se remplis de tout ce qui commence par pa, Paul, Paulissen, Paivard, Packard, etc si je continue et que complète par "pauli" la grid se rafraîchit et sort cette fois Paulic, Paulissen etc... c'est très rapide pour retrouver le nom que l'on cherche. Une fois le client choisit je transfert les infos sur ma première form et voilà. Je vais profiter de ce long week_end pour nettoyer le code et te l'envoyer.
En attendant Bon premier mai
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 30 avril 2008 à 11:13
Brosske, ton code fonctionne, ok...
je fais le pont, je ne répondrai a cette problématique que Lundi
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 30 avril 2008 à 11:00
ok, je voyais pas où tu souhaitais en vnir, précision utile
Brosske
Messages postés98Date d'inscriptionjeudi 25 novembre 2004StatutMembreDernière intervention12 août 20101 30 avril 2008 à 11:00
oups - donc ce code est a mettre juste avant le ors.movenext
Brosske
Messages postés98Date d'inscriptionjeudi 25 novembre 2004StatutMembreDernière intervention12 août 20101 30 avril 2008 à 10:59
ok :-)
alors pourquoi ne pas mettre dans le form2_load :
if le_nom_a_ajouter form1.nom_du_client.text then ListView1.ListItems( listview1.listitems.count-1 ).Selected True
(je n'ai pas vérifié le syntaxe - dslé - je voulais juste montrer le principe)
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 30 avril 2008 à 10:52
un label et pas une variable,si je lie mes controls directement à la table.
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 30 avril 2008 à 10:50
sûrement, un label est plus approprié.
Quand au FindItem, beh je prèfère des routines
personnalisée.De plus FindItem m' as fait tellement souffrir à mes débuts que je ne l' ai plus "revu" depuis :-)
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 30 avril 2008 à 10:45
hum!
Function FindItem(sz As String, [Where], [Index], [fPartial]) As ListItem
Membre de MSComctlLib.ListView
Recherche un élément dans la liste et renvoie une référence à cet élément.
pourquoi utiliser un textbox, si masqué... une varaibel publique serait surement plus appropriée, non ?
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 30 avril 2008 à 10:41
Bonjour,
en restant sur le concept de la selection dans une listview,
on peut tout imaginer.
-Utilisation de deux Zone une pour code et l' autre pour le nom.
Faisable mais très couteuse en code.Car il faudra toujours mettre
à jour un control par rapport à l' autre, et faire la recherche à partir
de la zone qui vient être modifié.
-Le découpage est faisable avec Split sur " - ", et un test sur la première partie.
-Pour la recheche, dans mes applics j' utilise trois sorte de procèdures pour ça.
//Recherche dans la première colonne .Généralement l' ID.
Public Function RECHERCHER(xValeur As Variant, xListView As ListView) As Boolean
Dim i As Integer
Dim iC As Integer
With xListView
iC = .ListItems.Count
If iC = 0 Then Exit Function
For i = 1 To iC
If .ListItems(i).Text = xValeur Then
.ListItems(i).Selected = .ListItems(i).EnsureVisible
RECHERCHER = True
Exit For
End If
Next i
End With
End Function
//Recherche dans un SubItem .Généralement le NOM en entier
Public Function RECHERCHER_(xValeur As Variant, xListView As ListView, xListsub As Integer) As Boolean
Dim i As Integer
Dim iC As Integer
With xListView
iC = .ListItems.Count
If iC = 0 Then Exit Function
For i = 1 To iC
If .ListItems(i).ListSubItems(xListsub).Text = xValeur Then
.ListItems(i).Selected = .ListItems(i).EnsureVisible
RECHERCHER_ = True
Exit For
End If
Next i
End With
End Function
//Recherche Partielle dansdans un SubItem .
Public Function RECHERCHER_PART(xValeur As Variant, xListView As ListView, xListsub As Integer) As Boolean
Dim i As Integer
Dim iC As Integer
Dim LenV As Integer
With xListView
iC = .ListItems.Count
If iC = 0 Then Exit Function
LenV = Len(xValeur)
For i = 1 To iC
If Left$(.ListItems(i).ListSubItems(xListsub).Text, LenV) = xValeur Then
.ListItems(i).Selected = .ListItems(i).EnsureVisible
RECHERCHER_PART = True
Exit For
End If
Next i
End With
End Function
Ainsi après avoir remplit ma listview je lance une recherche à partir du contenu de ma
zone de text.
Pour listr tous les Clients, je le fait mais uniquement si la zone de text est vide.
Pour l' ID, comme je l' ai dit précèdement, j' utilise un deuxi_me TextBox en arrière plan (visible=False).
Ainsi quand je fais
Form1.CcTxtClient.Text = cCode & " - " & cNom
Je fais aussi
Form1.TxtIdClient.Text = cCode
Ainsi sans devoir décomposer ma chaine, je peux rattacher la facture au client.
et p'ui c tout :-)
A+
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 30 avril 2008 à 10:23
l'idée est interessante.
on apercoit là l'une des problématique essentielle : la réutilisabilité, et l'intégration de/dans de nouvelles forms
cs_drissou
Messages postés160Date d'inscriptiondimanche 7 décembre 2003StatutMembreDernière intervention14 janvier 2009 30 avril 2008 à 10:17
Bonjour
j'arrive en retard..
pour ma part je créerai (et je l'ai déjà fait) un procédure publique dans form2 qui récupérerai le numéro interne du client choisi
du style
J'ai utilisé ceci pour qu'une feuille soit appelée de plusieurs feuilles différentes. J'ai donc introduit dans cette procédure une paramètre définissant la feuille appelante.
En fonction de la feuille appelante, losrque je clique sur le bouton OK, je tranmets à la feuille appelant le nouveu numéro interne du client
On aurait de la forme
select case Appelant
case "feuille1"
form1.MiseAjour (NumClient)
case else
end select
dans form1 j'ai donc une procédure publique qui met à jour les données voulues, en focntion de NumClient..
J'espère avoir été assez clair..
Driss
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 30 avril 2008 à 10:12
propirété Selected des objets ListItem :
ListView1.ListItems( n ).Selected = True
Brosske
Messages postés98Date d'inscriptionjeudi 25 novembre 2004StatutMembreDernière intervention12 août 20101 30 avril 2008 à 09:57
J'ai l'impression........
Par exemple avec un listbox on utilise :
listbox.listindex=x
et hop, le client est sélectionné :-)
Mais pour un listview je n'ai pas trouvé cette propriété.
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 30 avril 2008 à 09:38
... ne peut on pas selectionner un item donné, dans un listview ?
Brosske
Messages postés98Date d'inscriptionjeudi 25 novembre 2004StatutMembreDernière intervention12 août 20101 30 avril 2008 à 09:33
Je pense qu'il faut simplement abandonner le listview et utiliser un autre controle qui permets de placer le curseur là ou l'on veut :-)
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 30 avril 2008 à 06:22
on peut redécouper les données, pour en extraire l'ID
j'airais aussi pu utiliser deux zones de texte, remarques
par contre, si on recliques sur CcBtnClient, il faut afficher la liste de tous les clients, et séléctionner dans cette liste celui qui est lié a la facture.
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 30 avril 2008 à 00:28
Beh c' est encore moi...
Quand je suis sur un truc, je m' y colle :-)
D' un autre côté, s' il s' agit d' un condensé, autant faire les choses correctement.
d' ou ma question:
Qu e se passera t- il si suite à
Form1.CcTxtClient.Text = cCode & " - " & cNom
l' utilisateur reclique sur le CcBtnClient
Si on s' en tient à ce qu' on a prévu, c à d , récupèrer le contenu de la zone et faire une recherche (entière pour le code ou partielle pour le nom) , on ne trouvera jamais
123 - DUPOND Antoine par exemple.On a bien 123 comme code et DUPOND Antoine comme nom mais pas la comlnaison des deux.
123 - DUPOND Antoine n' étant pas numérique, il va chercher du coté des noms.Et c' est sûr qu' il ne trouvera pas.
Que prévoir alors dans ce cas ?
Ma suggestion:
Form1.CcTxtClient.Text = cCode & " - " & cNom
Form1.CcTxtClient.Tag = Form1.CcTxtClient.Text
Lorsqu' on clique sur rechercher, on vérifie si .Text=.Tag
ou non.
Premier cas: rien n' a changé =>on ne fait rien
Deuxième cas: l' utilisateur a reformuler sa recherche différement, on effectue la recherche.
La suite est facilement imaginable...
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 29 avril 2008 à 18:45
Voici la sub qui me permet de remplir ma liste avec
comme paramètre ma chaine expression sql et
l' objet listview .
Public Sub GET_TIERS(xQuery As String, xLV As ListView)
xLV.ListItems.Clear
Dim rsT As Recordset
Set rsT = pDB.OpenRecordset(xQuery, dbOpenSnapshot)
With rsT
On Error Resume Next
.MoveFirst
.MoveLast
If .BOF And .EOF Then GoTo EEXIT
Dim i As Integer
i = 0
.MoveFirst
Do While Not .EOF
i = i + 1
xLV.ListItems.Add i, , ![code]
xLV.ListItems(i).SubItems(1) = ![nom]
.MoveNext
Loop
End With
EEXIT:
rsT.Close
Set rsT = Nothing
End Sub
A appeler dans Private Sub CcBtnClient_Click()
On rècupère le contenu de la zone
et on construit notre expression en tenant compte de ce contenu.
LIBRE_MAX
Messages postés1402Date d'inscriptionmardi 1 mai 2007StatutMembreDernière intervention 7 octobre 20126 29 avril 2008 à 18:34
Re-,
A supposer que mon CcTxtClient.Text contient déjà le nom ou le code complet du client (ou du fournisseur),ma requete ne m' enverra qu' une seule ligne.
Alors à moi de voir si j' affiche ma form2 ou pas.
Deux possibilités:
Soit j' affiche , ce qui permet à l' utilisateur de vérifier les infos (surtout si dans ma liste
j' ai d' autres données outre le code et le nom (asresse, Tel/Fax etc...)
Soit je n' affiche pas ma form2.Mais l' utilisateur risque de ne pas comprendre le pourquoi.
Cette deuxième solution est préconusée quand il s' agit de remplir une grille Détails facture
avec le code et nom article.Si le code est saisi en entier, on se contente vérifier son existante.
Si ma requete me renvoie une ligne, je passe outre l' affichage de la liste et j' insère directement
le produit dans la grille.
Si tu as remarqué dans l' exemple que j' ai donné, je me sert de la même form, pour lister
les clients ou les fourniseurs en vue d' une facture achat, ou vente ou avoir achat ou avoir vente
ou edition situation client ou edition situation fournisseur ou reglement facture client ou règlement
facture fournisseur et plein d' autre choses encore.Un simple tag me permet de savoir de quoi il S' agit.
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 29 avril 2008 à 16:40
pas pour avoir votre avis...
pour mettre du code a dispo en vue d'aprécier les differents points de vue sur ce probleme.
l'idée, c'est de tout condenser, au final.
disons, sur le fil ^^
MadM@tt
Messages postés2167Date d'inscriptionmardi 11 novembre 2003StatutMembreDernière intervention16 juillet 20091 29 avril 2008 à 16:35
Ahhhh le vilain Renfield, il poste une source juste pour avoir l'avis des autres. ça mériterait une punition héhé ;-)
c'est quand meme une activité punie par la loi !
Renfield
Messages postés17287Date d'inscriptionmercredi 2 janvier 2002StatutModérateurDernière intervention27 septembre 202174 29 avril 2008 à 14:57
LIBRE_MAX a proposé :
Form1:
Private Sub CcBtnClient_Click()
With Form2
If .CcLst.ListItems.Count = 0 Then
MsgBox "...non défini ou introuvable !", vbInformation, "..."
Unload Form2
Else
.CcLst.ListItems(1).Selected = .CcLst.ListItems(1).EnsureVisible
.Show vbModal
End If
End With
End Sub
-------------------------------------
Form2:
Private Sub CcBtnOk_Click()
CcLst_DblClick
End Sub
Private Sub CcLst_DblClick()
Dim cCode As Long
Dim cNom As String
On Error GoTo Handler
With CcLst
If .ListItems.Count <> 0 Then
cCode = Mid$(.SelectedItem.Key, 2)
cNom = .SelectedItem.Text
Form1.CcTxtClient.Text = cCode & " - " & cNom
Unload Me
End If
End With
Exit Sub
Handler:
MsgBox Err.Description
End Sub
7 mai 2008 à 18:53
Bien que j'ai pas fait de mise a jour en ligne, j'utilise en gros cet objet pour tous mes contrôles de liste et je prefere un datagrid rattache a un recordset local qu'un listview, je vais d'aileurs regarder à quoi ressemble le scgrid de PLUPLU
7 mai 2008 à 14:30
Effectivement je ne pense pas assez à ce tag..
Je vais aller consulter l'article de Renfield..
5 mai 2008 à 15:11
C' est vraiment enrichissant, et ça permet de rappeler rout à chacun qu' on peut toujours faire autrement et surtout mieux.
C' est d' ailleurs ma devise.
A+
Bonne continuation.
5 mai 2008 à 15:03
5 mai 2008 à 14:56
Inconsciement peut être...du fait que je tenais beaucoup à ma méthode.
Maintenant que j' ai tout compris, ou presque, j' essayerais de mettre en application cette nouvelle approche..et voir.
A+
5 mai 2008 à 14:44
on renvoie un Boolean qui indique uniquement si la Form a été validée ou non (ou Annulée, quoi).
le parametre ClientID est passé par référence. on le modifie directement.
comme énoncé dans l'article on pourrait utiliser une propriété publique de la Form
genre:
Public property get ClientID As Long
5 mai 2008 à 14:41
5 mai 2008 à 14:34
Pas si indépendant que ça !
Corrigez-moi si j' ai mal compris mais Lauch ne me renvoie qu' une Boolean.
Ou est donc passer l' Id et surtout vers quelle control il va être dirrigé ?
If Launch Then
'# Pour cette Form, on renvoie l'ID
[...]
End If
Tout la question est dans [...] !
A vouloir contourner le Select Case on retombe dans pire !
Toutefois, je suis d' accord sur le fait que seul l' iD compte.
C ' est après qu' on s'occupera du reste, lorsque mon control dédié
à le recevoir change.
txtId_Change ==> Rechercher le reste.
5 mai 2008 à 13:14
http://blogs.codes-sources.com/renfield/archive/2008/05/05/vb6-bo-tes-de-dialogue-communication-inter-form.aspx
5 mai 2008 à 10:41
2 mai 2008 à 02:12
Ci-dessous ma proposition pour cette problématique.
FORM1
-----
Option Explicit
Private WithEvents Frm As Form2
Private lID As Long
Private Sub CcTxtClient_Validate(Cancel As Boolean)
lID = 0
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set Frm = Nothing
End Sub
Private Sub Frm_Annuler()
CcTxtClient = vbNullString
End Sub
Private Sub Frm_Valider(ByVal TbValeurs As Variant)
lID = TbValeurs(0)
CcTxtClient = lID & " - " & TbValeurs(1)
End Sub
Private Sub CcBtnClient_Click()
Set Frm = New Form2
With Frm
.Init App.Path & "\Bd1.mdb", "SELECT * From `Clients` ORDER BY `Nom`", lID, CcTxtClient.Text
.Show vbModal
End With
End Sub
FORM2
-----
Option Explicit
Public Event Valider(ByVal TbValeurs As Variant)
Public Event Annuler()
Private m_ID As Long, m_CheminBD As String, m_CmdText As String
Public Function Init(ByVal sCheminBD As String, ByVal sCmdText As String, ByVal lID As Long, Optional sValeur As String) As Boolean
m_ID = lID
m_CheminBD = sCheminBD
m_CmdText = sCmdText
End Function
Private Sub CcBtnOk_Click()
CcLst_DblClick
End Sub
Private Sub CcLst_DblClick()
On Error GoTo Handler
Dim i As Long, sValeurs As String
With CcLst
sValeurs = Mid(.SelectedItem.Key, 2) & Chr(0) & .SelectedItem.Text
For i = 2 To .ColumnHeaders.Count
sValeurs = sValeurs & Chr(0) & .SelectedItem.ListSubItems(i - 1)
Next i
End With
RaiseEvent Valider(Split(sValeurs, Chr(0)))
Unload Me
Exit Sub
Handler:
MsgBox Err.Description
End Sub
Private Sub CcBtnCancel_Click()
RaiseEvent Annuler
Unload Me
End Sub
Private Sub Form_Load()
Dim oDb As Database
Dim oRs As Recordset
Dim lIndex As Long, lID As Long, i As Long
Set oDb = OpenDatabase(m_CheminBD)
Set oRs = oDb.OpenRecordset(m_CmdText)
lIndex = 1
Do Until oRs.EOF
lID = oRs.Fields(0).Value
With CcLst.ListItems.Add(Key:="#" & lID)
.Text = oRs.Fields(1).Value
For i = 3 To oRs.Fields.Count
.SubItems(i - 2) = oRs.Fields(i - 1).Value
Next i
End With
If lID <> m_ID Then
lIndex = lIndex + 1
Else
CcLst.ListItems(lIndex).Selected = True
End If
oRs.MoveNext
Loop
oRs.Close
oDb.Close
End Sub
Je préfère des objets independants avec propriétés et méthodes et évènements en laissant le soin à l'appelant de jouer avec les évènements.
A+
1 mai 2008 à 16:37
Il m' est arrivé d' utiliser ta technique PLUPLU, avec une variante cependant.
Je ne rafraichissais pas ma liste à chaque frappe mais je me contentais
de faire un appel à ma fonction RECHERCHER_PART selon que je suis sur la
zone code ou la zone nom.Sitôt l' occurence trouvée je plaçais ma ligne au top
de la liste.
Autre façon de faire aussi, c' est d' utiliser une ListBox, et selon que le focus est
sur la zone code ou la zone nom la remplir ou avec les Codes ou les Noms.
Et dans l' evenement Change des deux zones, utiliser l' Api SendMessage qui permettera
de trouver la première occurence.
On voit bien ici que les techniques sont multiples, et je crois que le but recherché par
Renfield est justement d' en faire la synthèse.
A+
@DRISSOU.
Pas la peine d' avoir recours à une procèdure pour avoir la feuille appelante,
il suffit de palcer son Nom dans le Tag de ta form2 au chargement de celle-ci.
Faire ensuite:
select case Me.Tag
case "feuille1"
form1.MiseAjour (NumClient)
case else
end select
30 avril 2008 à 22:06
Je prend la cogitation en cours de route, perso j'utilise rarement le contrôle listview je préfère de loin le datagrid ou quelque chose de similaire comme le SCGrid http://www.scgrid.com/ sûrement plus souple que tous les autres. Le problème lorsqu'on utilise une form séparée pour rechercher un client c'est pour que se soit synchro avec la feuille appelante. J'ai retrouvé un exemple qui correspond à ce que tu veux faire, Dans la form de saisie de facture, j'ai un comboboxe avec la liste des clients par nom, ce qui convient pour quelques clients, mais si la liste s'allonge plus de 50 cela n'est pas top, alors avec un double clic sur le comboboxe, on ouvre une seconde fenêtre qui est composée d'une grid avec les informations complètes de tous les clients, au bas de cette grid j’ai deux texte boxes un pour le No de client et l'autre pour le nom, dès que je rentre dans l'un de ces texte boxes un début d'information automatiquement ma grid est rafraîchit par une requête qui pointe sur les éléments commençant par l'information que j'ai rentré. Un petit exemple, lorsque ma fenêtre apparaît en premier ma grid contient l'ensemble des clients, je rentre dans ma textboxe un début de nom "Pa" et ma grid se remplis de tout ce qui commence par pa, Paul, Paulissen, Paivard, Packard, etc si je continue et que complète par "pauli" la grid se rafraîchit et sort cette fois Paulic, Paulissen etc... c'est très rapide pour retrouver le nom que l'on cherche. Une fois le client choisit je transfert les infos sur ma première form et voilà. Je vais profiter de ce long week_end pour nettoyer le code et te l'envoyer.
En attendant Bon premier mai
30 avril 2008 à 11:13
je fais le pont, je ne répondrai a cette problématique que Lundi
30 avril 2008 à 11:00
30 avril 2008 à 11:00
30 avril 2008 à 10:59
alors pourquoi ne pas mettre dans le form2_load :
if le_nom_a_ajouter form1.nom_du_client.text then ListView1.ListItems( listview1.listitems.count-1 ).Selected True
(je n'ai pas vérifié le syntaxe - dslé - je voulais juste montrer le principe)
30 avril 2008 à 10:52
30 avril 2008 à 10:50
Quand au FindItem, beh je prèfère des routines
personnalisée.De plus FindItem m' as fait tellement souffrir à mes débuts que je ne l' ai plus "revu" depuis :-)
30 avril 2008 à 10:45
Function FindItem(sz As String, [Where], [Index], [fPartial]) As ListItem
Membre de MSComctlLib.ListView
Recherche un élément dans la liste et renvoie une référence à cet élément.
pourquoi utiliser un textbox, si masqué... une varaibel publique serait surement plus appropriée, non ?
30 avril 2008 à 10:41
en restant sur le concept de la selection dans une listview,
on peut tout imaginer.
-Utilisation de deux Zone une pour code et l' autre pour le nom.
Faisable mais très couteuse en code.Car il faudra toujours mettre
à jour un control par rapport à l' autre, et faire la recherche à partir
de la zone qui vient être modifié.
-Le découpage est faisable avec Split sur " - ", et un test sur la première partie.
-Pour la recheche, dans mes applics j' utilise trois sorte de procèdures pour ça.
//Recherche dans la première colonne .Généralement l' ID.
Public Function RECHERCHER(xValeur As Variant, xListView As ListView) As Boolean
Dim i As Integer
Dim iC As Integer
With xListView
iC = .ListItems.Count
If iC = 0 Then Exit Function
For i = 1 To iC
If .ListItems(i).Text = xValeur Then
.ListItems(i).Selected = .ListItems(i).EnsureVisible
RECHERCHER = True
Exit For
End If
Next i
End With
End Function
//Recherche dans un SubItem .Généralement le NOM en entier
Public Function RECHERCHER_(xValeur As Variant, xListView As ListView, xListsub As Integer) As Boolean
Dim i As Integer
Dim iC As Integer
With xListView
iC = .ListItems.Count
If iC = 0 Then Exit Function
For i = 1 To iC
If .ListItems(i).ListSubItems(xListsub).Text = xValeur Then
.ListItems(i).Selected = .ListItems(i).EnsureVisible
RECHERCHER_ = True
Exit For
End If
Next i
End With
End Function
//Recherche Partielle dansdans un SubItem .
Public Function RECHERCHER_PART(xValeur As Variant, xListView As ListView, xListsub As Integer) As Boolean
Dim i As Integer
Dim iC As Integer
Dim LenV As Integer
With xListView
iC = .ListItems.Count
If iC = 0 Then Exit Function
LenV = Len(xValeur)
For i = 1 To iC
If Left$(.ListItems(i).ListSubItems(xListsub).Text, LenV) = xValeur Then
.ListItems(i).Selected = .ListItems(i).EnsureVisible
RECHERCHER_PART = True
Exit For
End If
Next i
End With
End Function
Ainsi après avoir remplit ma listview je lance une recherche à partir du contenu de ma
zone de text.
Pour listr tous les Clients, je le fait mais uniquement si la zone de text est vide.
Pour l' ID, comme je l' ai dit précèdement, j' utilise un deuxi_me TextBox en arrière plan (visible=False).
Ainsi quand je fais
Form1.CcTxtClient.Text = cCode & " - " & cNom
Je fais aussi
Form1.TxtIdClient.Text = cCode
Ainsi sans devoir décomposer ma chaine, je peux rattacher la facture au client.
et p'ui c tout :-)
A+
30 avril 2008 à 10:23
on apercoit là l'une des problématique essentielle : la réutilisabilité, et l'intégration de/dans de nouvelles forms
30 avril 2008 à 10:17
j'arrive en retard..
pour ma part je créerai (et je l'ai déjà fait) un procédure publique dans form2 qui récupérerai le numéro interne du client choisi
du style
load Form2
form2.ProcTransmet NumClient
form2.show vbmodal
J'ai utilisé ceci pour qu'une feuille soit appelée de plusieurs feuilles différentes. J'ai donc introduit dans cette procédure une paramètre définissant la feuille appelante.
En fonction de la feuille appelante, losrque je clique sur le bouton OK, je tranmets à la feuille appelant le nouveu numéro interne du client
On aurait de la forme
select case Appelant
case "feuille1"
form1.MiseAjour (NumClient)
case else
end select
dans form1 j'ai donc une procédure publique qui met à jour les données voulues, en focntion de NumClient..
J'espère avoir été assez clair..
Driss
30 avril 2008 à 10:12
ListView1.ListItems( n ).Selected = True
30 avril 2008 à 09:57
Par exemple avec un listbox on utilise :
listbox.listindex=x
et hop, le client est sélectionné :-)
Mais pour un listview je n'ai pas trouvé cette propriété.
30 avril 2008 à 09:38
30 avril 2008 à 09:33
30 avril 2008 à 06:22
j'airais aussi pu utiliser deux zones de texte, remarques
par contre, si on recliques sur CcBtnClient, il faut afficher la liste de tous les clients, et séléctionner dans cette liste celui qui est lié a la facture.
30 avril 2008 à 00:28
Quand je suis sur un truc, je m' y colle :-)
D' un autre côté, s' il s' agit d' un condensé, autant faire les choses correctement.
d' ou ma question:
Qu e se passera t- il si suite à
Form1.CcTxtClient.Text = cCode & " - " & cNom
l' utilisateur reclique sur le CcBtnClient
Si on s' en tient à ce qu' on a prévu, c à d , récupèrer le contenu de la zone et faire une recherche (entière pour le code ou partielle pour le nom) , on ne trouvera jamais
123 - DUPOND Antoine par exemple.On a bien 123 comme code et DUPOND Antoine comme nom mais pas la comlnaison des deux.
123 - DUPOND Antoine n' étant pas numérique, il va chercher du coté des noms.Et c' est sûr qu' il ne trouvera pas.
Que prévoir alors dans ce cas ?
Ma suggestion:
Form1.CcTxtClient.Text = cCode & " - " & cNom
Form1.CcTxtClient.Tag = Form1.CcTxtClient.Text
Lorsqu' on clique sur rechercher, on vérifie si .Text=.Tag
ou non.
Premier cas: rien n' a changé =>on ne fait rien
Deuxième cas: l' utilisateur a reformuler sa recherche différement, on effectue la recherche.
La suite est facilement imaginable...
29 avril 2008 à 18:45
comme paramètre ma chaine expression sql et
l' objet listview .
Public Sub GET_TIERS(xQuery As String, xLV As ListView)
xLV.ListItems.Clear
Dim rsT As Recordset
Set rsT = pDB.OpenRecordset(xQuery, dbOpenSnapshot)
With rsT
On Error Resume Next
.MoveFirst
.MoveLast
If .BOF And .EOF Then GoTo EEXIT
Dim i As Integer
i = 0
.MoveFirst
Do While Not .EOF
i = i + 1
xLV.ListItems.Add i, , ![code]
xLV.ListItems(i).SubItems(1) = ![nom]
.MoveNext
Loop
End With
EEXIT:
rsT.Close
Set rsT = Nothing
End Sub
A appeler dans Private Sub CcBtnClient_Click()
On rècupère le contenu de la zone
et on construit notre expression en tenant compte de ce contenu.
29 avril 2008 à 18:34
A supposer que mon CcTxtClient.Text contient déjà le nom ou le code complet du client (ou du fournisseur),ma requete ne m' enverra qu' une seule ligne.
Alors à moi de voir si j' affiche ma form2 ou pas.
Deux possibilités:
Soit j' affiche , ce qui permet à l' utilisateur de vérifier les infos (surtout si dans ma liste
j' ai d' autres données outre le code et le nom (asresse, Tel/Fax etc...)
Soit je n' affiche pas ma form2.Mais l' utilisateur risque de ne pas comprendre le pourquoi.
Cette deuxième solution est préconusée quand il s' agit de remplir une grille Détails facture
avec le code et nom article.Si le code est saisi en entier, on se contente vérifier son existante.
Si ma requete me renvoie une ligne, je passe outre l' affichage de la liste et j' insère directement
le produit dans la grille.
Si tu as remarqué dans l' exemple que j' ai donné, je me sert de la même form, pour lister
les clients ou les fourniseurs en vue d' une facture achat, ou vente ou avoir achat ou avoir vente
ou edition situation client ou edition situation fournisseur ou reglement facture client ou règlement
facture fournisseur et plein d' autre choses encore.Un simple tag me permet de savoir de quoi il S' agit.
29 avril 2008 à 16:40
pour mettre du code a dispo en vue d'aprécier les differents points de vue sur ce probleme.
l'idée, c'est de tout condenser, au final.
disons, sur le fil ^^
29 avril 2008 à 16:35
c'est quand meme une activité punie par la loi !
29 avril 2008 à 14:57
Form1:
Private Sub CcBtnClient_Click()
With Form2
If .CcLst.ListItems.Count = 0 Then
MsgBox "...non défini ou introuvable !", vbInformation, "..."
Unload Form2
Else
.CcLst.ListItems(1).Selected = .CcLst.ListItems(1).EnsureVisible
.Show vbModal
End If
End With
End Sub
-------------------------------------
Form2:
Private Sub CcBtnOk_Click()
CcLst_DblClick
End Sub
Private Sub CcLst_DblClick()
Dim cCode As Long
Dim cNom As String
On Error GoTo Handler
With CcLst
If .ListItems.Count <> 0 Then
cCode = Mid$(.SelectedItem.Key, 2)
cNom = .SelectedItem.Text
Form1.CcTxtClient.Text = cCode & " - " & cNom
Unload Me
End If
End With
Exit Sub
Handler:
MsgBox Err.Description
End Sub
(Form_Load non recopié)