Gegevensprocedure werkt niet goed

Status
Niet open voor verdere reacties.

Robby2

Gebruiker
Lid geworden
3 feb 2006
Berichten
40
Hoi,

Ik zou graag het aantal getallen (dus niet cijfers) tellen in een string De string staat in een tekstvak. Als het tekstvak verandert dan moet de waarde van het aantal cijfers in een ander tekstvak komen te staan. Omdat ik niet weet hoe ik getallen die voorkomen in een string moet tellen, heb ik voor een suboptimale oplossing gekozen. Ik vraag de gebruiker van de database om de getallen te scheiden met een "+". De vraag is dus nu: "Ik wil het aantal '+'-jes tellen in de string die in het tekstvak c_cd staat en die wegschrijven in het tekstvak d_at. (Het aantal '+'-jes + 1 = aantal getallen).

Ik heb hiervoor de volgende VBA-code geschreven:

Private Sub d_cd_Dirty(Cancel As Integer)
Dim count As Integer
count = 1
Position = 1
Do While InStr(Position, Me!d_cd, "+")
Position = InStr(Position, Me!d_cd, "+") + 1
count = count + 1
Loop
Me!d_at.Value = count
End Sub


Dit zou toch moeten werken? Maar de uitkomst klopt niet en bovendien beinvloed deze procedure ook het gedrag van de invoer in tekstvak d_cd. Wat doe ik fout? Iemand een idee?

Groeten Rob
 
ken je de functie 'isnumeric'?

speel hier eens mee en je kunt bereiken wat jij wilt.
 
Als je plusjes gebruikt om de cijfers te scheiden (best wel handig, want hoe houd je anders de getallen onder de 10 = 1 cijfer en de cijfers boven de 10 = 2 cijfers uit elkaar), kun je VB(A) de getallen laten splitsen in een array - en dan de elementen in die array tellen.

Public Sub SplitsGetallenOpPlus()

' Even je tekstvak simuleren
Dim strReeks As String
strReeks = "1+12+4+5+34+23+2"

' Array definieren en tekenreeks splitsen
Dim astrCijfers() As String
astrCijfers = Split(strReeks, "+")

' Nu een melding, in jouw procedure moet het weer naar een ander tekstvak
MsgBox "De tekenreeks bevat " & UBound(astrCijfers) + 1 & " cijfers."

End Sub

-------------------

In jouw procedure wordt dat:

------------------

Private Sub d_cd_AfterUpdate()

Dim astrCijfers() As String

astrCijfers = Split(Me.d_cd, "+")
Me.d_at = Ubound(astrCijfers) + 1

End Sub
 
Laatst bewerkt:
Dat is een verrassend eenvoudige oplossing Frits. Mijn eigen code had ik gekoppeld aan het wijzigen van het tekstveld, nu ik hem heb gekoppeld aan "afterupdate", zoals jij hebt gedaan werkt die ook. Ik heb nu dus twee werkende codes, maar die van jou is het eenvoudigst.
Hele heldere uitleg trouwens. (Zelfs ik snap het! ;) )


Het blijft me echter puzzelen... De functie die thomrob voorsteld geeft een true of false terug. Is het dan ook mogelijk om een string te splitsen in delen en dan per deel te laten nagaan met de functie isnumeric of het een getal betreft? Het risico op fouten door foutieve invoer is dan minder.

Ik heb daar een tijd mee zitten spelen, maar mijn VBA-kennis laat me hier toch inde steek. Maar ik ben met de huidige oplossing ook al erg tevregen hoor.

Hartelijk dank!

Het is wel raar dat als ik het tekstveld wijzig en dan een enter geef de tekst in het veld verwijnt. Pas als ik na een andere veld toe ga, springt de aangepaste tekst weer terug in het veld. Dat ziet er wat raar uit.
 
Quote:
"Het is wel raar dat als ik het tekstveld wijzig en dan een enter geef de tekst in het veld verwijnt. Pas als ik na een andere veld toe ga, springt de aangepaste tekst weer terug in het veld. Dat ziet er wat raar uit."

Waarschijnlijk eigenschap op MultiLine, dus Enter is ook werkelijk een regelomhaal in het veld. Zet MultiLine op False en je hebt er geen last meer van.

Quote:
"... nagaan met de functie isnumeric of het een getal betreft."

---

Private Sub d_cd_AfterUpdate()

Dim astrCijfers() As String
Dim strReeks as String
Dim lngCounter as Long
Dim lingAantal as Long

' Even + teken erbij. Dan zitten alle elementen in de array.
strReeks = Me.d_cd & "+"
astrCijfers = Split(strReeks, "+")
' Het eerste element van een array is 0, de tweede 1 enz.
' Dus loopt de routine van de basiswaarde tot het aantal - 1
For lngCounter = 0 to Ubound(astrCijfers) - 1
If IsNumeric(astrCijfers(lngCounter)) Then lngAantal = lngAantal + 1
Next

Me.d_at = lngAantal

End Sub

---

Dank je voor je compliment. Succes met deze variant.
 
Laatst bewerkt:
Je aangepaste code werkt goed als de gebruiker zich netjes gedraagd. Maar gaat mis bij het gebruik van sommige leestekens. (& en , ). Er gebeuren ook vreemde dingen als de gebruiker eerst iets intikt en daarna het zelfde veld opnieuw gaat editen. Soms wordt de uitkomst zelfs verminderd als je iets toevoegd. Ik heb geprobeerd om de code aan te passen zodat het + teken niet meer wordt gebruikt als scheidingsteken tussen de tekstfragmenten; maar een spatie.
Volgens mij wil ik te veel. Ik zit net ook te bedenken dat als iemand intikt: "12, 14 en 31" de isnumeric functie ook al niet meer een true waarde oplevert bij de 12. Misschien is er ook een containsnumber functie ? (De nummers zijn overigens de dagen in de maand).


femda-punt-com zei:
Quote:
Waarschijnlijk eigenschap op MultiLine, dus Enter is ook werkelijk een regelomhaal in het veld. Zet MultiLine op False en je hebt er geen last meer van.
.

Inderdaad: probleem opgelost.

Groet Rob
 
Je wilt nooit teveel. VBA is een wonderlijke wereld, en praktisch alles is mogelijk. Kost soms (veel) tijd, soms geld, maar alles kan.

Ach, ik vind het leuk om je wegwijs te maken en heb vanmorgen tijd. Dus hieronder de variant van de code waarin elk scheidingsteken is toegestaan, willekeurig aantal scheidingstekens is toegestaan - als er maar een scheidingsteken inzit.

Omdat de code door de commentaarregels ingewikkeld en druk lijkt, vind je als afbeelding ook een schoon 'codescherm'.

Veel puzzelplezier.

----


Public Sub SplitsGetallenOpWillekeurigTeken()

' Even je tekstvak simuleren
' Alles en nog wat kan ingevuld worden, maar alleen cijfers tellen
' Komt er een niet-cijfer, dan is dan de scheiding met het volgende cijfer
' In deze reeks komen 10 cijfers voor. Dat moet de uitkomst zijn.
Dim strReeks As String
strReeks = "12, 14 en 31 1+12, ---- 4+5 HELPMIJ 34+23+2"

Dim strCijferreeks As String
Dim strTeken As String
Dim blnCijfer As Boolean
Dim lngCounter As Long

' Nu tekenreeks langslopen en opschonen
strCijferreeks = ""
For lngCounter = 1 To Len(strReeks)
strTeken = Mid$(strReeks, lngCounter, 1)
' Als het een cijfer is, dan aan tekenreeks toevoegen
' en bijhouden dat er een cijfer voorbijgekomen is
If strTeken >= "0" And strTeken <= "9" Then
strCijferreeks = strCijferreeks & strTeken
blnCijfer = True
Else
' Er is een niet-cijfer voorbijgekomen
' en als er een reeks niet-cijfers voorbijkomen
' is er toch maar 1 +-teken nodig.
If blnCijfer Then
strCijferreeks = strCijferreeks & "+"
blnCijfer = False
End If
End If
Next

' Het +-teken aan het einde
If Right$(strCijferreeks, 1) <> "+" Then
strCijferreeks = strCijferreeks & "+"
End If

' Array definieren en tekenreeks splitsen
Dim astrCijfers() As String
astrCijfers = Split(strCijferreeks, "+")

' Nu een melding, in jouw procedure moet het weer naar een ander tekstvak
MsgBox "De tekenreeks:" & vbCrLf _
& vbCrLf _
& "'" & strCijferreeks & "'" & vbCrLf _
& vbCrLf _
& " bevat " & UBound(astrCijfers) & " cijfers.", _
vbInformation + vbOKOnly, _
"VBA - een wonderlijke wereld!"

End Sub
 

Bijlagen

  • tekenreeks.jpg
    tekenreeks.jpg
    97,1 KB · Weergaven: 41
Frits HARTELIJK DANK!!!!! :thumb:

Dit werkt echt genadeloos goed. Ik heb van alles ingevoerd om de code te laten crashen, maar dat lukt me dus niet. Heel fijn.

Ik moet wel eerlijk bekennen dat ik nog even nodig heb om alles te snappen. Ik ga dus inderdaad nog even puzzelen. ... :confused:

handig hoor als je zo goed kunt programmeren

Groeten Rob
 
Oeps....

toch een kleinje vlekje in de code. Als er in het tekstvak de inhoud geheel wordt verwijdert, gaat het mis. Foutmelding 94 "ongeldig gebruik van 0"
en als ik een = vooraan in de zin gebruik wordt dat gezien als een getal.

Daar valt mee te leven....
 
Hoi Rob,

Fijn dat ik je een plezier kan doen. Ik verkeer in de luxe positie dat ik met mijn hobby mijn brood kan verdienen. Mag betaald deze dag met VB / VBA spelen ...

= teken op eerste plaats als getal. Onmogelijk (als ik zo vrij mag zijn), want het "=" komt na "9" in de ASCII-tabel. Maar ik geloof je toch, dus vervang:
---
If strTeken >= "0" And strTeken <= "9" Then
---
door:
---
If IsNumeric(strTeken) Then
---

En om af te vangen dat het tekstvak leeg kan zijn, boven regeltje erbij plaatsen. Na:
---
Dim lngCounter As Long
---
toevoegen:
---
If Len(strReeks) = 0 Then Exit Sub
---

Zo, kan je weer testen.
 
Ik verkeer in de luxe positie dat ik met mijn hobby mijn brood kan verdienen. Mag betaald deze dag met VB / VBA spelen ...

Verdorie zeg, dat is niet gek! (...voor mij trouwens ook niet :) , ik was er ander niet uit gekomen. .... vlug nog even reageren voor de dag voorbij is ;) )


Er gebeurt nu iets heel vreemds, dus is zal wel iets fouts hebben gedaan. De Isnumeric functie maakt niets uit. M.a.w. een ' = ' vooraan levert bij mij altijd een eindwaarde 0 op.

Nog vreemder ...
If Len(strReeks) = 0 Then Exit Sub
zorgt er voor dat de procedure helemaal niet meer loopt. Ik moet daarbij wel zeggen dat ik een endif heb toegevoegd (anders krijg ik een foutmelding). En ook heb ik toegevoegd Me!d_at = 1 in het geval er helemaal geen getallen in voorkomen. (Want dat is in mijn geval de minimale waarde voor deze variabele). Wat ik nu allemaal zeg kan ook niet; ik weet het. Maar misschien geloof je me toch ?



Private Sub d_cd_AfterUpdate()

Dim strCijferreeks As String
Dim strTeken As String
Dim blnCijfer As Boolean
Dim lngCounter As Long

If Len(strReeks) = 0 Then
Me!d_at = 1
Exit Sub
End If

strCijferreeks = ""
For lngCounter = 1 To Len(Me!d_cd)
strTeken = Mid$(Me!d_cd, lngCounter, 1)
If IsNumeric(strTeken) Then
strCijferreeks = strCijferreeks & strTeken
blnCijfer = True
Else
If blnCijfer Then
strCijferreeks = strCijferreeks & "+"
blnCijfer = False
End If
End If
Next
If Right$(strCijferreeks, 1) <> "+" Then
strCijferreeks = strCijferreeks & "+"
End If

Dim astrCijfers() As String

astrCijfers = Split(strCijferreeks, "+")
Me!d_at = UBound(astrCijfers)

End Sub
 
If Len(strReeks) = 0 Then
moet in jouw geval zijn:
Len(Me!d_cd)

End If
is uitstekend

= teken als numeriek. Snap ik niets van, maar ik geloof je ;-)

Ik stop er ook voor vandaag mee. Wel thuis.
 
femda-punt-com zei:
If Len(strReeks) = 0 Then
moet in jouw geval zijn:
Len(Me!d_cd)

.

Ik zie het, stomme fout van mij. Ik heb de '0' nog even vervangen voor n 'Null' maar het maakt niets uit. Als ik met de cursor op de variabele ga staan geeft VBA aan: 'Len(Me!d_cd)=Null' , maar de exit sub werkt blijkbaar toch niet, want ik krijg dan weer de foutmelding in de regel

For lngCounter = 1 To Len(Me!d_cd
(zelfde foutmelding als eerder)

Ik rommel nog wat aan..., wie weet

Hartelijk dank voor alles

Groeten Rob
 
Ter bemoediging....

Ik heb de routine omgebouwd naar een functie in Excel en daar werkt het prima; geen foutmeldingen. Ik heb de regel dat de minimale waarde 1 moet zijn verwijdert. Indien het veld nu leeg wordt gemaakt is de uitkomst toch 1 ipv 0 dat is wel vreemd.

Groet,

Rob
 
foutafhandeling

om de fout te onderscheppen kun je ook een foutafhandelingsroutetine aan de functie toevoegen. Niet zo netjes in dit geval, maar het werkt wel.
 
thomrob zei:
om de fout te onderscheppen kun je ook een foutafhandelingsroutetine aan de functie toevoegen. Niet zo netjes in dit geval, maar het werkt wel.

Misschien is dat nog wel het beste. Ik heb inmiddels nog een aantal uren zitten puzzelen en ben er redelijk zeker van dat het iets te maken heeft met de instellingen van Access en de manier waarop deze met tekstvelden omgaat.
Ik dacht nog even de fout te kunnen omzeilen door toe te voegen Me!d_cd = "?" indien Len(Me!d_cd) Null is. Maar Dan zou daarna Len(Me!d_cd) toch 1 moeten zijn. Maar die blijft stug op Null staan. Volgens mij wordt de routine gewoon niet doorlopen. Een leeg veld en een spatie aan het begin van het veld leveren daardoor een foutmelding en het "=" teken een foutieve telling.

Nou ja..., ik ben toch erg blij met de code. Werkt verder erg mooi.

Heb je nog suggesties op welk trefwoord kan ik het beste Googlen om iets te vinden over die foutafh.routetine?

Groeten Rob
 
Het is gelukt met de error handler

Wel vreemd... het lijkt alsof de error handler altijd in werking treedt (ik heb er een msgbox ingezet die altijd actief wordt) en als het veld leeg blijft, is de uitkomst altijd 1 ipv 0

Hoe dan ook het werkt! Bedankt
 
escapen

Rob,

hoe ziet je routine er nu dan uit? even een voorbeeld van een functie met foutafhandeling:



Code:
function TEST()
on error goto errhandler

'de dingen die je wil doen

'einde van de dingen die je wil doen


exithere:
exit function

errhandler:
select case err.number
case 94
msgbox "invoer niet juist"
case else
msgbox err.numer & " - " & err.description
end select
resume exithere

end function


als er geen fout optreedt wordt er afgebroken na de subrouteine 'exithere' door de instructie 'exit function'. Indien er wel een fout optreedt wordt deze afgehandeld door de subroutine 'errhandler'.

exithere moet je altijd uit laten voeren omdat je er je geheugen mee vrijgeeft, ook als er een fout ontstaat.


greetz Rob T
 
Hoi Rob,

Ik had er geen case bij staan. Ik heb er nu van gemaakt:

ErrorHandler:
Select Case Err.Number
Case 94
Me!d_at = 1
Exit Sub
Case Else
' MsgBox Err.numer & " - " & Err.Description
End Select
Exit Sub

Me!d_at = 1 hoeft eigenlijk niet, want om een of andere reden is de procedure van mening dat de minimale veldlengte altijd al 1 is (ook al staat er niets in), en Me!d_at wordt dan al 1.

Lijkt verder te werken zo. (op MsgBox .... enz krijg ik een foutmelding en heb ik maar verwijdert
 
Laatst bewerkt:
mooi zo

dat msgbox heb ik verkeerd gespeld; moet zijn:

msgbox err.number & " - " & err.description

als je zelf de code overtikt ipv knip-plak dan krijg je aanvulhulp, en dan kan het eigenlijk niets mis gaan.

is dit onderwerp nu afgesloten?
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan