Fenster an Bildschirmrand docken



  • Hi,
    ich möchte mir ein kleines Fenster mit einem Text machen, das, wenn man es bewegt und damit zu nah an den Bildschirmrand gelangt, sich dort automatisch andockt.

    Leider habe ich keine Ahnung, womit ich da anfangen könnte, deswegen erhoffe ich eure Hilfe, danke 🙂



  • Den Event WM_MOVE abfangen, die aktuelle Position deines Fensters bestimmen, wenn einer der 4 Ränder zu nahe am entsprechenden Fensterrand ist die Funktion MoveWindow(..) anwenden um das Fenster in Endpositioon zu bringen. Das war jetzt nur ganz grob.


  • Mod



  • Also wäre das Schema so ungefähr richtig:

    Screen:
    ------------------0------------------
    |..............................................|
    |..............................................|
    |..............................................|
    |..............................................|
    0.............GetSystemMetrics(SM_CXFULLSCREEN)
    |..............................................|
    |..............................................|
    |..............................................|
    |..............................................|
    ----GetSyMe.(SM_CYFuScr)----

    WM_MOVING:
    lParam
    Pointer to a RECT structure with the current position of the window, in screen coordinates. To change the position of the drag rectangle, an application must change the members of this structure.

    Somit:
    if(lParam.left < 40) {
    MoveWindow(...); //left = 0
    }
    Mit .top auch

    lParam.bottom > (GetSystemMetrics(SM_CYFULLSCREEN) - 40)
    --> bottom = GetSystemMetrics(SM_CYFULLSCREEN)
    Mit .right ebenso

    Wäre das so richtig? :0


  • Mod

    Jupp! Allerdings bitte nicht MoveWindow in WM_MOVING ausführen!



  • Ok, danke..
    Aber warum nicht in WM_MOVING und wo dann? 😕

    LRESULT CALLBACK proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    	switch(msg) {
    		case WM_CREATE:
    			break;
    		case WM_PAINT:
    			break;
    		case WM_MOUSEMOVE:
    			break;
    		case WM_LBUTTONDOWN:
    			break;
    		case WM_LBUTTONUP:
    			break;
    		case WM_TIMER:
    			break;
    		case WM_MOVING:
    			/*MoveWindow(..);*/
    			break;
    	}
    	return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    


  • Am besten nicht abfange 😛


  • Mod

    Weil Moving doch innerhalb von MoveWindow passiert und Du einfach nur das Rectangle, das benutzt werden soll angibst.
    Versuch doch einfach mal die Doku zu lesen.



  • Ich raff's nicht 😑

    Weshalb soll das nicht in die WM_MOVING Nachricht? 😕


  • Mod

    Du musst nicht in WM_MOVING ein Fenster "moven" weil dass schon in diesem Moment geschieht. In WM_MOVING fragt Dich jemand: Darf es diese Position sein?
    Moven macht dann die darunterliegende API. Du musst hier nur sagen was Du willst.

    Lies bitte mal die Doku.
    http://msdn2.microsoft.com/en-us/library/ms632632.aspx

    lParam
    Pointer to a RECT structure with the current position of the window, in screen coordinates. To change the position of the drag rectangle, an application must change the members of this structure.
    Return Value

    An application should return TRUE if it processes this message.



  • Ok, danke, nun habe ich es so:

    case WM_MOVING:
    			if(((RECT*)lParam)->left < 10) {
    				((RECT*)lParam)->right = ((RECT*)lParam)->right - ((RECT*)lParam)->left;
    				((RECT*)lParam)->left = 0;
    			}
    			if(((RECT*)lParam)->top < 10) {
    				((RECT*)lParam)->bottom = ((RECT*)lParam)->bottom - ((RECT*)lParam)->top;
    				((RECT*)lParam)->top = 0;
    			}
    			if(((RECT*)lParam)->right > (GetSystemMetrics(SM_CXFULLSCREEN) + 10)) {
    				((RECT*)lParam)->left = ((RECT*)lParam)->left + (GetSystemMetrics(SM_CXFULLSCREEN) + 20 - ((RECT*)lParam)->right);
    				((RECT*)lParam)->right = GetSystemMetrics(SM_CXFULLSCREEN) + 20;
    			}
    			if(((RECT*)lParam)->bottom > (GetSystemMetrics(SM_CYFULLSCREEN) + 10)) {
    				((RECT*)lParam)->top = ((RECT*)lParam)->top + (GetSystemMetrics(SM_CYFULLSCREEN) + 20 - ((RECT*)lParam)->bottom);
    				((RECT*)lParam)->bottom = GetSystemMetrics(SM_CYFULLSCREEN) + 20;
    			}
    			break;
    

    Aber so ganz flüssig läuft das nicht ab 😕
    Und das mit dem Mauszeiger ist auch nicht optimal..

    Test-Code (Copy & Paste)
    main.c:

    #include <windows.h>
    
    LRESULT CALLBACK MASTER(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    	int i;
    	switch(msg) {
    		case WM_LBUTTONDOWN:
    			PostQuitMessage(0);
    			break;
    		case WM_MOVING:
    			if(((RECT*)lParam)->left < 10) {
    				((RECT*)lParam)->right = ((RECT*)lParam)->right - ((RECT*)lParam)->left;
    				((RECT*)lParam)->left = 0;
    			}
    			if(((RECT*)lParam)->top < 10) {
    				((RECT*)lParam)->bottom = ((RECT*)lParam)->bottom - ((RECT*)lParam)->top;
    				((RECT*)lParam)->top = 0;
    			}
    			if(((RECT*)lParam)->right > (GetSystemMetrics(SM_CXFULLSCREEN) - 10)) {
    				((RECT*)lParam)->left = ((RECT*)lParam)->left + (GetSystemMetrics(SM_CXFULLSCREEN) - ((RECT*)lParam)->right);
    				((RECT*)lParam)->right = GetSystemMetrics(SM_CXFULLSCREEN);
    			}
    			if(((RECT*)lParam)->bottom > (GetSystemMetrics(SM_CYFULLSCREEN) + 10)) {
    				((RECT*)lParam)->top = ((RECT*)lParam)->top + (GetSystemMetrics(SM_CYFULLSCREEN) + 20 - ((RECT*)lParam)->bottom);
    				((RECT*)lParam)->bottom = GetSystemMetrics(SM_CYFULLSCREEN) + 20;
    			}
    			break;
    	}
    	return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdline, int nShowCmd) {
    	MSG msg;
    	HWND hWnd;
    	WNDCLASSEX wc;
    	wc.cbClsExtra = NULL;
    	wc.cbSize = sizeof(WNDCLASSEX);
    	wc.cbWndExtra = NULL;
    	wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    	wc.hCursor = LoadCursor(NULL, IDC_UPARROW);
    	wc.hIcon = LoadIcon(hInstance, NULL);
    	wc.hIconSm = LoadIcon(hInstance, NULL);
    	wc.hInstance = hInstance;
    	wc.lpfnWndProc = MASTER;
    	wc.lpszClassName = "Test";
    	wc.lpszMenuName = NULL;
    	wc.style = CS_DBLCLKS;
    	if(!RegisterClassEx(&wc)) {
    		return 1;
    	}
    	hWnd = CreateWindowEx(0, "Test", "Test", WS_OVERLAPPED, (GetSystemMetrics(SM_CXSCREEN) - 400) / 2, (GetSystemMetrics(SM_CYSCREEN) - 400) / 2, 400,400, (HWND)NULL/*HWND_DESKTOP?*/, (HMENU)NULL, hInstance, (LPVOID)NULL);
    	if(!hWnd) {
    		return 1;
    	}
    	ShowWindow(hWnd, nShowCmd);
    	while(GetMessage(&msg, 0, 0, 0)) {
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    	UnregisterClass("Test", 0);
    	return msg.wParam;
    }
    


  • Also ich hab das mal so gebaut:

    void CDocktestDlg::OnMoving(UINT fwSide, LPRECT pRect)
    {
    	if(pRect->left < 10) 
    	{ 
    		pRect->right = pRect->right - pRect->left; 
    		pRect->left = 0; 
        } 
        if(pRect->top < 10) 
    	{ 
            pRect->bottom = pRect->bottom - pRect->top; 
            pRect->top = 0; 
        } 
        if(pRect->right > (GetSystemMetrics(SM_CXFULLSCREEN) - 10)) 
    	{ 
    		pRect->left = pRect->left + (GetSystemMetrics(SM_CXFULLSCREEN) - pRect->right); 
            pRect->right = GetSystemMetrics(SM_CXFULLSCREEN);
        } 
        if(pRect->bottom > (GetSystemMetrics(SM_CYFULLSCREEN) + 10)) 
    	{ 
            pRect->top = pRect->top + (GetSystemMetrics(SM_CYFULLSCREEN) + 20 - pRect->bottom); 
            pRect->bottom = GetSystemMetrics(SM_CYFULLSCREEN) + 20; 
        } 
    
    	CDialog::OnMoving(fwSide, pRect);
    }
    

    Funktioniert und läuft auch flüssig.. weiß ja nicht, was du fürn Rechner hast 😉



  • Das scheint sich nicht gerade von meinem Code zu unterscheiden, trotzdem Danke für die Antwort..



  • Wenn ich das Fenster irgendwo andocken lasse, ein paar Sekunden warte und es dann wieder wegziehen will,



  • (Hans Solo/MrDock)
    d a n n i s t z u d e m Z e i t p u n k t, i n w e l c h e m s i c h d a s g e d o c k t e F e n s t e r w i e d e r u n d o c k e n l ä s s t , d e r M a u s z e i g e r f a s t a m a n d e r e n E n d e d e s B i l d s c h i r m s.
    Das heißt, dass ich den Mauszeiger immens bewegen muss, damit das Verschieben des Fensters wieder funktioniert


  • Mod

    Und wer setzt den Cursor? Windows nicht!

    Benutzt Du irgendwo SetCursorPos?



  • Nein.
    We nn ic h da s Fe nster e in w e nig be wege u nd de r Ra dius un ter 10 ble ibt, da nn wir d d as Fe nst er doc h zurü ck a n d ie 'Nu l ler' Posi tion ges etzt (a lso ge do ckt), jed och d er Cur sor bl eib t d a w o e r is t..


  • Mod

    Und? Was ist das Probklem? Entweder bewegst Du einfach den Cursor umdas Offset mit, oder eben nicht.

    Ansonsten würde ich mal die Koordination Deines Dauemns kontrollieren. Irgendwie passen die Leerzeichen nicht an die Stellen wo sie stehen. 🕶



  • Entweder bewegst Du einfach den Cursor umdas Offset mit, oder eben nicht.

    Und wenn es nur teilweise erfolgt, wandert der Cursor ins Unerreichbare, aber das Fenster bleibt an der Seite kleben.


  • Mod

    Sample Programm mit dem hier veröffentlichen Code zeigt dieses Verhalten nicht.


Anmelden zum Antworten