|
|
Used your code in my project, works flawless
Thank you!
|
|
|
|
|
I made an image in the GIMP and saved it as a transparent png but it isn't working?
I'm getting the "The bitmap must be 32ppp with alpha-channel." exception. How do I check to this? I've never hear of "ppp" before.
-Elmernite
After editing around I found that I need to set "Save color values from transparent pixels" With that checked it works.
modified on Thursday, December 17, 2009 11:37 AM
|
|
|
|
|
I think the author mis-typed bpp (Bits-Per-Pixel)... Gee
|
|
|
|
|
I noticed that anchoring doesnt work if you use PPAB,
I think its because of the way controls are drawn to bitmap, anchor offsets are not taken into account, Can you help me fix this ?
|
|
|
|
|
Is it possible to draw on that image ? say a rectangle ?
What is the way to access the pixel buffer and modify it ? rgba-wise
Would it take a double buffer for the drawing to avoid the flickering ?
tx
|
|
|
|
|
Here is a workaround:
...
class PerPixelAlphaForm : Form
{
<code>Timer _RefreshFormTimer = new Timer();</code>
public AlphaForm()
{
FormBorderStyle = FormBorderStyle.None;
<code>_RefreshFormTimer.Interval = 10;
_RefreshFormTimer.Tick += new EventHandler(RefreshFormTimer_Tick);
_RefreshFormTimer.Enabled = true;</code>
}
<code>private Bitmap _FormBitmap;
private byte _FormOpacity;
private void RefreshFormTimer_Tick(object sender, EventArgs e)
{
if (_FormBitmap != null)
SetBitmap(_FormBitmap, _FormOpacity);
}</code>
public void SetBitmap(Bitmap bitmap)
{
SetBitmap(bitmap, 255);
}
...
...
public void SetBitmap(Bitmap bitmap, byte opacity)
{
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
throw new ApplicationException("The bitmap must be 32ppp with alpha-channel.");
<code>_FormBitmap = bitmap;
_FormOpacity = opacity;</code>
IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr oldBitmap = IntPtr.Zero;
try {
<code>
foreach (Control ctrl in this.Controls)
ctrl.DrawToBitmap(bitmap, ctrl.Bounds);
</code>
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
oldBitmap = Win32.SelectObject(memDc, hBitmap);
Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);
Win32.Point pointSource = new Win32.Point(0, 0);
Win32.Point topPos = new Win32.Point(Left, Top);
Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();
...
Gottdrak99
modified on Thursday, November 27, 2008 3:22 AM
|
|
|
|
|
fantastic! exactly what i was looking for...
Small note: I also had to wrap a .Visible check around the .DrawToBitmap method to meet my requirements.
foreach (Control ctrl in this.Controls)
{<br />
if (ctrl.Visible) {
ctrl.DrawToBitmap(bitmap, ctrl.Bounds);
}<br />
}
|
|
|
|
|
With this solution (timer) how can you show a blinking caret in a textbox?
|
|
|
|
|
Great addition!
One could also add in front of
_FormBitmap = bitmap; to do that only if
_FormBitmap is null.
Thatway, if you change for example Text on Label with transparent background, it won't be mixed.
|
|
|
|
|
This is not really a workaround. You are just rastering the controls to the background image. There is no independent relationship for any sort of a control. You are relying on the alpha channel to be blended based on its opaqueness rather than the opacity in conjunction with properties of a control itself.
I think there needs to be some different means to achieve a more practical solution. Have your alpha form as background and a separate transparent form with all your controls sync'd with the movement of the underlying form. Your going to have to layer the forms accordingly and preserve the ordering amongst other open windows.
I just can't believe they still haven't put anything for this in GDI+ or WF in VS11b and expect us to interop with Win32 which doesn't make things easy for many. You do realize that even the resources can't even be imported correctly without losing the alpha channel? Still no fix, M$ cherry picks every single thing known to man and it's not that hard to fix simple issues.
Good idea and I like the button images even though they arn't actual buttons or controls. Let us know if you get a fix or update/thread/link that shows us your new research, otherwise now might be a good time to switch to WPF since beta x11/12 is not showing any easy way to do what we really want in WF.
Meanwhile, take a look at this recommendation: Here which then leads to the CodeProject found There
-Latency
|
|
|
|
|
|
Hi,
I'm looking for a function simular as this code.
But I don't need a transparent form - I just need a transparent control inside a form.
Maybe somebody can help.
Thanks,
Andre
|
|
|
|
|
good idea would be extend form class and put there Your implementation. It inherits Control internally, so there will be no problem.
|
|
|
|
|
just great!
peace & serenity
|
|
|
|
|
why using old win32 with .net and c#...? get rid of those old gdi handles...
|
|
|
|
|
because you cant update a layered window using a gdi+ bitmap....
|
|
|
|
|
How would I get this working with VB.Net 2005?
|
|
|
|
|
Class:
<br />
Imports System<br />
Imports System.Drawing<br />
Imports System.Drawing.Imaging<br />
Imports System.Windows.Forms<br />
Imports System.Runtime.InteropServices<br />
'Translation from C# by Dj Den4ik<br />
Public Class PerPixelAlphaForm<br />
'Implements Windows.Forms.IWin32Window<br />
<br />
Public Structure ARGB<br />
Public Blue As Byte<br />
Public Green As Byte<br />
Public Red As Byte<br />
Public Alpha As Byte<br />
End Structure<br />
<br />
Public Structure BLENDFUNCTION<br />
Public BlendOp As Byte<br />
Public BlendFlags As Byte<br />
Public SourceConstantAlpha As Byte<br />
Public AlphaFormat As Byte<br />
End Structure<br />
<br />
Public Const ULW_COLORKEY As Int32 = &H1<br />
Public Const ULW_ALPHA As Int32 = &H2<br />
Public Const ULW_OPAQUE As Int32 = &H4<br />
<br />
Public Const AC_SRC_OVER As Byte = &H0<br />
Public Const AC_SRC_ALPHA As Byte = &H1<br />
<br />
Public Declare Function UpdateLayeredWindow Lib "user32" Alias "UpdateLayeredWindow" (ByVal hwnd As IntPtr, ByVal hdcDst As IntPtr, ByRef pptDst As Point, ByRef psize As Size, ByVal hdcSrc As IntPtr, ByRef pprSrc As Point, ByVal crKey As Int32, ByRef pblend As BLENDFUNCTION, ByVal dwFlags As Int32) As Boolean<br />
Public Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hWnd As IntPtr) As IntPtr<br />
Public Declare Function ReleaseDC Lib "user32" Alias "ReleaseDC" (ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Integer<br />
Public Declare Function CreateCompatibleDC Lib "gdi32.dll" Alias "CreateCompatibleDC" (ByVal hDC As IntPtr) As IntPtr<br />
Public Declare Function DeleteDC Lib "gdi32.dll" Alias "DeleteDC" (ByVal hDC As IntPtr) As Boolean<br />
Public Declare Function SelectObject Lib "gdi32.dll" Alias "SelectObject" (ByVal hDC As IntPtr, ByVal hObject As IntPtr) As IntPtr<br />
Public Declare Function DeleteObject Lib "gdi32.dll" Alias "DeleteObject" (ByVal hObject As IntPtr) As Boolean<br />
<br />
Public Sub SetBitmap(ByVal bitmap As Bitmap, ByVal opacity As Byte, ByVal frm As Form)<br />
If bitmap.PixelFormat <> PixelFormat.Format32bppArgb Then Throw New ApplicationException("The bitmap must be 32ppp with alpha-channel.")<br />
<br />
' The ideia of this is very simple,<br />
' 1. Create a compatible DC with screen;<br />
' 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;<br />
' 3. Call the UpdateLayeredWindow.<br />
<br />
Dim screenDc As IntPtr = GetDC(IntPtr.Zero)<br />
Dim memDc As IntPtr = CreateCompatibleDC(screenDc)<br />
Dim hBitmap As IntPtr = IntPtr.Zero<br />
Dim oldBitmap As IntPtr = IntPtr.Zero<br />
<br />
Try<br />
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)) ' grab a GDI handle from this GDI+ bitmap<br />
oldBitmap = SelectObject(memDc, hBitmap)<br />
Dim size As New Size(bitmap.Width, bitmap.Height)<br />
Dim pointSource As New Point(0, 0)<br />
Dim topPos As New Point(frm.Left, frm.Top)<br />
Dim blend As New BLENDFUNCTION<br />
blend.BlendOp = AC_SRC_OVER<br />
blend.BlendFlags = 0<br />
blend.SourceConstantAlpha = opacity<br />
blend.AlphaFormat = AC_SRC_ALPHA<br />
UpdateLayeredWindow(frm.Handle, screenDc, topPos, size, memDc, pointSource, 0, blend, ULW_ALPHA)<br />
Finally<br />
ReleaseDC(IntPtr.Zero, screenDc)<br />
If hBitmap <> IntPtr.Zero Then<br />
SelectObject(memDc, oldBitmap)<br />
DeleteObject(hBitmap)<br />
End If<br />
DeleteDC(memDc)<br />
<br />
End Try<br />
End Sub<br />
Form:
<br />
Dim ppaf As New PerPixelAlphaForm<br />
Dim bmp As New Bitmap("D:\Audio\FL Studio 7\Artwork\FL Studio Producer Edition\Title_.png")<br />
<br />
Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams<br />
Get<br />
Dim SecPerm As New Security.Permissions.SecurityPermission(Security.Permissions.PermissionState.Unrestricted)<br />
SecPerm.Demand()<br />
<br />
' Extend the CreateParams property of the Button class.<br />
Dim cp As System.Windows.Forms.CreateParams = MyBase.CreateParams<br />
' Update the button Style.<br />
cp.ExStyle = &H80000<br />
<br />
Return cp<br />
End Get<br />
End Property<br />
<br />
Private Sub frmTest_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load<br />
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None<br />
Me.TopMost = True<br />
For Each ctrl As Control In Me.Controls<br />
ctrl.DrawToBitmap(bmp, ctrl.Bounds)<br />
Next<br />
Me.Region = New Region()<br />
ppaf.SetBitmap(bmp, 240, Me)<br />
End Sub<br />
<br />
<br />
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)<br />
<br />
Const WM_MOUSEMOVE As Int32 = &H200<br />
Const WM_NCLBUTTONDOWN As Int32 = &HA1<br />
Const HTCAPTION As Int32 = 2<br />
<br />
'// ????????????? WM_MOUSEMOVE <br />
If m.Msg = WM_MOUSEMOVE Then<br />
<br />
'
MyBase.Capture = False<br />
<br />
'// ??????? ???? ????????? <br />
Dim message As New Message<br />
With message<br />
.HWnd = Me.Handle<br />
.Msg = WM_NCLBUTTONDOWN<br />
.WParam = HTCAPTION<br />
.LParam = 0&<br />
End With<br />
<br />
'
MyBase.WndProc(message)<br />
End If<br />
<br />
MyBase.WndProc(m)<br />
<br />
End Sub<br />
|
|
|
|
|
|
personally, however, I'd drop VB.NET and move to C# like most eventually do ... including me
|
|
|
|
|
Simply the BEST!! Many thanks, Rui!!!
|
|
|
|
|
Add some controls to overlay transparent form and avoid refreshing it's content with common Refresh()/Invalidate() methods,
use UpdateLayeredWindow() instead. For correct controls rendering add code like
Bitmap temp_bmp = new Bitmap(bitmap);
foreach (Control ctrl in this.Controls)
{
ctrl.DrawToBitmap(temp_bmp, ctrl.Bounds);
}
hBitmap = temp_bmp.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap
to the PerPixelAlphaForm::SetBitmap() method. Every System.Windows.Forms controlhas method DrawToBitmap().
Actually, i used this way to render simple controls - labels, i don't know would it work with more complex
user controls, but i can't see why it should not
|
|
|
|
|
Thanks, I was wondering about this.
Works perfectly
Edit: Ok, I take that back sorta.. The actual clickable region is MUCH smaller than the visible control (a button in this case)...
modified on Sunday, August 24, 2008 2:37 PM
|
|
|
|
|
Thanks, this is just what I needed to complete my design. It appeared that the bitmap was not getting refreshed each time the procedure was called. The actual Form.BackgroundImage needs to be present underneath so the region cut out from your controls, e.g. so this background image can bleed through around the controls.
In order to achieve transparency of the form controls, just override the controls in question and make sure that the regions are set to the way you need along with the ctrl.BackColor = Color.Transparent.
Without spending too much time on this, ensure that the 'bitmap' you are using originated from the 'this.BackgroundImage' build-in Form property.
<br />
public void SetBitmap(Bitmap bitmap, byte opacity = 255) {<br />
}<br />
So just I just changed all references outside this function and used the pre-existing container for the Bitmap/Image with one already build into the Form control itself.
So what you get is something like this: <substitued class="" name="" mainform="" from="" perpixelalphaform="">
partial class MainForm: Form
{
Bitmap bkgrnd = null;
...
public MainForm()
{
InitializeComponent();
bkgrnd = lib.LoadBitmapResource(2005);
this.BackgroundImage = bkgrnd;
this.CenterToScreen();
}
...
private void RefreshFormTimer_Tick(object sender, EventArgs e)
{
if (bkgrnd != null)
SetBitmap(bkgrnd);
}
-Latency
modified on Monday, January 24, 2011 5:52 AM
|
|
|
|
|