Problème avec Redim Preserve

toutanplastix Messages postés 2 Date d'inscription samedi 8 janvier 2005 Statut Membre Dernière intervention 8 janvier 2005 - 8 janv. 2005 à 12:16
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 - 8 janv. 2005 à 21:29
Salut!
Je suis débutant en VB et j'ai quelques petits problèmes avec la fonction Redim Preserve. Pour que ce soit plus clair je vais vous expliquer le but de ce programme et les parties déjà réalisées.
Il s'agit en fait de se connecter à un serveur et à récupérer une fois connecté les données qu'il envoit. Tous les messages envoyés par le serveur passe par la partie du code en vert et sont stockés dans une variable appellée chaineDonnées.
Ils commencent tous par trois lettres représentant une commande (cnx, dnx, trj, tjp) et le reste de la chaine est composé de termes séparés pas des points virgules.
Le premier traitement consiste à récupérer les trois premiers caractères de la chaine et à les stocker dans la chaine commande qui servira à distinguer les différents types de traitement dans la fonction Traitementmessage (dernière fonction )du code.
Le deuxième traitement consiste à séparer la partie restante du message suivant les points virgules grâce à la fonction traitement séparateur.
Mon problème se situe dans la fonction Traitementmessage :

exemple:
1) je me connecte
2) le serveur m'envoit le message suivant : "tjptrajet1;20;2;1,2,3;11,12,13" qui correspond à
tjp : commande annoncant le trajet prévu (d'un robot)
trajet1 : nom du trajet
20 : durée du trajet
2 : nb de points dans le trajet
1,2,3 : coordonnées X,Y,Z du premier point
11,12,13 : coordonnées X,Y,Z du second point
3) je découpe le message
tjp est mis dans la variable "commande"
le reste du message est traité grace à la fonction traitement séparateur et le résultat est stocké dans un tableau mots() on a donc 5 lignes dans le tableau mots à cette étape
4) je traite le message grâce à la fonction Traitementmessage qui récupère les couples de coordonnées X,Y,Z le nom du trajet, la durée et stocke ces informations sous la forme d'un type dans le tableau tjp. Mon tableau tjp() a donc à cette étape deux lignes (puisque le premier message contenait deux couples de points).
Mon problème est qu'en cas d'un nouveau message tjp de la part du serveur, le programme redimensionne correctement le tableau en fonction du nb de points nouveaux mais efface les données précédentes du tableau et ce malgré la fonction Redim Preserve.

Je me rends compte que mon message est particulièrement long et je remercie par avance les courageux qui voudront bien me répondre. Si vous avez besoin d'autres infos n'hésitez pas à me le demander.


<HR>
Option Explicit
Option Base 1

<HR>
'Définition du type
Private Type coord_trj
nomtrj As String
num As Integer
x As Double
y As Double
z As Double
End Type


Private Type coord_tjp
nomtjp As String
num As Integer
duree As Integer
x As Double
y As Double
z As Double
End Type


Private Type info_obs
duree As Integer
x As Double
y As Double
z As Double
forme As Integer
taillex As Double
tailley As Double
taillez As Double
End Type

<HR>


Public nblintjp As Integer
Public nblinobs As Integer



<HR>

Private Sub envoyer(donnees As String)

' On renseigne la socket sur les infos de l'ordinateur destinataire
sckReseau.RemoteHost = txtIpServer.Text
sckReseau.RemotePort = txtPortCom.Text
' Envoyer les données
sckReseau.SendData donnees

' Ecrire dans la console
txtDonneesEchangees.Text = txtDonneesEchangees.Text & _
"Envoyées : " & donnees & vbCrLf

End Sub

<HR>


Private Sub Cmdconnexion_Click()
nblintjp = 0
nblinobs = 0
' Définition de la chaine de caractères du message de connexion
Dim connection As String


' Gestion de l'événement Click sur le bouton "Envoyer"
' Vérification de la zone de texte IP
If txtIpServer.Text = "" Then
MsgBox "Indiquez une adresse IP"
Exit Sub
End If

' Vérification de la zone de texte Port
If txtPortCom.Text = "" Then
MsgBox "Indiquez un port de communication"
Exit Sub
End If

' Vérification de la zone de texte de l'identifiant
If txtIdentifiant.Text = "" Then
MsgBox "Indiquez votre identifiant"
Exit Sub
End If

connection = "cnx" & txtIdentifiant.Text & ";" & sckReseau.LocalIP & ";" & sckReseau.LocalPort
Call envoyer(connection)

End Sub

<HR>


Private Sub Cmddeconnexion_Click()
' Définition de la chaine de caractères du message de déconnexion
Dim deconnection As String

deconnection = "dnx" & sckReseau.LocalIP
statut.Caption = "déconnecté"
statut.ForeColor = vbRed
Call envoyer(deconnection)

End Sub

<HR>


Private Sub cmdQuitter_Click()
Call Cmddeconnexion_Click
' Quitter le programme
End
End Sub

<HR>

Private Sub Form_Load()
' Cette procédure est exécutée au démarrage de l'application

' On indique à l'ordinateur que ce programme écoutera sur ce port de communication
sckReseau.Bind CInt(sckReseau.LocalPort)
End Sub

<HR>


Private Sub sckReseau_DataArrival(ByVal bytesTotal As Long)
' Gestion de l'événement DataArrival sur la socket


Dim chaineDonnees As String

' On ne tient pas compte des messages parasites qui seraient reçus
If (bytesTotal < 3) Then
Exit Sub
End If

' On met dans la variable chaîne de caractéres les données reçues par la socket
sckReseau.GetData chaineDonnees

' Ecrire dans la console
txtDonneesEchangees.Text = txtDonneesEchangees.Text & _
"Reçues : " & chaineDonnees & vbCrLf
'premier traitement correspondant à l'extraction des trois premiers caractères
'et à leur enregistrement dans une variable string appelée type

Dim commande As String
commande = Mid(chaineDonnees, 1, 3)
chaineDonnees = Mid(chaineDonnees, 4, Len(chaineDonnees) - 3)


'second traitement
txtDonneesTraitees.Clear
Dim mots() As String
Dim i As Integer


Call traitementSeparateur(chaineDonnees, mots, ";")

For i = 1 To UBound(mots)
txtDonneesTraitees.AddItem mots(i)
Next

Call Traitementmessage(commande, mots())

End Sub

<HR>


Function nombreOccurrences(texte As String, motif As String) As Integer
' Retourne le nombre d'occurrences de la chaine contenue dans motif,
' à l'intérieur de la chaine contenue dans texte

Dim nbOccurrences As Integer
Dim pos As Integer

nbOccurrences = 0
pos = InStr(texte, motif)
While (pos > 0)
nbOccurrences = nbOccurrences + 1
pos = InStr(pos + Len(motif), texte, motif)
Wend
nombreOccurrences = nbOccurrences
End Function

<HR>


Function traitementSeparateur(texte As String, ByRef mots() As String, motif As String) As Integer
' Traitement de séparation des mots contenus dans texte. Le séparateur est motif
' Retourne le nombre de mots trouvés.
' Le tableau passé en paramètre
Dim nbOccurrences As Integer
Dim nombreMots As Integer
Dim posSeparateur As Integer
Dim debut As Integer

' Enlever, s'il y en a un, le motif en début de texte
If Left(texte, 1) = motif Then
texte = Right(texte, Len(texte) - 1)
End If

' Ajouter, s'il n'y en a pas, un motif afin de faciliter l'algorithme de traitement
If Right(texte, 1) <> motif Then
texte = texte & motif
End If


' Estimer le nombre de mots en calculant le nombre de séparateur
nbOccurrences = nombreOccurrences(texte, motif)
' Redimensionner le tableau
ReDim mots(nbOccurrences)


' Récupération des mots, au fur et à mesure du parcours de la chaine
' et de la détermination des différentes positions successives du séparateur
nombreMots = 0
debut = 1
posSeparateur = InStr(debut, texte, motif)
While (posSeparateur > 0)
nombreMots = nombreMots + 1
mots(nombreMots) = Mid(texte, debut, posSeparateur - debut)
debut = posSeparateur + 1
posSeparateur = InStr(debut, texte, motif)
Wend

' Retourne le nombre de mots trouvés
traitementSeparateur = nombreMots
End Function

<HR>


Function Traitementmessage(commande As String, mots() As String)
'analyse du message selon les cas de messages reçus
Select Case commande
Case "cnx" ' 1 :connecté 2: problème
If mots(1) = 1 Then
statut.Caption = "connecté"
statut.ForeColor = vbGreen

ElseIf mots(1) = 2 Then MsgBox "problème : déjà connecté"
End If

Case "dnx"
MsgBox "Problème : " & mots(1)
statut.Caption = "déconnecté"
statut.ForeColor = vbRed


Case "tjp"
Dim j As Integer
Dim numtjp As Integer
Dim tab_traittjp() As String
Dim tjp() As coord_tjp 'comment faire pour que le tableau ne soit pas effacé lors du traitement du deuxième messsage ? sachant que je n'arrive pas à le déclarer en Public

numtjp = 1

For j = 4 To 3 + mots(3)
Call traitementSeparateur(mots(j), tab_traittjp, ",")
ReDim Preserve tjp(mots(3) + nblintjp)'le redim marche à l'intérieur de la boucle
tjp(numtjp + nblintjp).nomtjp = mots(1)
tjp(numtjp + nblintjp).num = numtjp
tjp(numtjp + nblintjp).duree = mots(2)
tjp(numtjp + nblintjp).x = Val(tab_traittjp(1))
tjp(numtjp + nblintjp).y = Val(tab_traittjp(2))
tjp(numtjp + nblintjp).z = Val(tab_traittjp(3))
numtjp = numtjp + 1
Next
nblintjp = nblintjp + mots(3) 'problème de redimensionnement


End Select

End Function

4 réponses

cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
8 janv. 2005 à 12:44
Salut
En fait, tout ça pour dire que tu n'arrives pas à déclarer ton tableau en Public.
Au moins, ta question est complète (et bien orthographiée, bravo)

Pour déclarer des variables qui soient communes à tout le projet, il suffit d'ajouter un Module et de déclarer (dans la partie Déclaration) ta (tes) variable(s) en Public.
Comme ton tableau est de type personnel, il faudra que tu déplaces aussi la définition de ton (tes) Type(s) et les rendre Public aussi.

Autre chose : Quand tu as une chaine et que tu veux séparer chaque donnée, ne te complique pas la vie : utilise Split :
Dim Tablo() As String
Tablo = Split(Données, ";") ' où ; est le séparateur
Tu récupèreras ainsi chaque donnée dans Tablo(0), Tablo(1) ... jusqu'à Tablo(x) où x = UBound(Tablo)

Vala
Jack
NB : Je ne répondrai pas aux messages privés

Le savoir est la seule matière qui s'accroit quand on la partage. (Socrate)
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
8 janv. 2005 à 12:50
bon j'ai pas tout lu mais vu que tu fais un tableau redifini à chaque fois dans ta fonction il est normal qu'il soit effaçé à chaque fois.
une solution consiste à le déclarer en Static pour qu'il conserve ses données à chaque appel de la fonction.
une autre solution de loin la meilleure consiste à déclarer le tableau au niveau général.

Daniel
0
toutanplastix Messages postés 2 Date d'inscription samedi 8 janvier 2005 Statut Membre Dernière intervention 8 janvier 2005
8 janv. 2005 à 21:12
Tout d'abord merci à vous deux pour avoir répondu si rapidement, je vais tester chaque solution et garder celle(s) que j'arrive à utiliser.
Jack----> merci pour l'astuce du Split c'est tellement plus simple et ça va m'économiser des lignes. Il ne me reste plus qu'à me renseigner sur les modules.

Gobillot-----> Je vais essayer le Static mais par contre je n'ai aucune idée de la méthode pour déclarer le tableau au niveau général, si tu pouvais être plus précis.

Merci encore !!!

Toutanplastix, respectueux, qui se dit que ça fait trois jours qu'il est dessus et qu'en même pas trente minutes il a la solution.
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
8 janv. 2005 à 21:29
ce que j'appelle niveau général c'est tout au début de la Forme juste en dessous de Option Explicit un simple Dim suffit.
il sera accessible dans toute la feuille.
un Static ne sera accessible que dans la Fonction où il a été déclaré.
par contre si tu veux avoir accès dans tout le project il faut le déclarer en Public dans un module commme Jack a dit.

Daniel
0
Rejoignez-nous