Bitmap scrollen und zoomen



  • hi leute
    ich möchte in einer box ein (grosses) bitmap anzeigen, mit scrollbars und zoom-buttons.
    wer hat mir gedankenanstösse / code-schnipsel?

    ich habe natürlich scho fleissig danach gesucht, und mich über diese schönen codes gefreut. leider musste ich herausfinden, dass sie für MFC sind (so mit CBitmap, CWnd..).

    kann ich diese codes gebrauchen, wenn ich sie genügend verändere?
    http://www.codeguru.com/Cpp/G-M/bitmap/displayingandsizing/article.php/c4939 [scrollen]
    http://www.codeproject.com/miscctrl/wndimg.asp [zoomen / scrollen]

    oder muss ich das ganz anders lösen?
    vielen dank um jeden hinweis, nate



  • Also ich versuche es mal zu später stund zu erklären 😃
    Vorweg sei erwähnt das ich alles in Klassen Packe um mehr als einmal sowas zu verwenden.

    a. ich erstelle mir ein Childwindow, das ein Child der Anwendung, bzw. dessen Fenster ist, dies nenne ich scrollbar und gebe ihm nen V+H Scroller

    b. Nun erstelle ich ein Childwindow ohne alles was später das Bild sein soll, und als Parent dient das Child aus Punkt a. (alles mittels CreateWindow() )

    c. Das erste Child, welches dem Hauptfenster unterlegen ist, gebe ich Position und Größe was mir als Anzeigebereich dient.

    d. dem nächsten Child, welches dem ersten Child unterlegen ist, gebe ich die größe der Bitmap an und blitte diese darauf, nu könne wa scrolle.

    c: ZOOM:: Ich vergrößere oder verkeinere Das Bildfenster, je nach wunsch und blitte das bild mittel stretch darauf

    Ich hoffe das reicht als anreitz, denn zum coden ist mir das jetzt zu spät, n8.



  • danke, micha!
    eigentlich wollte ich den code so schnell wie möglich irgendwo klauen, aber so ist der lerneffekt eigentlich um einiges grösser!

    frage: welche SystemClass bekommt das Scroll-window (und auch das hMapImage)?

    hMapScroll = CreateWindow("EDIT",
                                    NULL,
                                    WS_CHILD | WS_VISIBLE | WS_HSCROLL |
                                        WS_VSCROLL | ES_LEFT | ES_MULTILINE |
                                        ES_AUTOHSCROLL | ES_AUTOVSCROLL,
                                    0, 0, 0, 0, // Let the WM_SIZE messge below take care of the size
                                    hAppWnd,
                                    0,
                                    hInst,
                                    NULL);
    

    "Edit" ist es wohl kaum.. Static?



  • LOL
    Nene so nicht, lege 2 WindowProcedure an:

    LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK ScrollProc(HWND, UINT, WPARAM, LPARAM);
    

    Nach dem Registrieren deiner Hauptfensterklasse, änderst du paar angaben in der WNDCLASSEX, wie folgt:

    wincl.hIcon               = NULL;
    wincl.lpfnWndProc         = ScrollProc;
    wincl.lpszClassName       = szScrollName; /* global oben mit namen "Scroller" */
    

    Nun auch diese Registrieren

    if (!RegisterClassEx (&wincl))
            return 0;
    

    Nun änderst nur eine Angabe

    wincl.lpszClassName       = szBildName; /* global oben mit namen "Bild" */
    

    Und wieder Registrieren

    In der WndProc des hauptfensters, baust du unter WM_CREaTE: den Scroller (Scrollbox)

    static HWND hScroll = CreateWindow(  "Scroller",
                                     NULL,
                                     WS_CHILD | WS_VISIBLE | WS_DLGFRAME | WS_HSCROLL | WS_VSCROLL ,
                                     0,
                                     0,
                                     0,
                                     0,
                                     hwnd,
                                     NULL,
                                     ((LPCREATESTRUCT) lParam)->hInstance,
                                     NULL);
    

    und unter WM_SIZE: kommt das

    MoveWindow(hScroll, 10, 10, 150, 150, TRUE); /* x,y,width,height nach deinen wünschen */
    

    unter WM_CREATE: deiner ScrollProc kommt:

    static HWND hPic = CreateWindow(  "Bild",
                                     NULL,
                                     WS_CHILD | WS_VISIBLE,
                                     0,
                                     0,
                                     0,
                                     0,
                                     hScroll, /* Handle der Scrollbox */
                                     NULL,
                                     ((LPCREATESTRUCT) lParam)->hInstance,
                                     NULL);
    

    Und unter WM_SIZE:

    MoveWindow(hPic, 0, 0, 300, 300, TRUE); /* je nach größe des bildes */
    

    darauf folgt das Blitten des Bildes auf dem DC von hPic

    Ich glaub unter WM_SCROLL: mußt du ein InvalidateRect(hPic,NULL,true); setzten damit der inhalt neu gezeichnet wird und nochmals Blitten, ist zum vorteil wenn das HBITMAP also das bild global ist.

    ***Alle Angaben ohne gewähr, da aus dem FF, aber in dieser richtung geht das***



  • danke schön, micha, werd mich gleich mal dran machen, das ganze umzusetzen.. (versuche es gerade in die wnd-klasse einzubauen, aus: FoosYerDoos). mal schauen, ob ich das packe..



  • hi leute
    mannomann.. mein kopf raucht ziemlich.. ich hab den durchblick voll nicht mehr. 😕

    (1) einerseits hab ich etwas mühe damit, mir vorzustellen, wie die beiden Msg-Procedures nebeneinander laufen sollen.

    (2) zweierseits bringe ich den vorschlag von MiC++ha überhaupt nicht in meine Class-Struktur hinein. ich benutze die "Simple Wnd Class IV" aus: FoosYerDoos.
    Ich verstehe zwar einigermassen (≠ich verstehe), wie das gemacht wird, mir fehlt aber z.B. irgendwie die variable, wo ich die WindowStyles, wie "WS_CHILD | WS_HSCROLL", einsetzen kann. ausserdem fehlt mir allgemein die Übersicht über die Procedures / Wnd-Erstellungen..

    (3) ich bitte euch also (wenn ihr viel zeit übrig habt (und das haben ja scheinbar alle in diesem forum!) :p), vielleicht mal den folgenden Quellcode anzuschauen: http://www.nrg.to/ultinate/sourcecode_all.html (startseite: www.path-finder.ch.tt)

    (4) @micha: könnte ich das ganze auch weniger sauber lösen, d.h. ohne klassen? (bin eben so langsam am punkt, wo ich sagen muss: lieber irgendwas gebastelt, als gar nichts (MaturArbeit))

    vielen dank!



  • zu 1. Die beiden? Ich habe ein Prog in dem 76 nebeneinander laufen(?), wobei laufen nicht das richtige wort ist. Die WndProc wird von Windows aufgerufen, dabei ist es egal wie viele es sind.

    zu 2. Da dir vermutlich einiges Grundwissen fehlt, solltest du erst mal ohne diese "fremd" Klassen arbeiten, um das ganze besser Verstehen zu lernen.

    zu 3. Nana ⚠ Nicht überheblich werden!

    zu 4. Ausnahmsweise werde ich dir nacher mal ein beispielcode posten, mit paar Komentare, wichtig ist aber das du verstehst wie es mit den ebenen funktioniert, sprich:
    Scrollbox ist ein Kind vom Hauptfenster
    Das Bild ist ein Kind von der Scrollbox
    Stchwort: Parent-Window

    Also ich gehe jetz erstmal Bier holen und Kippen, danach mache ich mal ebend ein beispiel



  • Ich hatte das ganz vergessen, (jaja wenn die Augen groß werden bei Wahrsteiner) 😃

    Nun gut ich habe dann mal auf die schnelle was runter geleiert, ist nicht das wahre wie Warsteiner, aber als "dazu" lehrn Effeckt müßte es reichen.
    Ich blitte das Bild jetzt direkt in die Scrollbox (ging schneller beim schreiben 😉 ), da eh jetzt hier keine Klassen mit zusatzfunktionen verwendet werden, obwohl man das auch bei der Scrollbox machen kann, aber so wie ich das immer mache, niemt die Scrollbox auch andere sachen auf, als nur nen Bild, hier ist nun kein Zoom dabei, aber wie das geht wurde schon gesagt und du kannst es entsprechend dann umbauen, um erlich zu sein solltest du alles Umbauen, bzw. teile Abschreiben und besser selbst bilden (mit mehr zeit).
    Kopier den Mißt nur zum testen, verwende das nicht so, informiere dich über die ganzen Funktionen und lehrne daraus und mach es dann selber und besser.

    Auf die schnelle kann man nicht auf alles achten daher nur zum lehrneffeckt:

    #include <windows.h>
    
    /*  Die WinProcedure des Hauptfensters */
    LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
    /* und nun die für die ScrollBox */
    LRESULT CALLBACK ScrollProc(HWND, UINT, WPARAM, LPARAM);
    
    /* Nun geben wir allen einen Namen */
    char szClassName[ ] = "ScrollBild";
    char szScrollName[ ] = "Scroller";
    
    /* wenn wir schon mit globalen declarationen dabei sind, machen mir die HANDLE der fenster auch global */
    HWND hwnd; /* HANDLE für das Hauptfenster */
    HWND hScroll; /* für die Scrollbox */
    /* und noch was Wichtiges, die Scrollpositionen */
    int xPos,yPos;
    /* und nicht zu vergessen auch die ScrollInfo Struct */
    SCROLLINFO si;
    /* Unser HBITMAP mucke ma och global */
    HBITMAP dasBild;
    
    /* DAS hier müßtes du aber kennen ;) die WinMain */
    int WINAPI WinMain (HINSTANCE hThisInstance,
                        HINSTANCE hPrevInstance,
                        LPSTR lpszArgument,
                        int nFunsterStil)
    
    {
        MSG messages;            
        WNDCLASSEX wincl;        
    
        /* jetzt erstellen wir die Windows Struktur für das Hauptfenster */
        wincl.hInstance = hThisInstance;
        wincl.lpszClassName = szClassName;
        wincl.lpfnWndProc = WindowProcedure;      /* hier bekommt das Hauptfenster seine WndProc */
        wincl.style = CS_DBLCLKS;                 
        wincl.cbSize = sizeof (WNDCLASSEX);
    
        /* Die normalen Sachen, auch Icon und kein menu */
        wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
        wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
        wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
        wincl.lpszMenuName = NULL;                 /* Kein Menu */
        wincl.cbClsExtra = 0;                      
        wincl.cbWndExtra = 0;                      
        wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; /* normale Hintergrundfarbe */
    
        /* so jetzt wird das Fenster regestriert */
        if (!RegisterClassEx (&wincl))
            return 0;
    
        /* jetzt ändern wir einige Angaben um das Scrollbox-Fenster zu registrieren */    
        wincl.hIcon               = NULL; /* kein Icon */
        wincl.lpfnWndProc         = ScrollProc; /* seine eigene WndProc */
        wincl.lpszClassName       = szScrollName; /* tja und der Name */
        /* und ebenfalls registrieren */
        if (!RegisterClassEx (&wincl))
            return 0;
    
        /* Nun erstellen wir das hauptfenster, danach geht es weiter in der Wnd*/
        hwnd = CreateWindowEx (
               0,                   
               szClassName,        
               "Windows App",       
               WS_OVERLAPPEDWINDOW, 
               CW_USEDEFAULT,       
               CW_USEDEFAULT,       
               600,                 
               400,                 
               HWND_DESKTOP,        
               NULL,                
               hThisInstance,       
               NULL                 
               );
    
        /* Und anzeigen */
        ShowWindow (hwnd, nFunsterStil);
    
        /* diese Stelle habe ich mir ausgesucht um das Bild zu laden ;-) */
        /* beachte das bei diesem Beispiel das Bild im ProgVerzeichnis ist und bild.bmp heist */
        /* des weiteren ist das Bild 400x400pix groß */
        dasBild = (HBITMAP)LoadImage(NULL, "bild.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
    
        /* Die Messageschleife */
        while (GetMessage (&messages, NULL, 0, 0))
        {
            TranslateMessage(&messages);
            DispatchMessage(&messages);
        }
    
        return messages.wParam;
    }
    
    /*  Hier nun die WndProc des Hauptfensters  */
    
    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)                  
        {
            case WM_CREATE:
            {
                /* wenn das Hauptfenster erstellt wurde, erstellen wir die Scrollbox */
                hScroll = CreateWindow(  "Scroller",
                                     NULL,
                                     /*ein Kind | sichtbar | wie Dialog(klick etc.)|H-scroll|V-scroll*/
                                     WS_CHILD | WS_DLGFRAME | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL,
                                     0,
                                     0,
                                     0,
                                     0,
                                     hwnd,
                                     NULL,
                                     ((LPCREATESTRUCT) lParam)->hInstance,
                                     NULL);                    
    
               /* Scrollbars Einschalten */                                    
               EnableScrollBar(hScroll,SB_BOTH,ESB_ENABLE_BOTH);
               /* nun noch die Positions Startwerte 0,0 */
               xPos = 0;
               yPos = 0;                                                                
               /* hier setzten wir nun auch schon mal die Memebers der ScrollInfo */
               /* für die H-Scroll */
               si.cbSize = sizeof(si); 
               si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
               si.nMin   = 0; 
               si.nMax   = 170; /* Bildbreite - Anzeigebreite (und höhe) + Scrollbar*/
               si.nPage  = 50; 
               si.nPos   = 0; 
               SetScrollInfo(hScroll, SB_HORZ, &si, TRUE);
               /* und V-Scroll */ 
               SetScrollInfo(hScroll, SB_VERT, &si, TRUE); 
               UpdateWindow(hScroll);                                           
                break;
            }    
            case WM_SIZE:
                    /* hier setzten wir die Scrollbox mit Position und Größe */
                    MoveWindow(hScroll, 10, 10, 250, 250, TRUE);
                    break;    
            case WM_DESTROY:
                PostQuitMessage (0);       
                break;
            default:                      
                return DefWindowProc (hwnd, message, wParam, lParam);
        }
    
        return 0;
    }
    /* nun die WndProc für die Scrollbox */
    LRESULT CALLBACK ScrollProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)                  
        {          
            case WM_HSCROLL:
            {
                /*nun ermitteln wir die H-Position, bzw. setzen diese */
                switch (LOWORD(wParam)) 
                { 
    
                case SB_PAGEUP: 
                    xPos = xPos - 50; 
                    break; 
    
                case SB_PAGEDOWN: 
                    xPos = xPos + 50; 
                    break; 
    
                case SB_LINEUP: 
                    xPos = xPos - 5; 
                    break; 
    
                case SB_LINEDOWN: 
                    xPos = xPos + 5; 
                    break; 
    
                case SB_THUMBPOSITION: 
                    xPos = HIWORD(wParam); 
                    break;
    
                case SB_THUMBTRACK: 
                    xPos = HIWORD(wParam); 
                    break;
    
                default: 
                    xPos = xPos; /* nur zum verständnis ;-) */ 
            }
            /* prüfen ob nicht kleiner 0 */
            if (xPos <0) xPos = 0;
            /* und nicht größer Bild (400-250+20) */
            if (xPos >170) xPos=170;
            /* Und Window schieben */
            ScrollWindowEx(hScroll, -xPos, -yPos, (CONST RECT *) NULL, 
                (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, 
                SW_INVALIDATE); 
            UpdateWindow(hScroll);
            /* nun noch die daten in der ScollInfo ändern und setzen */ 
            si.cbSize = sizeof(si); 
            si.fMask  = SIF_POS; 
            si.nPos   = xPos; 
            SetScrollInfo(hScroll, SB_HORZ, &si, TRUE); 
    
                break;    
            }
            /* nun das ganze auch noch für V-Scroll */
            case WM_VSCROLL:
            {
                /*nun ermitteln wir die V-Position, bzw. setzen diese */
                switch (LOWORD(wParam)) 
                { 
    
                case SB_PAGEUP: 
                    yPos = yPos - 50; 
                    break; 
    
                case SB_PAGEDOWN: 
                    yPos = yPos + 50; 
                    break; 
    
                case SB_LINEUP: 
                    yPos = yPos - 5; 
                    break; 
    
                case SB_LINEDOWN: 
                    yPos = yPos + 5; 
                    break; 
    
                case SB_THUMBPOSITION: 
                    yPos = HIWORD(wParam); 
                    break;
    
                case SB_THUMBTRACK: 
                    yPos = HIWORD(wParam); 
                    break;
    
                default: 
                    yPos = yPos; /* nur zum verständnis ;-) */ 
            }
            /* prüfen ob nicht kleiner 0 */
            if (yPos <0) yPos = 0;
            /* und nicht größer Bild (400-250+20) */
            if (yPos >170) yPos=170;
            /* Und Window schieben */
            ScrollWindowEx(hScroll, -xPos, -yPos, (CONST RECT *) NULL, 
                (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, 
                SW_INVALIDATE); 
            UpdateWindow(hScroll);
            /* nun noch die daten in der ScollInfo ändern und setzen */ 
            si.cbSize = sizeof(si); 
            si.fMask  = SIF_POS; 
            si.nPos   = yPos; 
            SetScrollInfo(hScroll, SB_VERT, &si, TRUE); 
    
                break;    
            }
            case WM_PAINT:
            {
                /* und das Bild malen */
                InvalidateRect(hScroll,NULL,true);
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint(hScroll, &ps);
                HDC hdcMem = CreateCompatibleDC(NULL); 
                SelectObject(hdcMem, dasBild); 
                BitBlt(hdc, 0,0, 250, 250,hdcMem,xPos,yPos, SRCCOPY);                    
                DeleteDC(hdcMem);        
                EndPaint(hScroll, &ps); 
    
                break;    
            }            
            case WM_DESTROY:
                PostQuitMessage (0);       
                break;
            default:                     
                return DefWindowProc (hwnd, message, wParam, lParam);
        }
    
        return 0;
    }
    

    Ich erwähne es nochmal, NICHT für eigene projekte übernehmen, sondern nur raus lehrnen, höchstens zum Testen und Fummeln 1:1 kopieren.



  • hey, du hast echt zuviel zeit! 😃
    aber danke viel mal!!
    das bringt grade einige ordnung in meine gedanken. nicht gewusst, dass man sich auch noch um die scrollbars
    kümmern muss. denn bei einem "edit" geht das ja automatisch.. eben, so lernt man ständig neues..
    gruss nate

    übrigens: die WinMain hab ich tatsächlich schon gekannt! 😉 (man glaubt es kaum..)



  • nate7 schrieb:

    ...denn bei einem "edit" geht das ja automatisch...

    Eben nicht, auch das Edit hat eine WndProc in der die ScrollBars gesteuert werden, nur damit hast du nichts zu tun, da die WndProc von Windows vorgegeben ist, du kannst auch mit SetWindowLong eine eigene WndProc dem Edit zuteilen, solltest aber am Ende deiner WndProc die alte des Edits aufrufen.



  • ja, klar.. automatisch läuft ja (leider?) gar nichts..



  • nate7 schrieb:

    hey, du hast echt zuviel zeit! 😃

    Darauf hatte ich ja noch gar nicht Reagiert,
    wenn du erst mal Fit bist in WinAPI, zumindest für die normalen üblichen Sachen, dann leierst du sowas in 15-30min. (je nach dem wieviele Warsteiner schon weg hast 😃 ) runter.

    Bastelstunden Progger und Copy´n Paste Devs brauchen 2 Tage um zu verstehen was SetWindowText() macht.

    Zur Zeit sei gesagt, das ich wenig davon habe, aber zwischendurch mal rein schaue, und ich habe auch noch Familie und mich selbst, daher würde ich mich nicht hinsetzten und Stundenlang was Proggen um nen Fremden zu Zeigen wie was geht, bei sowas billigen mach auch ich mal ne Ausnahme und nehme mir paar Minuten zeit.

    Und nicht nur mir ist meine Zeit wichtig, und grob verplant, sondern bei allen anderen auch, daher frage ich mich immer warum einige Noobs es nicht verstehen das man ihnen hier keinen vollen Code liefert.

    Sie sahen: Off-Topic by MiC++ha


Anmelden zum Antworten