habe jetzt einen Versuch gestartet, ein Makro am Ende des Recordings zu speichern und bei Playback daraus zu laden.
Ich nehme eine fixe Datei TlazMacroFile mit Namen TLazMacroFileName = 'LazMacro.mrf' (Macro Recorder File)
In TsynMacroRecorder gibt es ja schon die beiden Prozeduren LoadFromFile und SaveToFile.
Dann wird diese Datei wie folg initilaisiert:
Code: Alles auswählen
Create:
fLazMacroFileName := ExtractFileDir(ParamStrUTF8(0)) // Lazarus Directory
+ PathDelim + 'LazMacro.mrf'; // = Macro Record File
Und dazu die zwei Prozeduren LoadFromLazMacroFile und SaveToLazMacroFile, abgewandelt von LoadFromFile und SaveToFile.
Die sehen dann so aus:
Code: Alles auswählen
procedure TCustomSynMacroRecorder.LoadFromLazMacroFile;
var
F : TFileStream; newage:longint;
const age:longint = 0; // Datei Datum des Erstellens
begin
if fileexists(fLazMacroFilename) then
F := TFileStream.Create(fLazMacroFilename, fmOpenRead) else
F := TFileStream.Create(fLazMacroFilename, fmCreate);
newage:= fileage(fLazMacroFileName);
if newage = age then exit; // Makrodatei wurde nicht verändert, events müssen nicht neu geladen werden
//- Gibt es noch eine andere Möglichkeit, die Änderung einer Datei zu verfolgen?
age:= newage;
try
LoadFromStream(F);
finally
F.Free;
end;
end;
procedure TCustomSynMacroRecorder.SaveToLazMacroFile;
var
F : TFileStream; c:integer;
begin
F := TFileStream.Create(LazMacroFileName, fmCreate);
try
SaveToStream(F);
finally
F.Free;
end;
end;
In procedure TCustomSynMacroRecorder.OnCommand() heißt es u.a.
Code: Alles auswählen
FStartPlayBack := False;
case State of
msStopped:
if Command = RecordCommandID then
begin
RecordMacro( TCustomSynEdit( Sender ) );
Handled := True;
end
else if Command = PlaybackCommandID then
begin
FStartPlayBack := True;
Handled := True;
end;
msPlaying:
;
msPaused:
if Command = PlaybackCommandID then
begin
Resume;
Handled := True;
end;
msRecording:
if Command = PlaybackCommandID then
begin
Pause;
Handled := True;
end
else if Command = RecordCommandID then
begin
// <--- hier Events in MacroDatei speichern
Stop;
Handled := True;
end;
end;
Der Zeitpunkt für LoadFrom..File scheint mir in PlaybackMacro angebracht zu sein, unmittelbar bevor die events abagearbeitet werden:
Code: Alles auswählen
procedure TCustomSynMacroRecorder.PlaybackMacro(aEditor: TCustomSynEdit);
var
cEvent: integer;
begin
if State <> msStopped then
Error( sCannotPlay );
fState := msPlaying;
try
StateChanged;
// <--- hier Events aus MacroDatei laden
for cEvent := 0 to EventCount -1 do
Events[ cEvent ].Playback( aEditor );
finally
fState := msStopped;
StateChanged;
end;
end;
Aber nur zwei Mal hintereinander kann ich Playback machen. Dann streikt das Programm, es folgt die ErrorMeldung: "Kann <MakroDatei> nicht öffnen. OK = weiter, Abbrechen = Programm abbrechen"
Woran kann das liegen?
Beim genaueren Anschauen der Prozeduren LoadFromStream und SaveToStream in den einzelnen EventKlassen (TsynMacroEvent) fand ich bei einigen EventKlassen Unterschied zwischen Save und Load: bei Save wird noch zusätzlich das ec-Command übertragen, aber nicht bei allen Eventklassen (nicht bei TSynDataEvent, TSynPositionEvent)
Mi scheint das ein Bug zu sein. Vielleicht hat der sogar diesen Fehler verursacht?
Denn in der Prozedur LoadFromStreamEx des MacroRecorders heißt es:
Code: Alles auswählen
while (aSrc.Position < aSrc.Size) and (i < cnt) do
begin
iCommand := 0;
aSrc.Read( iCommand, SizeOf(TSynEditorCommand) ); // ==> es wird immer zuerst das ec-Command gelesen
iEvent := CreateMacroEvent( iCommand );
iEvent.Initialize( iCommand, #0, nil );
iEvent.LoadFromStream( aSrc ); // ==> Aufruf des jeweiligen LoadFromStream
fEvents.Add( iEvent );
Inc(i);
end;
Es wird also jedes Mal erst ec-Command gelesen (und deshalb muß es ja wohl auch auch als erstes bei SaveToStream geschrieben werden).
(Warum nicht dieses ecCommand als weitere property, die dann initialisiert wird?)
Ich habe dann diese Veränderungen gemacht, neu kompiliert – wieder das gleiche Ergebnis: beim dritten Aufruf von Playback kommt wieder Fehlermeldung „Unable to open File ... “.
Es muß also noch irgendeinen anderen Grund geben....
Kannst Du Dir denken, was das sein könnte?
Außerdem gibt es noch algemein ein Problem beim Playback: Wenn bei den Events auch F9 dabei ist, also Run bis zum nächsten Fehler, und ich noch vor Beendigung des Runs Playback sende, dann bricht Lazarus ganz zusammen. Dann geht (fast) überhaupt nichts mahr. Ich kann noch schrieben, Cursor bewegen, auch Dateien öffnen, aber nicht mehr schließen, alle Buttons scheinen deaktiviert. So kannich auch nichts mehr speichern, es bleibt nur der Taskmanager, um Lazarus zu beenden.
Man bräuchte also eine globale Variable CompilerBusy o.ä.. Solange die auf TRUE gesetzt ist, soll das Playback nicht möglich sein.
Ich denke, die könnte man auch am besten gleich (fast) zu Beginn von PlaybackMacro() abfragen.
Ich wollte die Abfrage mit der Variablen (IDE)ToolStatus <> itNone machen, weil die von der MainIDE jedesmal gesetzt wird, aber ich finde keine Möglichkeit, vom MacroRecorder auf diese zuzugreifen...
Herzlichen Dank!