|
How to draw
a round-edge rectangle (lenght 200, height 30). Border color should be
white and the interior totally tansparent? Plus the borders should be
alpha-blended with smooth shadows / blurring effect? Is it possible to
create this using .NET's native GDI+? | | re infecta Friday, September 08, 2006 3:19 PM | The following piece of code will get you a rounded rectangle with a alpha blended white border:
protected override void OnPaint(PaintEventArgs e)
{
Rectangle b = new Rectangle(30, 30, 200, 30);
using (GraphicsPath path = new GraphicsPath(FillMode.Alternate))
{
path.AddArc(b.X, b.Y, 10, 10, 180, 90);
path.AddLine(b.X + 5, b.Y, b.X + b.Width - 5, b.Y);
path.AddArc(b.X + b.Width - 10, b.Y, 10, 10, 270, 90);
path.AddLine(b.X + b.Width, b.Y + 5, b.X + b.Width, b.Y + b.Height - 5);
path.AddArc(b.X + b.Width - 10, b.Y + b.Height - 10, 10, 10, 0, 90);
path.AddLine(b.X + b.Width - 5, b.Y + b.Height, b.X + 5, b.Y + b.Height);
path.AddArc(b.X, b.Y + b.Height - 10, 10, 10, 90, 90);
path.CloseFigure();
using (Pen pen = new Pen(Color.FromArgb(64, 255, 255, 255), 3.0f))
{
e.Graphics.DrawPath(pen, path);
}
}
}
I'm not sure what do you mean by "shadow" as for "blurring" that's not something you can achieve easily using GDI++. | | Mike Danes Saturday, September 09, 2006 9:39 PM | Thank you! Okay the shadow can be a tricky one, so I tried to approach this problem my using a transparent png file that represents the glass-like bar. Look at this example I made: example.gif. First there is the image in image editor (where you can see the complete transparency). The second is the goal I want to achieve: a form that is completely transparent so that the shadow of the bar looks smooth. The last image at the bottom is the current state (the problem). The image is in a picturebox that has the same background color as the form (white). White is set at the transparency key in order to make the form transparent. Opacity is 100 %. I think the problem is that the form is transparent only for one color (white) but the shadow has multiple shades of gray. How to achieve the goal and make the shadow look better? I would appreciate any help! I'm using VB.net. | | re infecta Sunday, September 10, 2006 9:46 AM | Yes, the problem is that the transparecy color is only one. You need per pixel alpha to achive what you want. See this Code Project page for a sample:
http://www.thecodeproject.com/cs/media/perpxalpha_sharp.asp
It's C#. If needed I can translate it to VB.NET.
Now I'm not sure what you're trying to do. If you're trying to do a Window Vista style window that has a glass border then you're pretty much out of luck. TransparencyKey can be used to make a non rectangular form, but not transparent regions. Opacity can be used to make the whole form transparent, but you need only the borders to be transparent. Per pixel alpha would work, but per pixel alpha forms don't display their child controls so they're sort of useless.
| | Mike Danes Sunday, September 10, 2006 11:44 AM | That article looks interesting and could work. I would be most grateful if you had time to translate that to VB.NET! I would like to set the png image as form's background in order to be able to put a textbox on it.
| | re infecta Sunday, September 10, 2006 1:06 PM | But I told you... any form child controls (including the TextBox) won't be visible. | | Mike Danes Sunday, September 10, 2006 1:56 PM | I'm sorry, I didn't understand the concept "child control". So there is no solution around this problem?
| | re infecta Sunday, September 10, 2006 2:17 PM | make the forms background color consistent, and then use that color as the background for the shadow in your image editor. | | Chris Rush Sunday, September 10, 2006 4:38 PM | Here's the translated version of the PerPixelAlphaForm. To use it call the SetBitmap function with your transparent image.
But as I already told you child controls won't be visibile so I don't know what good is it. The only thing that comes to my mind to make this work would be to show another form (that contains the textbox) on top of transparent form and try to move/resize/close those two forms together. That's not going to be very easy, if it works at all. On top of this all you should not expect to get very good performance if the form is large.
I hope I understood your problem correctly ...
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices
Public Class PerPixelAlphaForm
Inherits Form
Private Declare Auto Function GetDC Lib "user32.dll" (ByVal hWnd As IntPtr) As IntPtr
Private Declare Auto Function CreateCompatibleDC Lib "gdi32.dll" (ByVal hDC As IntPtr) As IntPtr
Private Declare Auto Function SelectObject Lib "gdi32.dll" (ByVal hDC As IntPtr, ByVal hObject As IntPtr) As IntPtr
Private Declare Auto Function UpdateLayeredWindow Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal hdcDst As IntPtr, ByRef pptDst As WIN32POINT, ByRef psize As WIN32SIZE, ByVal hdcSrc As IntPtr, ByRef pptSrc As WIN32POINT, ByVal crKey As Integer, ByRef pblen As BLENDFUNCTION, ByVal dwFlags As Integer) As Integer
Private Declare Auto Function ReleaseDC Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Integer
Private Declare Auto Function DeleteObject Lib "gdi32.dll" (ByVal hObject As IntPtr) As Boolean
Private Declare Auto Function DeleteDC Lib "gdi32.dll" (ByVal hDC As IntPtr) As Boolean
<StructLayout(LayoutKind.Sequential)> _
Private Structure WIN32POINT
Public x As Integer
Public y As Integer
Public Sub New(ByVal x As Integer, ByVal y As Integer)
Me.x = x
Me.y = y
End Sub
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure WIN32SIZE
Public cx As Integer
Public cy As Integer
Public Sub New(ByVal cx As Integer, ByVal cy As Integer)
Me.cx = cx
Me.cy = cy
End Sub
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Private Structure BLENDFUNCTION
Public BlendOp As Byte
Public BlendFlags As Byte
Public SourceConstantAlpha As Byte
Public AlphaFormat As Byte
End Structure
Public Sub SetBitmap(ByVal bitmap As Bitmap, ByVal opacity As Byte)
If (bitmap.PixelFormat <> PixelFormat.Format32bppArgb) Then
Throw New ArgumentException("The bitmap must be 32ppp with alpha-channel.", "bitmap")
End If
Dim hDCScreen As IntPtr = GetDC(IntPtr.Zero)
Dim hDCMemory As IntPtr = CreateCompatibleDC(hDCScreen)
Dim hBitmap As IntPtr = IntPtr.Zero
Dim hOldBitmap As IntPtr = IntPtr.Zero
Try
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0))
hOldBitmap = SelectObject(hDCMemory, hBitmap)
Dim size As New WIN32SIZE(bitmap.Width, bitmap.Height)
Dim pointSource As New WIN32POINT(0, 0)
Dim topPos As New WIN32POINT(Left, Top)
Dim blend As BLENDFUNCTION = New BLENDFUNCTION
blend.BlendOp = 0
blend.BlendFlags = 0
blend.SourceConstantAlpha = opacity
blend.AlphaFormat = 1
UpdateLayeredWindow(Handle, hDCScreen, topPos, size, hDCMemory, pointSource, 0, blend, 2)
Finally
ReleaseDC(IntPtr.Zero, hDCScreen)
If (hBitmap <> IntPtr.Zero) Then
SelectObject(hDCMemory, hOldBitmap)
DeleteObject(hBitmap)
End If
DeleteDC(hDCMemory)
End Try
End Sub
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim p As CreateParams = MyBase.CreateParams
p.ExStyle = (p.ExStyle Or &H80000)
Return p
End Get
End Property
Protected Overrides Sub WndProc(ByRef m As Message)
If (m.Msg = 132) Then
m.Result = CType(2, IntPtr)
Else
MyBase.WndProc(m)
End If
End Sub
End Class
| | Mike Danes Sunday, September 10, 2006 5:18 PM |
|