Taste Vista with C ++: the glass effect on the Interface

Source: Internet
Author: User

Introduction

This article will demonstrate how to use C ++ to generate aero glass effect in Windows Vista-based general Windows applications and dialog box programs, here, we use Vista and Windows SDK of Beta 2. Some APIs may change in details in subsequent versions. In addition, MFC is not used in this article. All examples are generated using wtl 7.5, which can be downloaded at http://wtl.sourceforge.net/. although visual c ++ 2003 is used here
C ++ 2005 is similar.

Aero themes and glass effects are new features that follow Vista's "desktop window management (DWM)" and are also a focus of Microsoft's marketing. They integrate glass effects into applications, when opening the aero topic, the program looks very different-it's cool, right.

Wool glass effect in Aero themes

With aero as the topic, Vista determines whether to enable the glass effect based on the computer graphics card. At this time, the desktop is drawn by DWM, and DWM uses a composition process to render the desktop, it will automatically use aero theme elements (somewhat similar to Windows XP) in non-customer areas of the top-level window ). In other words, these glass effects are not always added. If the computer runs in "battery mode", or the user decides to disable the transparent effect, as shown in.

 
If the transparent glass effect is enabled in the visible effect of the control panel, the non-customer area looks like this:

 
Note that the border of the notepad is highlighted in green. This is the color of the wallpaper, and you can also see some icons on the desktop through the title bar.

When writing the code, we only need to pay attention to whether the composition is enabled, rather than setting the glass effect, because DWM will process the part of the glass effect.

Project start

The first example is an SDI application without a window port, tool bar, or status bar. After running wtl Appwizard, the first thing is to set stdafx. # define in H to take advantage of the new features of Vista. The Windows version of Vista is 6 and the IE version of Vista is 7. After the configuration is complete, it should be as follows:

# Define winver 0x0600
# DEFINE _ win32_winnt 0x0600
# DEFINE _ win32_ie 0x0700
Next we will include the header files of ATL and wtl:

# DEFINE _ wtl_no_wtypes // do not define crect/cpoint/csize in the wtl header file
# Include <atlbase. h>
# Include <atltypes. h> // shared crect/cpoint/csize
# Include <atlapp. h>

Extern cappmodule _ module;

# Include <atlwin. h>
# Include <atlframe. h>
# Include <atlmisc. h>
# Include <atlcrack. h>
# Include <atltheme. h> // XP/vistatheme support
# Include <dwmapi. h> // DWM API
If the compilation is completed after the modification, four errors will be obtained from atltheme. h. For example, the following ctheme: getthemetextmetrics () code is not compiled:

Hresult getthemetextmetrics (..., ptextmetricw ptextmetric)
{
Atlassert (m_htheme! = NULL );

// Note: The uxtheme. h header file is converted to ptextmetric.
// It is incorrect to replace ptextmetricw.
Return: getthemetextmetrics (m_htheme,..., (ptextmetric );
}
The conversion in the getthemetextmetrics () API is the uxtheme of the Platform SDK. h. However, Windows SDK does not have this error. Therefore, this conversion causes an error. You can delete the conversion in the function, and the other three are the same. Glass effect of adding borders

By extending the glass effect from the non-customer area to the customer area, you can add the program's glass effect. This API is dwmexico tendframeworkclientarea (). Dwmextendframeworkclientarea () accepts two parameters: hwnd of the frame window and a margins structure that describes how far the glass effect has been extended to the four sides of the window. You can call this API in oncreate:

Lresult cmainframe: oncreate (lpcreatestruct lpcs)
{
// Add glass effect to the bottom
Margins MAR = {0 };
Mar. cybottomheight = 100;
Dwmexico tendframeworkclientarea (m_hwnd, & Mar );
Return 0;
}
However, if you run the program, you cannot see any changes:

 

This is because the frosted glass effect depends on the transparency of the window. to display the glass effect, the Alpha value of the pixel in the area (100 pixel at the bottom of the customer area in this example) must be set to 0. The simplest way is to use a black paint brush to draw this area. It sets the pixel color value (red, green, blue, and alpha) to 0, which can be in onerasebkgnd () completed:

Bool cmainframe: onerasebkgnd (HDC)
{
Cdchandle Dc = HDC;
Crect rcclient;
Getclientrect (rcclient );
DC. fillsolidrect (rcclient, RGB (0, 0 ));
Return true;
}
After modification, the Framework Window looks like this:

 
The 100 pixels at the bottom are now frosted glass.

Add text in the frosted glass Area

It is relatively simple to add the glass in the window, but it is difficult to add your own interface elements (UI) to the glass. Because the pixel Alpha value must be maintained all the time, you need to use the drawing APIs that understand and properly set Alpha. The bad message is that almost all the GDI functions ignore Alpha. The only remaining API is the bilblt () function with the srccopy grating operation. Therefore, the program must use the GDI + or theme APIs for plotting. These APIs do not forget Alpha at all times.

In Vista, the effects of the frosted glass are generally used in the area indicating the state of the Program (replacing the status bar in the general control), for example, windows Media Player 11 displays the playback control and current song information in the frosted glass area at the bottom of the window:

 

The following describes how to draw text in the frosted glass area and add luminous effects to the text so that the text can be easily read on any background. Use the correct font

Vista has completely abandoned the use of Ms sans serif and tahoma fonts, and switched to use segoe UI as the default UI font. Our program should also use the segoe UI font, so a font will be created based on the current topic. If the topic is disabled (for example, if you are using the Windows classic color scheme), use the systemparametersinfo () API.

First, you need to add topic support in cmainframe, which is very simple, because wtl already has a class for processing themes: cthemeimpl. We can add cthemeimpl to the continue list and link the message to cthemeimpl so that the program can receive notifications when the current topic changes.

Class cmainframe:
Public cframeworkwimpl <cmainframe>,
Public cmessagefilter,
Public cthemeimpl <cmainframe>
{
//...
Begin_msg_map (cmainframe)
Chain_msg_map (cthemeimpl <cmainframe>)
//...
End_msg_map ()

Protected:
Cfont m_font; // font used to draw text
};
In the cmainframe constructor, we call cthemeimpl: setthemeclasslist (), which specifies the window class of the topic we are using. For a common window (that is, a window that is not a common control), the name is "globals ".

Cmainframe: cmainframe ()
{
Setthemeclasslist (L "globals ");
}

Finally, in oncreate (), read the font information from the topic and create a font for your use:

Lresult cmainframe: oncreate (lpcreatestruct lpcs)
{
//...
// Determine which font is used in the text

Logfont LF = {0 };
If (! Isthemenull ())
Getthemesysfont (tmt_msgboxfont, & lf );
Else
{
Nonclientmetrics NCM = {sizeof (nonclientmetrics )};
Systemparametersinfo (spi_getnonclientmetrics, sizeof (nonclientmetrics), & NCM, false );
LF = NCM. lfmessagefont;
}
M_font.createfontindirect (& lf );
Return 0;
}
Draw text

To draw a text on a frosted glass effect, follow these steps:

· Create a memory DC for dual-buffer rendering.

· Create a 32-bit DiB and select DC.

· Use drawthemetextex () to draw the text on the DIB in the memory.

· Copy the text to the screen using bitbit.

Because our drawing code will vary depending on whether the composition is opened, we need to check the composition status during the painting. The check status API is dwmiscompositionenabled (). If the API fails to be executed, the open status is not indicated in the returned value. However, cmainframe has a packaged function iscompositionenabled (), which is very easy to use:

Bool cmainframe: iscompositionenabled () const
{
Hresult hr;
Bool benabled;
HR = dwmiscompositionenabled (& benabled );
Return succeeded (HR) & benabled;

}
Now let's check onerasebkgnd () again to see if every step is complete. This program is a clock program, so first use gettimeformat () to get the current time:

Bool cmainframe: onerasebkgnd (HDC)
{
Cdchandle Dc = HDC;
Crect rcclient, rctext;
Getclientrect (rcclient );
DC. fillsolidrect (rcclient, RGB (0, 0 ));
Rctext = rcclient;
Rctext. Top = rctext. bottomtom-100;
 
// Obtain the current time

Tchar sztime [64];
Gettimeformat (locale_user_default, 0, null, null, sztime, _ countof (sztime ));
......
}

If the composition is enabled, we will perform the merging and drawing step. First, set a memory DC:

If (iscompositionenabled ())
{
// Set a memory DC and bitmap
CDC dcmem;
Cbitmap BMP;
Bitmapinfo Dib = {0 };
Dcmem. createcompatibledc (DC );
Next, fill in the bitmapinfo structure to get a 32-bit color-depth bitmap, which is the same as the height and width of the glass area. Note that the bitmap height (that is, the biheight member of bitmapinfoheader) is negative, because BMP is usually stored in the memory in the descending order, however, drawthemetextex () requires the bitmap order from top to bottom, so set the height to a negative number.

DiB. bmiheader. bisize = sizeof (bitmapinfoheader );
DiB. bmiheader. biwidth = rctext. Width ();
DiB. bmiheader. biheight =-rctext. Height ();
DiB. bmiheader. biplanes = 1;
DiB. bmiheader. bibitcount = 32;
DiB. bmiheader. bicompression = bi_rgb;

BMP. createdibsection (DC, & Dib, dib_rgb_colors, null, null, 0 );
Now, we have created the graphic object and can start to draw the text.

// Set the DC

Dcmem. selectbitmap (BMP );
Dcmem. selectfont (m_font );

// Draw text

Dttopts DTO = {sizeof (dttopts )};
Const uint uformat = dt_singlelinedt_centerdt_vcenterdt_noprefix;
Crect rctext2 = rctext;
Dto. dwflags = dtt_compositeddtt_glowsize;
Dto. iglowsize = 10;
Rctext2-= rctext2.topleft (); // The same rect, but the upper left corner is (0, 0)

Drawthemetextex (m_htheme, dcmem, 0, 0, ct2cw (sztime),-1,
Uformat, rctext2, & DTO );
The dttopts structure controls how the text is drawn. In the flag, we specify the "synthesize text" to be drawn and give the text a luminous effect. Finally, paste the bitmap in the memory to the screen:

// Draw the text to the screen.
Bitblt (DC, rctext. Left, rctext. Top, rctext. Width (), rctext. Height (), dcmem, 0, 0, srccopy );
} // End if (iscompositionenabled ())
If composition is not enabled, we use the GDI function to draw the text:

Else
{
Const uint uformat = dt_singlelinedt_centerdt_vcenterdt_noprefix;
// Set the DC

DC. settextcolor (RGB (255,255,255 ));
DC. selectfont (m_font );
DC. setbkmode (transparent );

// Draw text

DC. drawtext (sztime,-1, rctext, uformat );
}
Return true; // we have drawn the entire background.
}
The following figure shows the appearance of "synthetic text:

 
To demonstrate the luminous effect, the following is a piece of text on the same background, but there is no luminous effect:

 

Handle notifications related to Composition

When the composition status of DWM is enabled or disabled, the system broadcasts a wm_dwmcompositionchanged message to all top-level windows. If the composition is enabled, you need to call dwmtendframeworkclientarea () again to inform DWM, which part of our window should be glass:

Lresult cmainframe: oncompositionchanged (...)
{
If (iscompositionenabled ())
{
Margins MAR = {0 };
Mar. cybottomheight = 100;

Dwmexico tendframeworkclientarea (m_hwnd, & Mar );
}
Return 0;
}
Apply the frosted glass effect in the dialog box Program

The process of adding the frosted glass effect in the dialog box program is very similar to the example in the frame window above, but the code needs to be slightly changed. In the example dialog box, the upper-Layer window is added with the frosted glass effect. below, the Code modified or added relative to the previous example is marked in black.

Setting Dialog Box

As before, let us know which themeimpl we want to use, and call dwmextendframeworkclientarea () to add the glass effect to the window border.

Cmaindlg: cmaindlg ()
{
Setthemeclasslist (L "globals ");
}

Bool cmaindlg: oninitdialog (hwnd hwndfocus, lparam)
{
// Some initialization code generated by the Wizard is deleted.
// Add the frosted glass effect to the top window

If (iscompositionenabled ())
{
Margins MAR = {0 };
Mar. cytopheight = 150;
Dwmexico tendframeworkclientarea (m_hwnd, & Mar );
}
Next, build the text font. Note: We need to explicitly call openthemedata (), but why does it not need to be called in the previous framework window example, because cthemeimpl has already been called in its wm_create handler. In contrast, the dialog box receives the wm_initdialog, while the cthemeimpl does not process the wm_initdialog, so we need to call openthemedata () by ourselves. In addition, the font is also set to a larger font in the code to demonstrate the luminous effect of a larger font.

// Decide which font to use
Logfont LF = {0 };
Openthemedata ();

If (! Isthemenull ())
Getthemesysfont (tmt_msgboxfont, & lf );
Else
{
Nonclientmetrics NCM = {sizeof (nonclientmetrics )};
Systemparametersinfo (spi_getnonclientmetrics, sizeof (nonclientmetrics), & NCM, false );
LF = NCM. lfmessagefont;
}

Lf. lfheight * = 3;
M_font.createfontindirect (& lf );
The top-level window of the dialog box has a large static text control, that is, the place where we want to draw the time. The Code sets the control's owner-draw style. Therefore, we can put all the text drawing code in ondrawitem:

// Set the owner-draw of the static text Control

M_wndtimelabel.attach (getdlgitem (idc_clock ));
M_wndtimelabel.modifystyle (ss_typemask, ss_ownerdraw );
Finally, call enablethemedialogtexture () to draw the background of the dialog box using the current topic.

// Other initialization code

Enablethemedialogtexture (etdt_enable );

// Set the timer interval to 1 second to update the clock every second.

Settimer (1, 1000 );
Return true;
}
Glass opening Effect

As before, we need to fill the glass area with a black brush to create a pivoting effect. Because the built-in dialog box processing process will respond to the wm_erasebkgnd message to process such as non-rectangular or translucent controls, we need to plot in onpaint () instead of onerasebkgnd.

Void cmaindlg: onpaint (HDC)
{
Cpaintdc DC (m_hwnd );
Crect rcglassarea;

If (iscompositionenabled ())
{
Getclientrect (rcglassarea );
Rcglassarea. Bottom = 150;
DC. fillsolidrect (rcglassarea, RGB (0, 0 ));
}
}
Draw text

In ontimer (), obtain the current time and set the text of the static control as follows:

Void cmaindlg: ontimer (uint uid, timerproc pproc)
{
// Obtain the current time
Tchar sztime [64];
Gettimeformat (locale_user_default, 0, null, null, sztime, _ countof (sztime ));
M_wndtimelabel.setwindowtext (sztime)
}
The setwindowtext () function redraws the static control and calls the ondrawitem () function. The code in the ondrawitem () function is similar to that in the previous frame window example. I will not repeat it here. The following is the appearance of the program:

 

Draw a graph on the frosted glass Effect

As mentioned earlier, the use of alpha-aware APIs, such as the GDI + function, is required for plotting in the frosted glass area. The following example uses the image class in GDI + to draw a logo in the upper left corner of the dialog box, as shown in:

 
This logostore is read from the mylogo.png file in the same directory as the exefile. Pay attention to this. Because the logo is drawn by using GDI +, the transparency around the logo has been retained and appears to be correct.

Blur the entire window

We can also make the entire window look like a block of glass. Here is a short piece of code, just set the first member of the margins structure to-1:

Margins MAR = {-1 };
Dwmexico tendframeworkclientarea (m_hwnd, & Mar );
If you add this code to our Dialog Box program, the program will eventually look like this:

 
Note that the text color on the four buttons is incorrect, and each button has an opaque rectangle on the periphery. Generally, transparency does not work very well with subwindows. If you want a dialog box with full glass effect, the control part needs to be drawn with an opaque background, for example, the "Windows mobility center" program:

 
Conclusion

Adding a glass wool effect to a program can make the program visually very distinctive, and provide a better display area than the status bar in the general control. This article is mainly to serve as a reference, it also helps you gain a preliminary understanding of DWM APIs when using local C ++ to add glass wool effects.

Reference: http://www.knowsky.com/395561.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.