none
GDI+编程,如何定义Image类的对象数组 RRS feed

  • 问题

  • 最近在用GDI+进行动画的显示,有man1.bmp到man7.bmp七幅图需要显示,按GDI+中的模式来,就需要用Image类实例化七个对象。定义Image类对象时构造函数好像不能为空,例如Image fullmap(L"bj.bmp");创建图片对象时要选择图片,更别说Image man[7];这样创建数组。

    这个函数之前用GDI写的,用的是位图数组HBITMAP man[7];,改用GDI+就不知道怎么写了=.=求教~~~~~~!!!!!!!!!
    #include "stdafx.h"
    #include <windows.h>
    #include <objidl.h>
    #include <gdiplus.h>
    using namespace Gdiplus;
    #pragma comment (lib,"Gdiplus.lib")

    #include <stdio.h>///////////////////////////////////////////

    //全局变量声明
    HINSTANCE hInst;
    Image *man[7];
    HDC  hdc,mdc;
    HWND hWnd;
    DWORD tPre,tNow,tCheck;                 //声明三个函数来记录时间,tPre记录上一次绘图的时间,tNow记录此次准备绘图的时间,tCheck记录每秒开始的时间
    int  num,frame,fps;                    //num用来记录图号,frame用来累加每次画面更新的次数,fps(frame per second)用来记录每秒画面更新的次数
    WCHAR filename[20];
    Graphics graphics(hdc);

    //全局函数的声明
    ATOM    MyRegisterClass

    (HINSTANCE hInstance);
    BOOL    InitInstance

    (HINSTANCE, int);
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,

    LPARAM);
    void    MyPaint(HDC hdc);

    //***WinMain函数,程序入口点函数**************************************
    int APIENTRY WinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPSTR     lpCmdLine,
                         int       nCmdShow)
    {

     MSG msg;
     GdiplusStartupInput gdiplusStartupInput;
     ULONG_PTR           gdiplusToken;


     // Initialize GDI+.
     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

     MyRegisterClass(hInstance);

     //运行初始化函数
     if (!InitInstance (hInstance, nCmdShow))
     {
      return FALSE;
     }

     //游戏循环
     GetMessage(&msg,NULL,NULL,NULL);
        while( msg.message!=WM_QUIT )
        {
            if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )
            {
                TranslateMessage( &msg );
                DispatchMessage( &msg );
            }
      else
      {
       tNow = GetTickCount();
       if(tNow-tPre >= 100)        //当此次循环运行与上次绘图时间相差0.1秒时再进行重绘操作
        MyPaint(hdc);
      }
        }

     GdiplusShutdown(gdiplusToken);

     return msg.wParam;
    }

    //****设计一个窗口类,类似填空题,使用窗口结构体*************************
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
     WNDCLASSEX wcex;

     wcex.cbSize = sizeof(WNDCLASSEX);
     wcex.style   = CS_HREDRAW |

    CS_VREDRAW;
     wcex.lpfnWndProc = (WNDPROC)WndProc;
     wcex.cbClsExtra  = 0;
     wcex.cbWndExtra  = 0;
     wcex.hInstance  = hInstance;
     wcex.hIcon   = NULL;
     wcex.hCursor  = NULL;
     wcex.hCursor  = LoadCursor(NULL,

    IDC_ARROW);
     wcex.hbrBackground = (HBRUSH)

    (COLOR_WINDOW+1);
     wcex.lpszMenuName = NULL;
     wcex.lpszClassName = "canvas";
     wcex.hIconSm  = NULL;

     return RegisterClassEx(&wcex);
    }

    //****初始化函数*************************************
    // 从文件加载位图
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
     char filename[20] = "";
     int i;

     hInst = hInstance;

     hWnd = CreateWindow("canvas", "动画演示" ,

    WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,

    NULL, NULL, hInstance, NULL);

     if (!hWnd)
     {
      return FALSE;
     }

     MoveWindow(hWnd,10,10,600,450,true);
     ShowWindow(hWnd, nCmdShow);
     UpdateWindow(hWnd);

     hdc = GetDC(hWnd);
     mdc = CreateCompatibleDC(hdc);

     

     //载入各个人物位图
     for(i=0;i<7;i++)
     {
      sprintf(filename,"man%02d.bmp",i);
      //man[i] = (HBITMAP)LoadImage
      //Image man[i](L"filename");
      man[i] = Image::FromFile(filename);   //错误 2 error C2664: “Gdiplus::Image::FromFile”: 不能将参数 1 从“char [20]”转换为“const WCHAR 

      //man[i].FromFile(filename);


     }
     
     num = 0;
     frame = 0;

     MyPaint(hdc);

     return TRUE;
    }

    //****自定义绘图函数*********************************
    // 1.计算与显示每秒画面更新次数
    // 2.按照图号顺序进行窗口贴图
    void MyPaint(HDC hdc)
    {
     char str[40] = "";

     if(num == 7)
      num = 0;
     frame++;          //画面更新次数加1
     if(tNow - tCheck >= 1000)               //判断此次绘图时间由前一秒算起是否已经达到1秒钟的时间间隔。若是,则将目前的'frame'值赋给"fps",表示这一秒内所更新的画面次数,然后将“frame”值回0,并重设下次计算每秒画面数的起始时间"iCheck"。
     {
      fps = frame;
      frame = 0;
      tCheck = tNow;
     }

     //SelectObject(mdc,man[num]);         //选用要更新的图案到mdc中,再输出显示每秒画面更新次数的字符串到mdc上,最后将mdc的内容贴到窗口中。
     sprintf(str,"每秒显示 %d个画面",fps);
     TextOut(mdc,0,0,str,strlen(str));
     //BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);
      graphics.DrawImage(&man[num], 60, 10);                                          

    //错误 3 error C2664: “Gdiplus::Status Gdiplus::Graphics::DrawImage(Gdiplus::Image*,Gdiplus::REAL,Gdiplus::REAL)”: 不能将参数 1 从“Gdiplus::Image **”转换为“Gdiplus::Image *” 

     tPre = GetTickCount();     //记录此次绘图时间,供下次游戏循环中判断是否已经达到画面更新操作设定的时间间隔。
     num++;
    }

    //******消息处理函数*********************************
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message,

    WPARAM wParam, LPARAM lParam)
    {
     int i;

     switch (message)
     {
      case WM_DESTROY:   //窗口结束消息
       DeleteDC(mdc);
       for(i=0;i<7;i++)
      //  DeleteObject(man[i]);
       ReleaseDC(hWnd,hdc);
       PostQuitMessage(0);
       break;
      default:     //其他消息
       return DefWindowProc(hWnd,

    message, wParam, lParam);
       }
       return 0;
    }

     

    2012年9月11日 16:29

答案

  • 您好,

    首先,初始化Image对象的时候,不能使用无参数的构造函数。查看Image类的定义便可知原因:无参数构造函数Image::Image()是保护成员,在类的外部不能访问。

    接下来说说代码中的两处错误:

      man[i] = Image::FromFile(filename);   //错误 2 error C2664: “Gdiplus::Image::FromFile”: 不能将参数 1 从“char [20]”转换为“const WCHAR 

    这条错误信息已经很明显地指出原因了,Image::FromFile需要一个const WCHAR*类型的参数,而您传给它的是一个char*类型的参数。

    可以直接将filename定义为WCHAR也可以用MultiByteToWideChar转换。

    graphics.DrawImage(&man[num], 60, 10);                                         

    //错误 3 error C2664: “Gdiplus::Status Gdiplus::Graphics::DrawImage(Gdiplus::Image*,Gdiplus::REAL,Gdiplus::REAL)”: 不能将参数 1 从“Gdiplus::Image **”转换为“Gdiplus::Image *”

    这个错误时由于二级指针使用不当引起的,您定义的是一个Image*类型的数组,每个数组元素内存放的是一个指向Image类型的指针。

    所以man[num]本身就已经是一个指针了,不必在前面再加上取地址符号。

    您可以参考以下代码,希望对您有帮助:

    WCHAR filename[20];
    hdc = GetDC(hWnd);
    Graphics graphics(hdc);
    Image* man[4];
    
    for (int i = 0; i<4; ++i)
    {
    	memset(filename, 0, sizeof(filename));
    	swprintf_s(filename, L"man%02d.bmp", i);
    	man[i] = Image::FromFile(filename);
    }
    
    for (int i = 0; i<4; ++i)
    {
    	graphics.DrawImage(man[i], i*200, 10);
    }

    Damon Zheng [MSFT]
    MSDN Community Support | Feedback to us

    2012年9月13日 12:21
    版主
  •   sprintf_s(filename,"man%d.bmp",i); 

    这里不应该用sprint_s这个函数,它是针对ANSI字符的操作,并且sprint_s没有这样的参数形式,Intellisense会报错的。

    关于sprint_s的用法,详见:http://msdn.microsoft.com/en-us/library/ce3zzk1k(v=vs.80).aspx(抱歉,只有英文版)

    对于Unicode字符,应该使用swprint_s

    swprintf_s(filename, L"man%d.bmp", i); 

    另外,MultiByteToWideChar并不复杂,它的参数看似很多,其实用起来很方便,这里有一些例子可以参考:http://blog.csdn.net/phpxin123/article/details/7540796

    如果您觉得我的回复对您有帮助,麻烦标记为答案,谢谢您的支持!


    Damon Zheng [MSFT]
    MSDN Community Support | Feedback to us

    2012年9月14日 2:57
    版主

全部回复

  • 代码贴多了不简明扼要,我把关键的贴出来吧,请指教啊~!!高手们~~!!!

    代码如下:

    WCHAR filename[20];
    Graphics graphics(hdc);

    Image *man[7];

     hdc = GetDC(hWnd);
     mdc = CreateCompatibleDC(hdc);

     

     //载入各个人物位图
     for(i=0;i<7;i++)
     {
      sprintf(filename,"man%02d.bmp",i);
      //man[i] = (HBITMAP)LoadImage
      //Image man[i](L"filename");
      man[i] = Image::FromFile(filename);   //错误 2 error C2664: “Gdiplus::Image::FromFile”: 不能将参数 1 从“char [20]”转换为“const WCHAR 

      //man[i].FromFile(filename);

     }

     graphics.DrawImage(&man[num], 60, 10);                                          

    //错误 3 error C2664: “Gdiplus::Status Gdiplus::Graphics::DrawImage(Gdiplus::Image*,Gdiplus::REAL,Gdiplus::REAL)”: 不能将参数 1 从“Gdiplus::Image **”转换为“Gdiplus::Image *” 

    2012年9月12日 15:42
  • 您好,

    首先,初始化Image对象的时候,不能使用无参数的构造函数。查看Image类的定义便可知原因:无参数构造函数Image::Image()是保护成员,在类的外部不能访问。

    接下来说说代码中的两处错误:

      man[i] = Image::FromFile(filename);   //错误 2 error C2664: “Gdiplus::Image::FromFile”: 不能将参数 1 从“char [20]”转换为“const WCHAR 

    这条错误信息已经很明显地指出原因了,Image::FromFile需要一个const WCHAR*类型的参数,而您传给它的是一个char*类型的参数。

    可以直接将filename定义为WCHAR也可以用MultiByteToWideChar转换。

    graphics.DrawImage(&man[num], 60, 10);                                         

    //错误 3 error C2664: “Gdiplus::Status Gdiplus::Graphics::DrawImage(Gdiplus::Image*,Gdiplus::REAL,Gdiplus::REAL)”: 不能将参数 1 从“Gdiplus::Image **”转换为“Gdiplus::Image *”

    这个错误时由于二级指针使用不当引起的,您定义的是一个Image*类型的数组,每个数组元素内存放的是一个指向Image类型的指针。

    所以man[num]本身就已经是一个指针了,不必在前面再加上取地址符号。

    您可以参考以下代码,希望对您有帮助:

    WCHAR filename[20];
    hdc = GetDC(hWnd);
    Graphics graphics(hdc);
    Image* man[4];
    
    for (int i = 0; i<4; ++i)
    {
    	memset(filename, 0, sizeof(filename));
    	swprintf_s(filename, L"man%02d.bmp", i);
    	man[i] = Image::FromFile(filename);
    }
    
    for (int i = 0; i<4; ++i)
    {
    	graphics.DrawImage(man[i], i*200, 10);
    }

    Damon Zheng [MSFT]
    MSDN Community Support | Feedback to us

    2012年9月13日 12:21
    版主
  • 谢谢大哥耐心的解答,第二的错误已经顺利解决了,那个&是不应当加,我粗心了。但是问题依旧有,我也改进了代码,最后的问题只在man[i] = Image::FromFile(filename);报了两个错,也就是char*和const WCHAR之间的转换问题。

    对于关键是filename我从一开始就一直定义的是WCHAR类型啊,还有那个MultiByteToWideChar用在这里好像不太合适啊,用起来也挺复杂,可以说得具体点吗,继续耐心地等待大家的回复与解答~~~~~~~~~~~~~~!!!!!!!!!!!

    下面是代码的报错的具体地方:

    WCHAR filename[20];
    Graphics graphics(hdc);

    Image *man[7];

     hdc = GetDC(hWnd);
     mdc = CreateCompatibleDC(hdc);

     for(i=0;i<7;i++)
     {
      memset(filename, 0, sizeof(filename));

      sprintf_s(filename,"man%d.bmp",i); 

      man[i] = Image::FromFile(filename);  //错误 1 error C2664: “Gdiplus::Image::FromFile”: 不能将参数 1 从“char [20]”转换为“const WCHAR *” f:\1【桌面】\【visual c++】code_note_8\canvas.cpp 143 1 canvas

                                                                // 错误2 IntelliSense: "char *" 类型的实参与 "const WCHAR *" 类型的形参不兼容 f:\1【桌面】\【visual c++】code_note_8\canvas.cpp 143 28 canvas

    }

    继续耐心地等待大家的回复与解答~~~~~~~~~~~~~~!!!!!!!!!!!

     

    2012年9月13日 18:20
  •   sprintf_s(filename,"man%d.bmp",i); 

    这里不应该用sprint_s这个函数,它是针对ANSI字符的操作,并且sprint_s没有这样的参数形式,Intellisense会报错的。

    关于sprint_s的用法,详见:http://msdn.microsoft.com/en-us/library/ce3zzk1k(v=vs.80).aspx(抱歉,只有英文版)

    对于Unicode字符,应该使用swprint_s

    swprintf_s(filename, L"man%d.bmp", i); 

    另外,MultiByteToWideChar并不复杂,它的参数看似很多,其实用起来很方便,这里有一些例子可以参考:http://blog.csdn.net/phpxin123/article/details/7540796

    如果您觉得我的回复对您有帮助,麻烦标记为答案,谢谢您的支持!


    Damon Zheng [MSFT]
    MSDN Community Support | Feedback to us

    2012年9月14日 2:57
    版主
  • 谢谢大哥,问题解决了~~~~~~~~~~~~

    2012年9月14日 4:58