当电脑进行个性化设置时,个性化→显示→最小(100%,默认)或中等(125%)时,用vc6开发的mfc程序对话框在不同的设置下GUI会有些变化;
1 对话框的字体由系统默认的system改成宋体,字体大小为小五(9);
2 高度会有所区别;
3 用画笔输出的文本和图像的位置坐会有所变化;
4 工具栏所能容纳的图标数量也有区别;
就这么几个控件自己算下left top width height 相对整个窗口的 比例 有这么难吗.
GetSystemMetrics ( SM_CXSCREEN )
GetSystemMetrics ( SM_CYSCREEN )
获取屏幕分辨率,创建窗口时SetWindowPos()设定窗口的大小为与屏幕分辨率相关联的大小就可以了
控件自适应窗口的话,要在OnSize里根据窗口尺寸的变化去设置控件大小和位置,不过想完美的实现还是有点难度的,可以参考别人已做好的类,直接拿过来用,比如EasySize
在使用Visual Studio 6.0(Visual C++ 6.0)开发的过程中,对话框中的控件在资源编辑器中的尺寸和其实际的像素尺寸之间的对应问题非常的令人烦恼。特别是在要求对话框控件大小随屏幕分辨率或程序窗口大小变化而变化时就更加令人挠头。
原因就在于,资源编辑器中的单位(DLU)与屏幕像素之间的对应关系随着对话框字体种类和大小的变化而变化。(1)在水平方向1 DLU == 1/4 字体平均宽度;(2)在垂直方向1 DLU == 1/8 字体平均高度。这一对应关系由于所使用字体的多变而难以确定。在绝大多数情况下,通过上面公式所计算的DLU甚至不会是整数像素。
为了在资源编辑器编辑的过程中就比较好的把握做出来的控件在屏幕上的像素尺寸,根据(1),思路:在对话框资源编辑器中应该采用等宽字体;根据(2),思路:最好采用所谓“系统”字体,这样字体高度也是固定的。
验证一下:在对话框资源编辑器中打开“Dialog Properties”,单击“Font...”按钮,为对话框选择字体。考察“FixedSys”和“System”两种,首先,从网上搜索得知,它们是等宽字体;其次,这两种字体只有一种尺寸大小“12”,这说明字体高度是固定的。
实地测试一下,在VC对话框工程中,将对话框的字体改为“FixedSys”或“System”,字号大小改为“12(即小四)”,并在对话框中创建一个100*100 DLU的按钮。在按钮单击响应函数里,用GetWindowRect()或GetClientRect()取得按钮尺寸。设置断点调试观察结果:按钮的像素尺寸是200*200!这表明对话框资源编辑器中的1 DLU现在等于2 Pixels。这样对于我们的设计就方便很多了。
如果屏幕分辨率改变了,结果如何呢?在不同的显示器上进行测试,结果都一样,仍然是1 DLU == 2 Pixels。
还有没有别的字体有这样的效果呢?“Terminal”字体也可以,选择字号为12,测试结果也是水平方向/垂直方向1 DLU == 2 Pixels。不过有个毛病:选择了该字体的对话框在资源编辑器里看起来怪怪的,水平方向1 DLU和垂直方向1 DLU的长度不同,好像被压扁了一样。但程序运行起来则没问题。另外,选择不同的“Terminal”字体大小,则对应关系也会改变。
到这里,索性对其他几种常用的字体也测试了一下,发现Verdana和宋体效果比较好(虽然对于英文来说这两种都不是等宽字体。而对于汉字,一般使用的汉字字体都是等宽的,方块字嘛)。下面是测试结果(仍然用100*100的按钮来测试):
字体 / 字号 / 水平尺寸 / 垂直尺寸
Verdana / 8 / 175 / 163
/ 9 / 200 / 175
/ 10 / 200 / 200
/ 11 / 225 / 225
/ 12 / 250 / 225
宋体 / 8 / 150 / 138
/ 9 / 150 / 150
/ 10 / 175 / 163
/ 11 / 200 / 188
/ 12 / 200 / 200
结论1:如果对FixedSys和System字体的效果不满意,选用12号宋体/10号Verdana是比较好的
结论2:虽然只能使用若干种有限的字体,但能给编程带来一些方便,还是值得的(相比字体效果的损失)
2014 年 8 月 7 日MFC程序,改变系统DPI后界面错位问题的处理无评论
MFC程序默认系统DPI96时调整的界面,在 【个性设置-显示-中等(win7, xp类似)】 后,出现控件错位的问题,是因为调整后DPI发生变化,相对的坐标也需要重新调整,修改方法如下:
1.调整函数的实现
#define DEFAULT_DPI 96.0
static int dpiX;
static int dpiY;
void moveWindow( CWnd &wnd ){
CRect rect;
wnd.GetWindowRect(rect);
wnd.GetParent()->ScreenToClient(rect);
rect.left = (int)(rect.left*DEFAULT_DPI/dpiX);
rect.right = (int)(rect.right*DEFAULT_DPI/dpiX);
rect.top = (int)(rect.top*DEFAULT_DPI/dpiY);
rect.bottom = (int)(rect.bottom*DEFAULT_DPI/dpiY);
rect.OffsetRect(CPoint((int)((dpiX-DEFAULT_DPI)/2), (int)((dpiY-DEFAULT_DPI)/2)));
wnd.MoveWindow(rect);}
void SetDPI( int x, int y ){
dpiX = x;
dpiY = y;}
int GetDPIX(){
return dpiX;}
int GetDPIY(){
return dpiY;}
2.设置dpi在程序第一个对话框初始化OnInitDialog()时,添加如下代码:
CDC* dc = GetDC();
int dpiX = GetDeviceCaps(dc->GetSafeHdc(), OGPIXELSX);
int dpiY = GetDeviceCaps(dc->GetSafeHdc(), LOGPIXELSY);
SetDPI(dpiX, dpiY);
ReleaseDC(dc);
如果有通过SetWindowPos函数设置的控件,需要进行比例转换,例如:
button.SetWindowPos(NULL,0,0,(size_t)(width/DEFAULT_DPI*dpiX),(size_t)(height/DEFAULT_DPI*dpiY),SWP_NOMOVE);
之后再调用函数moveWindow(CWnd &wnd)就可以进行坐标转换了。
GetDialogBaseUnits
所以用下列公式来把对话框模板单位转换为像素
PiselX=(temptateunitX★baseunitX)/4;PiseIY=(templateunitY★baseunitY)/8
MFC程序,在改变系统DPI后,控件显示位置混乱的问题
之前在自己机器上做的程序,
在周边几台机子运行都没有问题,
直到发给另外一人,程序界面在他那完全混乱了,后来查资料发现是因为各自系统DPI设置不同的问题,
首先,解释DPI
英文全称为Dot per inch,就是一英寸上显示的点,而这个点并不是意义上的像素。 一般来说,显示器是96DPI,也就是说96像素等于1 inch,但实际上不应该是这样,因为显示器的分辨率可以调整。
96DPI可以理解为用96象素来表示一英寸,而变成120DPI的时候,是用120像素来表示一英寸,而系统的对象(字体,图像)的是用英寸数来表示的,所以120DPI时,图象和字体就变大了。界面上的控件也就相应发生了变化。
在网上找了很多答案,没找到很完美的解决方案,
最后只好采取一种比较笨的方法,
因为在控件调用MoveWindow后控件的位置后不会再随dpi设置改变,所以对于每个控件,都MoveWindow一次,这样就基本可以解决这个问题,虽然复杂了些.
当你设计一个对话框的窗口时,就需要布局好所有按钮、文本显示框等等,由于每个按钮都是一个窗口,那么就需要移动这些窗口到合适的位置,这时就需要使用到MoveWindow函数。或者当你的界面需要动态地修改按钮位置,比如窗口放大了,按钮就需要跟着移动,否则按钮还在原来的位置,放大也不会移动按钮的位置,这时也需要使用MoveWindow函数重新设置按钮的位置。只要你想移动窗口,就可以考虑使用这个函数来实现。
控件中包含这样一个方法: void CAxCtrlCtrl::MoveCtrl(long left, long top, long right, long bottom) { MoveWindow(left, top, right-left, bottom-top, TRUE); } 然后在对话框中调用这个方法: void CTestDlg::OnOK() { m_ctrl.MoveCtrl(100,100,200,200); /*m_ctrl.MoveWindow(100, 100, 100, 100);*/ } 点OK的时候能看见控件移动了,但是一点控件,它又回到原来的位置上,为什么? 可是直接用控件的MoveWindow方法就很正常。百思不得其解! 又:MFC编写的控件和ATL编写的都有同样的问题 解决方案1: 你在OnOK中是MoveWindow了,但是你一点控件,它又执行IOleControl::DoVerb,把你的窗口变回去了。你可以在控件的WM_SIZE中修改控件的Extend。
m_listFriend.SetWindowPos(NULL, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOZORDER);