Autor |
Beitrag |
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 04.05.20 06:12
Hallo!
Weiss jemand, wie ich per Code in ein TRichMemo eine Grafik einfügen kann, ohne den Weg über ClipBoard zu nehmen?
Alternativ: Wie realisiere ich eine "eigene" Zwischenablage, die ich dazu verwenden kann? Der Hintergrund dabei ist, dass ich dabei den Inhalt der systemweiten Zwischenablage nicht überschreiben will.
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19289
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 04.05.20 07:54
Du musst soweit ich weiß ein TRichMemoInlinePicture erstellen, dem Konstruktor dein Bild mitgeben und das dann mit InDelInline in das TRichMemo einfügen.
|
|
Th69
Beiträge: 4791
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Mo 04.05.20 08:13
In der Wiki steht auch noch RichMemo: InsertImageFromFile (sowie InsertImageFromFileNoResize).
Für diesen Beitrag haben gedankt: galagher
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 04.05.20 08:14
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 04.05.20 15:43
Das fügt Grafiken als eingebettetes Objekte ein, ich möchte aber lediglich eine Grafik so einfügen, wie man sie auch per ClipBoard einfügen kann.
Ich sehe mir jetzt erstmal den Vorschlag von jaenicke an:
jaenicke hat folgendes geschrieben : | Du musst soweit ich weiß ein TRichMemoInlinePicture erstellen, dem Konstruktor dein Bild mitgeben und das dann mit InDelInline in das TRichMemo einfügen. |
Am einfachsten wäre es aber per ClipBoard. Kann man denn davon nicht eine eigene Instanz erstellen? - Ja, kann man, aber dabei wird trotzdem der Inhalt der "echten" Zwischenablage ersetzt. Wie kann ich das verhindern?
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19289
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 04.05.20 16:36
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 04.05.20 17:31
jaenicke hat folgendes geschrieben : | Nein, der korrekte Weg ist genauso einfach. |
Ist er nicht! In RichMemo.pas gibt es zwar die erfoderlichen Prozeduren, die sind aber leer.
Also habe ich das Ganze zuerst mal in Form1 erstellt und dort funktioniert es auch. Dann habe ich alles in RichMemo.pas kopiert, den Code natürlich angepasst, aber ich bekomme dort, sobald ich an imageList Width und Height zuweise, die Fehlermeldung:
Zitat: | Projekt project1 hat Exception-Klasse »External: SIGSEGV« ausgelöst. |
Wozu brauche ich denn da überhaupt eine ImageList?
Ich blicke da nicht durch, und das Sample-Projekt bringt mich auch nicht weiter (von dort habe ich ja die Vorgehensweise mit der ImageList)...
//Edit: Wenn ich die ImageList weglasse, wird ein "leerer Bereich" eingefügt, aber kein sichtbares Bitmap.
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 04.05.20 18:38
Es funktioniert dank: forum.lazarus.freepa...ex.php?topic=33563.0
Ein einziges Beispiel ist Goldes Wert!
Ich habe den Code angepasst, sodass nun keine Datei mehr geöffnet werden muss, sondern Picture übergeben wird. Nach dem Einfügen gebe ich piclist frei (aber natürlich nicht dessen Elemente).
Warum richmemo.pas das nicht schon OnBoard hat (genauso wie so maches andere), weiss der Kuckuck... Aber ich arbeite dran!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 06.05.20 16:51
Die Grafik wird nicht mitgespeichert. Da macht sich also jemand die Arbeit, eine gut funktionierende Funktion zum Einfügen von Grafiken zu schreiben. Aber natürlich kommt der niemals auf die Idee, dass man das Ganze dann auch speichern können will! Nein, wie denn auch? Das ist ja abwegig! Wer will schon Text UND Grafiken als Datei speichern?
Nein, im Ernst: Das ärgert mich. Eine halbe Sache, an sich gut, aber doch letzlich so, wie sie ist, unbrauchbar. Leider kann ich das nicht fertig schreiben, weil ich keine Idee habe, wie man die Daten der Grafik in den RTF-Text hinein bekommt.
Wenn man sich die rtf-Datei ansieht, findet sich darin der String {\pict{\*\picprop}\wmetafile0 , es fehlen aber die Daten der Grafik. Wie erhalte ich diese als Text? Ich habe zwar eine Funktion, die das zumindest mit Bitmaps erledigt, aber es funktioniert nicht, wenn man die da einfach dran hängt.
Ich habe das vorläufig so gelöst, dass ich den Text oder das Bitmap der Zwischenablage sichere, dann die Grafik über ClipBoard einfüge und danach den ursprünglichen Inhalt der Zwischenablage wiederherstelle. Das klappt, ist aber natürlich unelegant...
Weiss jemand wie ich beliebigen Inhalt der Zwischenablage sichern und wieder herstellen kann?
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 06.05.20 18:44
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19289
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 06.05.20 21:39
Du packst alles in einen Stream? Wie soll das denn funktionieren? Woher soll denn beim Laden erkannt werden wo welches Format endet usw.?
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 07.05.20 05:47
jaenicke hat folgendes geschrieben : | Du packst alles in einen Stream? Wie soll das denn funktionieren? |
Nun, AddFormat oder auch SetFormat verlangt eben einen Stream. Ich dachte, das Array erledigt das, aber da wird nun einmal ein Stream verlangt. Und das Array enthält die korrekten Daten ja (denke ich...).
jaenicke hat folgendes geschrieben : | Woher soll denn beim Laden erkannt werden wo welches Format endet usw.? |
Ja, stimmt. Das ist dann wohl auch der Grund, warum die Zwischenablage manchmal nur "Unsinn" enthält, einfach nur irgendwelche Zeichen. Das passiert genau dann, wenn zB. rtf-formatierter Text in der Zwischenblage ist. Dann ist dort ja nicht nur Text, sondern eben auch der rtf-Code.
Wie kann ich das also verbessern? Muss ja prinzipiell funktionieren: 1. Sichere ClipBoard, 2. schreibe da was rein, 3. stelle ClipBoard wieder her. Im Grunde nichts Aufregendes. Aber wie?
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19289
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 07.05.20 09:50
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 07.05.20 14:38
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Th69
Beiträge: 4791
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Do 07.05.20 15:23
Du benutzt doch schon die Anzahl ClipBoard.FormatCount? Und davon erstellst du dynamisch entsprechend viele Streams und packst jedes Format in den zugehörigen Stream (und beim Wiederherstellen entsprechend) - so wie du es ja bisher für das array of TClipBoardFormat auch schon gemacht hast.
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 07.05.20 15:36
Th69 hat folgendes geschrieben : | Du benutzt doch schon die Anzahl ClipBoard.FormatCount? Und davon erstellst du dynamisch entsprechend viele Streams und packst jedes Format in den zugehörigen Stream (und beim Wiederherstellen entsprechend) - so wie du es ja bisher für das array of TClipBoardFormat auch schon gemacht hast. |
Ich steh wohl auf der Leitung. Die können doch nicht alle den selben Namen haben? Und wie packe ich die einzelnen Formate da hinein?
Das Prinzip ist mir schon klar, aber die Umsetzung nicht...
//Edit:
Ok, die einzelnen Formate schreibe ich mit GetFormat hinein. Gut. aber wie erstelle ich n Streams? n ist eine Zahl, die ich vorher nicht kenne.
//Edit: Doch, n kenne ich. n = ClipBoard.FormatCount.
Bleibt die Frage: Wie erstelle ich die einzelnen Streams, die ja nicht alle einfach Stream heissen können?
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Th69
Beiträge: 4791
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Do 07.05.20 16:00
Genau so wie du es für aArray auch gemacht hast:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| var aStreams: array of TMemoryStream; begin n := ClipBoard.FormatCount;
SetLength(aStreams, n);
for i := 0 to n-1 do begin aArray[i] := ClipBoard.Formats[i]; ClipBoard.GetFormat(aArray[i], aStreams[i]); end; end |
PS: aArray solltest du besser aFormats nennen!
Für diesen Beitrag haben gedankt: galagher
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 07.05.20 16:24
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 11.05.20 22:56
Nach merfachem Testen kommt es öfter dann zu dem SIGSEGV-Fehler, wenn ich RTF-Daten in der Zwischenablage habe. Wenn ich jedoch ein Sleep(450) einfüge, tritt dieser Fehler nicht auf. Mittlerweile habe ich den Code so modifiziert, dass er die RTF-Formatierung in der Zwischenablage erkennt und einfügt. Aber es funktioniert immer nur zusammen mit Sleep!
Draufgekommen bin ich, als ich den Code mit Haltepunkten versehen habe: Eine Pause genügt, und es klappt, und auch Sleep bewirkt dies. Ausserdem tritt der Fehler nur dann auf, wenn die RTF-Daten "frisch" aus der Zwischenablage kommen. Wenn sie mit der Prozedur wieder dorthin zurück geschrieben wurden, funktioniert alles auch ohen Sleep.
Habt ihr eine Erklärung für dieses Phänomen?
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| procedure TCustomRichMemo.InsertGraphic(const aPicture: TPicture); var i, n: Integer; aFormats: array of TClipBoardFormat; aStreams: array of TMemoryStream; begin try n := ClipBoard.FormatCount; SetLength(aFormats, n); SetLength(aStreams, n);
Sleep(450) for i := 0 to n-1 do aStreams[i] := TMemoryStream.Create;
for i := 0 to n-1 do begin aFormats[i] := ClipBoard.Formats[i]; ClipBoard.GetFormat(aFormats[i], aStreams[i]); end;
ClipBoard.Assign(aPicture.Bitmap); PasteFromClipboard;
for i := Low(aFormats) to High(aFormats) do ClipBoard.SetFormat(aFormats[i], aStreams[i]);
finally for i := High(aStreams) downto Low(aStreams) do aStreams[i].Free; end; end; |
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher
Beiträge: 2534
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: So 17.05.20 17:59
Weiss denn keiner weiter? Der Fehler tritt jetzt, obwohl ich die unten stehende Prozedur seit Tagen nicht verändert habe, nur noch sehr selten auf, und wenn, dann immer dann, wenn die RTF-Daten schon vor dem Programmstart in der Zwischenablage waren. Da hilf auch das try-except nichts, es knallt beim Abfragen des Formats der Zwischenablage: if Windows.IsClipboardFormatAvailable(CF_RICHTEXT). Mit if ClipBoard.HasFormat(CF_RICHTEXT) ebenso.
Weiters: Muss CF_RICHTEXT als Word oder als UINT (= LongWord) dekalriert werden? In Lazarus' VirtualTree.pas sind ClipBoard-Formate als Word's deklariert, irgendwo im Internet habe ich aber UINT aufgeschnappt. Teste nun mit Word...
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58:
| implementation var CF_RICHTEXT: Word; procedure TCustomRichMemo.InsertGraphic(const aPicture: TPicture); var i, n: Integer; aFormats: array of TClipBoardFormat; aStreams: array of TMemoryStream; cpFormat: TClipBoardFormat; begin try try n := ClipBoard.FormatCount; SetLength(aFormats, n); SetLength(aStreams, n);
for i := 0 to n-1 do aStreams[i] := TMemoryStream.Create;
for i := 0 to n-1 do begin aFormats[i] := ClipBoard.Formats[i]; ClipBoard.GetFormat(aFormats[i], aStreams[i]); end;
if Windows.IsClipboardFormatAvailable(CF_RICHTEXT) then cpFormat := CF_RICHTEXT;
ClipBoard.Assign(aPicture.Bitmap); PasteFromClipboard;
if cpFormat = CF_RICHTEXT then for i := Low(aFormats) to High(aFormats) do begin if aFormats[i] = cpFormat then Clipboard.SetFormat(cpFormat, aStreams[i]) end else for i := Low(aFormats) to High(aFormats) do ClipBoard.SetFormat(aFormats[i], aStreams[i]);
finally for i := High(aStreams) downto Low(aStreams) do aStreams[i].Free; end;
except ; end; end;
initialization CF_RICHTEXT := RegisterClipboardFormat(RichEdit.CF_RTF); |
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
|