📜 ⬆️ ⬇️

Irregular windows

Start


Sometimes it is necessary to have a window of “irregular” (not rectangular) shape, be it a splash screen, or a desktop widget.

image


The Windows API has several functions with the help of which you can create "wrong" windows, such as: CreateEllipticRgn , CreateRectRgn , CreatePolygonRgn , CreateRoundRectRgn , CombineRgn , etc. unpleasant teeth, it is impossible to make a full-fledged shadow, and writing code that creates a window of complex shape sometimes requires a lot of effort.
')
Starting with Windows 2000, the windows have an expanded WS_EX_LAYERED style that makes the window multi-layered, and several API functions were added to work with such windows, one of which is UpdateLayeredWindow that updates the position, size, shape, content and transparency of a multi-layered window. This function allows you to create a window based on the image, including PNG , taking into account the alpha channel. Creating a window shape based on a previously prepared image is much more convenient and easier than working with regions, but this method also has its drawback. It is not possible to display any components, such as buttons, text fields, etc., on a multi-layered window. This is a consequence of the fact that the operating system takes over the entire window redrawing process and the standard WM_PAINT message is no longer sent to the window. For the most part, all kinds of screensavers, widgets and other decorations do not require the presence of any additional components, or require them in a minimum number of, and therefore you can close your eyes to the disadvantage.

Example


Next, I would like to give a small clear example of the use of multilayer windows. Since it all comes down to calling API functions, a programming language can be any, but I have Visual Studio installed at work, so I will write in VB.NET . I will not describe the functions used by the API; I’d rather give below the links to the description from the MSDN site, since the purpose of the article is to show their practical application.

  1. First you need to draw our future window in your favorite graphics editor, I painted in Photoshop, always of irregular shape and always with transparency, in order to feel all the delights of multi-layered windows, and save it in PNG format . I got this sticker:
    image
  2. Next, we create a new project in Visual Studio and add our image to the resource under the name “Sticker”; in the only form in the project we remove all unnecessary headers and borders.
  3. You need to define the API functions and structures that will be needed in the process. I usually do this in a separate class.
     Namespace System Public Class Win32API Public Const WS_EX_LAYERED = &H80000 Public Const ULW_ALPHA As Int32 = &H2 Public Const AC_SRC_OVER As Byte = &H0 Public Const AC_SRC_ALPHA As Byte = &H1 ' ()' <StructLayout(LayoutKind.Sequential)> _ Public Structure Point Public x As Int32 Public y As Int32 Public Sub New(ByVal x As Int32, ByVal y As Int32) Me.x = x Me.y = y End Sub End Structure '' <StructLayout(LayoutKind.Sequential)> _ Public Structure Size Public cx As Int32 Public cy As Int32 Public Sub New(ByVal cx As Int32, ByVal cy As Int32) Me.cx = cx Me.cy = cy End Sub End Structure '     ' <StructLayout(LayoutKind.Sequential, Pack:=1)> _ Public Structure BLENDFUNCTION Public BlendOp As Byte Public BlendFlags As Byte Public SourceConstantAlpha As Byte Public AlphaFormat As Byte Public Sub New(ByVal BledOp As Byte, ByVal BlendFlags As Byte, ByVal SourceContrastAlpha As Byte, ByVal AlphaFormat As Byte) Me.BlendOp = BledOp Me.BlendFlags = BlendFlags Me.SourceConstantAlpha = SourceContrastAlpha Me.AlphaFormat = AlphaFormat End Sub End Structure '         ' <DllImport("user32.dll")> _ Public Shared Function GetDC(ByVal hWnd As IntPtr) As IntPtr End Function '     ' <DllImport("gdi32.dll")> _ Public Shared Function CreateCompatibleDC(ByVal hDC As IntPtr) As IntPtr End Function ' ' <DllImport("user32.dll", ExactSpelling:=True)> _ Public Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Integer End Function ' ' <DllImport("gdi32.dll")> _ Public Shared Function DeleteDC(ByVal hdc As IntPtr) As Boolean End Function '    ' <DllImport("gdi32.dll", ExactSpelling:=True)> _ Public Shared Function SelectObject(ByVal hDC As IntPtr, ByVal hObject As IntPtr) As IntPtr End Function ' ' <DllImport("gdi32.dll")> _ Public Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean End Function '  ' <DllImport("user32.dll")> _ Public Shared Function UpdateLayeredWindow(ByVal hwnd As IntPtr, ByVal hdcDst As IntPtr, ByRef pptDst As Win32API.Point, ByRef psize As Win32API.Size, ByVal hdcSrc As IntPtr, ByRef pprSrc As Win32API.Point, ByVal crKey As Int32, ByRef pblend As Win32API.BLENDFUNCTION, ByVal dwFlags As Int32) As Boolean End Function End Class End Namespace 

  4. We write this and all subsequent code to the class of our only form in the project. First you need to describe a few local variables, we need them in the process.
      Private _ScreenDC As IntPtr = IntPtr.Zero Private _MemDC As IntPtr = IntPtr.Zero Private _BitmapHandle As IntPtr = IntPtr.Zero Private _OldBitmapHandle As IntPtr = IntPtr.Zero Private _Size As Win32API.Size = Nothing Private _PoinSource As Win32API.Point = Nothing Private _TopPos As Win32API.Point = Nothing Private _Blend As Win32API.BLENDFUNCTION = Nothing Private _Opacity As Byte = 255 Private bmpDest As Bitmap = Nothing Private bmpSrc As Bitmap = Nothing 

  5. Making the window multi-layered. In .NET, you can assign some window properties just before creating it (calling the CreateWindowEx function API) by overriding the property of the CreateParams class.
      Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams Get Dim CP As CreateParams = MyBase.CreateParams CP.ExStyle = CP.ExStyle Or Win32API.WS_EX_LAYERED Return CP End Get End Property 

  6. Creating an update function for a multi-layered window based on the image and the degree of overall transparency (from 0 to 255).
      Public Sub SetImage(ByRef Bitmap As Bitmap, ByVal Opacity As Byte) '    ' _ScreenDC = Win32API.GetDC(0) '    ' _MemDC = Win32API.CreateCompatibleDC(_ScreenDC) ' ' _BitmapHandle = IntPtr.Zero '  ' _OldBitmapHandle = IntPtr.Zero Try '  ' _BitmapHandle = Bitmap.GetHbitmap(Color.FromArgb(0)) '     ' _OldBitmapHandle = Win32API.SelectObject(_MemDC, _BitmapHandle) '  ,      ' _Size = New Win32API.Size(Bitmap.Width, Bitmap.Height) _PoinSource = New Win32API.Point(0, 0) _TopPos = New Win32API.Point(Me.Left, Me.Top) '  BLENDFUNCTION' _Blend = New Win32API.BLENDFUNCTION(Win32API.AC_SRC_OVER, 0, Opacity, Win32API.AC_SRC_ALPHA) '  ' Win32API.UpdateLayeredWindow(Me.Handle, _ScreenDC, _TopPos, _Size, _MemDC, _PoinSource, 0, _Blend, Win32API.ULW_ALPHA) Finally Win32API.ReleaseDC(IntPtr.Zero, _ScreenDC) If _BitmapHandle <> IntPtr.Zero Then Win32API.SelectObject(_MemDC, _OldBitmapHandle) Win32API.DeleteObject(_BitmapHandle) End If Win32API.DeleteDC(_MemDC) _Size = Nothing _PoinSource = Nothing _TopPos = Nothing _Blend = Nothing End Try End Sub 

  7. When loading an instance of a form, we form an image (we write the text on a sticker, just a static) and then we transfer it to the update function.
      Private Sub FormSticker_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load bmpSrc = My.Resources. bmpDest = New Bitmap(bmpSrc.Width, bmpSrc.Height) Using g As Graphics = Graphics.FromImage(bmpDest) With g .InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor .SmoothingMode = Drawing2D.SmoothingMode.AntiAlias .TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias ' ' .DrawImage(bmpSrc, 0, 0, bmpSrc.Width, bmpSrc.Height) ' ' Dim sf As New StringFormat(StringFormatFlags.LineLimit) sf.Alignment = StringAlignment.Center sf.LineAlignment = StringAlignment.Center .DrawString("       ", Me.Font, New SolidBrush(Me.ForeColor), New Rectangle(10, 10, bmpDest.Width - 20, bmpDest.Height - 20), sf) End With End Using Me.SetImage(bmpDest, Me._Opacity) bmpDest.Dispose() End Sub 


Well, that seems to be all, we launch and see what we have done (the result on the first image).

Links

  1. Descriptions of the structures and functions used
    Point , Size , GetDC , ReleaseDC , DeleteDC , SelectObject , DeleteObject , UpdateLayeredWindow
  2. Sample Source

To be continued...

Source: https://habr.com/ru/post/126793/


All Articles