起因
最近用mfc做了不少小软件,界面上都是基于CDialog或者CFormView,界面不能缩放一直是问题。一个办法是在OnSize()里面调用所有控件的MoveWindow()函数,根据比例调整控件大小。但是在界面上控件比较多的时候,这个发放就显得很繁琐了。于是我写了一个CAutoResize类,去实现控件的统一缩放。
工作原理
原理上很简单,对于MFC中的CDilalog,它的信息都存在程序文件夹下的XXX.rc中,XXX是项目名称。如下图所示,
CAutoResize类首先就读取XXX.rc,先获取控件长宽信息,dlgWidth和dlgHeight。然后获取相应控件上的ID,x和y坐标,控件宽度和高度,用这些值去除以dlgWidth和dlgHeight得到相应的比例,然后把信息存在Vector数组中。
Init函数
1 bool CAutoResize::Init(char *resourceName, char *dlgID) 2 { 3 CString strRcName; 4 CString strDlgID; 5 strDlgID.Format("%s", dlgID); 6 strRcName.Format("./%s", resourceName); 7 8 if(!rcFile.Open(strRcName, CFile::modeRead)) 9 { 10 AfxMessageBox("can't open the resource file"); 11 } 12 CString strRead; 13 14 //找到dlgID所在的行 15 16 while(rcFile.ReadString(strRead)) 17 { 18 TRACE("strRead:%s ", strRead); 19 20 if(!Match(strRead, strDlgID)) 21 { 22 continue; 23 } 24 else 25 { 26 int commaIndex = strRead.Find(","); 27 strRead = strRead.Mid(commaIndex + 1); 28 commaIndex = strRead.Find(","); 29 strRead = strRead.Mid(commaIndex + 1); 30 commaIndex = strRead.Find(","); 31 dlgWidth = atoi((const char*)strRead.Left(commaIndex)); 32 strRead = strRead.Mid(commaIndex + 1); 33 dlgHeight = atoi((const char*)strRead); 34 TRACE("dlgWidth:%d dlgHeight:%d ", dlgWidth, dlgHeight); 35 36 37 for(int i=0;i<3;i++) 38 { 39 rcFile.ReadString(strRead); 40 41 } 42 break; 43 } 44 } 45 46 47 // 开始读取各个控件的信息 48 while(rcFile.ReadString(strRead)) 49 { 50 Item item; 51 52 53 TRACE("strRead:%s ", strRead); 54 if(strRead == "END") 55 { 56 break; 57 } 58 CString str = strRead.Left(20); 59 str.TrimLeft(" "); 60 str.TrimRight(" "); 61 TRACE("begin to store items "); 62 strRead = strRead.Mid(20); 63 strRead.TrimLeft(" "); 64 65 66 CString tempRead, strTemp; 67 tempRead.Empty(); 68 strTemp.Empty(); 69 long pos; 70 71 do 72 { 73 tempRead.TrimLeft(" "); 74 strRead = strRead + tempRead; 75 pos = rcFile.GetPosition(); 76 77 rcFile.ReadString(tempRead); 78 TRACE("tempRead:%s ", tempRead); 79 strTemp = tempRead.Left(20); 80 strTemp.TrimLeft(" "); 81 strTemp.TrimRight(" "); 82 83 TRACE("strTemp:%s ", strTemp); 84 85 }while(strTemp.IsEmpty()); 86 87 88 rcFile.Seek(pos, CFile::begin); 89 90 TRACE("strRead:%s ", strRead); 91 92 TRACE("str:%s ", str); 93 94 //不同的控件类型格式不同,分情况讨论 95 // format: ID, x, y, width, height, style 96 if(str == _T("EDITTEXT") || str == _T("COMBOBOX")) 97 { 98 int commaIndex = strRead.Find(","); 99 //存储控件id 类型CString, 过会还要读取resource.h去获取对应的Int类型id 100 item.itemID = strRead.Left(commaIndex); 101 TRACE("itemID:%s ", strRead.Left(commaIndex)); 102 strRead = strRead.Mid(commaIndex + 1); 103 commaIndex = strRead.Find(","); 104 // 坐标x比例 105 106 item.xPercentage = (float)atoi((const char *)strRead.Left(commaIndex)) / (float)dlgWidth; 107 strRead = strRead.Mid(commaIndex + 1); 108 commaIndex = strRead.Find(","); 109 // 坐标y比例 110 item.yPercentage = (float)atoi((const char *)strRead.Left(commaIndex)) / (float)dlgHeight; 111 strRead = strRead.Mid(commaIndex + 1); 112 commaIndex = strRead.Find(","); 113 // 宽比例 114 item.widthPercentage = (float)atoi((const char *)strRead.Left(commaIndex)) / (float)dlgWidth; 115 strRead = strRead.Mid(commaIndex + 1); 116 //高比例 117 item.heightPercentage = (float)atoi((const char *)strRead) / (float)dlgHeight; 118 119 120 } 121 // format: text, id, class, style, x, y, width, height 122 else if(str == _T("CONTROL")) 123 { 124 int commaIndex = strRead.Find(","); 125 strRead = strRead.Mid(commaIndex + 1); 126 commaIndex = strRead.Find(","); 127 item.itemID = strRead.Left(commaIndex); 128 TRACE("itemID:%s ", strRead.Left(commaIndex)); 129 strRead = strRead.Mid(commaIndex + 1); 130 commaIndex = strRead.Find(","); 131 strRead = strRead.Mid(commaIndex + 1); 132 commaIndex = strRead.Find(","); 133 strRead = strRead.Mid(commaIndex + 1); 134 commaIndex = strRead.Find(","); 135 item.xPercentage = (float)atoi((const char *)strRead.Left(commaIndex)) / (float)dlgWidth; 136 137 strRead = strRead.Mid(commaIndex + 1); 138 commaIndex = strRead.Find(","); 139 item.yPercentage = (float)atoi((const char *)strRead.Left(commaIndex)) / (float)dlgHeight; 140 strRead = strRead.Mid(commaIndex + 1); 141 commaIndex = strRead.Find(","); 142 item.widthPercentage = (float)atoi((const char *)strRead.Left(commaIndex)) / (float)dlgWidth; 143 strRead = strRead.Mid(commaIndex + 1); 144 145 item.heightPercentage = (float)atoi((const char *)strRead) / (float)dlgHeight; 146 147 148 149 } 150 // format :text, id, x, y, width, height 151 else 152 { 153 TRACE("others "); 154 int commaIndex = strRead.Find(","); 155 strRead = strRead.Mid(commaIndex + 1); 156 commaIndex = strRead.Find(","); 157 item.itemID = strRead.Left(commaIndex); 158 TRACE("itemID:%s ", strRead.Left(commaIndex)); 159 strRead = strRead.Mid(commaIndex + 1); 160 commaIndex = strRead.Find(","); 161 item.xPercentage = (float)atoi((const char *)strRead.Left(commaIndex)) / (float)dlgWidth; 162 163 strRead = strRead.Mid(commaIndex + 1); 164 commaIndex = strRead.Find(","); 165 item.yPercentage = (float)atoi((const char *)strRead.Left(commaIndex)) / (float)dlgHeight; 166 strRead = strRead.Mid(commaIndex + 1); 167 commaIndex = strRead.Find(","); 168 item.widthPercentage = (float)atoi((const char *)strRead.Left(commaIndex)) / (float)dlgWidth; 169 strRead = strRead.Mid(commaIndex + 1); 170 171 item.heightPercentage = (float)atoi((const char *)strRead) / (float)dlgHeight; 172 173 174 175 176 } 177 178 TRACE("%s %f %f %f %f ", item.itemID, item.xPercentage, item.yPercentage, item.widthPercentage, item.heightPercentage); 179 itemVec.push_back(item); 180 TRACE("num of cotrol object is :%d", itemVec.size()); 181 182 } 183 184 return true; 185 }
GetIdFromString函数,读取resource.h获取对应Int类型id。
1 int CAutoResize::GetIdFromString(CString &str) // Convert the type of control's ID from string to int. 2 { 3 4 CStdioFile file; 5 int len = str.GetLength(); 6 if(!file.Open(_T("./resource.h"), CFile::modeRead)) // read the resource file 7 { 8 AfxMessageBox(_T("resource file open failed")); 9 return 0; 10 } 11 CString strRead; 12 while(file.ReadString(strRead)) 13 { 14 if(!strRead.IsEmpty()) 15 { 16 if(strRead.Left(2) == "#d") 17 { 18 strRead = strRead.Mid(8); 19 int commaIndex = strRead.Find(" "); 20 21 if(strRead.Left(commaIndex) == str) 22 { 23 strRead = strRead.Mid(commaIndex+1); 24 strRead.TrimLeft(" "); 25 TRACE("%s ", strRead); 26 return atoi((const char*)strRead); // get item id; 27 } 28 } 29 } 30 } 31 return 0; 32 }
Resize函数 改变控件大小
1 void CAutoResize::Resize(CView *pView, int cx, int cy) 2 { 3 4 //从vector中取出每个控件信息 5 std::vector<Item>::iterator iter; 6 for(iter = itemVec.begin(); iter != itemVec.end();++iter) 7 { 8 Item *item = static_cast<Item*>(iter); 9 int x = item->xPercentage*cx; 10 int y = item->yPercentage*cy; 11 int width = item->widthPercentage*cx; 12 int height = item->heightPercentage*cy; 13 CRect rc; 14 rc.SetRect(x, y, x+width, y+height); 15 TRACE("cotrol name:%s ", item->itemID); 16 TRACE(" x:%d, y:%d, %d, height:%d ", x, y, width, height); 17 int id = GetIdFromString(item->itemID); 18 19 // MoveWindow 20 21 if(id) 22 { 23 (pView->GetDlgItem(id))->MoveWindow(&rc); 24 } 25 } 26 }
使用方法
1.在CDialog类中加入CAutoSize类的成员变量
2.在对话框的初始化函数中调用Init函数,传入资源文件名和对话框id
3.在OnSize()中调用Resize函数。
注:对话框中必须给每个CStatic控件不同的id,不然就不能改变大小。
不足之处
1.一些控件类型格式不同,目前init函数里所测试过的格式不多,不排除有一些格式读不出来。所以这个类只是提供一种方法,并不通用。
2.由于运行时需要读取XXX.rc和resource.h文件,所以在生成的exe运行文件文件夹下也必须要有这两个文件。