'Rückgängig machen' bei VBA-Makros?

Hallöchen!

Ich bin mir nicht sicher, ob das wirklich geht, aber optimistisch bin ich immer :wink:
Ich habe in (m)einer Rangliste einige Buttons erstellt, womit man 1-7 Zeilen löschen kann. Gibt es eine Möglichkeit, per Makro die gelöschten Zeilen wieder zurück zu bekommen, falls der Anwender, der die Rangliste benutzt, „falsch geklickt“ hat (wahrscheinlich Makroüberwachung inkl. undo-Funktion)?

Das Makro für 7 Zeilen löschen sieht bei mir so aus:

Sub zeilen\_loeschen\_7()
 ActiveSheet.Unprotect
 Rows("5:11").Select
 Selection.Delete Shift:=x1Up
 Range("A5").Select
 ActiveSheet.Protect
 ActiveSheet.EnableSelection = xlUnlockedCells
End Sub

Viele Grüße,
Daniel

Hallo Daniel,
ich hab dir da was gebastelt. Das Makro geht davon aus dass die (Formular !) Buttons in ihrer Beschriftung als erste im Text vorkommende Zahl die Zahl haben der Zeilen die gelöscht werden sollen. Also so was wie:
„Lösche 7 Zeilen ab A5“
„erste 7 Zeilen in A5 entfernen“
„kill 7“ :smile:
Daraufhin werden dann bei Klick auf den Button die ersten x Zeilen ab und incl A5 gelöscht, also bei 7 Zeilen die Zeilen A5 bis A11.
Vergiss nicht bei den Buttons unter „Steuerelement formatieren“, dort bei Eigenschaften, die Buttons von Zellen unabhängig zu machen sonst verschwinden sie wenn sie im Bereich stehen mit den gelöschten Zeilen*g
Die Anzahl der zu löschenden Zeilen ist nach oben hin offen, also nicht auf 7 begrenzt.
Weiterhin kannst du noch einen Button erzeugen, Beschriftung „Rückgängig“ o.ä. und dem das Makro Rückgängig zuzuweisen.
Du hast dann die Wahl, entweder über diesen Button oder über Bearbeiten—Rückgängig eine Löschaktion zurückzuholen.
Falls du eine andere Startzelle als A5 benutzen willst, ich habe auskommentiert in welchen Zeilen des Codes du dann die A5 bzw die 5 abändern musst auf zum Beispiel A12 bzw 12.
Gruß
Reinhard

Public speicher() As Variant
Public gesp As Boolean
Sub Zeilen\_loeschen()
Dim a as long ' a ist Anzahl der zu löschenden Zeilen 1-65536:smile:
Dim Bezeich As String 'Bezeich=Aufschrift des Buttons
 Bezeich = ActiveSheet.Shapes(Application.Caller).TextFrame.Characters.Text
 While Asc(Bezeich) 57 'alle Buchstaben aus Bezeich vor der Zahl raus
 Bezeich = Mid(Bezeich, 2)
 Wend
 a = Val(Bezeich) ' a ist die (erste) Zahl die in Bezeich steht
 If a = 0 Then Exit Sub ' keine zahl gefunden , sub verlassen
 ActiveSheet.Unprotect
 ReDim speicher(a + 1, 256) ' Arrayvariable dimensionieren, je nach a
 speicher(a + 1, 1) = a ' Merken wieviel Zeilen gelöscht werden
 speicher = Range("5:" & 5 + a - 1) 'hier die 5 anpassen, Range in speicher() abbilden
 Rows("5:" & 5 + a - 1).Delete Shift:=x1Up 'hier die 5 anpassen, Löschen der Zeilen
 Range("A5").Select ' hier die A5 anpassen
 ActiveSheet.Protect
 ActiveSheet.EnableSelection = xlUnlockedCells
 Call zurück(a) ' Eintragung in die Undo-Liste
End Sub
Sub zurück(a)
'Text= Bearbeiten-Rückgängig-Text, Proceure=Makro was dann ausgeführt wird
Application.OnUndo Text:="Lösche " & a & " rückgängig machen", \_
 Procedure:=ThisWorkbook.Name & "!Zeilen\_löschenzurück"
 gesp = True
End Sub
Sub Zeilen\_löschenzurück()
Dim a as long, n as long
 ActiveSheet.Unprotect
 a = UBound(speicher) ' wieviel zeilen wurden gelöscht abrufen
 For n = 1 To a ' Die Zeilen wieder einfügen
 Range("A5").EntireRow.Insert ' hier die A5 anpassen
 Next n
 'zurüchschreiben der Zeileninhalte
 Range("A5:iv" & 5 + a - 1) = speicher ' hier die A5 UND die 5 anpassen,
 ActiveSheet.Protect
 ActiveSheet.EnableSelection = xlUnlockedCells
 gesp = False
End Sub
Sub Rückgängig()
If gesp Then
 Zeilen\_löschenzurück
Else
 MsgBox "Entweder nichts per Button gelöscht worden." & Chr(13) \_
 & "Ooder die Löschung wurde schon rückgängig gemacht," & Chr(13) \_
 & "dies geht nur einmal pro Löschvorgang"
End If
End Sub

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Reinhard!

Erstmal danke für die Mühe! Ich habe die Makros gerade ausprobiert („A5“ ist übrigens goldrichtig :wink:). Die Löschung der Zeilen (habs mit 1 und 7 getestet) klappt einwandfrei, nur die Widerherstellung nicht. Kann es daran liegen, dass die Variablen

Public speicher() As Variant
Public gesp As Boolean

etwas „hilflos“ im Raum stehen ?!? Egal wieviele gelöschte Zeilen ich wieder herstellen möchte, es wird immer die „Else“-Box aus dem Makro „Rückgängig“ angezeigt.

Ich hab die Rangliste im jetztigen Stand nochmal hochgeladen (zum besseren Nachvollziehen - 800kb):
http://www.kingpong.de/rangliste/rangliste_beta.xls

Die beiden obengenannten Variablen habe ich im Modul „diverse“ auskommentiert, da ich sonst mit dem Makro darüber Probleme bekomme.

Gruß Daniel

Hallo Daniel,

ohne jetzt das ganze Makro auszuprobieren, würde ich spontan sagen, das dies

Die beiden obengenannten Variablen habe ich im Modul „diverse“
auskommentiert, da ich sonst mit dem Makro darüber Probleme
bekomme.

das Problem ist. In diesen Variablen sollen die Informationen für das Undo hinterlegt werden. Die Deklaration über dem Begin Sub bewirkt, das diese Variablen auch nach dem Beenden der Prozedur noch da sind (wär ja sonst auch ein bisschen sinnlos, oder?) Versuch die 2 Zeilen mal in einem Modul ganz oben hin zu packen, also vor das 1. Makro, es kann auch ein anderes Modul sein als das in dem das Makro an sich liegt.

Ich nehme an, das du kein Option Explicit am Anfang des Moduls stehen hast, denn sonst hättest du schon einen Fehler bekommen, weil du nicht deklarierte Variablen benutzt hast (durch das auskommentieren). Dadurch geht unterstellt VBA einfach, das du diese Variablen innerhalb der Prozedur definieren wolltest, und schmeisst die nach dem Ende wieder weg. Kuck dir am besten mal die Hilfe zu Option Explicit an, diese 2 Worte sparen meistens eine Menge Ärger.

Also einfach die 2 Zeilen wieder einfügen, am besten am Anfang eines Modules und dann sollte es klappen.

Gruß
Daniel

Moin Daniel,
ja, dein Namensvetter hat Recht, die beiden Public-Anweisungen gehören ganz oben in ein Modul. Die Reihenfolge der danach folgenden Subs spielt keine Rolle.
Auch mit Option Explizit hat er Recht, je komplexer Makros werden erspart diese Option viel Sucherei weil Variablennamenprobleme sofort angezeigt werden.
Ich lass das meist weg, weil ich ja selten komplette Programme erstelle sondern nur kleinere Routinen austeste.
Wenn du Option Explicit benutzen willst (ist zu empfehlen), einfach im VB-Editor unter Extras–Optionen–Editor ein Häkchen bei Variablendeklaration erforderlich.
Dann erscheint automatisch Option Exlicit in jedem Modul und es erscheinen konkrete Fehlermeldungen bis du alle Variablen deklariert hast.
Deklaration erfolgt mit Dim x as Integer (in der Prozedur), public x as integer(global) usw.
Ansonsten, wenn die beiden Publics korrekt oben stehen und du den 7 Autoformen jeweils das gkleiche Makro „Zeilen_löschen“ zuweist funktioniert das mit „Béarbeiten–Rückgängig.“
Allerdings zerschiesst das dein Bild weil anscheinend beim wiedereinfügene die (stark verkleinerte)Zeilenhöhe von A4 übernommen wird, was dann nicht lesbar aussieht. Dies passiert dann, wenn vorher keine neuen Zeilen mit deinen anderen Autoformen eingefügt wurden.
Dann ist beim löschen die 25.4. zeile weg und kommt verkleinert wieder.
Soll das noch abgefangen werden? Bzw was soll passieren wenn in A5 ein Datum steht, soll dann das zeilen_löschen-Makro nicht löschen?

Noch was, bei deinen anderen Subs, wie gelb_mitte_3 usw, baue doch gleich als erste Zeile Application.ScreenUpdating = False ein und am Ende vor End Sub Application.ScreenUpdating = True, dann ist das Bild ruhiger.
Du kannst die Anzahl der Makros stark reduzieren, wenn du für die ganzen gelb_mitte bzw grün_mitte Subs nicht für 2, 3, 4 usw eigene Makros hast sondern nur eins,was für alle „gelben“ gilt, wie nachfolgend zu sehen für gelb_Mitte, auch da wird wieder die Anzahl aus der Bezeichnung der Autoform gewonnen.

Gruß
Reinhard

Sub gelb\_mitte\_Alle()
 Dim Bezeich As String
 Dim a As Integer
 Application.ScreenUpdating = False
 Bezeich = ActiveSheet.Shapes(Application.Caller).TextFrame.Characters.Text
 'MsgBox Bezeich
 a = Val(Bezeich)
 ActiveWorkbook.Unprotect
 ActiveSheet.Unprotect
 Sheets("Baukasten").Visible = True
 Sheets("Baukasten").Select
 Range("14:" & 14 + a - 1).Select ' geändert
 Selection.Copy
 Range("H1").Select
 Sheets("Baukasten").Visible = False
 Sheets("Ergebnisse").Select
 Rows("5:" & 5 + a - 1).Select ' geändert
 Selection.Insert Shift:=xlDown
 Range("A5").Select
 ActiveSheet.Protect
 ActiveSheet.EnableSelection = xlUnlockedCells
 ActiveWorkbook.Protect Structure:=True, Windows:=True
 Application.ScreenUpdating = True
End Sub

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

:wink: DANKE :wink:
Hallo Daniel!

Danke für den Tipp, mit der Positionierung am Anfang des Moduls ist die Fehlermeldung weg :wink:

Viele Grüße,
Daniel #2

Hallo Reinhard,

das Makro klappt jetzt! Allerdings bin ich mir nicht so sicher, ob ich die Funktion „Rückgängig machen“ wirklich einbauen soll, da es etwas kompliziert wird. Die zurückgeholten Zeilen sollten schon Höhe (12,75) und Farbe (gelb bzw. grün) der ursprünglichen Zeilen haben (ob in A5 ein Datum steht oder nicht, ist unrelevant). Es ist vielleicht einfacher, wenn ich eine Info neben die Buttons packe (und in die Hilfe), wo ich darauf hinweise.
Ich habe mir gestern schon Gedanken gemacht, wie ich den VBA-Code umstricken kann, dass beim Ausführen der Makros nicht alle beinhaltenden Blätter „aufblitzen“. Der Befehl

Application.ScreenUpdating

ist hier goldrichtig! Das erspart mir die Suche bei Google bzw. ein erneutes Posting :wink:
Vielen Dank auch für die elegantere Lösung der Makros „gelb_mitte“ bzw. „gruen_mitte“. Jetzt ist meine Makro-Sammlung etwas übersichtlicher als vorher.

Mein Angebot (Erwähnung in der Hilfe) steht natürlich noch. Ich hatte Dir diesbezüglich bereits eine Email an die hier im Forum angegebene Adresse geschickt.

Viele Grüße,
Daniel

Hi Daniel,
muss gleich weg, aber wegen der Zeilenhöhe kein Problem,
In die Schleife halt noch die Höhe einbauen:

 For n = 1 To a ' Die Zeilen wieder einfügen
 Range("A5").EntireRow.Insert ' hier die A5 anpassen
 Activecell.rows.height=12.75 ' oder auch range("A5").rows.height...
 Next n

Keine Ahnung ob die Syntax richtig ist, zeichne dir einmakro auf wo du ne zeile einfügst und von der Zeile die Höhe auf 15 setzt. Dann schau dir den Code ein und bau das in die obige Schleife ein.
Gruß
Reinhard

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hi Reinhard,

danke für die Info!

Gruß Daniel