做了一个触摸屏的图标滚动的界面模块(基于PC的),使用 GDI+ 进行绘图,独立编译成 DLL。
同一工程下建立了一个测试用的程序在VS2005下,按下“启动调试”按钮运行后,界面图标滚动时运行流畅(无论是 DEBUG 或 RELEASE 下)
图标滚动时CPU占用只有14%左右但如果在文件夹下直接运行该程序的话,界面图标滚动时则非常“卡”
看过任务栏管理器中的数据,内存增加到一定量后不会在递增、GDI对象也维持不变,即内存泄露的可能性不大
但滚动图标时的CPU占用去到25%了
但如果将 GDI+ 绘制图标的代码注释掉,其它保持不变,那么无论是VS启动调试或在文件夹下直接运行,那么速度是一样的
调用GDI+绘图的代码就只有几行:void CRollPanelWnd::DrawImage(CDC *pDC, Image *pImg, const RECT &rect, BOOL bDefaultSize)
{
    if (pImg == NULL || pImg->GetLastStatus() != Ok)
        return;    int cx = rect.right - rect.left;
    int cy = rect.bottom - rect.top;
    if (bDefaultSize)
    {
        cx = (int)pImg->GetWidth();
        cy = (int)pImg->GetHeight();
    }    Graphics graphics(pDC->m_hDC);
    graphics.DrawImage(pImg, rect.left, rect.top, cx, cy);
}pImg 是从按钮图标被创建起一直到按钮被删除都会一直保存的
究竟是什么原因?是 gdi+ 的库问题吗?还是 VS2005 的问题?最后还是不是我自己的问题?

解决方案 »

  1.   

    这个只能自己测试了,你可以先不用编绎成DLL通过其它程序来调用,直接编成一个程序试试,另外,看一下编绎选项,改变优化选项试试,等找出原因后再编绎成DLL
      

  2.   

    这个应该和GDI+没有关系,在其他机子上也会么
      

  3.   

    要不用TextureBrush看看
    TextureBrush myBrush(bmp);
    graphics.FillRectangle这个效率比那个DrawImage高很多。尝试下吧
      

  4.   

    是不是在不停的DrawImage啊
    调试的时候可能2秒画一次直接启动的时候就一秒画好几次了
      

  5.   

    最好上下调用CRollPanelWnd::DrawImage代码的地方和完整函数。感觉那里有问题哦
      

  6.   


    已经测试过了,结果还是一样!
    在IDE中按下"启动调试"后,程序的拖动过程会比直接在文件夹上运行要顺畅
      

  7.   


    问题是我把画图的代码注释后,无论程序在哪运行效率都一样~
    所以我怀疑是不是我的 GDI+ 库有问题~
    我自己在 C 盘搜索过,一共有3个版本的 GDI+ 库
      

  8.   

    是不是GDI+加载库的时间问题,开始有没有加载
      

  9.   

    如果怀疑是GDI+的问题的话,换成GDI试试可以用CDC画。或者CImage之类的库看看效果库有问题还是比较少见的。
      

  10.   

    把工程打包传上来, 大家来试试可以加些日志或dbgstring, 记录看哪个函数耗时多
      

  11.   

    // 绘画按钮
    void CRollPanelWnd::DrawButton(CDC *pDC, int nIndex, LPRECT lprc, BOOL *pbPress)
    {
        if (nIndex < 0 || nIndex >= m_lpPanelInfo->button.nButtonCount)
            return;    LPPANELBUTTON lpButton = &m_lpPanelInfo->button.lpButtons[nIndex];
        if (lpButton == NULL || (pbPress != NULL && *pbPress == lpButton->bPress))
            return;    if (lprc == NULL) lprc = &lpButton->rect;
        int cx = lprc->right - lprc->left;
        int cy = lprc->bottom - lprc->top;
        if (cx == 0 || cy == 0) return;    CRect rcItem(lprc);
        rcItem.OffsetRect(-lprc->left, -lprc->top);    CBitmap bmp; bmp.CreateCompatibleBitmap(pDC, cx, cy);
        CDC memDC; memDC.CreateCompatibleDC(pDC);
        memDC.SelectObject(&bmp);    CFont *pOldFont = memDC.SelectObject(&m_lpPanelInfo->button.fontText);    if (m_lpPanelInfo->bkgnd.hDC != NULL)
            memDC.BitBlt(0, 0, cx, cy, CDC::FromHandle(m_lpPanelInfo->bkgnd.hDC), lprc->left, lprc->top, SRCCOPY);    CSize sizeText = memDC.GetTextExtent(_T("焯"), 1);    CRect rcIcon(0, 0, 0, 0);
        if (lpButton->pImg != NULL && lpButton->pImg->GetLastStatus() == Ok)
        {
            rcIcon.bottom = rcIcon.right = rcItem.Height();        if (rcIcon.bottom > rcIcon.right)
                rcIcon.right = rcIcon.bottom = rcItem.Width();        if (!m_lpPanelInfo->button.bTile)
            {
                rcIcon.right = rcIcon.bottom = (rcIcon.Width() - (sizeText.cy + BUTTONTEXT_MARGIN));
                rcIcon.OffsetRect((rcItem.Width() - rcIcon.Width()) / 2, 0);
            }
        }    // 画高亮背景
        if (pbPress == NULL) pbPress = &lpButton->bPress;
        if (*pbPress)
        {
            CBitmap bmp; bmp.CreateCompatibleBitmap(pDC, cx, cy);
            CDC dcMem; dcMem.CreateCompatibleDC(pDC);
            dcMem.SelectObject(&bmp);
            dcMem.BitBlt(0, 0, cx, cy, &memDC, 0, 0, SRCCOPY);        CBrush br(RGB(0x7f, 0x9d, 0xb9));
            dcMem.SelectObject(&br);
            dcMem.RoundRect(0, 0, cx, cy, 10, 10);        BLENDFUNCTION bf = { AC_SRC_OVER };
            bf.SourceConstantAlpha = 0x4c;
            memDC.AlphaBlend(0, 0, cx, cy, &dcMem, 0, 0, cx, cy, bf);        if (!rcIcon.IsRectEmpty())
                rcIcon.InflateRect(-5, -5);
        }    lpButton->bPress = *pbPress;
        ////////////////////////////////////////////
        // 把这行注释掉之后, 就不会发生我说的情况了
        DrawImage(&memDC, lpButton->pImg, rcIcon);    if (lpButton->lpText != NULL)
        {
            memDC.SetBkMode(TRANSPARENT);        CRect rcText(rcItem);
            if (!m_lpPanelInfo->button.bTile)
            {
                rcText.InflateRect(-BUTTONTEXT_MARGIN, 0);
                rcText.top = rcIcon.bottom + BUTTONTEXT_MARGIN;
                if (!rcIcon.IsRectEmpty() && (*pbPress))
                    rcText.top += 5;            rcText.OffsetRect(1, 1);
                memDC.SetTextColor(RGB(0xcc, 0xcc, 0xcc));
                memDC.DrawText(lpButton->lpText[0], -1, rcText, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_END_ELLIPSIS);            rcText.OffsetRect(-1, -1);
                memDC.SetTextColor(0);
                memDC.DrawText(lpButton->lpText[0], -1, rcText, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
            }
            else
            {
                rcText.left = rcIcon.right + 5;
                if (!rcIcon.IsRectEmpty() && (*pbPress))
                    rcText.left += 5;            int nTextCount = lpButton->nTextCount;            // 计算按钮中可显示数量的文字行数
                int nRowCount = ((rcText.Height() + BUTTONTEXT_MARGIN) / (sizeText.cy + BUTTONTEXT_MARGIN));   // 可显示数量
                if (nRowCount > nTextCount) nRowCount = nTextCount;            int nTextHeight = (sizeText.cy + BUTTONTEXT_MARGIN) * nRowCount - BUTTONTEXT_MARGIN;           // 实际显示高度
                rcText.top = (rcItem.Height() - nTextHeight) / 2;
                rcText.bottom = rcText.top + nTextHeight;            // 画文字阴影
                rcText.OffsetRect(1, 1);
                memDC.SetTextColor(RGB(0xcc, 0xcc, 0xcc));
                memDC.DrawText(lpButton->lpText[0], -1, rcText, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS);            rcText.OffsetRect(-1, -1);
                memDC.SetTextColor(0);
                memDC.DrawText(lpButton->lpText[0], -1, rcText, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS);            memDC.SetTextColor(RGB(0x80, 0x80, 0x80));
                int nOffsetY = sizeText.cy + BUTTONTEXT_MARGIN;
                for (int i = 1; i < nRowCount; i++)
                {
                    rcText.top += nOffsetY;
                    memDC.DrawText(lpButton->lpText[i], -1, rcText, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS);
                }
            }
        }    memDC.SelectObject(pOldFont);    pDC->BitBlt(lprc->left, lprc->top, cx, cy, &memDC, 0, 0, SRCCOPY);
    }
      

  12.   


    之前没用 GDI+ 前,所有图片都是BMP或者是ICO格式的文件
    这些文件都是直接用 GDI 画上去,没有我说的问题后来换了 PNG, 就用到了 GDI+, 速度就变慢了!
      

  13.   

    网上查了一下, 说的是 GDI+ 初始化的代码必须放在调用这个 DLL 的程序里才行
    试了一下, 的确可行, 但这样就破坏了连接库的封装性了, 所以这个办法被我否决后来我是用多线程来管理画图这块, 每条线程管理10个图片~~~结贴