如何使用Win32下的GDI等接口实现绚丽,高效的界面

如何使用Win32下的GDI等接口实现绚丽,高效的界面,第1张

1如何让界面绚丽

怎么样的算绚丽有很漂亮的有Alpha透明有Animation

每个人的审美观点都不同,所以如果你的界面很多人认为绚丽那就可以了。设计界面主要是Designer的工作,包括UI逻辑的设计,色彩搭配设计等,我认为这也可以进一步分工:熟悉用户习惯的Designer、美学Designer等。但是一般情况下这些让程序员给代劳了。

下面介绍Windows提供给开发人员的相关接口,利用这些接口设计你认为绚丽的界面。

2如何透明如何半透明如何颜色渐变

以下是我使用Imaging COM组件封装的一个函数,可以使用其绘制PNG,当然也可以绘制其它。绘制带Alpha通道的PNG即实现了透明。

#include <imagingh>

#include <initguidh>

#include <imgguidsh>

#pragma comment(lib, "Imaginglib")

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;

bfBlendOp = AC_SRC_OVER;

bfBlendFlags = 0;

bfSourceConstantAlpha = alpha;

bfAlphaFormat = 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[39];

StringFromGUID2(pDimensionIDs[0], strGuid, 39);

UINT frameCount = 0;

pDecoder->GetFrameCount(&pDimensionIDs[0],&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);

rcleft = rctop = 0;

rcright = InfoWidth;

rcbottom = InfoHeight;

HDC tempDC;

HBITMAP hbmNew = NULL;

void pv;

BITMAPINFO bmi = { 0 };

HBITMAP hbmOld = NULL;

tempDC = CreateCompatibleDC(NULL);

bmibmiHeaderbiSize = sizeof(BITMAPINFOHEADER);

bmibmiHeaderbiWidth = InfoWidth;

bmibmiHeaderbiHeight = InfoHeight;

bmibmiHeaderbiPlanes = 1;

bmibmiHeaderbiBitCount = (SHORT) max(16, GetDeviceCaps(tempDC, BITSPIXEL));

bmibmiHeaderbiCompression = 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[0], ++fCount);

BitBlt(g_hdc, 0, 0, rcright - rcleft, rcbottom - rctop, 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,你不必知道设备。以下引用自MSDN文档:

"2-D vector graphics involves drawing primitives (such as lines, curves, and figures) that are specified by sets of points on a coordinate system

For example, the Rect class stores the location and size of a rectangle; the Pen class stores information about line color, line width, and line style; and the Graphics class has methods for drawing lines, rectangles, paths, and other figures There are also several Brush classes that store information about how closed figures and paths are to be filled with colors or patterns

Certain kinds of pictures are difficult or impossible to display with the techniques of vector graphics Imaging part will resolve this problem An example of such a class is CachedBitmap, which is used to store a bitmap in memory for fast access and display

Typography is concerned with the display of text in a variety of fonts, sizes, and styles One of the new features in GDI+ is subpixel antialiasing “

Windows CE/Windows Mobile下的GDI+仅仅是Windows桌面系统的一个很小的子集。

这个问题也曾经困扰过我,整理出来,供你参考。标题就定为:

                      Windows GDI 坐标系及坐标映射

参考资料:

1 windows程序设计(第五版) 第5章

2 windows图形编程  Feng Yuan 著

3 >

4>

1)处理WM_LBUTTONDOWN消息,获取当然鼠标坐标

2)判断鼠标坐标,如果落在矩形内部,拖动激活标志置1(用一个全局变量或WndProc局部静态变量来实现)

3)处理WM_MOUSEMOVE消息,获取新的鼠标坐标,如果拖动激活标志为1,那么就在新的鼠标位置重新绘制矩形

4)处理WM_LBUTTONUP消息,拖动激活标志置0

大致就这样了,细节地方自己研究。

打印机驱动程序分类GDI驱动程序:通常GDI打印机驱动程序生成的数据格式由打印机厂商制订,不同厂商的GDI打印机并不兼容。PCL驱动程序:PCL打印机是按照惠普的打印控制语言标准设计的,打印驱动程序生成的数据符合这个标准,因此不同厂商生产的打印机能够兼容PCL打印驱动程序生成的基本打印任务。Postscripq驱动程序:Postscripq打印机驱动程序生成的数据符合Adobe系统公司的Postscripq标准,它能够被带有Postscripq处理功能的打印机打印,同时它也能够被许多Adobe公司的软件如Acrobat、Photoshop等所处理。苹果电脑平台下的打印机驱动程序通常是Postscripq的打印驱动程序。各版本的特点与区别首先GDI驱动就是我们常说的基于主机的驱动,目前市场多数打印机已经不在使用此驱动程序,但少数机器仍在销售,比如HP laserjet 1005mfp。打印机驱动的分类:一 基于主机使用计算机而非打印机的内存资源和处理能力进行打印任务的处理 , 在计算机端完成打印光栅位图的转换过程,在打印机直接成像。特点:A 、 加速了打印速度。基于主机的打印机利用计算机的处理能力把应用软件的页面信息转换为光栅格式进行打印, 由于现在的计算机的处理速度比大多数打印机的处理速度快的多,用基于主机的打印机打印复杂的打印任务时通常会快些。大多数基于主机打印的打印机都使用打印速度更快的 USB 口而不用并口。例如, HP Color LaserJet 1500 标配基于主机驱动 ,在 Windows and Macintosh *** 作系统中可以打印更复杂的打印作业而不用增加打印机的内存或者是牺牲打印速度和性能。B 、 基于主机打印机可以处理光栅数据图像,减少打印机产生内存溢出的问题。C 、 基于主机打印要求计算机 *** 作系统具备打印引擎,不能从计算机接受 ASCII 文本,这与页面描述语言( Page Descripqion Language ) PDL 打印不同。这就意味着基于主机的打印只能在 Windows 和 Macintosh 已经明确支持打印引擎的系统环境中使用,而不支持没有打印引擎的 Windows 、 Macintosh 、 Linux, Unix, and OS/2 等。D 、 要求打印机和计算机直接相连,不适合网络打印作业,不支持网络服务器、共享器、磁带设备以及干扰通信设备的连接。二 PCL 与 PS 驱动程序PCL 和 PS 是两种标准化的页面描述语言,其工作流程都是首先在计算机端将打印内容解释成标准的页面描述文件然后传送到打印机控制器中,在打印控制器中再将页面描述文件解释成可以打印的光栅图像 , 从其工作流程看,此两种方式中都对打印机中的打印控制器有很高的要求,同时要求打印机内部有足够的内存。1PCL 驱动程序PCL 语言是 HP 公司于 70 年代针对其激光打印机产品推出的一种打印机页面描述语言。 PCL 指令内嵌于打印数据流,把应用程序输出快速转译成高质量的、特定设备的光栅化图像。PCL5是HP公司为它的激光打印机LaserJetⅢ设计的,它提供了一些与Postscripq语言相似的功能,开始支持矢量字库和矢量图形描述,实现了WYSIWYG(What You See Is What You Get, 所见即所得), PCL5中也使用了各种压缩技术来减小数据量,加快数据传输。 PCL5e 开始支持双向数据通讯,从而使打印机可以向计算机发送打印机的状态信息。PCL5c增加了对彩色打印的支持。1996年HP公司发布了PCL6,它更加灵活,是一个目标朝向的控制语言,使处理多图形的文件的速度大大加快,实现了更好的WYSIWYG,可以更好地处理Web页面。特点:使用 PCL 语言的打印机在处理文本或一些常见办公应用软件下的文档时具有非常明显的速度优势,比较适合一些普通的商务办公应用。2Postscripq 驱动程序这是一种与设备无关的打印机语言,即在定义图像时可以根本不考虑输出设备的特性 ( 如打印机的分辨率、纸张大小等 ) ,而它对文本和图形实行同样的处理过程,这就给处理字体带来了极大的灵活性。通过 PS 驱动程序,各种不同的应用软件将各自的数据转换成 Postscripq 格式。从打印引擎的工作原理可知,打印机只能接受位图格式,当打印机控制器将 Postscripq 转换成位图格式时,由于 Postscripq 十分复杂,一般的打印控制器难以胜任,通常由打印机中专门的光栅图像处理器 (Raster Image Processor) 来完成这一转换过程。特点:PS 驱动程序在处理 PDF 文件或在 Photoshop 等软件下打印大的图形图像文件时具有一定的速度优势,同时其在图形表现准确度色彩表现准 确度和一些字库表现准确度方面也 比 PCL 语言有 优势,适合对图形和色彩准确度要求比较高的专业应用。

不该学,了解即可

WIN API一般必学得有四类

user interface

system services

networking

graphics and multimedia

GDI属于第4类, 这类东西最没用, 里面像什么brush, clipping,lines and curves等等这些,基本就是鸡肋 绘图最好使用GDI+, GDI只要了解HDC的用法,和SetROP2,因为GDI+中没有SetROP

第1类UI是最重要的万物之基础

第2类编写系统工具, windows高手, 逆向等的第一步

第3类网络编程,比较重要

第4类绘图是最难的, 因为你要解决两个问题, 绘图本身的技术问题, 业务领域的问题, 绘图首先是需要用数学建模的, 如果你软件设计不是很精通, 那你 还得考虑架构问题

《GDI+高级编程》,《GDI+图形程序设计》,《GDI+程序设计》

>

画圆其实就是确定圆心的过程,圆的半径都是相等的。而一圈的圆,其实就是在大圆上取点的过程,设圆心坐标为(a,b),半径为r,则取点过程为

x=a+rsint

y=b+rcost

t属于(0,360)

此时可画出一个完整的圆,当然由于小圆还有半径,所以取点时t要隔一定角度进行取值,这要根据你的小圆半径为定

以上就是关于如何使用Win32下的GDI等接口实现绚丽,高效的界面全部的内容,包括:如何使用Win32下的GDI等接口实现绚丽,高效的界面、windows编程 GDI 坐标映射、Windows编程怎么把用GDI绘制好的图形进行拖拽 *** 作等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/9271583.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-26
下一篇2023-04-26

发表评论

登录后才能评论

评论列表(0条)

    保存