SetWindowRgn



  • Morgen Leute.
    Ich habe mal versucht einen Button zu erstellen der nicht rechteckig ist. Irgendwas mach ich aber offenbar falsch.
    Hier mein Code:

    void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
    {
        CRect r;
        this->GetClientRect(r);
        SetWindowRgn(NULL, FALSE);
    
        if(!this->isRgnSet)
        {
            rgn_.DeleteObject();
            rgn_.CreateEllipticRgn(r.left,r.top,r.right,r.bottom);
        }
        else
        {
        }
        SetWindowRgn(rgn_, TRUE);
        CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
        CBrush brush;
        brush.CreateSolidBrush(RGB(200,0,0));
        pDC->FillRgn(&rgn_,&brush);
    }
    

    Wenn ich das so ausführe kommt ein grauer Adler auf grauem Hintergrund. Wenn ich aber SetWindowRgn(rgn_, TRUE); auskommentiere erhalte ich das erwartete Ergebnis, nur möchte ich halt gern wirklich die Windowregion setzen. Was mach ich falsch? Kann mir wer helfen?



  • Warum setzt du die Region zuerst auf NULL???



  • In Funktionen, welche zum Zeichnen verwendet werden, sollte man nicht die Grösse oder Form eines Fensters ändern !!



  • @MaSTaH: Ich habe den Code nicht selbst erfunden sondern aus einem Beitrag von Codeguru. In den 2 Beispielen die ich gefunden habe machen die das genau so. Kann nicht beurteilen ob das richtig oder falsch ist.

    @ReneG: Selbe wie oben. Die auf Codeguru machen im Prinzip das selbe.

    Stimmt schon, wenn ich es GENAU so gemacht hätte wie in den Beispielen würde es auch funktionieren, aber die 2 Beispiele gehen mir zuwenig weit.
    Was ich brauche ist eine Klasse in die ich beim Konstruktor eine CReg übergeben kann und daraus den Button zeichnen kann UND natürlich auch nur dieser Teil des Buttons geklickt werden kann....
    Nur wo liegt mein Fehler daß bei mir rein gar nichts erscheint? Die Region ist gültig, sonst könnte ich auch den Roten Fleck nicht malen mit FillRgn()(Denk ich mal) Hat noch jemand Tipps oder Hinweise?



  • OK, ich glaub ich habs:

    void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
    {
        // TODO: Add your code to draw the specified item
        CRect r;
        this->GetClientRect(r);
        SetWindowRgn(NULL, FALSE);
    
        if(!this->isRgnSet)
        {
            rgn_.DeleteObject();
            rgn_.CreateEllipticRgn(0,0,r.Width(),r.Height());
        }
        else
        {
        }
        CRgn temp; temp.CreateRectRgn(0,0,0,0); //initial Region
        temp.CopyRgn(&rgn_);
        if (SetWindowRgn(temp, TRUE)) TRACE("-->OK\n");
        else TRACE("-->FALSCH\n");
    
        //CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
        CDC* pDC = GetWindowDC();
        CBrush brush;
        brush.CreateSolidBrush(RGB(200,0,0));
        //pDC->FillRect(&r, &brush);
        pDC->FillRgn(&rgn_,&brush);
        ReleaseDC(pDC);
    }
    

    Bemerkungen:

    1.) Laut MSDN sollte man die Region nach SetWindowRgn nicht mehr verwenden:

    After a successful call to SetWindowRgn, the operating system owns the region specified by the region handle hRgn. The operating system does not make a copy of the region, so do not make any further function calls with this region handle, and do not close this region handle.

    Das würde dann auch erklären, warum die Ellipse nur zu sehen ist, wenn du SetWindowRgn auskommentiertst. Also am besten eine Kopie anlegen und dann damit Zeichnen.

    2.) Den DC zum Zeichnen hole ich mir immer über GetWindowDC. Mache ich das über den Struckt, dann wird bei FillRect (im Bsp oben auskommentiert) das komplette Rechteck ausgefüllt, obwohl ja nur die Region/also auch nur die Ellipse ausgefüllt werden sollte.

    Gruß mathi

    [ Dieser Beitrag wurde am 13.01.2003 um 14:53 Uhr von mathi editiert. ]



  • @Thomas

    Dann machen die das bei codeguru auch falsch, denn SetWindowRgn veranlasst das Fenster dazu, sich neu zu zeichnen!

    Es ist wohl verständlich, was passiert, wenn die eine Funktion, die das Neuzeichnen veranlasst, innerhalb der Zeichnen-Funktions steht???

    Einzig und allein die Tatsache, dass sich nach 2 Aufrufen die UpdateRgn auf NULL setzt, weil sich die Grösse des Fensters nicht mehr geändert hat, hindert das ganze an einer Endlosschleife.

    Sauber ist es, SetWindowRgn innerhalb von WM_SIZE aufzurufen!



  • Sehe ich genauso. Beim Zeichnen sollte man auch wirklich nur zeichnen...



  • @mathi: Super klappt so. Besten Dank. yeahhhhhh!!!!!!!!!!!!!

    @RenéG: Ich habe das ganze mal versucht so wie du es vorgeschlagen hast in der OnSize() Funktion. Kann nicht mit letzter Sicherheit sagen ob ich noch einen Fehler eingebaut habe , scheint aber nicht zu klappen(Auch nicht mit den Änderungen vom mathi). Die einzige Methode die mal zum anfangen klappt ist die von mathi.

    Ist natürlich jetzt ne Krise wenn ich an der Stelle weitermache und Ihr sagt eigentlich ist es falsch, weil dann zu erwarten steht das ganz fällt mir irgendwann auf den Kopf. Also was tun?
    PS: Sowas wär extra gut in der FAQ aufgehoben.


Anmelden zum Antworten