Halbtransparente Objekte mit Polygon-Funktion aus gdi32.dll

  • VB6

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von Gonger96.

    Halbtransparente Objekte mit Polygon-Funktion aus gdi32.dll

    Hallo zusammen,

    ich nutze folgenden Code, um in einer PictureBox auf einem Hintergrundbild eine Raute einzuzeichnen:

    Visual Basic-Quellcode

    1. Rem Typen und API-Aufrufe für die Zeichenfunktionen
    2. Private Type pointapi
    3. X As Long
    4. Y As Long
    5. End Type
    6. Private Declare Function Polygon Lib "gdi32" (ByVal hdc As _
    7. Long, lpPoint As pointapi, ByVal nCount As Long) As Long
    8. Private Declare Function CreateEllipticRgn Lib "gdi32" ( _
    9. ByVal X1 As Long, _
    10. ByVal Y1 As Long, _
    11. ByVal X2 As Long, _
    12. ByVal Y2 As Long) As Long
    13. Private Declare Function CreateRectRgn Lib "gdi32.dll" ( _
    14. ByVal X1 As Long, _
    15. ByVal Y1 As Long, _
    16. ByVal X2 As Long, _
    17. ByVal Y2 As Long) As Long
    18. Private Declare Function PtInRegion Lib "gdi32" ( _
    19. ByVal hRgn As Long, _
    20. ByVal X As Long, _
    21. ByVal Y As Long) As Long
    22. Private Declare Function PaintRgn Lib "gdi32" ( _
    23. ByVal hdc As Long, _
    24. ByVal hRgn As Long) As Long
    25. Private Declare Function DeleteObject Lib "gdi32" ( _
    26. ByVal hObject As Long) As Long
    27. Dim Region As Long
    28. Dim Innen As Long
    29. Function Raute(Seitenlaenge, Farbe)
    30. X = 395 'Mittelpunkt der Raute auf dem Hintergrundbild
    31. Y = 400
    32. h = Round(Sqr(2 * Seitenlaenge ^ 2) / 2, 0)
    33. X1 = X
    34. Y1 = Y - h
    35. X2 = X + h
    36. Y2 = Y
    37. X3 = X
    38. Y3 = Y + h
    39. X4 = X - h
    40. Y4 = Y
    41. BaseForm.Picture1.FillColor = Farbe
    42. BaseForm.Picture1.ForeColor = Farbe
    43. Dim ret As Long
    44. Dim pt(1 To 4) As pointapi
    45. pt(1).X = X1
    46. pt(1).Y = Y1
    47. pt(2).X = X2
    48. pt(2).Y = Y2
    49. pt(3).X = X3
    50. pt(3).Y = Y3
    51. pt(4).X = X4
    52. pt(4).Y = Y4
    53. ret = Polygon(BaseForm.Picture1.hdc, pt(1), 4)
    54. BaseForm.Picture1.Refresh
    55. Raute = Y3
    56. End Function


    Ich möchte die Raute nun allerding nicht opak ausfüllen, sondern "halbtransparent", also sagen wir mal mit 60% Transparenz. Geht das mit dieser Funktion? Oder gibt es eine andere Funktion, mit der das geht?


    Für zierführende Hinweise Danke im Voraus,
    Sarek
    Hallo Neptun,

    Neptun schrieb:

    das geht mit der Api-Funktion AlphaBlend oder auch mit GDIAlphaBlend.
    Sieh' dir mal das an:
    activevb.de/cgi-bin/upload/download.pl?id=3348
    das sieht gut aus. Ich bin allerdings aus dem Code nicht ganz schlau geworden, da ist viel zu viel Schnickschnack rund um die eigentliche Funktion herum. Wenn ich es richtig gesehen habe, wurde dort (beim Polygon-Beispiel) auch die Polygon-Funktion verwendet. Heißt das, daß die AlphaBlend-Funktion zusätzlich mit eingebaut wird? Wo würde ich die in meinem Code unterbringen?

    Und welche Funktion hat die GDI-Funktion BitBlt, die in dem Beispiel auch verwendet wird? Gehört das mit zu der Transparenz, oder hat sie mit dem anderen Schnickschnak in dem Beispielprojekt (also z.B. der Animation) zu tun? Nein nein, keine Sorge - natürlich habe ich nach der Funktion gegoogelt, habe es aber nicht verstanden. Normalerweise programmiere ich eher mathematische Prozeduren als graphische Ausgaben.


    Danke im Voraus,
    Sarek
    Hallo Sarek,
    Heißt das, daß die AlphaBlend-Funktion zusätzlich mit eingebaut wird? Wo würde ich die in meinem Code unterbringen?

    Ja, du brauchst sowohl Polygon als auch Alphablend.

    Und welche Funktion hat die GDI-Funktion BitBlt, die in dem Beispiel auch verwendet wird? Gehört das mit zu der Transparenz, oder hat sie mit dem anderen Schnickschnak in dem Beispielprojekt (also z.B. der Animation) zu tun?

    BitBlt kopiert einen rechteckigen Bildausschnitt von einer Bitmap
    in eine Andere. Es hat eine ähnliche Funktion wie VB-PaintPicture,
    nur das es schneller ist (ca. Faktor 15). In Beispiel wird es sowohl
    für die Animation zum Kopieren des Hintergrundes, als auch für die
    Transparenz zum Zwischenspeichern des Bildausschnitts verwendet.

    Für transparentes Zeichnen (ohne Animation) folgende Vorgehensweise:
    1. Rechteckigen Bildausschnitt ermitteln, der vom Polygon überzeichnet
    wird.
    2. Diesen Bildausschnitt retten, also in einer nicht sichtbaren
    Picturebox (Autoredraw = True) zwischenspeichern.
    3. Polygon in die Zielbitmap zeichnen.
    4. Den geretteten Bildausschnitt mit Alphablend über das Polygon
    zeichnen.
    5. Neuzeichnen erzwingen: Picturebox.Refresh
    Gruss,

    Neptun
    Hallo Herr der Meere ;)

    Neptun schrieb:

    Für transparentes Zeichnen (ohne Animation) folgende Vorgehensweise:
    1. Rechteckigen Bildausschnitt ermitteln, der vom Polygon überzeichnet wird.
    2. Diesen Bildausschnitt retten, also in einer nicht sichtbaren Picturebox zwischenspeichern.
    3. Polygon in die Zielbitmap zeichnen.
    4. Den geretteten Bildausschnitt mit Alphablend über das Polygon zeichnen.
    5. Neuzeichnen erzwingen: Picturebox.Refresh
    Oje, ganz schön kompliziert. Das heißt, in Wirklichkeit wird nicht das Polygon halbtransparent gezeichnet, sondern die Bitmap wird an der Stelle halbtransparent über das Polygon gelegt, was aber auf das gleiche Ergebnis hinausläuft. Richtig?

    Verstehen tue ich dann aber folgendes nicht: Wenn ich einen rechteckigen Ausschnitt der Zielbitmap zwischenspeichern soll, und den nach dem Zeichnen des Polygons mit Alphablend über das selbige legen soll, dann trifft es ja auch Bereiche, die nicht zum Polygon gehören. Ist ja auch kein Problem, wenn das so funktioniert, wie ich es oben vermute. Kann ich aber dann nicht gleich die gesamte Zielbitmap nach dem Zeichnen des Polygons darüberlegen, statt noch groß einen rechteckigen Ausschnitt zu ermitteln und nur den zu sichern?

    Und wie speichere ich überhaupt den Bildausschnitt (oder eben noch mal das gesamte Bild) zwischen, um es hinterher über das Polygon zu legen? In dem Beispielprojekt habe ich keine unsichtbare Picturebox gefunden. Wo wurde das dann zwischengespeichert? In einer Variable vielleicht?
    Hallo Sarek,
    Das heißt, in Wirklichkeit wird nicht das Polygon halbtransparent gezeichnet, sondern die Bitmap wird an der Stelle halbtransparent über das Polygon gelegt, was aber auf das gleiche Ergebnis hinausläuft. Richtig?

    Ja, so ist es. Es gibt ja keine Funktion, die ein Polygon direkt
    transparent zeichnet. Wenn man dieses Verfahren verstandnen hat,
    kann man es auch leicht auf andere Zeichenfunktionen anwenden.
    Verstehen tue ich dann aber folgendes nicht: Wenn ich einen rechteckigen Ausschnitt der Zielbitmap zwischenspeichern soll, und den nach dem Zeichnen des Polygons mit Alphablend über das selbige legen soll, dann trifft es ja auch Bereiche, die nicht zum Polygon gehören. Ist ja auch kein Problem, wenn das so funktioniert, wie ich es oben vermute.

    An den Stellen, an denen Quelle und Ziel identisch sind, kommt,
    unabhängig vom Alpha-Wert, immer die Original-Grafik raus, egal
    ob jetzt 10 % von der Quelle und 90 % vom Ziel oder umgekehrt,
    es gibt immer 100 %.

    Kann ich aber dann nicht gleich die gesamte Zielbitmap nach dem Zeichnen des Polygons darüberlegen, statt noch groß einen rechteckigen Ausschnitt zu ermitteln und nur den zu sichern?

    Es ist kein grosser Aufwand dieses Rechteck zu ermitteln. Aber ja,
    du kannst auch das ganze Bild zwischenspeichern. Es kostet nur mehr
    CPU-Zeit und mehr Speicher. Bei sehr grossen Bildern (10000 Pixel)
    stellt GDI sich quer, wenn man versucht sie doppelt im Speicher zu halten, auch, wenn man genügend RAM hat.

    Und wie speichere ich überhaupt den Bildausschnitt (oder eben noch mal das gesamte Bild) zwischen, um es hinterher über das Polygon zu legen? In dem Beispielprojekt habe ich keine unsichtbare Picturebox gefunden. Wo wurde das dann zwischengespeichert? In einer Variable vielleicht?

    Im Beispielprojekt wird eine Bitmap über Api-Funktionen erzeugt. Wenn
    du dich mit Grafik nicht so auskennst, machst du das besser über eine
    Picturebox.
    Vorgehensweise:
    1. Zweite Picturebox zur Entwurfszeit hinzufügen. Visible = False,
    Autoredraw = True, Einheit Pixel, Borderstyle = 0
    2. Die Quellpicturebox muss ebenfalls Autoredraw = True, Einheit Pixel
    haben.
    3. Grösse der unsichtbaren Picturebox mit Width und Height anpassen.
    Achtung die Grössenangaben müssen in der Einheit der Form übergeben
    werden. Die Form am Besten auch auf Pixel stellen. Dann braucht
    man nichts umzurechnen. Cls um das Bild anzupassen.
    4. Rüberkopieren dann mit BitBlt oder mit VB-PaintPicture in beide
    Richtungen möglich. Bei Api-Funktionen Neuzeichnen mit Refresh
    erzwingen (nur bei der sichtbaren Picturebox).
    Beispiel PaintPicture:

    Visual Basic-Quellcode

    1. Picture2.PaintPicture Picture1.Image, 0, 0, 200, 150, 137, 71, 200, 150

    Kopiert einen 200 * 150 Pixel grossen Ausschnitt in Picturebox2.
    Beispiel BitBlt:

    Visual Basic-Quellcode

    1. Call BitBlt(Picture2.hdc, 0, 0, 200, 150, Picture1.hdc, 137, 71, vbSrcCopy)
    Gruss,

    Neptun
    Hallo Neptun,

    Neptun schrieb:

    1. Zweite Picturebox zur Entwurfszeit hinzufügen. Visible = False,
    Autoredraw = True, Einheit Pixel, Borderstyle = 0
    2. Die Quellpicturebox muss ebenfalls Autoredraw = True, Einheit Pixel
    haben.
    Ist das mit der Einheit Pixel unbedingt notwendig? Ich habe da jetzt "benutzerdefiniert" stehen, und ich weiß noch, was das damals für ein Gefummel war, damit die Längenangaben sich richtig berechnen ließen. Die Definition der PictureBox, in der das Polygon bisher eingezeichnet wird, sieht in der FRM-Datei so aus:

    Visual Basic-Quellcode

    1. Begin VB.PictureBox Picture1
    2. AutoRedraw = -1 'True
    3. FillStyle = 0 'Ausgefüllt
    4. Height = 12000
    5. Left = 840
    6. Picture = "GetMBUS.frx":41CADE
    7. ScaleHeight = 793.026
    8. ScaleMode = 0 'Benutzerdefiniert
    9. ScaleWidth = 1150
    10. TabIndex = 0
    11. Top = 0
    12. Width = 17250
    13. End

    Neptun schrieb:

    Hallo Sarek,
    das geht mit der Api-Funktion AlphaBlend oder auch mit
    GDIAlphaBlend.
    Sieh' dir mal das an:
    activevb.de/cgi-bin/upload/download.pl?id=3348


    So, ich habe das Projekt jetzt endlich umsetzen können (es waren noch ein paar Voraussetzungen zu schaffen). Danke für den Tipp, es hat geklappt :) (war aber ganz schön Arbeit, die eigentliche Funktion aus dem Projekt herauszulösen)