
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桌面系统的一个很小的子集。
1
程序正在阻止windows关闭解决方法一:
2
出现报错提示窗口后,不要“确定”和“取消”,直接打开“任务管理器”;
3
打开“任务管理器”,在“应用程序”选项下面应该会有相应的报错程序在运行;
4
程序正在阻止windows关闭解决方法二: 如果第1种方法不行,下载个“360系统急救箱
5
程序正在阻止windows关闭解决方法三: 你下载的“播放器”,或“聊天软件
GDI
GDI System | 缸内喷注式汽油发动机;[详见: 三菱直喷式汽油机]
原理缸内喷注式汽油发动机与一般汽油发动机的主要区别在于汽油喷射的位置,目前一般汽油发动机上所用的汽油电控喷射系统,是将汽油喷入进气歧管或进气管道上,与空气混合成混合气后再通过进气门进入气缸燃烧室内被点燃作功;而缸内喷注式汽油发动机顾名思义是在气缸内喷注汽油,它将喷油嘴安装在燃烧室内,将汽油直接喷注在气缸燃烧室内,空气则通过进气门进入燃烧室与汽油混合成混合气被点燃作功,这种形式与直喷式柴油机相似,因此有人认为缸内喷注式汽油发动机是将柴油机的形式移植到汽油机上的一种创举。 优点缸内喷注式汽油发动机的优点是油耗量低,升功率大。混合比达到40:1(一般汽油发动机的混合比是15:1),也就是人们所说的“稀燃”。机内的活塞顶部一半是球形,另一半是壁面,空气从气门冲进来后在活塞的压缩下形成一股涡流运动,当压缩行程行将结束时,在燃烧室顶部的喷油嘴开始喷油,汽油与空气在涡流运动的作用下形成混合气,这种急速旋转的混合气是分层次的,越接近火花塞越浓,易于点火作功。由于缸内喷注压缩比达到12,与同体积的一般发动机相比功率与扭矩都提高了10%
-------------------
GDI是Graphics Device Interface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。
在Windows *** 作系统下,绝大多数具备图形界面的应用程序都离不开GDI,我们利用GDI所提供的众多函数就可以方便的在屏幕、打印机及其它输出设备上输出图形,文本等 *** 作。GDI的出现使程序员无需要关心硬件设备及设备驱动,就可以将应用程序的输出转化为硬件设备上的输出,实现了程序开发者与硬件设备的隔离,大大方便了开发工作。
GDI是如何实现输出的?
要想在屏幕或者其它输出设备上输出图形或者文字,那么我们就必须先获得一个称为设备描述表( DC:Device Context)的对象的句柄,以它为参数,调用各种GDI函数实现各种文字或图形的输出。设备描述表是GDI内部保存数据的一种数据结构,此结构中的属性内容与特定的输出设备(显示器,打印机等)相关,属性定义了GDI函数的工作细节,在这里属性确定了文字的颜色,x坐标和y坐标映射到窗口显示区域的方式等。
设备描述表句柄一旦获得,那么系统将使用默认的属性值填充设备描述表结构。
如果有必要,我们可以使用一些GDI函数获取和改变设备描述表中的属性值。
GDI是Graphics Device Interface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。
在Windows *** 作系统下,绝大多数具备图形界面的应用程序都离不开GDI,我们利用GDI所提供的众多函数就可以方便的在屏幕、打印机及其它输出设备上输出图形,文本等 *** 作。
GDI具有如下特点:
1 不允许程序直接访问物理显示硬件,通过称为“设备环境”的抽象接口间接访问显示硬件;
2 程序需要与显示硬件(显示器、打印机等) 进行通讯时,必须首先获得与特定窗口相关联的设备环境;
3 用户无需关心具体的物理设备类型;
4 Windows参考设备环境的数据结构完成数据的输出。
GDI函数大致可分类为:
设备上下文函数(如GetDC、CreateDC、DeleteDC)、 画线函数(如LineTo、Polyline、Arc)、填充画图函数(如Ellipse、FillRect、Pie)、画图属性函数(如SetBkColor、SetBkMode、SetTextColor)、文本、字体函数(如TextOut、GetFontData)、位图函数(如SetPixel、BitBlt、StretchBlt)、坐标函数(如DPtoLP、LPtoDP、ScreenToClient、ClientToScreen)、映射函数(如SetMapMode、SetWindowExtEx、SetViewportExtEx)、元文件函数(如PlayMetaFile、SetWinMetaFileBits)、区域函数(如FillRgn、FrameRgn、InvertRgn)、路径函数(如BeginPath、EndPath、StrokeAndFillPath)、裁剪函数(如SelectClipRgn、SelectClipPath)等。
游戏难度:困难-已通过
并完成每一关所有奖励任务和相关收集情报
序曲
第一关:北卡罗莱纳州
任务简报
情报多次显示NOD兄弟会在北卡罗莱纳州边界进行着不明活动,你的任务是调查这一情况,并及时回报。附近有一座小型GDI训练设施——重新启动这一基地作为己用。
首要目标「必须完成」
⒈保护GDI前哨站不被Nod摧毁
⒉建造一座兵营并训练三组步q兵
⒊建造一座发电厂
⒋修理指挥所
⒌摧毁Nod前哨站
⒍修理桥梁
⒎建造一座飞机场
⒏摧毁Nod兵营、车辆工厂和建造中心
奖励目标「可选完成」
⒈建造哨塔
⒉制造一条储备性步兵生产线
⒊占领一座Nod建筑
⒋出售占领的Nod建筑
⒌建造一座泰矿储藏井
⒍占领泰矿炼掘塔
收集新情报
⒈GDI基地关闭
⒉泰伯利亚读本
⒊移动基地车
⒋兵营
⒌GDI步q兵
⒍GDI导d小队
⒎GDI工程师
任务流程:
01首先,开场时会被空降两组精英级别的步q兵,着陆后迅速分别进驻前方GDI前哨基地的两座哨塔,这时正遇Nod步兵部队的骚扰。消灭后,完成第一首要目标。
02稍后移动基地车会进入GDI前哨基地并展开,这时要求完成第二首要目标,建造一座兵营并训练三组步q兵。
03完成第二首要目标后,Nod狂热者会冲进基地将发电厂摧毁,电力会出现供应不足,这时要求完成第三首要目标,建造一座发电厂。同时教官会提示当电力不足时关闭某些设施从而达到临时释放电力,使基地中其他建筑保持正常运行。
04重新建造发电厂恢复供电后,任务会被要求完成第四首要目标,修复雷达指挥所。
05雷达指挥所恢复正常工作后,探测到Nod正准备派出大量部队破坏我们的基地,教官会要求马上建造并安置一座机q哨塔,这是一个奖励目标,所以可选完成。
建议:建造两到三座稍塔在基地外围、位置分别在基地右面出口处、右下方围墙拐角处、下方出口处靠右,从而达到最佳阻挡效果。
06消灭大量Nod步兵部队后,任务要求你完成第五首要目标,摧毁Nod前哨站——只摧毁两座目标建筑物即可。此时会增援两组火箭兵协助完成,同时兵营允许购买火箭兵。
07在执行过程中,第二奖励目标要求触发,制造一条储备性步兵生产线,其意是再建造一座兵营从而允许同时或者备用生产。
GDI是一个图形翻译系统,是介于应用程序和图形硬件之间的一层。GDI可以输出到任意的兼容设备,不过最常使用的设备是视频监视器、图形硬拷贝设备(如打印机或绘图仪),或者是内存中的图元文本。 扩展资料
GDI函数能够绘制直线、曲线、封闭的`图形和文本。所有访问GDI的Windows函数都需要一个设备上下文句柄作为参数。
假如是在测验软件中的,在图形绘制当中,提供了一个叫做设备上下文(DC)的结构,是一个GDI是提供的接口供我们来访问设备,所有的绘图都是通过设备上下文来进行。因此,同一应用程序可以在配有不同的类型显示器的计算机上使用。应用程序不需要针对所有显示器进行更改。
一、Windows中的映射模式
1、Windows定义映射模式的目的
经过我的综合,Windows定义映射模的目的又以下几个方面:1、不同人的使用习惯。不同国家的,不同地区,以及不同的人因为习惯喜欢用不同的度量单位,有的人人喜欢用英寸,而有的人喜欢用公制中的厘米,毫米等。其他的人又喜欢用另外一些单位。、2、使软件与硬件向分离开来。让开发的软件能够最大限度的与硬件无关。3、提供逻辑和物理的一种转换。就相当于银行的利率。
2、默认的映射模式
默认的映射模式使MM_TEXT,它使以象素为单位的。X轴向左为正,Y轴向下为正。默认的坐标原点在左上角。
3、固定比例映射模式
固定比例的映射模式有MM_LOMETRIC、MM_HIMETRIC、MM_LOENGLISH、MM_HIENGLISH、MM_TWIPS种。它们默认的坐标原点都使在左上角。其区别在于每一个逻辑单位对应的物理大小不一样。所对用的逻辑单位分别为01毫米,001毫米,001英寸,0001英寸,1/1440英寸(00007英寸)。
4、可变比例映射模式
对于可变比例的映射模式用户可以自己定义一个逻辑单位代表的大小,其大小可以任意。也可以让这个大小随环境改变而改变。有MM_ISOTROPIC,MM_ANISOTROPIC这两种映射模式。其逻辑单位的大小等于视口范围和窗口范围的比值。两者的不同在于前者要求X轴和Y轴的度量单位必须相同,而后者没有这样的限制。
二、Windows中的几种坐标体系
1、屏幕坐标
屏幕坐标描述物理设备(显示器、打印机等)的一种坐标体系,坐标原点在屏幕的左上角,X轴向右为正,Y轴向下为正。度量单位是象素。原点、坐标轴方向、度量单位都是不能够改变的。
2、设备坐标(又称物理坐标)
设备坐标是描述在屏幕和打印机显示或打印的窗体的一种坐标体系。默认的坐标原点是在其客户区的左上角。X轴向右为正,Y轴向下为正。度量单位为象素。原点和坐标轴方向可以改变,但是度量单位不可以改变。
3、逻辑坐标
逻辑坐标是在程序中控制显示,打印使用的坐标体系。该坐标系与定义的映射模式密切相关。默认的映射模式是MM_TEXT。我们可以通过设置不同的映射模式来改变该坐标体系的默认行为。
三、逻辑坐标和设备坐标之间的转换
现有如下代码:
void CMapModeView::OnPaint()
{
CPaintDC dc(this);
//获取设备类的设置
CPoint ptOrgView,ptOrgWindow;
CSize sizeView,sizeWindow;
CString strMsg;
ptOrgView=dcGetViewportOrg();//获取视口原点
ptOrgWindow=dcGetWindowOrg();//获取窗口原点
sizeView=dcGetViewportExt();//获取视口范围
sizeWindow=dcGetWindowExt();//获取窗口范围
strMsgFormat(_T("Viewport Extent:(%d,%d),\tViewport Org:(%d,%d)\tWindow Extent:(%d,%d)\tWindow Org(%d,%d)"),
sizeViewcx,sizeViewcy,ptOrgViewx,ptOrgViewy,
sizeWindowcx,sizeWindowcy,ptOrgWindowx,ptOrgWindowy);
TRACE("%s\n",strMsg);
//设置映射模式以及原点
dcSetMapMode(MM_TEXT);//设置映射模式
dcSetWindowOrg(100,100);//设置窗口的坐标原点
dcSetViewportOrg(200,200);//设置视口的坐标原点
dcSetWindowExt(5,10);//改语句仅对可变比例映射模式有效
dcSetViewportExt(1,1);//同上
ptOrgView=dcGetViewportOrg();
ptOrgWindow=dcGetWindowOrg();
sizeView=dcGetViewportExt();
sizeWindow=dcGetWindowExt();
strMsgFormat(_T("Viewport Extent:(%d,%d),\tViewport Org:(%d,%d)\tWindow Extent:(%d,%d)\tWindow Org(%d,%d)"),
sizeViewcx,sizeViewcy,ptOrgViewx,ptOrgViewy,
sizeWindowcx,sizeWindowcy,ptOrgWindowx,ptOrgWindowy);
TRACE("%s\n",strMsg);
//将点(300,400)从逻辑坐标体系映射到设备坐标体系。
CPoint ptMap;
ptMap=CPoint(300,400);
dcLPtoDP(&ptMap);
strMsgFormat(_T("The Orginal Point(In LP):CPoint(300,400),Convert to DP is:CPoint(%d,%d)"),
ptMapx,ptMapy);
TRACE("%s\n",strMsg);
//将点(300,400)从设备坐标体系映射到逻辑坐标体系
ptMap=CPoint(300,400);
dcDPtoLP(&ptMap);
strMsgFormat(_T("The Orginal Point(In DP):CPoint(300,400),Convert to LP is:CPoint(%d,%d)"),
ptMapx,ptMapy);
TRACE("%s\n",strMsg);
}
以上代码最后调试输出结果为:
Viewport Extent:(1,1), Viewport Org:(0,0) Window Extent:(1,1) Window Org(0,0)
Viewport Extent:(1,1), Viewport Org:(200,200) Window Extent:(1,1) Window Org(100,100)
The Orginal Point(In LP):CPoint(300,400),Convert to DP is:CPoint(400,500)
The Orginal Point(In DP):CPoint(300,400),Convert to LP is:CPoint(200,300)
按照MSDN上,函数SetWindowOrg(x,y)设定设备坐标下的点(x,y)对应于逻辑坐标的原点。SetVieportOrg(x,y)设定逻辑坐标下点(x,y)对应逻辑坐标的原点。而实际上如果同时设置了逻辑坐标和设备坐标原点的话,那么以上的说法是错误的。
在默认映射模式MM_TEXT下,一个逻辑单位对应于设备坐标下的一个象素。改变默认原点以后的坐标体系如下图所示:
(0,0) Dx,Lx (0,0)
(100,100) Lx
(200,200) Dx
(300,400)
Dy,Ly Ly Dy
在VC中坐标系的转换和数学中的数学转化是不一样的。在这里是以距离为标准。首先看一下如何把点(300,400)如何从设备坐标转换成逻辑坐标。
在设备坐标体系下,点(300,400)与Y轴的距离为100个逻辑单位。那么所对应的逻辑坐标也要满足与逻辑坐标Y轴的距离为100个单位。又1个逻辑单位对应1个象素。所以所对应的设备坐标的X值为100+100=200。同样可以出对应的逻辑坐标的Y值为300。
按照同样的方法,我们也可以把逻辑坐标下的点(300,400)转换成设备坐标。在逻辑坐标下,点(300,400)与逻辑坐标Y轴的距离为200。那么在设备坐标体系,相应的设备坐标与设备坐标Y轴的距离也要为200。又1个逻辑单位对应1个象素,所以对应的设备坐标X值为200+200=400。同样的道理,可以求出对应的设备坐标Y值为500。
在这里,因为逻辑单位和设备单位一一对应,也可以把这个问题看作一个很简单的坐标平移问题来看。其结果是很显然的。
另外又找到一篇:
一、映射模式基本知识
当windows应用程序在其客户区绘制图形时,必须给出在客户区的位置,其位置用x和y 两个坐标表示,x表示横坐标,y表示纵坐标。在所有的gdi绘制函数中,这些坐标使用的是一 种"逻辑单位"。当gdi函数将输出送到某个物理设备上时,windows将逻辑坐标 转换成设备坐标(如屏幕或打印机的像素点)。逻辑坐标和设备坐标的转换是由映射模式决 定的。映射模式被储存在设备环境中。getmapmode函数用于从设备环境得到当前的映射模 式,setmapmode函数用于设置设备环境的映射模式。
1逻辑坐标
逻辑坐标是独立于设备的,它与设备点的大小无关。使用逻辑单位,是实现"所 见即所得"的基础。当程序员在调用一个画线的gdi函数lineto,画出254mm(1英寸) 长的线时,他并不需要考虑输出的是何种设备。若设备是vga显示器,windows自动将其转化 为96个像素点;若设备是一个300dpi的激光打印机,windows自动将其转化为300个像素点。
2设备坐标
windows将gdi函数中指定的逻辑坐标映射为设备坐标,在所有的设备坐标系统中, 单位以像素点为准,水平值从左到右增大,垂直值从上到下增大。
windows中包括以下3种设备坐标,以满足各种不同需要:
(1)客户区域坐标,包括应用程序的客户区域,客户区域的左上角为(0,0)。
(2)屏幕坐标,包括整个屏幕,屏幕的左上角为(0,0)。屏幕坐标用在wm_move消息 中(对于非子窗口)以及下面的windows函数中:createwindow和movewindow(都对于非子窗 口)、getmessage、getcursorpos、getwindowrect、windowfrompoint和setbrushorg中。用函 数clienttoscreen和screentoclient可以将客户区域坐标转换成屏幕区域坐标,或反之。
(3)全窗口坐标,包括一个程序的整个窗口,包括标题条、菜单、滚动条和窗口框,窗 口的左上角为(0,0)。使用getwindowdc得到的窗口设备环境,可以将逻辑单位转换成窗口 坐标。
3逻辑坐标与设备坐标的转换方式
映射方式定义了windows如何将gdi函数中指定的逻辑坐标映射为设备坐标。要继续 讨论映射方式我们要介绍windows有关映射模式的一些术语:我们将逻辑坐标所在的坐标 系称为"窗口",将设备坐标所在的坐标系称为"视口"。
"窗口"依赖于逻辑坐标,可以是像素点、毫米或程序员想要的其他尺度。
"视口"依赖于设备坐标(像素点)。通常,视口和客户区域等同。但是,如 果程序员用getwindowdc或createdc获取了一个设备环境,则视口也可以指全窗口坐标或 屏幕坐标。点(0,0)是客户区域的左上角。x的值向右增加,y的值向上增加。
对于所有映射模式,windows都用下面两个公式将窗口坐标转换成视口坐标:
xviewport=(xwindow-xwinorg)(xviewext/xwinext)+xvieworg
yviewport=(ywindow-ywinorg)(yviewext/ywinext)+yvieworg
其中,(xwindow,ywindows)是待转换的逻辑点,(xviewport,yviewport)是转换后 的设备点。如果设备坐标是客户区域坐标或全窗口坐标,则windows在画一个对象前,还必 须将这些坐标转换成屏幕坐标。
这两个公式使用了分别指定窗口和视口原点的点:(xwinorg,ywinorg)是逻辑坐标 的窗口原点;(xvieworg,yvieworg)是设备坐标的视口原点。在缺省的设备环境中,这两个 点均设置为(0,0),但它们可以改变。此公式意味着,逻辑点(xwinorg,ywinorg)总被映射 为设备点(xvieworg,yvieworg)。
windows还能将视口(设备)坐标转换为窗口(逻辑)坐标:
xwindow=(xviewport-xvieworg)(xwinext/xviewext)+xwinorg
ywindow=(yviewport-yvieworg)(ywinext/yviewext)+ywinorg
可以使用windows提供的两个函数dptolp和lptodp在设备坐标及逻辑坐标之间互相 转换。
4映射模式的种类
windows定义了表1所列出的8种映射方式。
上述映射模式中又可分成以下3类:
映 射 方 式 逻 辑 单 位 x 轴 增 加 y 轴 增 加 毫 米 mm_text 像 素 点 右 下 与 设 备 有 关 mm_lometric 0 1mm 右 上 01 mm_himetric 0 01mm 右 上 001 mm_loenglish 0 254mm 右 上 0254 mm_hienglish 0 0254mm 右 上 00254 mm_twips 00176mm 右 上 00176 mm_isotropic 任 意(x=y) 可 选 可 选 可 设 mm_anisotropic 任 意(x!=y) 可 选 可 选 可 设
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)