Auswahlbereich auf Bildschirm erstellen



  • Hallo C++-Programmierer 🙂

    ich möchte ein Programm schreiben, mit dem man Screenshots von bestimmten Bereichen des Bildschirms machen kann.
    Es ist meine erste MFC-Anwendung und ich bin noch etwas verwirrt ob der vielen Klassen, die der Anwendungsassistent mir automatisch angelegt hat 😉 (es soll eine MDI-Anwendung werden, ich benutze VS.NET 2003 als Entwicklungsumgebung).

    Mein konkretes Problem ist nun: wie kriege ich es hin, einen Auswahlbereich auf den Bildschirm zu erstellen ("rubber banding"). Ich habe dazu schon zwei Artikel gefunden:
    http://support.microsoft.com/kb/q135865/
    http://www.willemer.de/informatik/windows/wincapt.htm

    Aber damit kann ich nicht so viel anfangen, da meine MFC-Anwendung ja keine globale WndProc-Funktion hat 🙄

    Wo, d.h. in welcher Klasse, muss ich die Funktionen zur Verarbeitung der Nachrichten unterbringen ?
    In CMainFrame ? Die reagiert aber nichtmal normal auf WM_LKEYDOWN, habe ich bemerkt 😮
    Oder kann ich dafür einen extra Benutzeroberflächenthread erstellen ? Das hab ich auch schon getestet, aber irgendwie können scheinbar nur von CWnd abgeleitete Klassen auf Mouse-Events reagieren 😕

    Wäre super, wenn mir jemand einen Tipp hätte... 👍



  • Hmm, ich verstehe dein Problem noch nicht ganz. Möchtest du so etwas wie das hier machen ?:

    http://www.codeproject.com/dialog/windowsnapshot.asp

    Wobei man auch von bestimmten Bereichen eines Windows ein Screenshot machen kann.

    Gruß
    :: NoName ::



  • Ja, genau, so was in der Art. Aber ich möchte es selber machen.
    Es soll so ablaufen:
    - der Benutzer drückt einen Hotkey (das funktioniert auch schon :))
    - dann werden mit SetCapture die Mausbewegungen an meine Anwendung umgeleitet
    - so kann ich die Mausbewegung verfolgen und dementsprechend ein Rechteck auf den Bildschirm zeichnen
    - der Inhalt des Rechtecks wird dann "geblitzt", also ein Screenshot davon erstellt

    Ich denke auch dass ich es hinkriegen könnte - momentan ist mein Problem gerade nur: wo muss ich die Mouse-Events behandeln, nachdem ich SetCapture aufgerufen hab, wenn ich keine WndProc-Funktion habe (ist bei einer MFC-MDI-Anwendung ja nicht der Fall, sondern es gibt viele verschiedene Fenster, und ich weiss nicht, an welches diese Events standardmäßig geschickt werden).



  • Ich _vermute_ mal, dass du auf WM_MOUSEMOVE reagieren musst. WM_LBUTTONDOWN bzw. UP kannst du sicherlich auch gebrauchen. 🙂



  • Danke! Das ist mir schon klar, aber WO ??
    Eine MFC-MDI-Anwendung besteht doch aus vielen verschiedenen Fenstern (und u.a. den Klassen CWinApp, CMDIFrameWnd, CMDIChildWnd). In welcher Klasse muss ich diese Events behandeln?



  • Das kannst du dir zum Glück aussuchen. 🙂

    Ich würde es im ChildWnd machen, jedenfalls da, wo der Rest auch gemacht wird, weil man dann weniger Variablen rumreichen muss. 😃



  • Danke 🙂
    Aaaber: habe das gerade mit einer stinknormalen WM_LBUTTONDOWN in der CMDIChildWnd-Klasse (heisst CChildFrame) ausprobiert. Der reagiert da nicht 😡
    Die einzige Stelle, wo ich ganz normal z.B. auf Klicks reagieren kann, ist in der CView-Klasse, also in dem momentan im MDI-Fenster angezeigten Dokument.
    Die Behandlung der Maus-Events in dieser Klasse ist aber für meine Zwecke nicht so toll, da ja dann die Capture-Funktion immer an ein Document gebunden wäre...



  • Wo ist das Problem ? Was willst du genau machen ?
    Eine Rubber-Band Routine in ein CView Template einzubauen kriegst du ja schon hinn. Und von diesen Template kannst dann einfach all deine Views ableiten.

    Willst du etwa die Auswahl View übergreifend zu machen ?



  • Sorry dass das so schlecht rüberkommt was ich machen will 🙄

    Ja, ich wollte die Auswahl View übergreifend machen. Hab nicht damit gerechnet dass das Probleme machen könnte.

    Ich versuche das Problem etwas ausführlicher zu beschreiben:

    es gibt folgende wichtige Klassen:

    //Standardmäßig vom VS.NET 2003 Assistenten erstellte Klassen
    class CScreenshotApp : public CWinApp
    class CMainFrame : public CMDIFrameWnd
    class CChildFrame : public CMDIChildWnd
    class CScreenshotDoc : public CDocument
    class CScreenshotView : public CView
    
    class CHotkeyHandler : public CWinThread
    

    Bis jetzt läuft das so ab:

    Im Konstruktor von CScreenshotApp (also bei Programmstart) wird ein neuer Thread zum Überwachen des Hotkeys gestartet:

    CScreenshotApp::CScreenshotApp()
    {
    	// TODO: Hier Code zur Konstruktion einfügen
    	// Alle wichtigen Initialisierungen in InitInstance positionieren
    	CHotkeyHandler h;
    	h.CreateHotkeyHandler();
    }
    

    wobei die statische Funktion CreateHotkeyHandler so aussieht:

    static void CHotkeyHandler::CreateHotkeyHandler()
    {
      CHotkeyHandler* hotkey;
      hotkey = new CHotkeyHandler();
      hotkey->CreateThread();
    
    }
    

    Es wird also ein Thread gestartet, im Konstruktor von CHotkeyHandler wird mit RegisterHotkey(...) ein Hotkey registriert . Das funktioniert auch soweit, der Thread ist auch in der Lage ein WM_HOTKEY Ereignis zu empfangen und zu bearbeiten 🙂

    #define ON_MY_MESSAGE(message, memberFxn) \
    	{ message, 0, 0, 0, AfxSig_lwl, \
    		(AFX_PMSG)(AFX_PMSGW) \
    		(static_cast< LRESULT (AFX_MSG_CALL CWinThread::*)(WPARAM, LPARAM) > \
    		(memberFxn)) },
    
    BEGIN_MESSAGE_MAP(CHotkeyHandler, CWinThread)
    	ON_MY_MESSAGE(WM_HOTKEY,CHotkeyHandler::OnPress)
    END_MESSAGE_MAP()
    
    ...
    
    LRESULT CHotkeyHandler::OnPress(WPARAM wParam, LPARAM lParam)
    {
    	MessageBox(0,"Hotkey gedrückt!","Test",0);
             SetCapture(0);
    	return 0;
    }
    

    Das ist der aktuelle Stand.

    Jetzt möchte ich es hinkriegen, dass der HotkeyHandler-Thread auch Mausevents (besonders WM_MOUSEMOVE) behandeln kann, nachdem diese mit SetCapture ja eigentlich zu ihm geleitet wurden.
    Habe eine Weile dran rumprobiert, aber es nicht hingekriegt. Dann bin ich auf die Idee gekommen, Mausereignisse mit SetCapture an eines der Fenster-Klassen zu leiten - aber auch das hat nicht geklappt. Deshalb habe ich hier fachkundige Hilfe gesucht 🙂

    Also: wie schaffe ich es, dass mein Thread ein WM_MOUSEMOVE bekommt und behandeln kann?



  • Warum brauchst du einen extra Thread für das Message Handling ?
    Ich würde bei WM_LBUTTONDOWN das ganze starten, sprich Startposition des Rubberbands speichern und über MOUSEMOVE den RubberBand aufspannen. Bei WM_LBUTTONUP beendest du dann die Auswahl.



  • Ja schon.
    Aber ich will ja den rubber-band auch über fremden Fenstern, die nicht zu meiner Anwendung gehören, aufspannen können!
    Und in diesem Falle wird mein Fenster niemals ein WM_LBTTONDOWN erhalten! Auch nicht, nachdem voher SetCapture aufgerufen wurde, denn SetCapture leitet nur die Mausbewegung weiter, sobald geklickt wird, gehen die Nachrichten wieder ganz normal an das Fenster, auf das geklickt wurde.

    Deshalb hab ich mir die Variante mit dem Hotkey ausgedacht.



  • ok anderer Ansatz, selbe Idee.
    Es gibt doch die Möglichkeit transparente Fenster zu erstellen.
    Erstell ein solches Fenster und mach es Fullscreen. Innerhalb dieses Fenster kannst du dann dein Rubberband wie zuvor gesagt aufspannen.

    Die Thread Variante versteh ich nicht 🙄



  • Das mit dem transparenten Fenster ist eine gute Idee 👍

    Ich werde es mal so versuchen.
    Die Frage verschiebt sich also: wie mache ich ein Fenster Fullscreen und transparent auf? Wieder das alte Problem: der Assistent hat so viele Fenster bzw. Klassen erstellt und ich hab leider immernoch nicht kapiert wofür welche gut ist 😞 🙄



  • schau am besten auf CodeProject.com nach.
    da sollte es einige bespiele geben.
    Ein Nachteil könnte noch sein, das die Transparenzgeschichte nur unter 2000/XP läuft. Aber dies ist auf jeden Fall die schnellste und einfachste Lösung wenn du auf den Nachteil pfeifen kannst 😉



  • franky.b schrieb:

    wie mache ich ein Fenster transparent auf?

    Hier ist mal wieder ein kleines Beispiel von mir ^^

    http://www.codeproject.com/dialog/wintrans1.asp

    Hoffe konnte dir weiterhelfen....

    Gruß
    :: NoName ::



  • naja, das Fenster das ich transparent machen will, gehört ja sogar zu meiner eigenen Anwendung 🙂 Von daher ist dein Artikel etwas "oversized" für meine Zwecke 😉
    Sieht so aus, als ob ich mich frühestens wieder am Wochenende darum kümmern könnte - dann schreib ich euch, wie und ob ich das Problem lösen konnte.
    Auf jeden Fall schonmal danke an alle die hier was beigetragen haben 👍

    Gruß,
    Frank



  • Schaut euch bitte auch mal meinen Thread an:
    http://www.c-plusplus.net/forum/viewtopic.php?t=94245

    Schreckt der Titel echt so ab ? 😉


Anmelden zum Antworten