大家好,我想在对话框中插入位图,然后通过按键的形式,按下对话框的一个按钮就会再位图的指定位置画出一个圆,下面是我的程序,显示结果是只有位图,并没有画出圆,请大家帮我修改修改,谢谢啦!void CmapDlg::OnPaint()
{
        if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
// CDialogEx::OnPaint();
CPaintDC dc(this);
CRect rect;
GetDlgItem(IDC_MAP)->GetWindowRect(rect); //这里的IDC_STATIC_NAME是你要添加位图的范围
ScreenToClient(rect); //将屏幕坐标转换成客户区坐标

CDC dcMem;
dcMem.CreateCompatibleDC(&dc); //创建兼容DC
CBitmap bmBackGround;
bmBackGround.LoadBitmap(IDB_BITMAP1); //载入位图
BITMAP bitmap;
bmBackGround.GetBitmap(&bitmap); //获取位图信息
CBitmap *pbitold=dcMem.SelectObject(&bmBackGround); //将位图选入DC中
SetStretchBltMode(dc, HALFTONE);
dc.StretchBlt(rect.TopLeft().x,rect.TopLeft().y,rect.Width(),rect.Height(),
&dcMem,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY); //以stretchBlt的方式添加位图到相应区域
dcMem.SelectObject(pbitold);
}
}
void CmapDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
CPaintDC dc(this);
CRect rect;
GetDlgItem(IDC_MAP)->GetWindowRect(rect); //这里的IDC_STATIC_NAME是你要添加位图的范围
ScreenToClient(rect); //将屏幕坐标转换成客户区坐
CBrush brush;
brush.CreateSolidBrush(RGB(255, 0, 0));
dc.SelectObject(brush);
dc.Ellipse(rect.left+485, rect.top+153, rect.left+495, rect.top+163);
}
按键画图

解决方案 »

  1.   

    可以把dcMem声明为类成员变量,然后什么绘制都是对dcMem绘制,在OnPaint中就只把dcMem绘制到dc中。
    或者就是声明一些存储空间,保存你需要绘制圆形图的数据,然后点击按钮时就增加数据,调用Invalidata,在OnPaint中就调用这些存储空间的数据进行图形绘制
      

  2.   

    可以放个bool变量,在按钮按下时设置为true,然后重绘,而按钮响应的绘制代码放到paint中实现
      

  3.   

    BOOL变量和按钮响应是如何建立联系的?直接通过按键响应可以吗?
      

  4.   

    BOOL变量和按钮响应是如何建立联系的?直接通过按键响应可以吗?类似于这样:
    定义成员变量:BOOL m_bDraw; 并初始化为FALSE
    然后:void CmapDlg::OnPaint()
    {
    //.................
    else
    {
    // CDialogEx::OnPaint();
    CPaintDC dc(this);
    CRect rect;
    GetDlgItem(IDC_MAP)->GetWindowRect(rect);  //这里的IDC_STATIC_NAME是你要添加位图的范围
    ScreenToClient(rect);  //将屏幕坐标转换成客户区坐标CDC dcMem;
    dcMem.CreateCompatibleDC(&dc);  //创建兼容DC
    CBitmap bmBackGround;
    bmBackGround.LoadBitmap(IDB_BITMAP1);  //载入位图
    BITMAP bitmap;
    bmBackGround.GetBitmap(&bitmap);  //获取位图信息
    CBitmap *pbitold=dcMem.SelectObject(&bmBackGround);  //将位图选入DC中
    SetStretchBltMode(dc, HALFTONE);
    if(m_bDraw)//-----------画椭圆
    {
       CBrush brush;
       brush.CreateSolidBrush(RGB(255, 0, 0));
       dcMem.SelectObject(brush);
       dcMem.Ellipse(rect.left+485, rect.top+153, rect.left+495, rect.top+163);
    }
    //------------------end draw Ellipse
    dc.StretchBlt(rect.TopLeft().x,rect.TopLeft().y,rect.Width(),rect.Height(),
    &dcMem,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);  //以stretchBlt的方式添加位图到相应区域
    dcMem.SelectObject(pbitold);
    }
    }
    然后在OnBnClickedButton1()中:void CmapDlg::OnBnClickedButton1()
    {
       m_bDraw = TRUE;
       Invalidate();
    }
      

  5.   

    CBitmap bmBackGround声明成成员变量, LoadBitmap在OnInitDialog 或 构造函数里加载就可以了,在OnPaint里反复加载是没有意义的。缓冲DC dcMem就像2楼说的,也声明成成员变量,每次OnPaint的时候往上面贴。
    圆实际也可以考虑弄到第二个缓冲DC里面 dcMemEllipse,然后再往位图上面贴,dcMemEllipse要SetBkMode(TRANSPARENT)。这个主要是在如果你画的不是圆而是更大的图的时候的区别,画圆很快所以也没有什么必要。
    另外
    1.CPaintDC只能在OnPaint里面才可以用,所以你那个在CLICK事件时候用是不对的。
    2.可以考虑所有的绘画在OnEraseBkgnd事件里面执行,而且要用InvalidateRect,指定区域刷新。主要是你这个对话框里面啥也没有所以不会觉得,如果有很多东西,即使用了缓冲DC但在Invalidate后也会闪一大下子。
      

  6.   

    BOOL变量和按钮响应是如何建立联系的?直接通过按键响应可以吗?类似于这样:
    定义成员变量:BOOL m_bDraw; 并初始化为FALSE
    然后:void CmapDlg::OnPaint()
    {
    //.................
    else
    {
    // CDialogEx::OnPaint();
    CPaintDC dc(this);
    CRect rect;
    GetDlgItem(IDC_MAP)->GetWindowRect(rect);  //这里的IDC_STATIC_NAME是你要添加位图的范围
    ScreenToClient(rect);  //将屏幕坐标转换成客户区坐标CDC dcMem;
    dcMem.CreateCompatibleDC(&dc);  //创建兼容DC
    CBitmap bmBackGround;
    bmBackGround.LoadBitmap(IDB_BITMAP1);  //载入位图
    BITMAP bitmap;
    bmBackGround.GetBitmap(&bitmap);  //获取位图信息
    CBitmap *pbitold=dcMem.SelectObject(&bmBackGround);  //将位图选入DC中
    SetStretchBltMode(dc, HALFTONE);
    if(m_bDraw)//-----------画椭圆
    {
       CBrush brush;
       brush.CreateSolidBrush(RGB(255, 0, 0));
       dcMem.SelectObject(brush);
       dcMem.Ellipse(rect.left+485, rect.top+153, rect.left+495, rect.top+163);
    }
    //------------------end draw Ellipse
    dc.StretchBlt(rect.TopLeft().x,rect.TopLeft().y,rect.Width(),rect.Height(),
    &dcMem,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);  //以stretchBlt的方式添加位图到相应区域
    dcMem.SelectObject(pbitold);
    }
    }
    然后在OnBnClickedButton1()中:void CmapDlg::OnBnClickedButton1()
    {
       m_bDraw = TRUE;
       Invalidate();
    }

    恩,谢谢,就是用Invalidate函数会产生闪烁,还需要解决闪烁问题。
      

  7.   

    你所有的 绘画放在 OnEraseBkgnd 里
    然后
    void CmapDlg::OnBnClickedButton1()
    {  
      m_bDraw = TRUE;   
    CRect rect;
    GetDlgItem(IDC_MAP)->GetWindowRect(rect);  
    ScreenToClient(rect);
    CRect rectEllipse(rect.left+485, rect.top+153, rect.left+495, rect.top+163);
     InvalidateRect(rectEllipse);}
      

  8.   


    您说的第一种方法我没有理解,不知道怎么做,我试了您说的第二种方法,是能成功的,但是图形重绘的时候有闪烁,请问这怎样消除。
    双缓存
    这是我根据以上几位提出的建议更改的程序,用于消除重绘时的闪烁,可是程序编译没问题,运行产生中断。请帮我看看程序哪里有问题?我已经把bmBackGround和dcMem声明成了成员变量。CPaintDC dc(this);
    CRect rect;
    GetDlgItem(IDC_MAP)->GetWindowRect(rect); //这里的IDC_STATIC_NAME是你要添加位图的范围
    ScreenToClient(rect); //将屏幕坐标转换成客户区坐标 dcMem.CreateCompatibleDC(&dc); //创建兼容DC


    BITMAP bitmap;

    bmBackGround.GetBitmap(&bitmap); //获取位图信息
    bmBackGround.CreateCompatibleBitmap(&dcMem,rect.Width(),rect.Height());//创建兼容位图
    CBitmap *pbitold=dcMem.SelectObject(&bmBackGround); //将位图选入DC中
    // dcMem.FillSolidRect(rect,dc.GetBkColor());//按原来背景填充客户区,不然会是黑色
    SetStretchBltMode(dc, HALFTONE);
    dc.StretchBlt(rect.TopLeft().x,rect.TopLeft().y,rect.Width(),rect.Height(),
    &dcMem,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY); //以stretchBlt的方式添加位图到相应区域
    dcMem.SelectObject(pbitold);
    dc.BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&dcMem,0,0,SRCCOPY);
    dcMem.DeleteDC();                                      //删除DC
    // bmBackGround.DeleteObject();                                       //删除位图
    CBrush brush;
    brush.CreateSolidBrush(RGB(255, 0, 0));
    dc.SelectObject(brush);
    if (m_draw)
    {
    dc.Ellipse(rect.left+m_x-5, rect.top+m_y-5, rect.left+m_x+5, rect.top+m_y+5);
    }
    m_draw=false;
      

  9.   

    你把bmBackGround.DeleteObject() 注释掉了,所以这里肯定会中断的:
    bmBackGround.CreateCompatibleBitmap而且既然都声明成了成员变量,为什么还非得在OnPaint里面反复的Create , delete?
      

  10.   

    我没太明白您的意思。我所有绘图都放在OnEraseBkgnd,也包括加载位图吗?
      

  11.   

    原来是LOADBITMAP 现在是 CreateCompatibleBitmap, 如果你在例如ONINITDIALOG里面已经bmBackGround.loadbitmap 过 那么你现在又在OnPaint里面CreateCompatibleBitmap,那么就会中断。如果是这样OnPAINT里面就不需要再CreateCompatibleBitmap了。
      

  12.   

    你所有的 绘画放在 OnEraseBkgnd 里
    ON_WM_erasebkgnd
     然后
     void CmapDlg::OnBnClickedButton1()
     {  
       m_bDraw = TRUE;   
     CRect rect;
     GetDlgItem(IDC_MAP)->GetWindowRect(rect);  
     ScreenToClient(rect);
     CRect rectEllipse(rect.left+485, rect.top+153, rect.left+495, rect.top+163);
      InvalidateRect(rectEllipse);
     
    }这样就只有圆的部分闪一下,Invalidate会使整个对话框重绘。