Solved

Create Bitmap of a Dialog that is not in view

Posted on 2003-11-28
9
643 Views
Last Modified: 2013-11-20

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
Comment
Question by:richardpeters
  • 4
  • 4
9 Comments
 
LVL 13

Expert Comment

by:SteH
ID: 9837291
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
 

Author Comment

by:richardpeters
ID: 9837564
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 9837581
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
 

Author Comment

by:richardpeters
ID: 9837951
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
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 44

Expert Comment

by:AndyAinscow
ID: 9838308
Use a CDC instead of a CMetaFileDC.
Does it work now?
0
 

Author Comment

by:richardpeters
ID: 9838571
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
 
LVL 44

Accepted Solution

by:
AndyAinscow earned 500 total points
ID: 9839219
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 9839302
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
 

Author Comment

by:richardpeters
ID: 9840526
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

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now