各位高手,本人最近用了一个CPictureEx的类,用于在picture控件内显示图片,尤其是显示动态的GIF图片,很好用。可是美中不足的地方是该类的作者提供的函数显示的GIF不能自动适应picture框的大小,而是让picture控件去适应GIF的大小。问题如下:
1. 有没有其他方法可做到在对话框特定区域内显示一个多贞的GIF动画图片?而且GIF图片要自适应该区域的大小;2. 我的对话框已经通过OnEraseBkgnd创建了背景,而且面板上有Edit 编辑框和 ListControl控件 ,有没有办法让控件所占有的白色区域透明化,做到不遮掩背景图片并把背景图片显示出来?我曾经用过 HBRUSH OnCtlColor,可是失败了……3. 列表框list 如何按我所想随时隐藏和显示?    还请各位指点!

解决方案 »

  1.   

    1、你看看CPictureEx的具体实现方法,如果是用贴图方式,可以试试把贴图函数换成自动缩放的。
    2、可以用自绘控件的方式来解决。
    3、调用ShowWindow就可以。
      

  2.   

    如果只是默认风格的Edit和ListCtrl控件,可以不用自绘。在对话框类中响应WM_CTLCOLOR消息,判断出是需要处理成透明背景的控件时直接return (HBRUSH)GetStockObject(NULL_BRUSH);另外自己从CListCtrl派生一个类,子类化对应的控件,响应WM_ERASEBKGND消息,直接返回TRUE。
      

  3.   

    如果对话框背景是纯色,可以用OnCtlColor,如果是贴图,就得自绘控件。
      

  4.   

    没错,的确需要贴图的,可是我对自绘很不熟悉……
        “从CListCtrl派生一个类,子类化对应的控件,响应WM_ERASEBKGND消息”是否近似等效于把CListCtrl 当作 CDialog 一样地看待,按创建对话框的思路载入背景贴图?然后放大图片使得局部显示的区域正好和对话框那部分的背景重合以达到效果?
         另外,对于edit编辑框呢,是不是也可以用这样的思路处理? 
      

  5.   

    我把CPicture类相关函数贴一下,因为该类是很复杂的,只能罗列局部:
    BOOL CPictureEx::Draw()
    {
    if (!m_bIsInitialized)
    {
    TRACE(_T("Call of one the CPictureEx::Load() member functions before calling Draw()\n"));
    return FALSE;
    }; if (IsAnimatedGIF())
    {
    // the picture needs some animation
    // we'll start the thread that will handle it for us

    unsigned int nDummy;
    m_hThread = (HANDLE) _beginthreadex(NULL,0,_ThreadAnimation,this,
    CREATE_SUSPENDED,&nDummy);
    if (!m_hThread)
    {
    TRACE(_T("Draw: Couldn't start a GIF animation thread\n"));
    return FALSE;

    else 
    ResumeThread(m_hThread);

    else
    {
    if (m_pPicture)// IPicture * m_pPicture;
    {
    long hmWidth;
    long hmHeight;
    m_pPicture->get_Width(&hmWidth);
    m_pPicture->get_Height(&hmHeight);
    if (m_pPicture->Render(m_hMemDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy, 
    0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK)
    {
    Invalidate(FALSE);
    return TRUE;
    };
    };
    }; return FALSE;
    }
    // std::vector<TFrame> m_arrFrames;
    BOOL CPictureEx::IsAnimatedGIF() const
    {
    return (m_bIsGIF && (m_arrFrames.size() > 1));
    }void CPictureEx::OnPaint() 
    {
    CPaintDC dc(this); // device context for painting

    ::BitBlt(dc.m_hDC,0,0,m_PictureSize.cx,m_PictureSize.cy,
    m_hMemDC,0,0,SRCCOPY);
    }
      

  6.   

    把这部分代码贴出来,默认控件的话应该不用自绘的:
    HBRUSH CXXXDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
    {
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

    // TODO: Change any attributes of the DC here
    if ( nCtlColor == CTLCOLOR_STATIC )
    {
    pDC->SetBkMode(TRANSPARENT);
    return (HBRUSH)GetStockObject(NULL_BRUSH);
    }
    // TODO: Return a different brush if the default is not desired
    return hbr;
    }
      

  7.   

    响应WM_ERASEBKGND消息的目的是不让控件擦除背景。
    BitBlt换成StretchBlt试试,感觉应该可以。
      

  8.   

    HBRUSH C***Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
    {
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

        // TODO: Change any attributes of the DC here
        if ( nCtlColor == CTLCOLOR_STATIC )
        {
            pDC->SetBkMode(TRANSPARENT);
            return (HBRUSH)GetStockObject(NULL_BRUSH);
        }
        if ( nCtlColor == CTLCOLOR_EDIT )
        {
            pDC->SetBkMode(TRANSPARENT);
            return (HBRUSH)GetStockObject(NULL_BRUSH);
        }

    // TODO: Return a different brush if the default is not desired
    return hbr;
    }
    试用了以上的代码,发现效果不错,暂时谢过楼上2位高手的指点,其他情况还有待解决
      

  9.   

    补充一下,以上代码虽然暂时达到我要的效果,可是发现有一个刷新上的缺陷:
       编辑框是要进行数据编辑的, 在我想修改多行文本的编辑框 的时候, 选定某2个字会发现文字显示混乱;特别是利用键盘上的Delete 去做文字删除的时候,编辑框内的背景处于蓝色选定状态,内部文字显示混乱!
       请问这种显示应该如何解决?
      

  10.   

    9楼的代码有资源泄露,要按照我在3楼所说的方式,不要在最开始就调用CDialog::OnCtlColor。
    因为设置了文字背景透明,在输出文字前需要自己用InvalidateRect刷新编辑框的父窗口中相应的区域。
      

  11.   

    我运用了一个函数
    void COneDlg::OnRefresh() 
    {
    CRect rect;
    GetDlgItem(IDC_EDIT_TIME)->GetWindowRect(rect);
    ScreenToClient(rect);
    InvalidateRect(rect);
    }   可是,我还是没掌握如何在[color=#3366FF]合时的时机设置相关响应函数去清理编辑框的背景…… 当我把鼠标点击放入编辑框,选定特定的文字,按Delete键修改,或者是输入文字,回车等,问题依旧,想了一下,难不成以上的都要进行特别的消息响应再调用OnRefresh?[/color]
       曾经试过在OnEraseBkgnd或者OnPaint内调用,但是编辑框内不停地闪弄得我眼都花了……也想过设定定时器进行刷新,但是似乎也是无法避开闪烁的问题……
    有没有更完善的解决方法?
      

  12.   

    你可以先试试响应Edit控件发出的EN_CHANGE通知来刷新。
      

  13.   

    可惜不行,每打一个字母就闪烁一次……
    我主要是对编辑框的多行文本进行编辑和选定,删除的时候用键盘的Delete
    有没有对选定文本或Dlete 的时候产生响应的函数?   如果注定用CDialog::OnCtlColor无法使我的问题得到圆满解决,那么是不是我应该往Edit控件内加载图片了?
      

  14.   

    能否在Edit的EN_CHANGE通知内编写一个函数,捕获键盘输入,然后进行判断是否要刷新。如何捕获键盘输入呢?用Hook?
      

  15.   

    这种情况想不出简便的解决方法。如果要获得键盘输入,可以重载窗口的PreTranslateMessage来判断发给Edit控件的消息。
      

  16.   

    我以前也可以用过用CPictureEx来显示GIF,你可以设置一个参数让pic适应窗口大小的啊,我当时是吧gif显示在一个button的区域
    CPicViewButton 从button继承过来
    BOOL CPicViewButton::SetGifImagePath(CString strImageFilePath)
    {
    m_strImagePath = strImageFilePath;
    if(m_pGifRead!=NULL)
    {
    delete m_pGifRead;
    m_pGifRead = NULL;
    }
    m_pGifRead = new CPictureEx ;
    CRect rect ;
    this->GetClientRect(&rect) ;
    rect.left += 5;
    rect.right -=5;
    rect.top +=5;
    rect.bottom -=5;
    m_pGifRead->Create(_T(""), WS_CHILD , rect, this, 1) ;
    m_pGifRead->Load(m_strImagePath) ;
    m_pGifRead->SetRenderMode(CPictureEx::RENDER_MODE_STRETCH) ;
    m_pGifRead->Draw();
    m_pGifRead->ShowWindow(SW_SHOW) ;
    m_pGifRead->UpdateWindow() ;
    return TRUE;
    }
      

  17.   

    我有个新想法,在对应编辑框内设置焦点的时候,给其背景填充上白色,而且不通过CDialog::OnCtlColor进行设置;
    等焦点转移后,再进行刷新,就可以把闪烁次数减少。
    请问这个想法能否做到? 
      

  18.   

    17楼的朋友,请问你使用的是哪个CPictureEx?
    m_pGifRead->SetRenderMode(CPictureEx::RENDER_MODE_STRETCH) ; 报错了,我使用的那个不存在SetRenderMode这个函数我使用的CPictureEx类包含如下信息, 你的呢?
    // Written by Oleg Bykov ([email protected])
    // Copyright (c) 2001如果你有新的,请传一份给我,谢谢!
      

  19.   

    以上方法已经找到解决途径,现将代码贴出供大家分享:
    HBRUSH COneDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
    { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

        // TODO: Change any attributes of the DC here
        if ( nCtlColor == CTLCOLOR_STATIC )
        {
            pDC->SetBkMode(TRANSPARENT);
            return (HBRUSH)GetStockObject(NULL_BRUSH);
        }
        if ( nCtlColor == CTLCOLOR_EDIT )
        {//关键:利用判断决定是否采用透明模式
    if(GetFocus()->GetDlgCtrlID() == IDC_EDIT_TIME)
    {
    OnChangeEditTime() ;
    }
    else
            {
    pDC->SetBkMode(TRANSPARENT);
    return (HBRUSH)GetStockObject(NULL_BRUSH);
    }
        }

    // TODO: Return a different brush if the default is not desired
    return hbr;
    }
    //对应EditBox资源的刷新
    void COneDlg::OnRefresh(UINT nCtrlResource) //On Refresh
    {
    CRect rect;
    GetDlgItem(nCtrlResource)->GetWindowRect(rect);
    ScreenToClient(rect);
    InvalidateRect(rect);
    }
    //响应对应的EditBox
    void COneDlg::OnSetfocusEditTime() 
    {
    Invalidate();//the key
    }
    void COneDlg::OnKillfocusEditTime() 
    {
    // TODO: Add your control notification handler code here
    OnRefresh(IDC_EDIT_TIME);
    }
        以上代码只是针对单一的Editbox,如果控件较多,必须再次封装函数。
    当然,希望还有更加简洁方便的方法,希望有兴趣的朋友一同参与讨论。
      

  20.   

    以上代码中有个Bug:当在Editbox设置焦点后,如果不按下对话框上任意一个按钮做为焦点转移, 而是随后直接单击其它程序的窗口,则造成程序崩溃!
        本人已经发帖,题为:关于对话框焦点转移后出现程序崩溃的问题
    希望在那里可以找到解决途径,欢迎大家参与讨论!