Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Screenshot bei Tastendruck machen und speichern (https://www.delphipraxis.net/144790-screenshot-bei-tastendruck-machen-und-speichern.html)

gasty 16. Dez 2009 18:49


Screenshot bei Tastendruck machen und speichern
 
Hi,
also ich habe nun versucht, ein Programm zu schreiben, welches die Tasten überwacht, und wenn man Druck drückt, einen Screenshot macht, ihn mit Datum und Zeit deklariert und abspeichert.
In der Theorie klappt das auch einwandfrei, doch leider in der Praxis nicht...
Hier mal mein Code:
Delphi-Quellcode:
procedure ScreenToFile(aFileName: string);
var
  Bitmap: TBitmap;
  Canvas: TCanvas;
begin
  Canvas := TCanvas.Create;
  try
    Canvas.Handle := GetWindowDC(0);
    try
      Bitmap := TBitmap.Create;
      try
        Bitmap.Width := Screen.DesktopWidth;
        Bitmap.Height:= Screen.DesktopHeight;
        Bitmap.PixelFormat := pfDevice;

        BitBlt(Bitmap.Canvas.Handle, 0, 0, Pred(Screen.DesktopWidth), Pred(
            Screen.DesktopHeight), Canvas.Handle, Screen.DesktopLeft,
            Screen.DesktopTop, Bitmap.Canvas.CopyMode);
        Bitmap.SaveToFile(aFileName+'.bmp');
      finally
        Bitmap.Free;
      end;
    finally
      ReleaseDC(0, Canvas.Handle);
    end;
  finally
    Canvas.Free;
  end;
end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
   if Key = #44 then
      ScreenToFile(DateToStr(now)+'_'+TimeToStr(now));
end;
So, nun erstens das Problem, dass das Programm den KeyPress nicht erkennt, zweitens spuckt mir das Programm einen Error (Falscher Parameter) aus, wenn ich die Prozedur in einem Button abrufe.
Bitte um Hilfe bzw Lösungsvorschläge :D

PS: Am besten wäre es dann noch, wenn ich das Programm in die Tray Leiste setzen könnte, aber das hab ich jetz noch nicht angefangen zu coden, würde mich trotzdem über einen Ansatz freuen.

Gruß,
gasty

gasty 17. Dez 2009 20:03

Re: Screenshot bei Tastendruck machen und speichern
 
Kann denn keiner helfen? :(
Also der Error kommt in Zeile
Delphi-Quellcode:
Bitmap.SaveToFile(aFileName+'.bmp');
Also denke ich, dass es etwas mit dem Datum zu tun hat, dass er das nicht umsetzen kann.
Delphi-Quellcode:
ScreenToFile(DateToStr(now)+'_'+TimeToStr(now));
Und das mit dem KeyPress verstehe ich nicht, wieso er das nicht erkennt, ist bestimmt ein dummer Fehler von mir nur leider findet man die einfachsten Sachen meist nie ;)

Progman 17. Dez 2009 20:11

Re: Screenshot bei Tastendruck machen und speichern
 
DateToStr und TimeToStr liefern (m.W.) sowas "11.12.2009" und "14:22". Da hast du Punkte und einen Doppelpunkt im Dateinamen. Das mag Windows nicht :)
FormatDateTime('yyyy-mm-dd_hh-nn-ss',Now) wäre eventuell günstiger?
(das Jahr als erstes, um die Dateien nach exaktem Datum sortiert anzeigen zu können)

gasty 17. Dez 2009 20:15

Re: Screenshot bei Tastendruck machen und speichern
 
*Omg*
Stimmt ja :D
Danke, jetzt klappt das auch.
Das Problem mit dem nicht erkannten KeyPress besteht jedoch weiterhin :/


Und gibt es einen Weg, die Datei gleich in eine jpeg umzuwandeln, da ~7mb pro Screen dann doch etwas viel sind?

Progman 17. Dez 2009 20:34

Re: Screenshot bei Tastendruck machen und speichern
 
KeyPress klappt bei den Systemtasten nicht richtig.
Pack das mal in OnKeyDown, da ist dann Key auch vom Typ Word, und nicht Char. Das müsste dann klappen.

Namenloser 17. Dez 2009 20:37

Re: Screenshot bei Tastendruck machen und speichern
 
Zitat:

Zitat von gasty
Und gibt es einen Weg, die Datei gleich in eine jpeg umzuwandeln, da ~7mb pro Screen dann doch etwas viel sind?

Binde die Unit "jpeg" ein (weiß nicht, ob die bei Delphi 7 schon dabei ist, wenn nicht, musst du sie erst runterladen). Dann konvertierst du das Bild vorm Speichern in ein TJPEGImage:
Delphi-Quellcode:
JPEGImage := TJPEGImage.Create;
JPEGImage.Assign(Bitmap);
JPEGImage.SaveToFile(...);
JPEGImage.Free;
Natürlich solltest du noch Ressourcenschutzblöcke verwenden.

Allerdings dazu noch etwas von meinem Senf: JPEG halte ich als Kompressionsformat aufgrund der Artefakte für Screenshots als weniger geeignet. PNG ist eigentlich derzeit IMO das optimale Format (*) für Screenshots (solange es sich nicht um Screenshots von Videos oder grafikintesniven Spielen handelt, natürlich). PNGs lassen sich mit Delphi eigentlich genau so einfach verarbeiten wie JPEGs, nur dass die Unit pngimage und die Klasse TPNGObject heißt.

(*) Wenn man mal von dem sehr wenig verbreiteten JPEG-2000-Format absieht, das nach meiner Erfahrung noch etwas bessere Kompressionsraten hat.

gasty 17. Dez 2009 20:45

Re: Screenshot bei Tastendruck machen und speichern
 
Ok, danke, das mit jpg klappt jetzt auch.
Nur immernoch das Problem mit dem Key.
Habs jetzt mal in ein KeyDown geschrieben, aber gleicher Effekt. (Btw. Welche Taste ist denn DRUCK? VK_PRINT oder VK_SNAPSHOT? Hab zwar beide probiert und keine klappt, aber würds mal gerne eindeutig wissen, irgendwie stehen immer diese beiden da)
Delphi-Quellcode:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
   if Key = VK_PRINT then
      ScreenToFile(FormatDateTime('yyyymmddhhnnss',Now))
end;

Progman 17. Dez 2009 20:49

Re: Screenshot bei Tastendruck machen und speichern
 
Welchen Tasten-Code die Drucktaste hat, weiß ich jetzt nicht aus dem Kopf.
Schreib doch mal ins OnKeyDown zusätzlich: ShowMessage(IntToStr(Key)):
Dann siehst du, welchen numerischen Wert die Druck-Taste liefert. ( So kann man auch alle anderen Tasten rauskriegen :) )
Dann vergleich einfach mit den Zahlenwert statt der VK-Konstanten.

Luckie 17. Dez 2009 20:53

Re: Screenshot bei Tastendruck machen und speichern
 
Steht die Eigenschaft KeyPreview der Form auf True?

gasty 17. Dez 2009 20:54

Re: Screenshot bei Tastendruck machen und speichern
 
Ok, das ist jetz komisch... Die Druck taste spuckt keinen Wert aus oO
Dann nehm ich eben Rollen, das ist die 145.
Muss ich die dann noch in Word umwandeln, wenn in den numerischen Wert nehmen will im KeyDown?
Weil KeyPress funktioniert ja nicht richtig.

Und sorry nochmal für die doofen Fragen aber hab lange nichts mehr geschrieben in Delphi :P

KeyPreview hab ich im FormCreate auf true gesetzt.

Progman 17. Dez 2009 20:59

Re: Screenshot bei Tastendruck machen und speichern
 
if Key = 145 then.....
das reicht vollkommen, da muss nix umgewandelt werden.
Die Drucktaste ist anscheinend eine der Systemtasten, die mit dem standardmäßigen KeyDown keinen Wert liefern.
Die liefert nämlich von Haus aus einen Screenshot. Der befindet sich dann in der Zwischenablage.

gasty 18. Dez 2009 10:27

Re: Screenshot bei Tastendruck machen und speichern
 
Danke es klappt :D
So nun ein weiteres Problem:
Ich hab das Programm nun soweit, dass es sich in die Tray Leiste setzt und unsichtbar wird (Hab die Komponente "CoolTrayIcon" und setze Form.Visible auf false).
Nun klappt das mit dem Screenshot aber nicht, wenn das Programm nicht im Fokus ist.

Progman 18. Dez 2009 10:48

Re: Screenshot bei Tastendruck machen und speichern
 
Nunja, ein unsichtbares Programm-Fenster erhält keine Tastaturereignisse.
Da müsste man Tastatureingaben schon global abfangen (Hook). Aber das hier zu erläutern, würde den Rahmen sprengen. Denn das ist nicht so ohne weiteres mal eben zu lösen.

Eine Alternative wäre, die Drucktaste zu benutzen.
Diese macht ja einen Screenshot und kopiert ihn in die Zwischenablage. Dann vom Programm zyklisch (über Timer) die Zwischenablage abfragen, ob sich der Inhalt geändert hat. Diesen dann holen und abspeichern. Vielleicht gibt es ja auch das Ereignis OnClipBoardChanging (Unit ClipBrd einbinden). Dann könnte man prüfen, ob der ClipBoard-Inhalt ein Bitmap ist und das dann holen und abspeichern. Würde allerdings auch ansprechen, wenn man über Ctrl+C ein Bild in die Zwischenablage kopiert :)

gasty 18. Dez 2009 11:13

Re: Screenshot bei Tastendruck machen und speichern
 
Hm ok, das mit den Hooks hab ich mir mal angeschaut, sieht nicht wirklich so einfach aus :/
Aber das mit der Zwischenablage ist wirklich ne gute Idee, nur leider scheitert es wieder an der Umsetzung :x
Im Moment bin ich so weit:
Delphi-Quellcode:
  Clipboard.Open;
    try
      if not Clipboard.HasFormat(CF_BITMAP) then
        exit;
      Bitmap := TBitmap.Create;
      JPEGImage := TJPEGImage.Create;
      Bitmap.LoadFromClipboardFormat(cf_BitMap,ClipBoard.GetAsHandle(cf_Bitmap),0);
      JPEGImage.Assign(Bitmap);
      JPEGImage.SaveToFile(FormatDateTime('yyyymmddhhnnss',Now)+'.jpg');
    finally
      Bitmap.Free;
      JPEGImage.Free;
    end;
Und er spuckt mir einen Zugriffsverletzungs-Error aus.

Namenloser 18. Dez 2009 11:51

Re: Screenshot bei Tastendruck machen und speichern
 
Das liegt daran, dass du du Objekte im Try-Abschnit erzeugst, aber im Finally-Abschnitt wieder freigibst. Wenn Clipboard.HasFormat(CF_BITMAP) False ergibt, beendest du ja die Prozedur mit exit. Vorher wird allerdings noch automatisch der Finally-Abschnitt ausgeführt, wo es dann kracht, weil du Objekte freigibst, die noch gar nicht erzeugt wurden.

Progman 18. Dez 2009 11:56

Re: Screenshot bei Tastendruck machen und speichern
 
Liste der Anhänge anzeigen (Anzahl: 1)
Du solltest Bitmap.Assign verwenden.
Ich hab mal ein Testprojekt angehangen, dass die Zwischenablage speichert. Ist aber keine Überprüfunmg drin. Soll nur zur Demo sein.
Compilieren, Exe starten, Druck betätigen und dann auf den Button klicken. Dann ist ein 'blubb.bmp' im Exe-Verzeichnis, das den Screenshot enthält.

gasty 18. Dez 2009 12:10

Re: Screenshot bei Tastendruck machen und speichern
 
Nun, wenn ich das in den Timer schreibe, macht er jede Sekunde eine Datei, die aber 0 Byte ist, und keinen Screenshot beinhaltet (selbst wenn ich Druck gedrückt habe).
Daraus schließen sich 2 Probleme: 1. Ich will auch einen Screenshot in der Datei (logisch :D) und 2. Ich möchte mit dem Timer ja "überprüfen" ob ein Bild im Clipboard ist, und wenn nicht, einfach nichts tun.
Mein Code sieht jetzt so aus:
Delphi-Quellcode:
  try
    Bitmap := TBitmap.Create;
    JPEGImage := TJPEGImage.Create;
    if not Clipboard.HasFormat(CF_BITMAP) then
      exit
    else
    Bitmap.Assign(ClipBoard);
    //JPEGImage.Assign(Bitmap);
    //JPEGImage.SaveToFile(FormatDateTime('yyyymmddhhnnss',Now)+'.jpg');
    Bitmap.SaveToFile(FormatDateTime('yyyymmddhhnnss',Now)+'.bmp');
  finally
    Bitmap.Free;
    JPEGImage.Free;
  end;

Progman 18. Dez 2009 12:33

Re: Screenshot bei Tastendruck machen und speichern
 
Das
Delphi-Quellcode:
    if not Clipboard.HasFormat(CF_BITMAP) then
      exit
muss vor das try.
Dann müsste er rausspringen, wenn kein Bild drin ist.
Und nach dem Bild abspeichern einfach ClipBoard.Clear machen. Dann ist es leer.

gasty 18. Dez 2009 12:46

Re: Screenshot bei Tastendruck machen und speichern
 
Wenn ich es so mache, gibt es wieder einen Zugriffsverletzungs-Error (sofern ich ein Bild im Clipboard habe, also klappt das mit dem rausspringen schonmal)
Delphi-Quellcode:
  if not Clipboard.HasFormat(CF_BITMAP) then
    exit
  else
  try
    Bitmap := TBitmap.Create;
    JPEGImage := TJPEGImage.Create;
    Bitmap.Assign(ClipBoard);
    //JPEGImage.Assign(Bitmap);
    //JPEGImage.SaveToFile(FormatDateTime('yyyymmddhhnnss',Now)+'.jpg');
    Bitmap.SaveToFile(FormatDateTime('yyyymmddhhnnss',Now)+'.bmp');
    ClipBoard.Clear;
  finally
    Bitmap.Free;
    JPEGImage.Free;
  end;
Delphi zeigt mir an, dass es irgendwas mit der Zeile ClipBoard.Clear zu tun hat

Außerdem werden zwar Bitmaps erstellt, aber sie sind alle 0 Byte groß und beinhalten keine Screenshots. (Also wenn ich ein Bild im Clipboard habe)

Progman 18. Dez 2009 12:58

Re: Screenshot bei Tastendruck machen und speichern
 
Wenn ich in meinem Testproject
Delphi-Quellcode:
procedure TForm2.Button1Click(Sender: TObject);
begin
  Bitmap.Assign(ClipBoard);
  Bitmap.SaveToFile('blubb.bmp');
  ClipBoard.Clear;
end;
mache, wird nach Drücken von "Druck" und Klick auf den Button das Bild gespeichert und anschließend ist das ClipBoard leer. Ohne irgendwelche Fehler.
Hab da jetzt auch keinen Plan, wo bei dir der Fehler herkommt.

gasty 18. Dez 2009 13:07

Re: Screenshot bei Tastendruck machen und speichern
 
Ok, ich gebe zu, jetzt bin ich verwirrt.
Ich habe nichts verändert, aber jetzt klappt alles so wie ich will, kann ins Tray setzen und dann mit Druck einen jpg Screenshot machen. :mrgreen:
Naja auf jeden Fall danke an alle für die Hilfe ! :dp:

Aphton 18. Dez 2009 14:26

Re: Screenshot bei Tastendruck machen und speichern
 
Zitat:

Zitat von gasty
(...) da ~7mb pro Screen (...)

Es tut zwar nichts zur Sache, aber ich wills trotzdem wissen -
wie groß ist das Bild (Dateigröße) exakt? Nach meinen Berechnungen dürfte
sie etwa genau 6.5917 mb (ohne BMP Header-Daten) sein.

Falls dem so ist, dann dürftest du eine Auflösung von 1920x1200 haben, stimmt das?

Btw. mir ist langweilig :P

MfG

gasty 18. Dez 2009 14:36

Re: Screenshot bei Tastendruck machen und speichern
 
7,91 MB sinds und ich hab ne Auflösung von 1920x1080 :P

CazperFuture 18. Dez 2009 22:00

Re: Screenshot bei Tastendruck machen und speichern
 
bin grade auf den thread aufmerksam geworden, hört sich gut an!
ich haben ur ein prob. bei mir kommt immer die Fehlermeldung "[Error] Unit1.pas(55): Undeclared identifier: 'FormKeyDown'" :wall:
weis jemand eine antwort?, hab die meldung schobn bei google eingegeben aber da wure ich nicht wirklich schlau
ps. wenn jemand kann man ja ne komplette unit posten ;-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:58 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz