基于对话框的ActiveX控件开发以及MFC对话框调用点击无响应问题

基于MFC的ActiveX控件,主要功能是
Demo小样:


一、放大控件的设计过程

1.新建MFC ActiveX项目
2.添加对话框MyDlg类,对话框ID为IDD_MYDLG;
3.在控件类CActiveXDemoCtrl类中进行改写如下函数

  • 在CActiveXDemoCtrl.h声明对话框类的变量CMyDlg m_mydlg;
  • 改写OnCreate方法
 int CActiveXDemoCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (COleControl::OnCreate(lpCreateStruct) == -1)
        return -1;
    // TODO:  在此添加您专用的创建代码
    m_mydlg.Create(IDD_MYDLG, this); 
    return 0;
}
  • 重写OnSize方法
 void CActiveXDemoCtrl::OnSize(UINT nType, int cx, int cy)
{
    COleControl::OnSize(nType, cx, cy);
    // TODO:  在此处添加消息处理程序代码
    m_mydlg.MoveWindow(0,0,cx,cy);
}
  • 改写OnDraw函数
 void CActiveXDemoCtrl::OnDraw(
            CDC* pdc, const CRect& rcBounds, const CRect& /* rcInvalid */)
{
    if (!pdc)
        return;
    // TODO:  用您自己的绘图代码替换下面的代码。
}

4.为控件添加组件,设置好ID

  • 添加Button按钮
  • 添加2个Picture控件
  • 添加Slider bar滑块

5.相应的组件的初始化

BOOL CMyDlg::OnInitDialog()
{
    //TheImage Picture控件的初始化代码
    CvSize ImgSize;
    ImgSize.height = 127;
    ImgSize.width = 127;
    TheImage = cvCreateImage(ImgSize, IPL_DEPTH_8U, IMAGE_CHANNELS);
    //TheBigImage Picture控件的初始化代码
    CvSize ImgBigSize;
    ImgBigSize.height = 160;
    ImgBigSize.width = 480;
    TheBigImage = cvCreateImage(ImgBigSize, IPL_DEPTH_8U, IMAGE_CHANNELS);
    //滑动条代码
    CSliderCtrl *pSlidCtrl = (CSliderCtrl*)GetDlgItem(IDC_SLIDER_NUM);
    pSlidCtrl->SetRange(1, 5, TRUE);//设置滑动条范围
    pSlidCtrl->SetPos(1);//设置滑动条
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

6.添加点击Button的相应函数

void CMyDlg::OnBnClickedOpen()
{
    Filestr = OpenFileName();
    IplImage* ipl = cvLoadImage(Filestr, 1);
    // 判断是否成功读取图片   
    if (!ipl)
    {
        MessageBox(_T("读取不到图片"));
        return;
    }
    // 对上一幅显示的图片数据清零
    if (TheImage)
        cvZero(TheImage);
    // 对读入的图片进行缩放,使其宽或高最大值者刚好等于 180,再复制到 TheImage 中
    ResizeImage(ipl);
    // 调用显示图片函数
    ShowImage(TheImage, IDC_STATIC_PIC);
    // 释放 ipl 占用的内存 
    cvReleaseImage(&ipl);
}

CString CMyDlg::OpenFileName()
 {
    if (CString strFile = _T("")){
        CFileDialog dlg(
            TRUE, _T("*.jpg"), NULL,
            OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
            _T("image files (*.bmp; *.jpg) |*.bmp;*.jpg;*.png | All Files (*.*) |*.*||"), NULL
            );
        // 打开文件对话框的标题名
        dlg.m_ofn.lpstrTitle = _T("Open Image");
        // 判断是否获得图片
        if (dlg.DoModal() != IDOK)
            return 0;
        // 获取图片路径   
        strFile = dlg.GetPathName();
        return strFile;
    }
    else
        return strFile;
 }

7.将图片加载进Picure控件,用到了两个函数ResizeImage()和ShowImage()

void CMyDlg::ResizeImage(IplImage* img)
{
    // 读取图片的宽和高
    int imgwidth = img->width;
    int imgheight = img->height;
    // 找出宽和高中的较大值者
    int max = (imgwidth > imgheight) ? imgwidth : imgheight;
    // 计算将图片缩放到TheImage区域所需的比例因子
    scale = (float)((float)max / 127.0f);
    // 缩放后图片的宽和高
    int nw = (int)(imgwidth / scale);
    int nh = (int)(imgheight / scale);
    // 设置 TheImage 的 ROI 区域,用来存入图片 img
    cvSetImageROI(TheImage, cvRect(0, 0, nw, nh));
    // 对图片 img 进行缩放,并存入到 TheImage 中
    cvResize(img, TheImage);
    // 重置 TheImage 的 ROI 准备读入下一幅图片
    cvResetImageROI(TheImage);
}

void CMyDlg::ShowImage(IplImage* img, UINT ID)
{
    // 获得显示控件的 DC
    CDC* pDC = GetDlgItem(ID)->GetDC();
    // 获取 HDC(设备句柄) 来进行绘图操作     
    HDC hDC = pDC->GetSafeHdc();
    CRect rect;
    GetDlgItem(ID)->GetClientRect(&rect);
    // 求出图片控件的宽和高
    PicControlWidth = rect.right - rect.left;
    PicControlHeight = rect.bottom - rect.top;
    // 使图片的显示位置正好在控件的正中
    SetRect(rect, 0, 0, PicControlWidth, PicControlHeight);
    // 复制图片
    CvvImage cimg;
    cimg.CopyOf(img);
    // 将图片绘制到显示控件的指定区域内 
    cimg.DrawToHDC(hDC, &rect);
    ReleaseDC(pDC);
}

8.通过以上步骤就可以把图片加载到Picture控件中了,下面写鼠标在picture控件上的点击事件,注意一下几点

  • 点击Picture控件外的处理问题
  • 点击获取鼠标的相对位置
  • 通过缩放比计算出点击原图的坐标像素点
  • 在原图上绘制感兴趣区域ROI,然后进行放大至另外的Picture控件中

9.鼠标点击Picture控件上的处理函数

  • 根据图片的大小动态的调整ROI的区域大小
  • 感兴趣区域的越界处理问题,进行贴边处理
void CMyDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO:  在此添加消息处理程序代码和/或调用默认值
    if (Filestr == "")
    {
        MessageBox(_T("Please open the image!"));
        return;
    }
    CRect rect_ctr;
    (this->GetDlgItem(IDC_STATIC_PIC))->GetWindowRect(&rect_ctr); //获取Picture控件相对屏幕左上角的坐标,   
    //存储到rect_ctr中   
    ScreenToClient(rect_ctr);//获取Picture控件相对对话框客户区左上角的坐标   
    point.x -= rect_ctr.left;//point获取的是鼠标相对对话框客户区左上角的坐标,减去rect_ctr.left和   
    point.y -= rect_ctr.top;//rect_ctr.top后,即为鼠标相对Picture控件左上角的坐标  
    if (point.x > (rect_ctr.right - rect_ctr.left) || point.y > (rect_ctr.bottom - rect_ctr.top)
        || point.x < 0 || point.y < 0)
    {
    }
    else
    {
        //上图缩放比例系数
        original_x = scale * point.x;
        original_y = scale * point.y;
        CPoint point = CPoint(original_x, original_y);
        // 判断是否成功读取图片   
        CString mPath = Filestr;
        IplImage* ipl2 = cvLoadImage(mPath, 1);
        // 对上一幅显示的图片数据清零
        if (TheBigImage)
            cvZero(TheBigImage);
        // 对读入的图片进行缩放,使其宽或高最大值者刚好等于 180,再复制到 TheImage 中
        ResizeBigImage(ipl2, point);
        // 调用显示图片函数
        ShowImage(TheBigImage, IDC_STATIC_BIGPIC);
        // 释放 ipl 占用的内存 
        cvReleaseImage(&ipl2);
    }
}

10.放大至Picture控件上

void CMyDlg::ResizeBigImage(IplImage* img, CPoint point)
{
    //读取原图的坐标
    int x = point.x;
    int y = point.y;
    //读取原图的长宽
    int ori_height = img->height;
    int ori_width = img->width;
    int pic_size_set_h = 32;
    int pic_size_set_w = 96;
    //设置原图的ROI区域
    CvRect rect;
    //滑块的值
    int b = m_ctrlSlider;
    if (ori_height <= 100 && ori_width <= 100)
    {
        pic_size_set_h = 1;
        pic_size_set_w = 3;
    }
    if (ori_height > 100 || ori_height <= 200 && ori_width > 100 || ori_width <= 200)
    {
        pic_size_set_h = 8;
        pic_size_set_w = 24;
    }
    if (ori_height > 200 || ori_height <= 300 && ori_width >200|| ori_width <= 300)
    {
        pic_size_set_h = 15;
        pic_size_set_w = 45;
    }
    if (ori_height > 300 || ori_height <= 500 && ori_width >300 || ori_width <= 500)
    {
        pic_size_set_h = 30;
        pic_size_set_w = 90;
    }
    if (ori_height > 500&& ori_width > 500)
    {
        pic_size_set_h = 35;
        pic_size_set_w = 35*3;
    }
    rect.height = b * pic_size_set_h;
    rect.width = b * pic_size_set_w;
    rect.x = x - 0.4*(rect.width);
    rect.y = y - 0.4*(rect.height);
    //对感兴趣区域越界进行处理
    if (rect.x<0)
    {
        rect.x = 0;
    }
    if (rect.x + rect.width > ori_width)
    {
        rect.x = rect.x - (rect.x + rect.width - ori_width);
    }
    if (rect.y + rect.height > ori_height)
    {
        rect.y = rect.y - (rect.y + rect.height - ori_height);
    }
    if (rect.y < 0)
    {
        rect.y = 0;
    }
    cvSetImageROI(img, rect);
    cvResize(img, TheBigImage);
    // 重置 TheImage 的 ROI 准备读入下一幅图片
    cvResetImageROI(TheBigImage);
}

11.为Slide bar滑块添加滚轮响应函数

基于对话框的ActiveX控件开发以及MFC对话框调用点击无响应问题_第1张图片


二、控件的调试过程

1.测试控件工具ActiveX Control text Container,在CSDN上可以下载到编译好添加至工具栏就可以使用了

基于对话框的ActiveX控件开发以及MFC对话框调用点击无响应问题_第2张图片

2.添加控件,点击File->Insert Control

基于对话框的ActiveX控件开发以及MFC对话框调用点击无响应问题_第3张图片

3.控件显示

)


三、控件的调用过程

1.新建一个基于对话框的MFC程序
2.为控件添加包装类 VS2013下

  • 点击项目
  • 点击添加类
  • 选择MFC -> ActiveX控件中的MFC类
  • 生成保装类

3.添加你的包装类的控件变量
4.运行后卡死


四、MFC对话框调用点击无响应问题

这个问题困扰了我很久,在其他的C#和C++窗体函数中调用控件中都没有出现点击卡死问题
具体的原因是因为:

  • 父对话框与子对话框的消息传不过去

解决办法

基于对话框的ActiveX控件开发以及MFC对话框调用点击无响应问题_第4张图片

你可能感兴趣的:(OpenCV,图像处理,MFC)