-2

我正在开发一个 Windows 程序,其目标是使用 GDIPlus 和 Windows 头文件显示图像按钮。

图像附加到全局 CAutoPtr 数组。在按钮回调中,我通过使用按钮的标识符 (GetDlgCtrlID(hWnd)) 搜索图像数组 (imageList) 来处理 WM_PAINT 消息。

我可以使用 imageList 中的第一张图像进行绘制,但是,当我尝试使用 imageList[2] 绘制下一个按钮时,它不会显示任何图像。

问题到底出在哪里,为什么除了 imageList 的第一个插槽中的任何内容之外,我不能显示任何图像?

谢谢!

这处理所有按钮消息。

CAutoPtr<Gdiplus::Image> typedef GdiplusImagePtr;
GdiplusImagePtr imageList[50];
Rect imagePositions[50];

LRESULT CALLBACK CustomButtonProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg) {
    case WM_CREATE:
    {
        // Same as WM_PAINT
        break;
    }
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC newDC = BeginPaint(hWnd, &ps);

        Gdiplus::Graphics newGraphics(hWnd);
        newGraphics.DrawImage(imageList[GetDlgCtrlID(hWnd)], imagePositions[GetDlgCtrlID(hWnd)]);

        EndPaint(hWnd, &ps);
        ReleaseDC(hWnd, GetDC(hWnd));
        DeleteDC(newDC);
        break;
    }
    return CallWindowProc(customButtonProc, hWnd, msg, wp, lp);
}

我使用这行代码将图像附加到 imageList。我确认 imageList 确实包含其他图像;我只是无法显示它们。

imageList[1].Attach(new Gdiplus::Bitmap(L"TestImage.png"));
4

1 回答 1

0
CAutoPtr<Gdiplus::Image> typedef GdiplusImagePtr;
GdiplusImagePtr imageList[50];
imageList[1].Attach(new Gdiplus::Bitmap(L"TestImage.png"));

你不能Gdiplus::Image在一个地方和Gdiplus::Bitmap另一个地方使用。

您不能CAutoPtr用于以这种方式创建数组。此外,您似乎将指针数组声明为全局值。这直到程序结束才会被释放。这样做没有意义,即使它有效。请注意,当程序退出时,系统将释放所有内存。目标应该是在程序运行时尽量减少内存使用。

用于CAutoPtr一个对象并CAutoPtrArray用于一个数组。但是自己处理分配和清理会更容易、更有效。例子:

std::vector<Gdiplus::Image*> list;
LRESULT CALLBACK MyProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM)
{
    switch (msg)
    {

    case WM_CREATE:
        list.push_back(new Gdiplus::Image(L"pic1.bmp"));
        list.push_back(new Gdiplus::Image(L"pic2.bmp"));
        return TRUE;

    case WM_NCDESTROY:
        //free memory here:
        for (auto e : list) delete e;
        break;
    ...
    }
}

用于绘图

case WM_PAINT:
{
    PAINTSTRUCT ps = { 0 };
    HDC hdc = BeginPaint(hWnd, &ps);
    Gdiplus::Graphics graphics(hWnd); 
    graphics.DrawImage(list[0], 0, 0); 
    EndPaint(hWnd, &ps); 
    return 0; 
}

清理只是一行。如果您有较旧的 VS 版本,请使用

for (size_t i = 0; i < list.size(); i++) 
    delete list[i];

如果制作自定义绘制按钮,您应该WM_DRAWITEM在按钮的父级中处理。否则WM_PAINT,如果主题被禁用(适用于 XP/Vista/Win7),子类将无法工作。

您也可以考虑只保存图像名称,然后加载/绘制/卸载以节省内存。

另请注意:

ReleaseDC(hWnd, GetDC(hWnd));
DeleteDC(newDC);

您应该删除以上 2 行。请阅读有关其用法的文档。

于 2016-07-17T23:08:24.713 回答