MFC编程记录--图片控件类

       因公司项目需要,使用mfc写一个可以编辑图片的功能。本人初学,所以就四处查询资料,下面是我实现的细节介绍,如有不对,请指出,谢谢。

       本人使用了atlimage.h库中得CImage类来作为图片编辑的主要功能实现。主要是CImage类对图片的插入、保存都有很方便的封装。直接LoadFile就可以加载一张图片,Save就可以将内存中的图片保存到本地,很方便。本人实现的图片类是基于CEdit类的,主要是因为CEdit类是我接触的第一个基本控件(mfc提供的标准控件)。大致思路是将CEdit类作为图片显示的区域,然后将CEdit作为画布区域,将图片绘制在上面即可。其次是图片需要可以被编辑大小和位置,我就想着把这个功能封装在图片控件的内部,作为控件本身的功能来实现,而不是将编辑功能作为调用类的控制。因此,我就查了各方资料,最后觉得windows的ncHittest消息很是方便,就在我的图片控件中添加了ncHittest的消息(名字应该是这个,记不太清楚)。而ncHittest的消息我的理解是告诉windows系统,此时用户的鼠标所处的位置是在客户区还是在非客户区,而windows对于客户区和非客户区有默认的处理方式。而对于非客户区,系统又分为HTTOPLEFT,HTTOPRIGHT,HTBOTTOMLEFT,HTBOTTOMRIGHT,HTLEFT,HTTOP,HTRIGHT,HTBOTTOM,HTCAPTION等几种处理方式(具体的说明可以百度,很容易找到)。因此有了这个基础之后,我们只需要欺骗windows,我们此时是在HTCLIENT还是非HTCLIENT即可。然后,只需在事件处理时通过判断鼠标的位置告诉windows此时的位置即可。自此,图片的插入、拖动和放大缩小就ok了。

       但是,却存在一个问题,就是图片在被拖动和改变大小时的界面显示存在问题(图片滞留)。因此,我就添加了刷新函数(Invalidate,UpdateWidnow),但是却并没有改善。于是我就加上this->GetParent()->Invalidate()和this->GetParent()->UpdateWindow()函数,虽然解决来界面的图片滞留问题,但是却导致了界面被频繁的刷新而闪烁严重的问题(未能找到解决方案)。

      该图片控件还有一个很苦恼的地方就是,因为是将图片绘制在区域上的,但是调用了刷新函数之后,之前绘制的图片就没有了,就需要在刷新之后重新绘制。因此,我就添加了onPaint消息,然后在onPaint()函数中重新调用图片绘制函数。但是如果在OnPaint中直接调用重新绘制图片的函数,则会导致严重的刷新问题,因此需要再加上一些条件(比如用户焦点在控件上时则不调用重新绘制函数等)。

     这其中还有一个小细节,就是关于向画布中绘制图片的几种方式(详细的解说百度,代码在稍后函数中有体现,注释掉的那块)。还有一点是在图片被修改大小时会出现失真的问题,这个只要加上一句代码就可(我也是后来查资料解决的,稍后代码里面已经加了):cdc->SetStretchBltMode(HALFTONE);

下面的部分代码是绘制图片的函数:

void CMyPictureCtrl::ShowImage(){
    CRect rc;
    this->GetWindowRect(&rc);

    if(hasFile){
        if(image == NULL){
            int pw,ph;

            image = new CImage();
            image->Load(picFile);

            if(rc.Width() == 0 || rc.Height() == 0){
                GetParent()->GetClientRect(&rc);

                pw = image->GetWidth();
                ph = image->GetHeight();

                if(pw < rc.right - rc.left){
                    rc.left = ( rc.right - pw ) / 2;
                    rc.right = rc.left + pw;
                }else{
                    rc.left = 2;
                }

                if(ph < rc.bottom - 80 - rc.top ){
                    rc.top  = ( rc.bottom -  ph ) / 2 + 65;
                    rc.bottom = rc.top + ph ;
                }else{
                    rc.top = 65;
                }

                this->MoveWindow(rc,TRUE);
            }
        }
        
        CDC* cdc = this->GetDC();
        ScreenToClient(&rc);

//第一种绘图方式

//         SetStretchBltMode(cdc->m_hDC,STRETCH_HALFTONE);
//         image->StretchBlt(cdc->m_hDC,rc,SRCCOPY);


//第二种绘图方式
        cdc->SetStretchBltMode(HALFTONE);
        image->Draw(cdc->m_hDC,0,0,rc.Width(),rc.Height(),0,0,
            image->GetWidth(),image->GetHeight());
       

//第三种绘图方式

//         CDC dcMem;
//         dcMem.CreateCompatibleDC(cdc);
//         CBitmap bitmap;
//         bitmap.CreateCompatibleBitmap(cdc,rc.Width(),rc.Height());
//         dcMem.SelectObject(bitmap);
//         dcMem.FillSolidRect(rc,RGB(255,255,255));
//
//         image->Draw(dcMem.m_hDC,rc,rc);
//         dcMem.SetBkMode(TRANSPARENT);
//
//         cdc->BitBlt(0,0,rc.Width(),rc.Height(),&dcMem,0,0,SRCCOPY);
//         bitmap.DeleteObject();

        ReleaseDC(cdc);
    }

}


因为是新手,所以现在各种功能都是自己YY,然后配合使用mfc的消息机制来完成的,所以在实现上显得很杂乱,望能指点,谢观!

猜你喜欢

转载自blog.csdn.net/u014443884/article/details/49069823