Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1516to1520
Aktuelles Verzeichnis
Verzeichnis Index
Übersicht Verzeichnisse
Vorheriger Thread
Rückwärts Blättern
Nächster Thread
Vorwärts blättern
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

Typen unverträglich

Typen unverträglich
24.09.2016 18:27:24
Frank
Hallo zusammen,
folgendes Makro liest aus einer Spalte mit Datum (TTMMJJ)die Jahreszahlen aus.
Wenn diese mit dem aktuellen Jahr übereinstimmen, werden sie auf ein zweites
Tabellenblatt kopiert.
Leider bringt er für die Variable "D" ständig die Fehlermeldung "Typen
unverträglich".
"D" soll die ausgelesene Jahreszahl der aktiven Zelle ausgeben.
Wenn ich die Prozedur in Einzelschritten durchlaufe, läuft der Code komischerweise.
Bitte helft mir bei dem Problem.
Muss ich "D" eine anderen Typ bedaten oder woran liegts ?
Hier das Makro:
Option Explicit
Dim i As Integer
Dim LaufzBeginn As Range
Dim LaufzEnde As Range
Dim Jahr
Dim D As Integer
Dim Zelle As Object
Dim Z As Integer
Dim s As Integer
Dim iAnz As Integer
Const Blatt1 = "Grunddaten"
Const Blatt2 = "Test"

Sub Datum_kopiern()
Sheets("Grunddaten").Select
i = Cells(Rows.Count, 5).End(xlUp).Row
i = i - 2
MsgBox ("Die letzte beschriebene Spalte ist Nr.  " & i)
Set LaufzBeginn = Range(Cells(2, 5), Cells(i, 5))
Set LaufzEnde = Range(Cells(2, 6), Cells(i, 6))
Sheets("Grunddaten").Select
Sheets("Grunddaten").Range("3:1").Select
'Sheets("Test").Range("A1").Select
Application.ScreenUpdating = False
Sheets(Blatt1).Activate
LaufzBeginn.Select
iAnz = 0
s = 0
Z = 1
Do Until s = i
Set Zelle = ActiveCell
D = Year(Zelle)
Jahr = Year(Date)
If D  Jahr Then
End If
If D = Jahr = True Then
Zelle.Copy
Sheets(Blatt2).Activate
Sheets(Blatt2).Cells(Z, 1).Select
ActiveSheet.Paste
ActiveCell.Offset(1, 0).Select
Z = Z + 1
Sheets(Blatt1).Select
End If
ActiveCell.Offset(1, 0).Select
Loop
Application.CutCopyMode = False
Application.ScreenUpdating = True
'MsgBox ("Es wurden   " & iAnz & " Zellen übertragen.")
MsgBox ("Test erfolgreich")
End Sub

Danke für Eure Zeit und Mühe !!!
Gruß Frank.

14
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW: Warum ein neuer Beitrag zum gleichen Thema
24.09.2016 18:55:46
Werner
Hallo Frank,
warum bleibst du nicht in deinem alten Beitrag? Dort habe ich dir was geschrieben.
Gruß Werner
AW: Warum ein neuer Beitrag zum gleichen Thema
24.09.2016 19:00:38
Frank
Hallo Werner,
sorry, hätte ich machen sollen.
Kann man diesen Beitrag löschen ?
Danke !
Gruß Frank.
vermutlich steht kein Datum in ActiveCell ...
24.09.2016 18:59:11
Matthias
Hallo
vermutlich steht kein Datum in ActiveCell ...
... sondern Text.
Gruß Matthias
AW: vermutlich steht kein Datum in ActiveCell ...
24.09.2016 19:04:48
Frank
Hallo Matthias,
ich hab zu diesem Thema dummerweise einen zweiten Beitrag eingestellt der aktueller ist.
Dieser hat den Titel "Typen unverträglich".
Sorry nochmal.
Gruß Frank.
ja, der Fehler entsteht bei Text in einer Zelle oT
24.09.2016 19:08:52
Matthias
AW: ja, der Fehler entsteht bei Text in einer Zelle oT
24.09.2016 19:24:34
Frank
Hallo Matthias, Werner,
wie muss ich dann den Code in dem Fall ändern ?
Hier nochmal das aktuelle Makro:
Option Explicit
Dim i As Integer
Dim LaufzBeginn As Range
Dim LaufzEnde As Range
Dim Jahr
Dim D As Integer
Dim Zelle As Object
Dim Z As Integer
Dim s As Integer
Dim iAnz As Integer
Const Blatt1 = "Grunddaten"
Const Blatt2 = "Test"
Sub Datum_kopiern()
Sheets("Grunddaten").Select
i = Cells(Rows.Count, 5).End(xlUp).Row
i = i - 2
MsgBox ("Die letzte beschriebene Spalte ist Nr.  " & i)
Set LaufzBeginn = Range(Cells(2, 5), Cells(i, 5))
Set LaufzEnde = Range(Cells(2, 6), Cells(i, 6))
Sheets("Grunddaten").Select
Sheets("Grunddaten").Range("3:1").Select
'Sheets("Test").Range("A1").Select
Application.ScreenUpdating = False
Sheets(Blatt1).Activate
LaufzBeginn.Select
iAnz = 0
s = 0
Z = 1
Do Until s = i
Set Zelle = ActiveCell
D = Year(Zelle)
Jahr = Year(Date)
If D  Jahr Then
End If
If D = Jahr = True Then
Zelle.Copy
Sheets(Blatt2).Activate
Sheets(Blatt2).Cells(Z, 1).Select
ActiveSheet.Paste
ActiveCell.Offset(1, 0).Select
Z = Z + 1
Sheets(Blatt1).Select
End If
ActiveCell.Offset(1, 0).Select
Loop
Application.CutCopyMode = False
Application.ScreenUpdating = True
'MsgBox ("Es wurden   " & iAnz & " Zellen übertragen.")
MsgBox ("Test erfolgreich")
End Sub

Dank Euch !
Gruß Frank.
Anzeige
AW: ja, der Fehler entsteht bei Text in einer Zelle oT
24.09.2016 19:57:39
Frank
Hallo Matthias, Werner,
anbei die Datendatei zum Makro.
https://www.herber.de/bbs/user/108390.zip
Die betreffende Spalte ist die E und die F.
Ich habe jetzt mal mit der E angefangen.
Die ist aber vollständig als Datum formatiert.
Schaut's Euch bitte mal an.
Danke !
Gruß Frank.
AW: ja, der Fehler entsteht bei Text in einer Zelle oT
24.09.2016 21:46:48
Werner
Hallo Frank,
jetzt noch mal:
1. Es geht um Spalte E und F Blatt "Grunddaten" die nur für das Jahr 2016 ins Blatt "Test" kopiert werden sollen?
2. Sonst keine weiteren Daten?
3. Wenn beide Datumsspalten aus 2016 aus Grunddaten nach Test kopiert werden sollen, sollen die dann im Blatt Test dann auch wieder in zwei Spalten nebeneinander stehen?
Erklärung doch mal was du letztendlich erreichen möchtest. Willst du wirklich nur die zwei Datumsspalten für ein bestimmtes Jahr von einem Blatt in ein anderes kopieren oder was ist dein eigentliches Ziel?
Das ist mir ehrlich gesagt immer noch nicht klar.
Gruß Werner
Anzeige
Es liegt an einer Endlosschleife
24.09.2016 23:46:05
Zwenn
Hallo Frank,
abgesehen davon, dass die Fragen von Werner mehr als berechtigt sind, möchte ich Dich auf folgende Dinge bezüglich Deines Codes hinweisen. Ich mache das etwas ausführlicher, weil du angegeben hast nur über Basiskenntnisse in VBA zu verfügen.
Grundsätzlich funktioniert Dein Code und macht genau das, was er soll. Nachdem Du nun eine Arbeitsmappe mit Beispieldaten hochgeladen hast, habe ich diese als .xlsm Datei abgespeichert und Deinen Code in ein Modul eingefügt. Makros lassen sich nicht in .xlsx Dateien speichern, achte darauf bitte in Zukunft.
Der Type Mismatch Fehler kommt nicht, weil das Makro mit irgend einem Datum nicht umgehen kann, sondern weil Du eine Endlosschleife programmiert hast, die aufgrund dieses Laufzeitfehlers nur nicht unendlich laufen kann ;-)
Du hast Dich für eine Do Until Schleife entschieden, was ich schonmal sehr löblich finde, weil mir die Auswahl zeigt, dass Du Dich mit den möglichen Schleifentypen auseinander gesetzt hast.
Dein Schleifenkopf besteht aus der Zeile
Do Until s = i
Im Schleifenrumpf veränderst Du aber weder den Inhalt der Variablen s noch den der Variablen i. Deshalb wird Deine Abbruchbedingung s = i niemals erreicht, was eigentlich zu einer Endlosschleife führt. Da Du im Schleifenrumpf aber mit dem Datentyp Date arbeitest, kommt es zum Type Mismatch Fehler, sobald das Makro eigentlich durchgelaufen ist.
Schaut man nach einem Lauf deines Codes (und Wegklicken der Fehlermeldung) in die Tabelle 'Test', stehen dort 35 Daten. Genau die Anzahl, die wirklich übertragen werden soll. Das Makro versucht aber noch das nächste Datum auszulesen und stößt in Zeile 47 der Tabelle 'Grunddaten' auf eine leere Zelle in Spalte 5. Da ein leerer Wert nicht dem Datentyp Date entspricht, kommt es an dieser Stelle zu besagter Fehlermeldung.
Nun könnte ich einfach sagen, Du musst dafür sorgen, dass die Abbruchbedingung der Schleife erreicht wird. Aber Dein Code ist *hüstel* einigermaßen gruselig und ich habe ihn ehrlich gesagt auch erst richtig verstanden, als ich ihn ausgeführt habe. Mit "ihn verstanden" meine ich, ich glaube ich habe verstanden, was Du beim Programmieren gedacht hast.
Da Du Anfänger in dieser Materie bist, nehme ich mir die Zeit und pflücke Deinen Code mal auseinander. Das mache ich nicht, weil ich mit dem Oberlehrer Zeigefinger auf Dich deuten will, sondern weil ich glaube, Du willst es wirklich verstehen und deshalb hat es einen Sinn.
Zunächst einmal der Hinweis, dass der Deklarationsteil der Variablen in das Makro gehört und nicht davor. Das hat etwas mit dem Gültigkeitsbereich von Variablen zu tun. So wie Du sie deklariert hast, sind es globale Variablen, die jedes Sub und jede Function nach belieben verwenden könnte. Globale Variablen sind beim Programmieren zu vermeiden, weil sie den Code unübersichtlich machen. In VBA habe ich einzig keine Möglichkeit gefunden, sie bei der Verwendung von User Forms zu vermeiden, was mir selbst nicht so richtig paßt.
Den Variablen selbst hast Du wenig sprechende Namen gegeben. Das macht den Code schwerer lesbar. Nicht nur für Dich (vor allem nach ein paar Wochen oder mehr), sondern auch für uns hier im Forum. Mit einem Z kann ich erstmal wenig anfangen, bis ich aus dem Quellcode den Kontext sehe. mit Zeile wäre mir gleich klar, worum es geht. Gewöhne Dir am besten direkt an, sprechende Namen zu vergeben. Um nicht zu lange Variablen oder Funktionsnamen zu erhalten, sind auch Abkürzungen erlaubt.
Darüber hinaus ist es ratsam, den Datentyp als Abkürzung vor den eigentlichen Variablennamen zu setzen. Also z.B. nicht Zeile sondern lZeile, wenn der Datentyp long verwendet wird oder iSpalte, wenn der Datentyp Integer verwendet wird.
Du erleichterst Dir das Programmierer-Leben selbst enorm damit.
Die ganzen Select-Anweisungen sind in den allermeisten Fällen überflüssig. Sie brauchen vor allem eine Menge Zeit beim Programmlauf und Du kannst das gleiche Ergebnis erzielen, wenn Du die entsprechenden Objekte wie Tabellen, Zellen, usw. direkt ansprichst.
So hast Du z.B. geschrieben:

Sheets("Grunddaten").Select
i = Cells(Rows.Count, 5).End(xlUp).Row
i = i - 2
Genau das Gleiche erreichst Du mit der Zeile:
i = Sheets("Grunddaten").Cells(Rows.Count, 5).End(xlUp).Row - 2
Darüber hinaus hast Du Konstanten für die Balttnamen eingeführt. Auch das finde ich echt gut. Du machst nur nicht konsequent Gebrauch davon. Denn eigentlich muss die von mir zusammengefasste Version deiner 3 Zeilen lauten:
i = Sheets(Blatt1).Cells(Rows.Count, 5).End(xlUp).Row - 2
Nun zum Kern Deiner Annahme, wie ich glaube. Du hast folgende zwei Zeilen programmiert und bist dabei Vermutlich davon ausgegangen, die Zeilen-Grenzen festzulegen, in denen Dein Makro arbeiten soll. (Das ist der Teil, den ich glaube in Deiner Denkweise verstanden zu haben.)

Set LaufzBeginn = Range(Cells(2, 5), Cells(i, 5))
Set LaufzEnde = Range(Cells(2, 6), Cells(i, 6))
Du kannst dieses Konstrukt zwar grundsätzlich so verwenden, aber nur die beiden Zeilen reichen nicht aus. Du definierst die Bereiche damit nur, wendest sie in der Folge aber gar nicht an. Sowohl die Variable LaufzBeginn, wie auch LaufzEnde, werden nicht mehr verwendet. Dabei enthält vor allem LaufzEnde den Wert, den Du in Deiner Schleife als Abbruchbedingung verwenden müsstest. Naja, fast ;-) Cells(i, 6) ist der Teil, den Du abfragen musst, woraus sich ergibt, dass Du die beiden Variablen LaufzBeginn und LaufzEnde eigentlich gar nicht brauchst.
Ebenso wenig brauchst Du die beiden folgenden If-Abfragen:

If D  Jahr Then
End If
Diese beiden Konstrukte haben gar keinen Rumpf mit Anweisungen, die beim Zutreffen der Bedingung ausgeführt werden sollen. Deshalb sind sie komplett überflüssig und Du kannst sie ersatzlos löschen. Du musst nicht alle Möglichkeiten prüfen, sondern nur die, auf die es ankommt. Das machst Du mit:
If D = Jahr = True Then
Das funktioniert zwar (was ich schon fast lustig finde), ist aber des Guten ein Gleichheitszeichen zuviel ;-)
If D = Jahr Then

reicht völlig aus, denn der Vergeleich ergibt entweder true, wenn beide Werte gleich sind oder false, wenn nicht. Die explizite Abfrage auf einen der beiden Wahrheitswerte ist an dieser Stelle überflüssig.
Ich gebe an dieser Stelle keine Lösung an, weil Werner die eigentlich relevanten Fragen gestellt hat, die Du zunächst mal beantworten solltest
Viele Grüße,
Zwenn
Anzeige
So, jetzt hast du dir ja sehr viel Mühe mit der …
25.09.2016 00:18:02
Luc:-?
…Analyse dieses Pgms gegeben, Zwenn, ;-)
aber 2 deiner Aussagen sollen trotz allen Verdienstes nicht unwidersprochen bleiben:
1. Globale Variablen sind beim Programmieren zu vermeiden … → Wo steht das und warum sollte man diesen Rat befolgen? Es gibt nämlich noch mehr Gründe für globale Variablen als du sie genannt hast! Hier wird es sich doch wohl einfach nur, wie auch von dir vermutet, um einen ggf etwas untypischen Anfänger­Fehler handeln (aber wer weiß…).
2. Darüber hinaus ist es ratsam, den Datentyp als Abkürzung vor den eigentlichen Variablennamen zu setzen → Das ist schlicht weit verbreiteter Nonsense und führt nur dazu, dass das bei einer evtl Datentyp­Änderung vergessen wird und somit letztlich etwas Falsches aussagt und damit wertlos ist/wird. Wenn man schon die UN verwenden will, dann bitte schön auch im Sinne ihres Erfinders und nicht sinn­loser­weise einfach nur den Datentyp wiederholen. Dafür kennt VBA andere Möglich­keiten allgemeiner Deklaration, bei denen so etwas tatsächlich berück­sichtigt würde.
Gruß & schöSo, Luc :-?
Besser informiert mit …
Anzeige
AW: So, jetzt hast du dir ja sehr viel Mühe mit der …
25.09.2016 01:03:26
Zwenn
Hallo Luc:-?,
Deine Einwände sind berechtigt und ich nehme gerne Stellung dazu.
Dabei möchte ich mit 2. anfangen. Das Voranstellen des Datentyps ist nicht zwingend notwendig:
Ja, das stimmt und ich kann Deine angeführten Gründe auch nachvollziehen. Nichts desto Trotz hat sich diese Konvention in VBA durchgesetzt und viele Programmierer, die diese Sprache verwenden, machen es so und erwarten es auch von anderen.
Ich kannte das vorher auch nicht (ich komme von C) und fand es erst komisch. Aber ich habe mich daran gewöhnt und finde es in machen Situationen sehr praktisch, den Datentyp direkt aus der Variablen ablesen zu können. Zwingend notwendig ist es nicht, da hast Du recht. Es ist nur eine Konvention.
Dem Punkt 1. Deiner Anmerkungen widerspreche ich aber vehement. Globale Variablen sind zu vermeiden! Ja!
Das Verwenden von globalen Variablen ist genauso unnötig, wie das Verwenden des GoTo Befehls. Es entspricht gutem Programmierstil, jede Variable nur in dem Gültigkeitsbereich zu definieren, in dem sie auch verwendet werden muss. 'Global' ist dabei ein Gültigkeitsbereich, der schlicht und ergreifend niemals notwendig ist. Ganz im Gegenteil ist 'Global' eine Seuche.
Damit knüpft man (genau wie mit GoTo) an die Zeiten des Spaghetti-Codes an. Die Möglichkeit den Wert einer Variablen an jeder X-beliebigen Stelle eines Programms verändern zu können, widerspricht dem Prinzip der Modularisierung durch Funktionen und ist deswegen zu unterlassen.
Das habe ich mir nicht ausgedacht, das habe ich bereits in den 90ern so gelernt und finde es richtig. Aber ich bin gespannt darauf von Dir zu erfahren, welche Gründe es für globale Variablen gibt. Aber bitte bei der prozeduralen Programmierung bleiben und nicht Klassen-Variablen nennen. Auch wenn VBA Objektorientiert ist, (fast) niemand verwendet es (bewußt) so.
Dir auch einen schönen Sonntag :-)
Zwenn
Anzeige
Ja, danke, das Wetter hat ja mitgespielt, …
26.09.2016 02:12:50
Luc:-?
…Zwenn… ;-)
Ich fange mal wieder bei 1. an:
1. Globale Variablen verwende ich nur gelegentlich und dann idR auch keine ObjektVariablen, sondern nur deren Namen. Bei kom­plexen Abläufen kann das sehr nützlich sein. Es muss eine modulare PgmGestaltung auch nicht unbedingt stören. Alternativ müsste man solche Variablen, die an verschiedenen Stellen (in mehreren TeilPgmm) benötigt wdn, nämlich ständig weiterreichen.
Wenn ich UDFs pgmmiere, auch wenn sie für ein komplettes AddIn bestimmt sind, verwende ich so etwas idR nicht, außer viell für organisierende DienstPgmm des AddIns oder zB eine eine UDF unter­stützende SubProzedur, die durch ein Ereignis ausgelöst wird und der ich deshalb nicht direkt notwendige Daten übergeben kann. Die wdn dann aus einer GlobalVariablen abgerufen.
Das mit dem GoTo ist genauso eine modische Erscheinung, deren Anfänge bzgl Spaghetti-Code ich schon vor 45 Jahren kennen­lernte. Wir haben das schon damals so sparsam eingesetzt, dass dieser Spaghetti-Effekt nicht eingetreten ist, lebten also nicht in einer „Spaghetti-Code-Zeit“. Ich habe aber später auch Anfänger erlebt, die mehrfach benötigte PgmTeile einfach immer wieder einkopiert haben, was noch grauenvoller war (vor allem bei Fehlern und Änderungen) als ein paar sinnvoll gesetzte Sprung­Befehle, zB zu UnterPgmmen.
Außerdem dürften die Compiler etliche der modischen ErsatzKonstrukte intern ohnehin durch Sprünge ersetzen.
Warum in aller Welt soll ich auf solche Möglichkeiten verzichten, wenn sie denn die Sprache mitbringt?
2. Das du das von C nicht kennst, verwundert mich nicht, denn die vehemente Ablehnung solcher (Pseudo-)UN-Kürzel kommt ja auch aus dem C-Lager (dort oft „Warzen­schweine“→ warthogs genannt). Leider gilt das aber vielen als VB(A)-Konvention, obwohl das MS ursprünglich nicht durch Code-Bspp unterstützt hatte (neuerdings taucht so etwas auch in der VBE-Hilfe mitunter auf) und es auch in .Net kontraproduktiv sein soll. Allerdings hatte die MS-Office-Riege die UN intern verwendet, aber die echte. Die Win­Pgmmierer haben es dann übernommen, aber falsch verstanden. Und in dieser, mit Verlaub, idiotischen Form ist das dann zur „Konvention“ avanciert!
Ich bezeichne mit solchen Präfixen höchstens mal eine Array-Variable, Text- und Namens­Konstanten und einer Vgls­Abfrage die­nende Variablen, die dann sowohl vom Datentyp Boolean als auch Enumerationen mit Integer-Werten sein können. Es geht also um die Funktion dieser Variablen im Pgm (ganz im Sinne des UN-Erfinders), nicht um ihren Datentyp.
Ansonsten scheren mich solche angeblichen Konventionen und NoGoes nicht die Bohne. Meine Pgmm muss niemand begutachten u/o zensieren → use it like it is und in Foren zusätzlich wysiwyg, obwohl dieser (Durch-)Blick nicht immer leicht fallen dürfte…! ;-]
SchöWo, Luc :-?
Anzeige
AW: ja, der Fehler entsteht bei Text in einer Zelle oT
26.09.2016 00:07:41
Werner
Hallo Frank,
seither leider keine Antwort deinerseits mehr. Ich habe dir jetzt mal was zusammengestrickt, das die Spalten E und F aus dem Blatt "Grunddaten" ins Blatt "Test" kopiert.
Die Auswahl des Jahres habe ich über eine Input-Box gemacht, ist wohl etwas flexibler wie dein Year(Date).
Schau es dir mal an.
Sub Kopieren()
Dim loVon As Long
Dim loAnzahl As Long
Dim loLetzte As Long
Dim loLetzte2 As Long
loVon = Application.InputBox("Für welches Jahr sollen Daten kopiert werden?", _
"Jahr 4-stellig eingeben", 2016, Type:=1)
loLetzte = Sheets("Grunddaten").Cells(Rows.Count, 5).End(xlUp).Row
With Sheets("Test")
loLetzte2 = .Cells(.Rows.Count, 1).End(xlUp).Row
If .Cells(loLetzte2, 1)  "" Then loLetzte2 = loLetzte2 + 1
End With
Application.ScreenUpdating = False
With Sheets("Grunddaten").Range("E1:F" & loLetzte)
.AutoFilter Field:=1, Criteria1:= _
"=01/01/" & loVon
loAnzahl = .Range("E1:E" & loLetzte).SpecialCells(xlCellTypeVisible).Count - 1
End With
If Sheets("Grunddaten").Range("E1:E" & loLetzte).SpecialCells(xlCellTypeVisible).Count > 1 Then
Sheets("Grunddaten").AutoFilter.Range.Offset(1).Resize(Sheets("Grunddaten") _
.AutoFilter.Range.Rows.Count - 1).SpecialCells(xlCellTypeVisible) _
.Copy Sheets("Test").Cells(loLetzte2, 1)
Else
MsgBox "Keine Daten für das Jahr " & loVon & " vorhanden."
End If
If Sheets("Grunddaten").AutoFilterMode Then Sheets("Grunddaten").AutoFilterMode = False
Application.ScreenUpdating = True
MsgBox "Es wurden " & loAnzahl & " Zellen übertragen"
End Sub
Gruß Werner
Anzeige
AW: Feedback ein Fremdwort! o.w.T.
28.09.2016 10:05:48
Werner

Links zu Excel-Dialogen

Beliebteste Forumthreads (12 Monate)

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige