VB 5/6-Tipp 0470: Form-Regions anhand einer Bitmap erstellen
von Benjamin Wilger
Beschreibung
Unter Windows 2000/XP geht dies mit der API SetLayeredWindowAttributes. Mit Hilfe dieses Moduls können sie dies auch unter älteren Windows Versionen machen! Und das sehr schnell, durch die Benutzung von DIBs(Device Independend Bitmaps). Die Routine erkennt, ob das Betriebssystem die API SetLayeredWindowAttributes unterstützt, und wenn nicht, macht es die Form manuell transparent. Das einzige, was Sie nur tun müssen, ist eine Farbe anzugeben, welche die Form transparent macht. Was noch beachtet werden sollte ist, dass beim Zielobjekt AutoRedraw aktiviert ist.
Schwierigkeitsgrad: | Verwendete API-Aufrufe: BitBlt, CombineRgn, CreateCompatibleDC, CreateDIBSection, CreateRectRgn, DeleteDC, DeleteObject, FreeLibrary, GetDIBits, GetModuleHandleA (GetModuleHandle), GetPixel, GetProcAddress, GetWindowLongA (GetWindowLong), LoadLibraryA (LoadLibrary), OleTranslateColor, ReleaseCapture, SelectObject, SendMessageA (SendMessage), SetLayeredWindowAttributes, SetWindowLongA (SetWindowLong), SetWindowRgn | Download: |
'Dieser Quellcode stammt von http://www.activevb.de 'und kann frei verwendet werden. Für eventuelle Schäden 'wird nicht gehaftet. 'Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum. 'Ansonsten viel Spaß und Erfolg mit diesem Source! '------------- Anfang Projektdatei Projekt1.vbp ------------- '--------- Anfang Formular "Form1" alias Form1.frm --------- ' Steuerelement: Schaltfläche "Command1" Option Explicit Private Const WM_NCLBUTTONDOWN As Long = &HA1& Private Const HTCAPTION As Long = 2& Private Declare Function SendMessage Lib "user32" _ Alias "SendMessageA" ( _ ByVal hWnd As Long, _ ByVal wMsg As Long, _ ByVal wParam As Long, _ lParam As Any) As Long Private Declare Function ReleaseCapture Lib "user32" () As Long Private Sub Command1_Click() Unload Me End Sub Private Sub Form_Load() Me.Picture = LoadPicture(App.Path & "\Back.gif") Me.Width = Me.ScaleX(Me.Picture.Width, vbHimetric, vbTwips) Me.Height = Me.ScaleY(Me.Picture.Height, vbHimetric, vbTwips) MakeFormTransparent Me, vbMagenta End Sub Private Sub Form_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single) ReleaseCapture SendMessage Me.hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0& End Sub '---------- Ende Formular "Form1" alias Form1.frm ---------- '--- Anfang Modul "RegionFromBitmap" alias RegionFromBitmap.bas --- ' Code von Benjamin Wilger ' Benjamin@ActiveVB.de ' Copyright (C) 2001 Option Explicit Private Declare Function CreateRectRgn Lib "gdi32" ( _ ByVal X1 As Long, _ ByVal Y1 As Long, _ ByVal X2 As Long, _ ByVal Y2 As Long) As Long Private Declare Function GetPixel Lib "gdi32" ( _ ByVal hDC As Long, _ ByVal x As Long, _ ByVal y As Long) As Long Private Declare Function CombineRgn Lib "gdi32" ( _ ByVal hDestRgn As Long, _ ByVal hSrcRgn1 As Long, _ ByVal hSrcRgn2 As Long, _ ByVal nCombineMode As Long) As Long Private Declare Function DeleteObject Lib "gdi32" ( _ ByVal hObject As Long) As Long Private Declare Function SetWindowRgn Lib "user32" ( _ ByVal hWnd As Long, _ ByVal hRgn As Long, _ ByVal bRedraw As Boolean) As Long Private Const RGN_OR As Long = 2& Private Declare Sub OleTranslateColor Lib "oleaut32.dll" ( _ ByVal clr As Long, _ ByVal hpal As Long, _ ByRef lpcolorref As Long) Private Type BITMAPINFOHEADER biSize As Long biWidth As Long biHeight As Long biPlanes As Integer biBitCount As Integer biCompression As Long biSizeImage As Long biXPelsPerMeter As Long biYPelsPerMeter As Long biClrUsed As Long biClrImportant As Long End Type Private Type RGBQUAD rgbBlue As Byte rgbGreen As Byte rgbRed As Byte rgbReserved As Byte End Type Private Type BITMAPINFO bmiHeader As BITMAPINFOHEADER bmiColors As RGBQUAD End Type Private Declare Function CreateCompatibleDC Lib "gdi32" ( _ ByVal hDC As Long) As Long Private Declare Function CreateDIBSection Lib "gdi32" ( _ ByVal hDC As Long, _ pBitmapInfo As BITMAPINFO, _ ByVal un As Long, _ ByVal lplpVoid As Long, _ ByVal handle As Long, _ ByVal dw As Long) As Long Private Declare Function SelectObject Lib "gdi32" ( _ ByVal hDC As Long, _ ByVal hObject As Long) As Long Private Declare Function BitBlt Lib "gdi32" ( _ ByVal hDestDC As Long, _ ByVal x As Long, _ ByVal y As Long, _ ByVal nWidth As Long, _ ByVal nHeight As Long, _ ByVal hSrcDC As Long, _ ByVal xSrc As Long, _ ByVal ySrc As Long, _ ByVal dwRop As Long) As Long Private Declare Function GetDIBits Lib "gdi32" ( _ ByVal aHDC As Long, _ ByVal hBitmap As Long, _ ByVal nStartScan As Long, _ ByVal nNumScans As Long, _ lpBits As Any, _ lpBI As BITMAPINFO, _ ByVal wUsage As Long) As Long Private Declare Function DeleteDC Lib "gdi32" ( _ ByVal hDC As Long) As Long Private Const BI_RGB As Long = 0& Private Const DIB_RGB_COLORS As Long = 0& Private Declare Function GetModuleHandle Lib "kernel32" _ Alias "GetModuleHandleA" ( _ ByVal lpModuleName As String) As Long Private Declare Function LoadLibrary Lib "kernel32" _ Alias "LoadLibraryA" ( _ ByVal lpLibFileName As String) As Long Private Declare Function GetProcAddress Lib "kernel32" ( _ ByVal hModule As Long, _ ByVal lpProcName As String) As Long Private Declare Function FreeLibrary Lib "kernel32" ( _ ByVal hLibModule As Long) As Long Private Const LWA_COLORKEY As Long = &H1& Private Const GWL_EXSTYLE As Long = (-20&) Private Const WS_EX_LAYERED As Long = &H80000 Private Declare Function GetWindowLong Lib "user32" _ Alias "GetWindowLongA" ( _ ByVal hWnd As Long, _ ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" _ Alias "SetWindowLongA" ( _ ByVal hWnd As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long Private Declare Function SetLayeredWindowAttributes Lib "user32" ( _ ByVal hWnd As Long, _ ByVal crKey As Long, _ ByVal bAlpha As Byte, _ ByVal dwFlags As Long) As Long Public Function MakeFormTransparent(frm As Form, ByVal lngTransColor As Long) Dim hRegion As Long Dim WinStyle As Long ' Systemfarben ggf. in RGB-Werte übersetzen If lngTransColor < 0 Then OleTranslateColor lngTransColor, 0&, lngTransColor ' Ab Windows 2000/98 geht das relativ einfach per API ' Mit IsFunctionExported wird geprüft, ob die Funktion ' SetLayeredWindowAttributes unter diesem Betriebsystem unterstützt wird. If IsFunctionExported("SetLayeredWindowAttributes", "user32") Then ' Den Fenster-Stil auf "Layered" setzen WinStyle = GetWindowLong(frm.hWnd, GWL_EXSTYLE) WinStyle = WinStyle Or WS_EX_LAYERED SetWindowLong frm.hWnd, GWL_EXSTYLE, WinStyle SetLayeredWindowAttributes frm.hWnd, lngTransColor, 0&, LWA_COLORKEY Else ' Manuell die Region erstellen und übernehmen hRegion = RegionFromBitmap(frm, lngTransColor) SetWindowRgn frm.hWnd, hRegion, True DeleteObject hRegion End If End Function Private Function RegionFromBitmap(picSource As Object, _ ByVal lngTransColor As Long) As Long Dim lngRetr As Long, lngHeight As Long, lngWidth As Long Dim lngRgnFinal As Long, lngRgnTmp As Long Dim lngStart As Long Dim x As Long, y As Long Dim hDC As Long Dim bi24BitInfo As BITMAPINFO Dim iBitmap As Long Dim BWidth As Long Dim BHeight As Long Dim iDC As Long Dim PicBits() As Byte Dim Col As Long Dim OldScaleMode As ScaleModeConstants OldScaleMode = picSource.ScaleMode picSource.ScaleMode = vbPixels hDC = picSource.hDC lngWidth = picSource.ScaleWidth ' - 1 lngHeight = picSource.ScaleHeight - 1 BWidth = (picSource.ScaleWidth \ 4) * 4 + 4 BHeight = picSource.ScaleHeight ' Bitmap-Header With bi24BitInfo.bmiHeader .biBitCount = 24 .biCompression = BI_RGB .biPlanes = 1 .biSize = Len(bi24BitInfo.bmiHeader) .biWidth = BWidth .biHeight = BHeight + 1 End With ' ByteArrays in der erforderlichen Größe anlegen ReDim PicBits(0 To bi24BitInfo.bmiHeader.biWidth * 3 - 1, 0 To _ bi24BitInfo.bmiHeader.biHeight - 1) iDC = CreateCompatibleDC(hDC) ' Gerätekontextunabhängige Bitmap (DIB) erzeugen iBitmap = CreateDIBSection(iDC, bi24BitInfo, DIB_RGB_COLORS, ByVal 0&, ByVal 0&, _ ByVal 0&) ' iBitmap in den neuen DIB-DC wählen Call SelectObject(iDC, iBitmap) ' hDC des Quell-Fensters in den hDC der DIB kopieren Call BitBlt(iDC, 0, 0, bi24BitInfo.bmiHeader.biWidth, _ bi24BitInfo.bmiHeader.biHeight, hDC, 0, 0, vbSrcCopy) ' Gerätekontextunabhängige Bitmap in ByteArrays kopieren Call GetDIBits(hDC, iBitmap, 0, bi24BitInfo.bmiHeader.biHeight, PicBits(0, 0), _ bi24BitInfo, DIB_RGB_COLORS) ' Wir brauchen nur den Array, also können wir die Bitmap direkt wieder löschen. ' DIB-DC Call DeleteDC(iDC) ' Bitmap Call DeleteObject(iBitmap) lngRgnFinal = CreateRectRgn(0, 0, 0, 0) For y = 0 To lngHeight x = 0 Do While x < lngWidth Do While x < lngWidth And RGB(PicBits(x * 3 + 2, lngHeight - y + 1), _ PicBits(x * 3 + 1, lngHeight - y + 1), PicBits(x * 3, lngHeight - y + 1) _ ) = lngTransColor x = x + 1 Loop If x <= lngWidth Then lngStart = x Do While x < lngWidth And RGB(PicBits(x * 3 + 2, lngHeight - y + 1), _ PicBits(x * 3 + 1, lngHeight - y + 1), PicBits(x * 3, lngHeight - y _ + 1)) <> lngTransColor x = x + 1 Loop If x + 1 > lngWidth Then x = lngWidth lngRgnTmp = CreateRectRgn(lngStart, y, x, y + 1) lngRetr = CombineRgn(lngRgnFinal, lngRgnFinal, lngRgnTmp, RGN_OR) DeleteObject lngRgnTmp End If Loop Next picSource.ScaleMode = OldScaleMode RegionFromBitmap = lngRgnFinal End Function ' Code von vbVision: ' Diese Funktion überprüft, ob die angegebene Function von einer DLL exportiert wird. Private Function IsFunctionExported(ByVal sFunction As String, ByVal sModule As String) _ As Boolean Dim hMod As Long, lpFunc As Long, bLibLoaded As Boolean ' Handle der DLL erhalten hMod = GetModuleHandle(sModule) If hMod = 0 Then ' Falls DLL nicht registriert ... hMod = LoadLibrary(sModule) ' DLL in den Speicher laden. If hMod Then bLibLoaded = True End If If hMod Then If GetProcAddress(hMod, sFunction) Then IsFunctionExported = True End If If bLibLoaded Then Call FreeLibrary(hMod) End Function '--- Ende Modul "RegionFromBitmap" alias RegionFromBitmap.bas --- '-------------- Ende Projektdatei Projekt1.vbp --------------
Tipp-Kompatibilität:
Windows/VB-Version | Win32s | Win95 | Win98 | WinME | WinNT4 | Win2000 | WinXP |
VB4 | |||||||
VB5 | |||||||
VB6 |
Ihre Meinung
Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.
Archivierte Nutzerkommentare
Klicken Sie diesen Text an, wenn Sie die 9 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.
Kommentar von TiKu am 09.02.2010 um 10:23
Der Code hat ein GDI-Handle-Leak, also ein Speicherleck. Die Bitmap iBitmap wird in einen DC selektiert, vor dem Löschen aber nicht wieder herausselektiert. Dadurch schlägt das Löschen fehl.
Kommentar von P. Soell am 08.02.2006 um 11:08
Wie kann der Code auch für MDI-Formulare verwendet werden? Sobald MDIChild auf True gesetzt wird, wird das Fenster nicht mehr durchsichtig angezeigt.
Kommentar von Reichenbach am 14.08.2005 um 19:43
Ich möchte die Form noch wahlweise in zwei Arten modifizieren:
(1) Die Form soll Eingaben (z.B. Mausclicks) auch in den transparenten Bereichen entgegennehmen.
bzw.
(2) Die Form soll die Eingaben an die darunterliegende Applikation weiterreichen, selbst aber im Vordergrund (passiv) sichtbar bleiben.
Vielen Dank für einen evtl. Tipp!!
Kommentar von Benjamin Wilger am 16.06.2005 um 09:31
Lieber Coolzero,
das Modul hat den Vorteil, dass je nachdem welches Betriebssystem verwendet wird, jeweils die beste Variante genutzt wird.
Die einfachste mir bekannte Variante ist die mit den SetLayeredWindowAttributes. Jedoch funktioniert die nur ab Win2K.
Gruß,
Benjamin
Kommentar von Coolzero am 18.02.2005 um 11:46
Also mal ehrlich,
findet Ihr nicht das das ein wenig zu aufwändig ist nur um das aussehen der Form zu ändern ???
Ich kann mich daran erinnern das es da ne einfachere Methode gibt aber weis sie eben nicht mehr.
MFG
Coolzero
Kommentar von ... am 28.07.2003 um 21:53
Die Methode ohne SetLayeredWindowAttributes hat den Vorteil, daß sie auch mit Bildboxen und wahrscheinlich allen anderen Steuerelementen funktioniert, die einen hWnd haben.
Kommentar von Frager am 20.10.2002 um 20:42
kann man das auch so verändern das das bild was als hintergrund genommen wird mit in die exe-datei eingebunden ist und nicht mehr einzeln dazu gegeben werden muß?
Kommentar von Benjamin Wilger am 19.07.2002 um 18:39
Hallo Peter,
ich habe das trotzdem aus dem Upload entfernt, weil es eben redundant ist.
Du kannst im Forum direkt auf einen Tipp verweisen, indem Du !tipXXXX schreibst. Das XXXX steht für die Tippnummer.
Beste Grüße,
Benjamin Wilger
Kommentar von Peter am 23.06.2002 um 10:49
Ähm, Sorry dass ich das ganze noch mal in den Download gestellt habe, aber im Forum hat einer danach gefragt, und ich hab dann gesucht wo das hier steht, habs aber nicht gefunden. Darum steht's halt nochmal im Download (aber nur das Modul)
Ich hoffe das macht nix!
Peter