Brief Full Advanced Search Search Tips
|  |  | To access the contents, click the chapter and section titles. Fast Track Visual C++ 6.0 Programming (Publisher: John Wiley & Sons, Inc.) Author(s): Steve Holzner ISBN: 0471312908 Publication Date: 09/01/98 Search this book:
Previous | Table of Contents | Next
Figure 6.1 Capturing the screen. Figure 6.2 We support screen capture. Now that we’ve taken a look at some advanced screen graphics, we examine how to use metafiles next. ### Metafiles Metafiles are a powerful component of graphics programming, and they allow us solve a persistent Windows programming problem—refreshing the screen when needed. Metafiles are indeed files, but files of a special type designed to be used with the MFC graphics functions. These files usually exist in memory, although they can also be written out to disk (in .wmf format), and you use them to store calls to the CDC class. When you want, you can replay the metafile in a device context, recreating all the calls you’ve already stored in the metafile. That’s how we solve the screen refresh problem. Instead of having to save all the actions the user makes in creating the view, we just store all those calls in a metafile. When the screen needs to be refreshed, we play those that metafile back. Our example is called Circles; the program lets the user draw circles as they like in the view. Instead of storing the location and size of each circle, we store all the device context calls in a metafile at the same time we draw each circle. We can simply play the metafile back when needed. In fact, we can design a whole new class, CRedraw, that you can use over and over again in your programs to store and replay graphics. #### Designing the CRedraw Class The CRedraw class has four functions: a constructor; a destructor; GetDC(), which allows you to draw in the metafile; and PlayMetaFile(), which plays back the metafile. If you duplicate all device context calls in the metafile, you can simply place this one line in the OnDraw() function to handle all screen refreshes:
    void CCirclesView::OnDraw(CDC* pDC)

    {
        CCirclesDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);

        redraw.PlayMetaFile(pDC);                        ⇐

    }
You can see what a simplification this is, so let’s put together CRedraw now. Create a new MDI project now named Circles. We create the CRedraw class in a new file, CRedraw.h (we put everything into this header file to make it easier to add to other projects), so add that file to the project now. We start that class with a pointer, pDC, to a new metafile of the CMetaFileDC class, making this a protected member of the class.
    class CRedraw

    {
    protected:                     ⇐
        CMetaFileDC* pDC;          ⇐
            .
            .

            .
The CMetaFileDC class’s functions appear in Table 6.3. #### Writing the CRedraw Class We can add the CRedraw class’s constructor and destructor next. In the constructor, we allocate a new CMetaFileDC object and then call its Create() function.
Table 6.3 The CMetaFileDC Class’s Functions
Function | Does this
--- | ---
Close | Closes the device context and creates a metafile handle.
CloseEnhanced | Closes an enhanced-metafile device context and creates an enhanced metafile handle.
CMetaFileDC | Constructs a CMetaFileDC object.
Create | Creates the Windows metafile device context and attaches it to the CMetaFileDC object.
CreateEnhanced | Creates a metafile device context for an enhanced-format metafile.
    class CRedraw
    {
    protected:
        CMetaFileDC* pDC;

    public:
        CRedraw(){pDC = new CMetaFileDC();             ⇐
                    pDC->Create();}                     ⇐
                            .
                            .

                            .
Creating a Metafile on Disk If you want to create a metafile on disk instead of memory, pass the name of the file on disk to the Create() function. Now our metafile is created and ready to go. In the destructor, we delete the metafile.
    class CRedraw

    {
    protected:
        CMetaFileDC* pDC;

    public:
        CRedraw(){pDC = new CMetaFileDC();
                    pDC->Create();}

        ~CRedraw(){delete pDC;}                ⇐
            .
            .

            .
In addition, we return a pointer to that metafile in GetDC(), giving the rest of the program access to the metafile so we can duplicate all drawing actions in that metafile.
    class CRedraw

    {
    protected:
        CMetaFileDC* pDC;

    public:
        CRedraw(){pDC = new CMetaFileDC();
                    pDC->Create();}

        ~CRedraw(){delete pDC;}

        CMetaFileDC* GetDC() {return pDC;}         ⇐
            .
            .

            .
We’re ready to write the major CRedraw function: PlayMetaFile(). #### Writing the PlayMetaFile() Function When we call the PlayMetaFile() function, we want to play the metafile back into a specific device context, so we make sure a pointer to that device context, which we call pRefreshDC, is passed to that function.
    class CRedraw

    {
    public:
        void PlayMetaFile(CDC* pRefreshDC){              ⇐
            .
            .

            .
To play back a metafile, you first get a handle to the metafile, which you can do by closing it.
    class CRedraw

    {
    public:
        void PlayMetaFile(CDC* pRefreshDC){

            HMETAFILE OldMetaFileHandle = pDC->Close();            ⇐
            if(OldMetaFileHandle == NULL)                          ⇐
                return;                                            ⇐
                       .
                       .

                       .
Now we can play the metafile into the device context with the PlayMetaFile() function, passing that function the handle to the metafile.
    class CRedraw

    {
    public:
        void PlayMetaFile(CDC* pRefreshDC){

            HMETAFILE OldMetaFileHandle = pDC->Close();
            if(OldMetaFileHandle == NULL)
                return;

            pRefreshDC->PlayMetaFile(OldMetaFileHandle);      ⇐
                  .
                  .

                  .
At this point, the screen is refreshed. However, that’s only part of the process—we have to set up the metafile for the next screen refresh. In fact, we’ve had to close the metafile to get a handle to it, so we have to create a whole new metafile. We create the new metafile, ReplacementMetaFile, with the Create() function. We also play the old metafile into the new one so we can take up where the last one left off.
    class CRedraw

    {
    public:
        void PlayMetaFile(CDC* pRefreshDC){

            HMETAFILE OldMetaFileHandle = pDC->Close();
            if(OldMetaFileHandle == NULL)
                return;

            pRefreshDC->PlayMetaFile(OldMetaFileHandle);

            CMetaFileDC* ReplacementMetaFile = new CMetaFileDC();             ⇐
            ReplacementMetaFile->Create();                                    ⇐
            ReplacementMetaFile->PlayMetaFile(OldMetaFileHandle);             ⇐
                   .
                   .

                   .
Previous | Table of Contents | Next

| Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.