[C#] GDI+能实现PNG格式背景图片的透明吗

[C#] GDI+能实现PNG格式背景图片的透明吗

[C#] GDI+能实现PNG格式背景图片的透明吗


  能实现,以下为步骤:
  1、IntPtr代表指针变量,是c#的基本类型。
  2、BLENDFUNCTION是我定义的结构体,用于对应UpdateLayeredWindow这个API函数的BLENDFUNCTION类型参数:定义如下,UpdateLayeredWindow函数下面有说。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BLENDFUNCTION
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}
  3、SelectObject是API函数,这里把其作为常函数定义在Win32API这个类里面,作用是将对象选进DC。具体怎么在c#里面引用API函数,可以参考MSDN
  [DllImport(“gdi32.dll“, ExactSpelling = true)]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
  4、UpdateLayeredWindow也是API函数,定义在Win32API这个类里面,作用是把设置窗口的透明度或透明方式(Alapha还是透明指定颜色),下面是这个函数在c#里面引用的方法。
[DllImport(“user32.dll“, ExactSpelling = true, SetLastError = true)]
public static extern Bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);
  5、createParams.ExStyle |= 0x80000;是为了把窗口设为Layer窗口,一定要设置这个,不然窗口无法透明。其实这是API里面的CreateWindowEx函数创建窗口时用的扩展属性,可以参考MSDN。

C# 透明窗体


迅雷那个窗体应该重绘了窗体的标题栏和边框,重绘标题栏的代码网上很多但只是覆盖在原来那个上面而不是替换它,替换的代码我没有找到,不过你要是只想实现这个功能的话,我知道是有一个另类的方法,就是用两个窗体一个当标题栏和边框另一个当显示区域,代码如下

using System.Runtime.InteropServices;

[DllImport(“user32.dll“, EntryPoint = “GetWindowLong“)]

        public static extern int GetWindowLong(IntPtr hwnd, int nIndex);

        [DllImport(“User32.dll“, CharSet = CharSet.Auto)]

        public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

        TestForm test = new TestForm();

        private void button1_Click(object sender, EventArgs e)

        {

            this.Location = new Point(100,200);

            test.FormBorderStyle = FormBorderStyle.None;

            test.StartPosition = FormStartPosition.Manual;

            test.TopMost = true;

            test.ShowInTaskbar = false;//在任务栏里隐藏test

            int value = GetWindowLong(test.Handle, (-20));

            SetWindowLong(test.Handle, (-20), value | 0x00000080);//在Alt+Tab里隐藏test

            test.Location = new Point(this.Left + (this.Width - test.Width) / 2, this.Top + (this.Height - test.Height) / 2);

            test.Show();

        }

        private void Form1_Load(object sender, EventArgs e)

        {

            this.FormBorderStyle = FormBorderStyle.None;

            this.Opacity = 0.7;

            this.Activated += new EventHandler(Form1_Activated);

            this.Deactivate += new EventHandler(Form1_Deactivate);

        }

        void Form1_Activated(object sender, EventArgs e)

        {

            test.TopMost = true;

        }

        void Form1_Deactivate(object sender, EventArgs e)

        {

            test.TopMost = false;

        }


VB图片快速透明处理


很简单,使用GDI的AlphaBlend函数就可以。可以设置全局Alpha混合系数(0到255),也可以混合带有Alpha通道的32位BMP。
如果要做稍复杂的处理,可以使用GDI+,里面的所有绘图手段都支持Alpha通道。
附AlphaBlend函数在VB中的声明:
Public Type t_BLENDFUNCTION
BlendOp As Byte
BlendFlags As Byte
SourceConstantAlpha As Byte
AlphaFormat As Byte
End Type
Public Declare Function AlphaBlend Lib “msimg32“ (ByVal hDestDC As Long, _
ByVal xDest As Long, _
ByVal yDest As Long, _
ByVal nWidthDest As Long, _
ByVal nHeightDest As Long, _
ByVal hSrcDC As Long, _
ByVal xSrc As Long, _
ByVal ySrc As Long, _
ByVal nWidthSrc As Long, _
ByVal nHeightSRC As Long, _
ByVal BLENDFUNCTION As Long) As Long

如何使用win32中新增的gdi对象


1.如何让界面绚丽?
怎么样的算绚丽?有很漂亮的图片?有Alpha透明?有Animation?
每个人的审美观点都不同,所以如果你的界面很多人认为绚丽那就可以了。设计界面主要是Designer的工作,包括UI逻辑的设计,色彩搭配设计等,我认为这也可以进一步分工:熟悉用户习惯的Designer、美学Designer等。但是一般情况下这些让程序员给代劳了。
下面介绍Windows提供给开发人员的相关接口,利用这些接口设计你认为绚丽的界面。
2.如何透明?如何半透明?如何颜色渐变?
以下是我使用Imaging COM组件封装的一个函数,可以使用其绘制PNG图片,当然也可以绘制其它图片。绘制带Alpha通道的PNG图片即实现了透明。
#include 《imaging.h》
#include 《initguid.h》
#include 《imgguids.h》
#pragma comment(lib, “Imaging.lib“)
BOOL DrawPNG(HDC hDC, TCHAR *szPicString, RECT &rcDraw)
{
BOOL br = FALSE;
IImagingFactory *pImgFactory = NULL;
IImage *pImage = NULL;
ImageInfo sImgInfo;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
// Create the imaging factory.
if (SUCCEEDED(CoCreateInstance(CLSID_ImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IImagingFactory,
(void **)&pImgFactory)))
{
// Load the image from the JPG file.
if (SUCCEEDED(pImgFactory-》CreateImageFromFile(
szPicString,
&pImage)))
{
// Draw the image.
pImage-》Draw(hDC, &rcDraw, NULL);
pImage-》Release();
pImage = NULL;
br = TRUE;
}
pImgFactory-》Release();
}
CoUninitialize();
return br;
}
------------------------------------------------------------------------------------------------------
而封装的这个函数实现了将一个DC根据Alpha值半透明绘制到另一个DC上,使用GDI函数AlphaBlend实现。
BOOL AlphaBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest,
int nWidthDest, int nHeightDest,
HDC hdcSrc, int nXOriginSrc, int nYoriginSrc,
int nWidthSrc, int nHeightSrc,
BYTE alpha) {
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = alpha;
bf.AlphaFormat = 0;
return AlphaBlend(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
hdcSrc, nXOriginSrc, nYoriginSrc, nWidthSrc, nHeightSrc, bf);
}
如果你的设备支持AlphaBlend硬件加速那将是非常棒的事情,否则软件方式会有点影响性能。
------------------------------------------------------------------------------------------------------
颜色渐变也是直接有API可以支持:
BOOL GradientFill(
HDC hdc,
PTRIVERTEX pVertex,
ULONG nVertex,
PVOID pMesh,
ULONG nCount,
ULONG ulMode
);
hdc
[in] Handle to the destination device context.
pVertex
[in] Pointer to an array of TRIVERTEX structures, each of which defines a triangle vertex.
nVertex
[in] The number of vertices in pVertex.
pMesh
[in] Array of GRADIENT_RECT structures in rectangle mode.
nCount
[in] The number of rectangles in pMesh.
ulMode
[in] Specifies gradient fill mode. The following table shows the possible values for ulMode.
This function fills rectangular regions with a background color that is interpolated from color values specified at the vertices.
不管你使用.Net CF平台调用这些API,还是Win32/MFC/ATL/WTL直接调用这些API,你都是可以实现这些效果的。更多内容请查询开发文档,毕竟那才是最好的参考资料。
3.如何实现动画?
动画的原理就是一帧一帧的画面按照时间轴向后移动,在骗过眼睛之后就成了动画,所以你得到动画最简单的方法就是按照一定间隔将不同图片一张一张绘制到屏幕上,虽然很简单,但是在编程中经常使用这种方法。有时简单的往往是最好的。
这里还有个技巧,比如将每张图片使用Photoshop中的运动滤镜模糊下,这样使用上面方法得到的动画会有种非常快速的感觉。也可以用类似的方法来用2D表现三维的事物,得到3D动画的效果。
还可以使用GIF动画的方式,比如在开机和关机时。以下封装的函数仅供参考,我没用心整理。
BOOL DisplayGIF(TCHAR *szPicString)
{
HANDLE hFile = CreateFile(strFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return FALSE;
}
DWORD dwFileSize = GetFileSize(hFile, NULL);
if ( (DWORD)-1 == dwFileSize )
{
CloseHandle(hFile);
return FALSE;
}
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize);
if (hGlobal == NULL)
{
CloseHandle(hFile);
return FALSE;
}
LPVOID pvData = GlobalLock(hGlobal);
if (pvData == NULL)
{
GlobalUnlock(hGlobal);
CloseHandle(hFile);
return FALSE;
}
DWORD dwBytesRead = 0;
BOOL bRead = ReadFile(hFile, pvData, dwFileSize, &dwBytesRead, NULL);
GlobalUnlock(hGlobal);
CloseHandle(hFile);
if (!bRead)
{
return FALSE;
}
IStream* pStream = NULL;
if ( FAILED(CreateStreamOnHGlobal(hGlobal, TRUE, &pStream)) )
{
return FALSE;
}
IImage *pImage = NULL;
RECT rc;
IImagingFactory *pImgFactory = NULL;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
if ( !SUCCEEDED(CoCreateInstance(CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void **)&pImgFactory)) )
{
return FALSE;
}
IImageDecoder* pDecoder = NULL;
UINT nCount = 0;
if ( !SUCCEEDED(pImgFactory-》CreateImageDecoder(pStream, DecoderInitFlagNone, &pDecoder)) )
{
return FALSE;
}
pDecoder-》GetFrameDimensionsCount(&nCount);
GUID *pDimensionIDs = (GUID*)new GUID[nCount];
pDecoder-》GetFrameDimensionsList(pDimensionIDs,nCount);
TCHAR strGuid;
StringFromGUID2(pDimensionIDs, strGuid, 39);
UINT frameCount = 0;
pDecoder-》GetFrameCount(&pDimensionIDs,&frameCount);
UINT iSize = 0;
pDecoder-》GetPropertyItemSize(PropertyTagFrameDelay,&iSize);
BYTE* pBuff = new BYTE[iSize];
PropertyItem* pItem = (PropertyItem*)pBuff;
pDecoder-》GetPropertyItem(PropertyTagFrameDelay,iSize,pItem);
int fCount = 0;
ImageInfo Info;
pImgFactory-》CreateImageFromStream(pStream,&pImage);
pImage-》GetImageInfo(&Info);
rc.left = rc.top = 0;
rc.right = Info.Width;
rc.bottom = Info.Height;
HDC tempDC;
HBITMAP hbmNew = NULL;
void * pv;
BITMAPINFO bmi = { 0 };
HBITMAP hbmOld = NULL;
tempDC = CreateCompatibleDC(NULL);
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = Info.Width;
bmi.bmiHeader.biHeight = Info.Height;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = (SHORT) max(16, GetDeviceCaps(tempDC, BITSPIXEL));
bmi.bmiHeader.biCompression = BI_RGB;
hbmNew = CreateDIBSection(tempDC, &bmi, DIB_RGB_COLORS, &pv, NULL, 0);
hbmOld = (HBITMAP)SelectObject(tempDC, hbmNew);
pImage-》Draw(tempDC, &rc, NULL);
pDecoder-》SelectActiveFrame(&pDimensionIDs, ++fCount);
BitBlt(g_hdc, 0, 0, rc.right - rc.left, rc.bottom - rc.top, tempDC, 0, 0, SRCCOPY);
delete pBuff;
delete pDimensionIDs;
pDecoder-》Release();
pImage-》Release();
pImgFactory-》Release();
CoUninitialize();
return TRUE;
}
4.如何有较高的运行效率?
后面的内容会介绍到使用GDI这些“较高层次”的接口是很难有较高的运行效率。
但是可以使用一些技巧,比如“空间换取时间”。相信“Lazy Computation”你有听过,延迟处理这项任务直到真正需要的时候(在编程中我们也会经常用到,需要有这个意识。)这里使用的技巧有点恰恰相反的味道,把用户将来很可能用到的地方先处理好,然后储存起来,而并不是等到用户真正需要的时候才去处理。
比如使用Imaging COM组件绘制PNG图片时,每次都需要加载组件的库文件,然后卸载,界面可能要反复刷新,然后反复绘制PNG图片。这时可以考虑在程序启动的时候使用非界面主线程将绘制好的PNG图片保存起来(比如以Device Context的形式),界面刷新的时候仅仅是BitBlt到目标设备。BitBlt的效率是比较高的,如果仍然不能满足你的效率要求,可以考虑下面介绍的DirectDraw等技术。
上面的方法对于具有丰富开发经验的应该比较清楚,但是新手往往会忽略。在开发界面时我们要保证一个基本原则:想尽一切办法在现有的条件下提高界面响应用户的速度,界面要以用户为中心。所以开发时需要保持这个意识。
5.如何提高程序启动速度?
第4部分说过,为了提高运行效率,可以将常用的界面在程序启动时一起缓存到内存中,那么程序的启动时间会大大增加,如何解决这个问题?我的建议是UI主线程仅仅加载少量的用户启动后直接就能看到的界面,而另起一个子线程(叫A)用于加载其它界面,其它界面加载完之后这个子线程退出,当用户点击其它界面时,主线程如果发现子线程A并没有退出,说明其它界面还没有加载完,让用户等待。
这么设计的好处是,将最耗时的任务分摊出去,即能保证了用户快速看到界面,又能在之后的运行中有较高的效率。
6.如何在绚丽和效率之间平衡?
最好的方法是得到界面运行时具体的时间消耗数据,如果必要可以精确到每个函数。得到一份系统正常情况下的数据,得到几份环境恶劣情况下的数据(比如系统非常繁忙、设备电量很少、要处理的数据非常多等)。定量的去分析解决这些问题。如果在恶劣的环境下你的绚丽界面表现的仍然不错,恭喜你,你太棒了!
Windows CE/Windows Mobile也提供了些基本的Performance API(像DirectDraw等技术还有自己的Performance接口和工具):
BOOL QueryPerformanceCounter(
LARGE_INTEGER* lpPerformanceCount
);
lpPerformanceCount
[in] Pointer to a variable that the function sets, in counts, to the current performance-counter value. If the installed hardware does not support a high-resolution performance counter, this parameter can be set to zero.
This function retrieves the current value of the high-resolution performance counter if one is provided by the OEM.
BOOL QueryPerformanceFrequency(
LARGE_INTEGER* lpFrequency
);
lpFrequency
[out] Pointer to a variable that the function sets, in counts per second, to the current performance-counter frequency. If the installed hardware does not support a high-resolution performance counter, the value passed back through this pointer can be zero.
This function retrieves the frequency of the high-resolution performance counter if one is provided by the OEM.
上面两个API需要OEM在OAL层提供实现,精度可以低于1ms,否则可以使用下面的API。
DWORD GetTickCount(void);
For Release configurations, this function returns the number of milliseconds since the device booted, excluding any time that the system was suspended. GetTickCount starts at zero on boot and then counts up from there.
For debug configurations, 180 seconds is subtracted from the the number of milliseconds since the device booted. This enables code that uses GetTickCount to be easily tested for correct overflow handling.
另外优化PNG、Bitmap、GIF等图片,让图片清晰度和大小刚好满足要求。
7.控件为什么如此降低运行效率?怎样减少控件的使用?
手机软件不同于桌面系统软件,一方面手机的处理速度更低、电池容量更小,另一方面用户会使用手机处理更紧急的事情。所以这也是我认为 不应该完全把桌面系统软件开发经验借鉴到手机软件开发上的原因。一个240x320分辨率大小的手机界面,你给放上5、6个控件,甚至更多,这个界面注定不会太高效率,这样的界面也不适合作为用户最常用的界面,比如今日界面。另一方面,Windows的标准、通用控件不会有太绚丽的外观,即使自定义的。但是这些控件能够带来很明显的开发速度。所以我们要协调好。不能为了窗口而窗口,更不能一切皆窗口。
那么你会问如何协调。我的建议是能不用控件的地方就不要用,大多地方可以直接使用图片,比如实现多状态按钮你可以这样做:
WM_LBUTTONDOWN消息处理里面先判断Point是否在按钮的Rect中,如果是将按下状态的图片DC BitBlt到屏幕对应位置,WM_LBUTTONUP消息处理里面再BitBlt回来。
8.基于Win32的界面运行效率比基于.Net CF高,但是开发效率低,怎么办?
Win32编程已经很古老、很“落后”了。但是在处理速度还不及奔三的Windows嵌入式设备上有时你不得不选择。把界面常用的功能代码封装成库(类库也可以),积累这样的资源可以提高团队的开发效率。C++泛型编程就是以牺牲编译时效率换取代码重用,但是不影响运行时效率,值得去深入学习下,而且有现成的库可用,比如STL。
还有其它的技术可供选择:DirectDraw(后面介绍的)、Direct3DM、OpenGL ES等。但是开发难度较高。
9.如何使用GDI+(Native/Managed)?
GDI+是GDI的下一个版本,它进行了很好的改进,并且易用性更好。GDI的一个好处就是你不必知道任何关于数据怎样在设备上渲染的细节,GDI+更好的实现了这个优点,也就是说,GDI是一个中低层API,你还可能要知道设备,而GDI+是一个高层的API,你不必知道设备。
Windows CE/Windows Mobile下的GDI+仅仅是Windows桌面系统的一个很小的子集。OpenNETCF中封装了GDI+,可以为基于.Net CF的开发者提供便利,微软提供的Native Code版本就是前面有提到的Imaging COM组件,你也可以直接调用gdiplus.dll里面的类和方法。网上已经有人将Windows CE版本GDI+不支持的部分桌面系统版本GDI+的功能整理进来,你可以使用其提供的Lib库和头文件进行开发。但可能不是很稳定。

怎么调用user32.dll函数


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace WindowsAPI
{
class CSharp_Win32Api
{
#region User32.dll 函数
/// 《summary》
/// 该函数检索一指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄,以后可以在GDI函数中使用该句柄来在设备上下文环境中绘图。hWnd:设备上下文环境被检索的窗口的句柄
/// 《/summary》
[DllImport(“user32.dll“, CharSet = CharSet.Auto)]
public static extern IntPtr GetDC(IntPtr hWnd);
/// 《summary》
/// 函数释放设备上下文环境(DC)供其他应用程序使用。
/// 《/summary》
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
/// 《summary》
/// 该函数返回桌面窗口的句柄。桌面窗口覆盖整个屏幕。
/// 《/summary》
static public extern IntPtr GetDesktopWindow();
/// 《summary》
/// 该函数设置指定窗口的显示状态。
/// 《/summary》
static public extern bool ShowWindow(IntPtr hWnd, short State);
/// 《summary》
/// 通过发送重绘消息 WM_PAINT 给目标窗体来更新目标窗体客户区的无效区域。
/// 《/summary》
static public extern bool UpdateWindow(IntPtr hWnd);
/// 《summary》
/// 该函数将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。
/// 《/summary》
static public extern bool SetForegroundWindow(IntPtr hWnd);
/// 《summary》
/// 该函数改变一个子窗口,弹出式窗口式顶层窗口的尺寸,位置和Z序。
/// 《/summary》
static public extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int Width, int Height, uint flags);
/// 《summary》
/// 打开剪切板
/// 《/summary》
static public extern bool OpenClipboard(IntPtr hWndNewOwner);
/// 《summary》
/// 关闭剪切板
/// 《/summary》
static public extern bool CloseClipboard();
/// 《summary》
/// 打开清空《/summary》
static public extern bool EmptyClipboard();
/// 《summary》
/// 将存放有数据的内存块放入剪切板的资源管理中
/// 《/summary》
static public extern IntPtr SetClipboardData(uint Format, IntPtr hData);
/// 《summary》
/// 在一个矩形中装载指定菜单条目的屏幕坐标信息
/// 《/summary》
static public extern bool GetMenuItemRect(IntPtr hWnd, IntPtr hMenu, uint Item, ref RECT rc);
[DllImport(“user32.dll“, ExactSpelling = true, CharSet = CharSet.Auto)]
/// 《summary》
/// 该函数获得一个指定子窗口的父窗口句柄。
/// 《/summary》
public static extern IntPtr GetParent(IntPtr hWnd);
/// 《summary》
/// 该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。
/// 《/summary》
/// 《param name=“hWnd“》其窗口程序将接收消息的窗口的句柄《/param》
/// 《param name=“msg“》指定被发送的消息《/param》
/// 《param name=“wParam“》指定附加的消息指定信息《/param》
/// 《param name=“lParam“》指定附加的消息指定信息《/param》
/// 《returns》《/returns》
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
public static extern void SendMessage(IntPtr hWnd, int msg, int wParam, ref RECT lParam);
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref POINT lParam);
public static extern void SendMessage(IntPtr hWnd, int msg, int wParam, ref TBBUTTON lParam);
public static extern void SendMessage(IntPtr hWnd, int msg, int wParam, ref TBBUTTONINFO lParam);
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref REBARBANDINFO lParam);
public static extern void SendMessage(IntPtr hWnd, int msg, int wParam, ref TVITEM lParam);
public static extern void SendMessage(IntPtr hWnd, int msg, int wParam, ref LVITEM lParam);
public static extern void SendMessage(IntPtr hWnd, int msg, int wParam, ref HDITEM lParam);
public static extern void SendMessage(IntPtr hWnd, int msg, int wParam, ref HD_HITTESTINFO hti);
/// 《summary》
/// 该函数将一个消息放入(寄送)到与指定窗口创建的线程相联系消息队列里
/// 《/summary》
public static extern IntPtr PostMessage(IntPtr hWnd, int msg, int wParam, int lParam);
public static extern IntPtr SetWindowsHookEx(int hookid, HookProc pfnhook, IntPtr hinst, int threadid);
[DllImport(“user32.dll“, CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool UnhookWindowsHookEx(IntPtr hhook);
[DllImport(“user32.dll“, CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhook, int code, IntPtr wparam, IntPtr lparam);
/// 《summary》
/// 该函数对指定的窗口设置键盘焦点。
/// 《/summary》
public static extern IntPtr SetFocus(IntPtr hWnd);
/// 《summary》
/// 该函数在指定的矩形里写入格式化文本,根据指定的方法对文本格式化(扩展的制表符,字符对齐、折行等)。
/// 《/summary》
public extern static int DrawText(IntPtr hdc, string lpString, int nCount, ref RECT lpRect, int uFormat);
/// 《summary》
/// 该函数改变指定子窗口的父窗口。
/// 《/summary》
public extern static IntPtr SetParent(IntPtr hChild, IntPtr hParent);
/// 《summary》
/// 获取对话框中子窗口控件的句柄
/// 《/summary》
public extern static IntPtr GetDlgItem(IntPtr hDlg, int nControlID);
/// 《summary》
/// 该函数获取窗口客户区的坐标。
/// 《/summary》
public extern static int GetClientRect(IntPtr hWnd, ref RECT rc);
/// 《summary》
/// 该函数向指定的窗体添加一个矩形,然后窗口客户区域的这一部分将被重新绘制。
/// 《/summary》
public extern static int InvalidateRect(IntPtr hWnd, IntPtr rect, int bErase);
/// 《summary》
/// 该函数产生对其他线程的控制,如果一个线程没有其他消息在其消息队列里。
/// 《/summary》
public static extern bool WaitMessage();
/// 《summary》
/// 该函数为一个消息检查线程消息队列,并将该消息(如果存在)放于指定的结构。
/// 《/summary》
public static extern bool PeekMessage(ref MSG msg, int hWnd, uint wFilterMin, uint wFilterMax, uint wFlag);
/// 《summary》
/// 该函数从调用线程的消息队列里取得一个消息并将其放于指定的结构。此函数可取得与指定窗口联系的消息和由PostThreadMesssge寄送的线程消息。此函数接收一定范围的消息值。
/// 《/summary》
public static extern bool GetMessage(ref MSG msg, int hWnd, uint wFilterMin, uint wFilterMax);
/// 《summary》
/// 该函数将虚拟键消息转换为字符消息。
/// 《/summary》
public static extern bool TranslateMessage(ref MSG msg);
/// 《summary》
/// 该函数调度一个消息给窗口程序。
/// 《/summary》
public static extern bool DispatchMessage(ref MSG msg);
/// 《summary》
/// 该函数从一个与应用事例相关的可执行文件(EXE文件)中载入指定的光标资源.
/// 《/summary》
public static extern IntPtr LoadCursor(IntPtr hInstance, uint cursor);
/// 《summary》
/// 该函数确定光标的形状。
/// 《/summary》
public static extern IntPtr SetCursor(IntPtr hCursor);
/// 《summary》
/// 确定当前焦点位于哪个控件上。
/// 《/summary》
public static extern IntPtr GetFocus();
/// 《summary》
/// 该函数从当前线程中的窗口释放鼠标捕获,并恢复通常的鼠标输入处理。捕获鼠标的窗口接收所有的鼠标输入(无论光标的位置在哪里),除非点击鼠标键时,光标热点在另一个线程的窗口中。
/// 《/summary》
public static extern bool ReleaseCapture();
/// 《summary》
/// 准备指定的窗口来重绘并将绘画相关的信息放到一个PAINTSTRUCT结构中。
/// 《/summary》
public static extern IntPtr BeginPaint(IntPtr hWnd, ref PAINTSTRUCT ps);
/// 《summary》
/// 标记指定窗口的绘画过程结束,每次调用BeginPaint函数之后被请求
/// 《/summary》
public static extern bool EndPaint(IntPtr hWnd, ref PAINTSTRUCT ps);
/// 《summary》
/// 半透明窗体
/// 《/summary》
public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref POINT pptDst, ref SIZE psize, IntPtr hdcSrc, ref POINT pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);
/// 《summary》
/// 该函数返回指定窗口的边框矩形的尺寸。该尺寸以相对于屏幕坐标左上角的屏幕坐标给出。
/// 《/summary》
public static extern bool GetWindowRect(IntPtr hWnd, ref RECT rect);
/// 《summary》
/// 该函数将指定点的用户坐标转换成屏幕坐标。
/// 《/summary》
public static extern bool ClientToScreen(IntPtr hWnd, ref POINT pt);
/// 《summary》
/// 当在指定时间内鼠标指针离开或盘旋在一个窗口上时,此函数寄送消息。
/// 《/summary》
public static extern bool TrackMouseEvent(ref TRACKMOUSEEVENTS tme);
/// 《summary》
///
/// 《/summary》
public static extern bool SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool redraw);
/// 《summary》
/// 该函数检取指定虚拟键的状态。
/// 《/summary》
public static extern ushort GetKeyState(int virtKey);
/// 《summary》
/// 该函数改变指定窗口的位置和尺寸。对于顶层窗口,位置和尺寸是相对于屏幕的左上角的:对于子窗口,位置和尺寸是相对于父窗口客户区的左上角坐标的。
/// 《/summary》
public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int width, int height, bool repaint);
/// 《summary》
/// 该函数获得指定窗口所属的类的类名。
/// 《/summary》
public static extern int GetClassName(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);
/// 《summary》
/// 该函数改变指定窗口的属性
/// 《/summary》
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

几种绘制半透明多边形/绘制半透明矩形的方法


HDC
hBitmapDC
=
CreateCompatibleDC(hDC);
HBITMAP
hBitmap
=
CreateCompatibleBitmap(hDC,
rt.Width(),
rt.Height());
SelectObject(hBitmapDC,hBitmap);
步骤2)在内存DC中绘图
FillRgn(hBitmapDC,
(HRGN)rgn,
(HBRUSH)m_pGdiBrush);
Rectangle(hBitmapDC,
0,
0,
100,
100);
步骤3)
半透明混合
BLENDFUNCTION
bf;
bf.BlendOp
=
AC_SRC_OVER;
bf.BlendFlags
=
0;
bf.AlphaFormat
=
0;
bf.SourceConstantAlpha
=
50;
AlphaBlend(hDC,rt.left,rt.top,rt.Width(),rt.Height(),hBitmapDC,0,0,rt.Width(),rt.Height(),bf);
2、GDI+
步骤1)
创建半透明画刷
m_pBrush
=
new
SolidBrush(Color(128,
GetRValue(clrMask),
GetGValue(clrMask),
GetBValue(clrMask)));
//
透明度
128
步骤2)使用画刷绘图
Graphics
graphics(hDC);
graphics.FillPolygon(&m_pBrush,
pts,
3,
FillModeAlternate);
效率:
GDI+
GDI。
使用GDI+绘图简单而高效,所以推荐使用GDI+。
3、Direct
Draw
此方法比较复杂,没有对Direct
Draw有一定的了解,不推荐此方法。
代码比较多,不做列举,需要注意的地方有:
使用Direct
Draw时,注意,绘制半透明多边形的时候,因为牵涉到已有的图像数据,所以会对绘图页面原有的图像进行读取操作。如果当前绘制页面开辟在显存中的时候,
对显存的读操作会导致整个渲染流水线的暂停,
从而严重影响程序的效率,此时,绘制半透明多边形就会变得异常的慢。这时候需要将绘制页面从显存中更改至内存中。或者在内存中创建一个过度页面,绘制完成后再往显存页面上贴图。效率会有显著提升,实测:

求API中AlphaBlend函数使用示例


1 AlphaBlend
函数功能:该函数用来显示透明或半透明像素的位图。
函数原型:AlphaBlend(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int hHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,BLENDFUNCTION blendFunction);
参数:
hdcDest:指向目标设备环境的句柄。
nXoriginDest:指定目标矩形区域左上角的X轴坐标,按逻辑单位。
nYOriginDest:指定目标矩形区域左上角的Y轴坐标,按逻辑单位。
nWidthDest:指定目标矩形区域的宽度,按逻辑单位。
hHeghtdest:指向目标矩形区域高度的句柄,按逻辑单位。
hdcSrc:指向源设备环境的句柄。
nXOriginSrc:指定源矩形区域左上角的X轴坐标,按逻辑单位。
nYOriginSrc:指定源矩形区域左上角的Y轴坐标,按逻辑单位。
nWidthSrc:指定源矩形区域的宽度,按逻辑单位。
nHeightSrc:指定源矩形区域的高度,按逻辑单位。
blendFunction:指定用于源位图和目标位图使用的alpha混合功能,用于整个源位图的全局alpha值和格式信息。源和目标混合功能当前只限为AC_SRC_OVER。
返回值:如果函数执行成功,那么返回值为TRUE;如果函数执行失败,那么返回值为FALSE。
Windows NT:若想获取更多错误信息,请调用GetLastError函数。
备注:如果源矩形区域与目标矩形区域大小不一样,那么将缩放源位图与目标矩形区域匹配。如果使用SetStretchBltMode函数,那么iStretchMode的值是BLACKONWHITE和WHITEONBLACK,在本函数中,iStretchMode的值自动转换成COLORONCOLOR。目标坐标使用为目标设备环境当前指定的转换方式进行转换。源坐标则使用为源设备环境指定的当前转换方式进行转换。如果源设备环境标识为增强型图元文件设备环境,那么会出错(并且该函数返回FALSE)。如果目标和源位图的色彩格式不同,那么AlphaBlend将源位图转换以匹配目标位图。
AlphaBlend不支持镜像。如果源或目标区域的宽度或高度为负数,那么调用将失败。
注意添加 #pragma comment(lib,“Msimg32.lib“)库
下面是一个例子:
#include 《windows.h》
#pragma comment(lib,“Msimg32.lib“)
HINSTANCE g_hIns;
HWND g_hWnd;
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow)
{
g_hIns=hInstance;
static TCHAR szAppName=TEXT(“HelloWin“);
HWND hWnd;
MSG msg;
WNDCLASS wndClass;
wndClass.style=CS_HREDRAW|CS_VREDRAW;
wndClass.lpfnWndProc=WndProc;
wndClass.cbClsExtra=0;
wndClass.cbWndExtra=0;
wndClass.hInstance=hInstance;
wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName=NULL;
wndClass.lpszClassName=szAppName;
if(!RegisterClass(&wndClass))
{
MessageBox(NULL,TEXT(“error“),szAppName,MB_ICONERROR|MB_OK);
return 0;
}
hWnd=CreateWindow(szAppName,TEXT(“The hello program“),WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
int iReturn;
//也可以放在此
ShowWindow(hWnd,iCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg,hWnd,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
static HDC hdc;
static HDC hBitmapDC;
static HBITMAP hBitmap;
static int w=50;
static int h=50;
static BLENDFUNCTION bf;
PAINTSTRUCT ps;
switch (message)
{
case WM_PAINT :
hdc=BeginPaint(hWnd,&ps);
hBitmapDC = CreateCompatibleDC(hdc);
hBitmap = CreateCompatibleBitmap(hdc,w,h);
SelectObject(hBitmapDC,hBitmap);
SetTextColor(hBitmapDC,RGB(0,255,0));
TextOut(hBitmapDC,0,0,TEXT(“asdf“),4);
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = 0;
bf.SourceConstantAlpha = 50;
AlphaBlend(hdc,0,0,w,h,hBitmapDC,0,0,w,h,bf);
EndPaint (hWnd, &ps) ;
break;
case WM_DESTROY :
PostQuitMessage (0) ;
break ;
default:
return DefWindowProc (hWnd, message, wParam, lParam) ;
}
return 1;
}

如何使用GDI绘制半透明矩形


HDC hBitmapDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap = CreateCompatibleBitmap(hDC, rt.Width(), rt.Height());
SelectObject(hBitmapDC,hBitmap);
步骤2)在内存DC中绘图
FillRgn(hBitmapDC, (HRGN)rgn, (HBRUSH)m_pGdiBrush);
Rectangle(hBitmapDC, 0, 0, 100, 100);
步骤3) 半透明混合
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = 0;
bf.SourceConstantAlpha = 50;
AlphaBlend(hDC,rt.left,rt.top,rt.Width(),rt.Height(),hBitmapDC,0,0,rt.Width(),rt.Height(),bf);
2、GDI+
步骤1) 创建半透明画刷
m_pBrush = new SolidBrush(Color(128, GetRValue(clrMask), GetGValue(clrMask), GetBValue(clrMask))); // 透明度 128
步骤2)使用画刷绘图
Graphics graphics(hDC);
graphics.FillPolygon(&m_pBrush, pts, 3, FillModeAlternate);
效率: GDI+ GDI。
使用GDI+绘图简单而高效,所以推荐使用GDI+。
3、Direct Draw
此方法比较复杂,没有对Direct Draw有一定的了解,不推荐此方法。
代码比较多,不做列举,需要注意的地方有:
使用Direct Draw时,注意,绘制半透明多边形的时候,因为牵涉到已有的图像数据,所以会对绘图页面原有的图像进行读取操作。如果当前绘制页面开辟在显存中的时候,
对显存的读操作会导致整个渲染流水线的暂停,
从而严重影响程序的效率,此时,绘制半透明多边形就会变得异常的慢。这时候需要将绘制页面从显存中更改至内存中。或者在内存中创建一个过度页面,绘制完成后再往显存页面上贴图。效率会有显著提升,实测:

什么是linear color blending


线性混合颜色
linear color blending
linear是线的,线型的意思。
color是颜色;肤色的意思。
blending是混合;调配;混和物的意思。
颜色混合是指将两个颜色混合在一起产生第三个颜色的处理过程。
第一个颜色叫做源颜色(source color)。第二个颜色叫做目标颜色(destination color),这个颜色已经存在(例如在后备缓冲中)。每个颜色都一个单独的的混合因子确定每种颜色在最终图像中的多少。当源颜色和目标颜色乘以各自的混合因子后,最终结果根据指定的混合函数进行合成。通常混合函数只是简单的相加。
完整公式如下所示:
(source × source blend factor) (blend function) (destination × destination blend factor)
源颜色的混合因子是由SourceBlend属性指定的,目标颜色的混合因子是由DestinationBlend属性指定的。BlendFunction属性指定使用的混合函数,通常是BlendFunction.Add,这种情况公式如下表示:
(source × SourceBlend) + (destination × DestinationBlend)
当AlphaBlendEnable属性为false时,在绘制时不进行混合。

推荐阅读