一.添加最大化最小化窗口
鼠标右键单击对话框空白处选择属性,将Maximize Box和Minimize Box修改为True,即可实现对话框最大化和最小化功能的添加。
二.控件变化
目的:使所用控件的大小随着对话框窗口的最大化和最小化进行相应尺寸的变化。
思路:比如原来对话框大小为a,现在为b,原来控件大小为c,那么现在的控件大小应该为c*b/a;(注意a不能是0)。
方法:通过Windows的WM_SIZE消息响应函数,这个函数在对话框大小发生变化的时候调用,系统便可自动给出当前对话框的大小,我们可以再记录一下原对话框大小,然后根据控件做出相应比例的调整。
WM_SIZE消息响应函数的添加方法:
右击窗口的空白处,选择类向导,点击“消息”选项卡,找到WM_SIZE并选中,然后单击右侧“添加处理程序”,再点击"编辑代码即可"。
举例:
假设对话框类为CMyDlg类,那么首先设置一个变量
CRect m_rect; //用于保存原对话框大小
那么在对话框创建的时候先获得对话框的大小
BOOL CMyDlg::OnInitDialog()
{
…
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
GetClientRect(&m_rect); //获取对话框的大小
return TRUE; // return TRUE unless you set the focus to a control
}
然后再手动添加一个函数,用以实现具体的变化
void CMyDlg::ChangeSize(UINT nID, int x, int y) //nID为控件ID,x,y分别为对话框的当前长和宽
{
CWnd *pWnd;
pWnd=GetDlgItem(nID);
if(pWnd!=NULL) //判断是否为空,因为在窗口创建的时候也会调用OnSize函数,但是此时各个控件还没有创建,Pwnd为空
{
CRect rec;
pWnd->GetWindowRect(&rec); //获取控件变化前的大小
ScreenToClient(&rec); //将控件大小装换位在对话框中的区域坐标
rec.left=rec.left*x/m_rect.Width(); //按照比例调整空间的新位置
rec.top=rec.top*y/m_rect.Height();
rec.bottom=rec.bottom*y/m_rect.Height();
rec.right=rec.right*x/m_rect.Width();
pWnd->MoveWindow(rec); //伸缩控件
}
}
最后添加windows消息响应函数OnSize:
void CMyDlg::OnSize(UINT nType, int cx, int cy) //cx,cy就是当前对话框的长和宽
{
CDialog::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
if(nType!=SIZE_MINIMIZED ) //判断窗口是不是最小化了,因为窗口最小化之后 ,窗口的长和宽会变成0,当前一次变化的时就会出现除以0的错误操作
{
ChangeSize(IDC_BUTTON1,cx,cy); //对每一个控件依次做调整
ChangeSize(IDC_BUTTON2,cx,cy);
GetClientRect(&m_rect); //最后要更新对话框的大小,当做下一次变化的旧坐标
}
}
三.图片显示在控件上
前面两个虽然实现了窗口的最大化和最小化,以及各个控件随着窗口变化所进行的相应变化,但是如何保证对话框窗口、控件变化的同时,使得图片或者视频帧显示在变化后的控件上呢?
在BOOL CMFCYOLODlg::OnInitDialog()中添加如下代码:
cv::namedWindow("src1", WINDOW_AUTOSIZE);//设置窗口名
HWND hWndl = (HWND)cvGetWindowHandle("src1");//hWnd 表示窗口句柄,获取窗口句柄
HWND hParent1 = ::GetParent(hWndl);//GetParent函数一个指定子窗口的父窗口句柄
::SetParent(hWndl, GetDlgItem(IDC_PIC)->m_hWnd);
::ShowWindow(hParent1, SW_HIDE);
然后再在各个消息响应代码函数中添加如下代码:
CWnd *pWnd1 = GetDlgItem(IDC_PIC);//CWnd是MFC窗口类的基类,提供了微软基础类库中所有窗口类的基本功能。
pWnd1->GetClientRect(&rect1);//GetClientRect为获得控件自身的坐标大小
在.h中定义CRect rect1;
resize(mat_img, mat_img, Size(rect1.Width(), rect1.Height()));
imshow("src1", mat_img);
按钮一响应函数如下:实现打开一张图片,并显示在图片控件上。
void CMFCYOLODlg::OnBnClickedButton1()
{
CWnd *pWnd1 = GetDlgItem(IDC_PIC);//CWnd是MFC窗口类的基类,提供了微软基础类库中所有窗口类的基本功能
pWnd1->GetClientRect(&rect1);//GetClientRect为获得控件自身的坐标大小
CFileDialog dlg(TRUE, _T("*.jpg;*.jpeg"), 0, 6UL, _T("Image(*.jpg;*.jpeg)|*.jpg;*.jpeg||"));
if (dlg.DoModal() != IDOK)return;
USES_CONVERSION;
std::string filename = T2A(dlg.GetPathName());
mat_img = cv::imread(filename);
resize(mat_img, mat_img, Size(rect1.Width(), rect1.Height()));
imshow("src1", mat_img);
检测视频时以及调用摄像头时同理,只需在按钮响应函数中获取变化后的控件大小,并利用resize函数使得要显示的图像和变化后控件大小一致,同时通过初始化时利用父、子窗口方式使得图像显示图片控件上。
我的mfc工程界面截图:
这是我利用mfc调用yolov3动态链接库的完整工程界面,其中无论检测单张图片还是视频亦或是摄像头检测均可实现随着窗口最大或者最小化的同时,各种控件以及显示图像(视频帧)的相应变化。
补充:
对于视频和摄像头检测:
每次窗口大小变化后,需要退出,然后重新点击对应按钮载入输入内容,方可实现要显示的内容正好显示在图片控件上。
对于图片的显示以及检测结果图片的显示:
均可以实现图片大小随控件大小相应变化,不需要重新点击对应按钮。因为这部分在代码中添加了定时器的使用。
具体请看完整工程代码:
MFC+YOLOv3