• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 687
  • Last Modified:

Create Bitmap of a Dialog that is not in view


This is a similar question to "bitmap of a window"  09/18/2001, but this question was not answered fully and a refund of points was issued.  I don't think it is particulalry difficult for an expert, but I need to solve it urgently.

I am drawing graphs in a dialog box, and can save these to a bitmap file.

However, my application can run in batch mode, so when I do this automatically I end up saving a bitmap of the topmost window rather than of the dialog which is drawing itself in the background.

I think the solution has something to do with using CMetaFileDC, but am out of my depth on this.

What I am looking for is some example code that will do this.  Here (below) is the code I am using at the moment, which works fine for saving the dialog when it is in view.

Thank you in advance for any help on this.

Richard


bool CGraph::SaveBitmap()
{

      CLiftsimDoc* pDoc=CLiftsimDoc::GetDoc();

      CString FileName= pDoc->m_ResultsFile.GetFileName() + "_" + GetGraphID() + ".bmp";

      int x, y,W,H;

    CRect rect;
    GetClientRect(&rect);

      CPoint pt=rect.TopLeft();
      x=pt.x;
      y=pt.y+3*nTH;
      W=rect.Width();
      H=rect.Height()-3*nTH;

      CDC* pDC;
      CDC tDC;
      HBITMAP Bitmap, oBitmap;

      pDC=GetDC();
      tDC.CreateCompatibleDC(pDC);

      Bitmap=CreateCompatibleBitmap(pDC->m_hDC, W, H);

      oBitmap=(HBITMAP )SelectObject(tDC.m_hDC, Bitmap);
      tDC.BitBlt(0, 0, W, H, pDC, x, y, SRCCOPY);

      SelectObject(tDC.m_hDC, oBitmap);
      ReleaseDC(pDC);

      bool success;
    CFile file(FileName.GetBuffer(0), CFile::modeCreate|CFile::modeWrite);
    CDIBitmap DIBitmap;
    success=DIBitmap.AssignDDP(Bitmap);
      if (!success) return (false);
    success=DIBitmap.Save(file);
      if (!success) return (false);
    file.Close();

      return(true);
}

 
0
richardpeters
Asked:
richardpeters
  • 4
  • 4
1 Solution
 
SteHCommented:
The window is only repainted when in foreground. I am not sure whether the following lines will bring it to the foreground but at least they repaint it.

Invalidate ();
UpdateWindow ();

You then only need to wait for the paint to finish before using the client DC. Another way would be to use something similar as OnPaint but to draw into the given DC. This could be done using the Print command.

0
 
richardpetersAuthor Commented:
Hi

Invalidate ();
UpdateWindow ();

Does not bring the dialog to the foreground.  It is my understanding that Windows does not allow an application in the background to bring itself to the top (although in the old days 16 bit Windows did).  You can only bring something to the top within your own application.  Actaully I would prefer for it all to happen in the background anyway, rather than interrupt the user.

So, I have to draw somewhere which is not currently visible.

Richard


0
 
AndyAinscowFreelance programmer / ConsultantCommented:
You have a DC in memory, compatible with your screen DC and the size you want.
Now draw your graph into that memory DC (as you do normally to screen).  You should then be able to save to file.

eg Have a graph drawing function DrawGraph(CDC* pDC) so you just plug in the screenDC when drawing to the dialog and this memoryDC when you want to save.
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
richardpetersAuthor Commented:
Yes, this seems a good approach.  But I think I am using the memoryDC wrong as I am still getting a bitmap of the other application window on top.  Here is my code below.

Richard


CDC* pDC;
pDC=GetDC();

if (m_Mode==MAKE_BITMAPS)
{
      CMetaFileDC * pMDC = new CMetaFileDC();
      pMDC->CreateCompatibleDC(pDC);
      PlotCurrentGraph(pMDC);
}
else
{
      PlotCurrentGraph(pDC);
}

0
 
AndyAinscowFreelance programmer / ConsultantCommented:
Use a CDC instead of a CMetaFileDC.
Does it work now?
0
 
richardpetersAuthor Commented:
Actually, it was capturing the top screen because, even though I was passing pDC to SaveBitmap, I had forgot to delete the line pDC=GetDC();  Sorry.

Now,

     CMetaFileDC * pMDC = new CMetaFileDC();
     pMDC->CreateCompatibleDC(pDC);
     PlotCurrentGraph(pMDC);

gives me a bitmap that is all back.  And I get the same if I subsitute CDC for CMetaFileDC.

All this is still happenning within the dialog box class.  So, I am still firing up a DoModal() even when I am in make_bitmap mode.  Perhaps the dialog is the problem, and I need to plot the graphs from within my CScrollView?

Richard
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
If you mean you draw the graph on screen (without dialog) then it would be sensible to do that.
Does PlotCurrentGraph work and display the graph to screen?  If it does then it should also work when drawing to the bitmap.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
This is something I answered another question re drawing to bitmaps some time ago

/*Also in the OnInitialUpdate I did 3 different coloured pens to help see the lines you draw
     m_mainLine.CreatePen(PS_INSIDEFRAME, 2, RGB(192,0,0));
     m_mediumLine.CreatePen(PS_INSIDEFRAME,1, RGB(0,0,192));
     m_interLine.CreatePen(PS_DOT, 1, RGB(0,192,0));
*/

#define WIN_HEIGHT 400
#define WIN_WIDTH 300

void CMyView::OnDraw(CDC* pDC)
{
     CRect rect;
     GetClientRect(rect);

    pDC->SetMapMode(MM_ANISOTROPIC);    
     pDC->SetWindowExt(WIN_WIDTH, WIN_HEIGHT);
     pDC->SetViewportExt(rect.Width(), rect.Height());
     pDC->SetViewportOrg(0, 0);


    CBitmap bitmap;
     CBitmap* pOldBitmap;
    CDC* pMemDC = pDC;
     bool bUseSepMemDC = true;     //set to false to see effect in drawing direct to DC
     if(bUseSepMemDC)
     {
         pMemDC = new CDC;
          pMemDC->CreateCompatibleDC(pDC);
          pMemDC->SetMapMode(pDC->GetMapMode());
          pMemDC->SetWindowExt(pDC->GetWindowExt());
          pMemDC->SetWindowOrg(pDC->GetWindowOrg());
          pMemDC->SetViewportExt(pDC->GetViewportExt());
          pMemDC->SetViewportOrg(pDC->GetViewportOrg());

          bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
          pOldBitmap = pMemDC->SelectObject(&bitmap);
     }

    pMemDC->FillRect(CRect(0, 0, WIN_WIDTH, WIN_HEIGHT), &m_Brush);

     int iMax = ((m_nYWinOrg < WIN_HEIGHT) ? m_nYWinOrg : WIN_HEIGHT);
     int iOffset = 0;
     if(m_nYWinOrg > WIN_HEIGHT)
          iOffset = (m_nYWinOrg - WIN_HEIGHT) % 80;

     for(int j, i = 0; i <= iMax; i+=2)
     {
          bool bDraw = false;
          j = i - iOffset;
          if(j % 80 == 0)
          {
               bDraw = true;
               pMemDC->SelectObject(m_mainLine);
          }
          else if(j % 40 == 0)
          {
               bDraw = true;
               pMemDC->SelectObject(m_mediumLine);
          }
          else if(j % 8 == 0)
          {
               bDraw = true;
               pMemDC->SelectObject(m_interLine);
          }
          if(bDraw)
          {
               pMemDC->MoveTo(0,i);pMemDC->LineTo(WIN_WIDTH / 3, i);
               pMemDC->MoveTo(WIN_WIDTH - (WIN_WIDTH / 3),i);pMemDC->LineTo(WIN_WIDTH, i);
          }
     }


     if(bUseSepMemDC)
     {
          pDC->BitBlt(0,0, WIN_WIDTH, WIN_HEIGHT, pMemDC, 0, 0, SRCCOPY);
          pMemDC->SelectObject(pOldBitmap);
          delete pMemDC;
     }
}

Maybe that could help you?
0
 
richardpetersAuthor Commented:
Just for the record, the accepted answer gave me the clue to make my code work.

"Does PlotCurrentGraph work and display the graph to screen?  If it does then it should also work when drawing to the bitmap."

Yes, it was displaying to the screen.  But in the save bitmap mode I was drawing on the CMetaFileDC rather than the bitmap.  I am still doing this all within my dialog class.  Anyway, my working code was....

bool CGraph::SaveBitmap(CDC* pDC)
{

      CLiftsimDoc* pDoc=CLiftsimDoc::GetDoc();

      CString FileName= pDoc->m_ResultsFile.GetFileName() + "_" + GetGraphID() + ".bmp";

      int x, y,W,H;

    CRect rect;
    GetClientRect(&rect);

      CPoint pt=rect.TopLeft();
      x=pt.x;
      y=pt.y+3*nTH;
      W=rect.Width();
      H=rect.Height()-3*nTH;

      CDC tDC;
      HBITMAP Bitmap, oBitmap;
      tDC.CreateCompatibleDC(pDC);
      Bitmap=CreateCompatibleBitmap(pDC->m_hDC, W, H);
      oBitmap=(HBITMAP )SelectObject(tDC.m_hDC, Bitmap);
      tDC.FillRect(rect,&WhiteBrush);

      //*******
      PlotCurrentGraph(&tDC);
      //*******

      tDC.BitBlt(0, 0, W, H, pDC, x, y, SRCCOPY);
      SelectObject(tDC.m_hDC, oBitmap);

      bool success;
    CFile file(FileName.GetBuffer(0), CFile::modeCreate|CFile::modeWrite);
    CDIBitmap DIBitmap;
    success=DIBitmap.AssignDDP(Bitmap);
      if (!success) return (false);
    success=DIBitmap.Save(file);
      if (!success) return (false);
    file.Close();

      return(true);
}



Thank you for your help.  10 out of 10.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

  • 4
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now