Using the DwmExtendFrameIntoClientArea API call with Aero Glass enabled works just fine. However, I want it to work when Aero Glass is disabled as well, like how it works in the Windows control panel:
Notice how the frame has extended into the client area, even though Aero Glass is disabled? When I make the DwmExtendFrameIntoClientArea API call in my application, the returned HRESULT is definitely not success, and my application ends up looking like this:
http://img197.imageshack.us/img197/9629/clientapplication.png
Normally, with Aero Glass enabled, the border stretches down to underneath the navigation buttons, like in the control panel. How do I do this? DwmExtendFrameIntoClientArea clearly isn't working.
By the way, if it is relevant, my application is a WPF application.
Nir's answer is correct; when composition is disabled you have to draw that area yourself.
i can show you the code i have in the paint handler of the panel at the top of my form - the panel normally responsible for drawing the 0x00000000 transparent black to make the glass appear:
Psuedo-code:
procedure DrawGlassHeaderArea(g: Graphics; r: Rectangle; IsFormFocused: Boolean);
const
clFakeGlassColor = $00EAD1B9; //(185, 209, 234) This is the fake foreground glass color (for use when composition is disabled)
clFakeGlassColorUnfocused = $00F2E4D7; //(215, 228, 242) This is the fake background glass color (for use when composition is disabled)
begin
if Dwm.IsCompositionEnabled then
begin
g.FillRectangle(r, 0x00000000); //fill rectangle with transparent black
end
else
//Composition disabled; fake it like Microsoft does
//The color to use depends if the form has focused or not
Color glassColor;
if (IsFormFocused) then
c = clFakeGlassColor
else
c = clFakeGlassColorUnfocused;
g.FillRectangle(r, glassColor); //fill rectangle with fake color
//Now we have to draw the two accent lines along the bottom
Color edgeHighlight = ColorBlend(Colors.White, glassColor, 0.33); //mix 33% of glass color to white
Color edgeShadow = ColorBlend(Colors.Black, glassColor, 0.33); //mix 33% of glass color to black
//Draw highlight as 2nd-last row:
g.DrawLine(edgeHighlight, Point(r.Left, r.Bottom-2), Point(r.Right, r.Bottom-2);
//Draw shadow on the very last row:
g.DrawLine(edgeHighlight, Point(r.Left, r.Bottom-1), Point(r.Right, r.Bottom-1);
end;
end;
Sample usage
procedure MyForm.PaintBox1Paint(PaintEventArgs e)
begin
DrawGlassHeaderArea(e.Graphics, PaintBox1.ClientRectangle, this.HasFocus);
end;
Bonus Screenshot
Update 7/9/2014
#JakePetroules was right, and i was wrong. The "blue" used for fake glass is not hard-coded into Windows. And it is accessible using GetThemeColor.
I coded up all the available colors (TMT_COLOR) available for a Window class:
Note: For more information about Classes, Parts, and States, see Aero Style Classes, Parts, and States
When using:
Class: Window
Part: WP_CAPTION
State: n/a (StateID is not used for the Caption part, nor the entire Window class)
and fetch the color code propertyID:
TMT_FILLCOLORHINT: for when the window has focus
TMT_BORDERCOLORHINT: for when the window does not have focus
you get the two important colors:
The pseudo-code i now use to get the fake glass color:
public Color GetFakeClassColor(Boolean isWindowFocused=true)
{
static Color fakeGlass= 0x00B8D0E9; //the correct answer anyway
if ((GetThemeAppProperties() && STAP_ALLOW_CONTROLS) == 0)
return fakeGlass;
hTheme = OpenThemeData(GetDesktopWindow(), "Window");
if (hTheme = 0)
return fakeGlass;
Int32 propID;
if (isWindowFocused)
propID= TMT_FILLCOLORHINT; //The color used as a fill color hint for custom controls.
else
propID= TMT_BORDERCOLORHINT; //The color used as a border color hint for custom controls.
DWORD rgb;
if (Failed(GetThemeColor(hTheme, WP_CAPTION, 0, propID, ref rgb))
return fakeGlass;
Result = new Color(rgb);
}
In reality, since i use Delphi, my actual code is:
function GetFakeGlassColor(IsWindowFocused: Boolean=True): TColor;
var
ted: TThemedElement;
hTheme: THandle;
propID: Integer;
rgb: DWORD;
begin
Result := $00B8D0E9; //the correct answer anyway
//We can't use the ThemeServcies.ThemesEnabled, as that mistakenly checks for version 6 of the common controls library
//Themes can be enabled without using ComCtl V6, or common controls at all
if not ThemeServices.ThemesAvailable then
Exit;
if (GetThemeAppProperties and STAP_ALLOW_CONTROLS) = 0 then
Exit;
htheme := ThemeServices.Theme[teWindow];
if hTheme = 0 then
Exit;
if IsWindowFocused then
propID := TMT_FILLCOLORHINT //The color used as a fill color hint for custom controls.
else
propID := TMT_BORDERCOLORHINT; //The color used as a border color hint for custom controls.
if Failed(GetThemeColor(hTheme, WP_CAPTION, 0, propID, {var}rgb)) then
Exit;
Result := rgb;
end;
You have to paint it to be frame-like yourself.
You have to use DwmIsCompositionEnabled to check if the DWM is enabled and handle WM_DWMCOMPOSITIONCHANGED to detect DWM state changed.
Then you have to have to separate way of drawing the window, if DWM is enabled you use DwmExtendFrameIntoClientArea, if it's disabled you draw the "frame" yourself.
I have no idea how to duplicate the Aero frame in WPF (in my app I have my own color scheme and I'm not using the Auro frame).
This is annoying but when the DWM is disabled the system falls back to XP-style drawing and none of the DWM's services work - even those that aren't related to the glass effect.
You need to paint the window background yourself. You should not actually hard-code the colors as previous posts have suggested, but use the theme functions to retrieve them, like so (semi-pseudocode):
DWORD rgb;
HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
GetThemeColor(hTheme, WP_CAPTION, CS_ACTIVE,
<is active window> ? TMT_FILLCOLORHINT : TMT_BORDERCOLORHINT, &rgb);
// Can use these functions to retrieve the individual RGB values
BYTE r = GetRValue(rgb);
BYTE g = GetGValue(rgb);
BYTE b = GetBValue(rgb);
These colors will remain correct even if the user changes title bar colors in the control panel (unlike using COLOR_ACTIVECAPTION / COLOR_GRADIENTACTIVECAPTION). You should also check that themes are active using IsThemeActive() before attempting to get theme colors.
The values of the constants for quick reference:
WP_CAPTION: 1
CS_ACTIVE: 1
TMT_FILLCOLORHINT: 3821
TMT_BORDERCOLORHINT: 3822
Related
How to make a circle with text inside ?? then move it from one location to another, and then access it later (to delete it).
I want to make something like this
Your question is really very broad and you got a few nice links you should study to learn all about GDI+ drawing.
But if taken literally there is a slightly exotic alternative which puts the burdon of most chores onto the Chart control from DataVisualization.Charting.
You can create EllipseAnnotations and add them to a Chart control.
Disable the Axes and clear the Legends and then use code like this to add a moveable circle wit thext inside:
EllipseAnnotation ea = new EllipseAnnotation();
ea.X = 11; // put at..
ea.Y = 11; // 11% of the chart's area
ea.AllowMoving = true;
ea.BackColor = Color.BlanchedAlmond;
ea.Text = (chart1.Annotations.Count + 1) + "";
chart1.Annotations.Add(ea);
Note that there are quite a few annotation types available. which allow you to add Rectangles, Images, Polygons, Lines and pure Text.
And another pro is that saving or loading the graphics takes only one line each, as you can serialize a Chart out of the box!
:-)
GraphX for .NET is an advanced open-source graph layout and visualization library that supports different layout algorithms and provides many means for visual customizations It is capable of rendering large amount of vertices
https://github.com/panthernet/GraphX
To draw shapes follow here.Also you need a complete tut,you can follow here
Some insight is here:
To draw a simple shape at design time Drag the OvalShape or
RectangleShape control from the Visual Basic PowerPacks tab (to
install, see Visual Basic Power Packs Controls)in the Toolbox to a
form or container control.
Drag the sizing and move handles to size and position the shape. You
can also size and position the shape by changing the Size and Position
properties in the Properties window To create a rectangle with rounded
corners, select the CornerRadius property in the Properties window
and set it to a value that is greater than 0. In the Properties
window, optionally set additional properties to change the appearance
of the shape. To draw a simple shape at run time On the Project
menu, click Add Reference. In the Add Reference dialog box, select
Microsoft.VisualBasic.PowerPacks.VS, and then click OK. In the Code
Editor, add an Imports or using statement at the top of the module:
using Microsoft.VisualBasic.PowerPacks; Add the following code in an Event procedure:
ShapeContainer canvas = new ShapeContainer();
// To draw an oval, substitute
// OvalShape for RectangleShape.
RectangleShape theShape = new RectangleShape();
// Set the form as the parent of the ShapeContainer.
canvas.Parent = this;
// Set the ShapeContainer as the parent of the Shape.
theShape.Parent = canvas;
// Set the size of the shape.
theShape.Size = new System.Drawing.Size(200, 300);
// Set the location of the shape.
theShape.Location = new System.Drawing.Point(100, 100);
// To draw a rounded rectangle, add the following code:
theShape.CornerRadius = 12;
Customizing Shapes When you use the default settings, the OvalShape and RectangleShape controls are
displayed with a solid black border that is one pixel wide and a
transparent background. You can change the width, style, and color of
the border by setting properties. Additional properties enable you to
change the background of a shape to a solid color, a pattern, a
gradient fill, or an image. Before you change the background of a
shape, you should know how several of the properties interact. The
BackColor property setting has no effect unless the BackStyle property
is set to Opaque. If the FillStyle property is set to Solid, the
FillColor overrides the BackColor. If the FillStyle property is set to
a pattern value such as Horizontal or Vertical, the pattern will be
displayed in the FillColor. The background will be displayed in the
BackColor, provided that the BackStyle property is set to Opaque. In
order to display a gradient fill, the FillStyle property must be set
to Solid and the FillGradientStyle property must be set to a value
other than None. Setting the BackgroundImage property to an image
overrides all other background settings.
This SO link I found is also nice here
I'm writing a custom Button control as part of a (soon to be) free Control suite, and I would like to base my (default) Control colors on the corresponding Windows System colors. So, after looking up "default windows system colors" online I could not find information on the System Colors for Windows controls (especially not Button controls).
Is there a way to get this color information (e.g. Button Border Color, Button Highlight Color, Button Hover Color, Button Clicked Background Color, etc) in .NET?
Yes. In fact, there is an entire class dedicated to this:
The SystemColors class.
...or for WPF (thanks #ORMapper), The System.Windows.SystemColors class.
There is a System Color Class out, which will provide you the Colors.
For WinForms use:
System.Drawing.SystemColors
For WPF use:
System.Windows.SystemColors
You can use also the GetSysColor function api function.
Valter
You could use the Win API, GetSysColor function...
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int GetSysColor(int nIndex);
The function returns the red, green, blue (RGB) color value of the given element.
To display the component of the RGB value, use the GetRValue, GetGValue, and GetBValue macros.
System colors for monochrome displays are usually interpreted as shades of gray.
To paint with a system color brush, an application should use GetSysColorBrush(nIndex), instead of CreateSolidBrush(GetSysColor(nIndex)), because GetSysColorBrush returns a cached brush, instead of allocating a new one.
I am wanting the same thing. My approach is to, upon initialization, create a temporary window with the background color specified in GetSysColor(COLOR_BTNFACE), the "standard" background color for dialog boxes. Then, I create a button with no text and get the colors. This temporary window is never displayed, and is destroyed immediately (WM_CREATE exit code = -1).
Is there a way to retrieve the margins that were set by DwmExtendFrameIntoClientArea?
I've scanned the documentation. I would have expected DwmGetWindowAttribute to be the most logical place to look it up.
(What I would like to do is discern what portion of an inserted child should be painted black to allow Aero glass effects through and what portion should be painted the parent's background colour.)
There is no way to do this. The developer is expected to know the size of the frame they extended into the client area.
MARGINS g_Margins;
g_Margins.cxLeftWidth = 0;
g_Margins.cxRightWidth = 0;
g_Margins.cyTopHeight = 15*fontHeight;
g_margins.cyBottomHeight = 7*fontHeight;
DwmExtendFrameIntoClientArea(g_hwnd, g_margins);
Note: Any code released into public domain. No attribution required.
I am trying to make a tool in c# which allows the user to put a grid on the screen on a picturebox. At the moment i don't know how to do this, so when a button is clicked, the picturebox comes up with a grid. It needs to be a grid which is spaced out enough that users can find out locations of objects on the picture in the picturebox. Help with what code i can use to do this would be very helpful as i was going to use ControlPaint.DrawGrid but not sure of the values i need to put in it to get my desired effect?
Thanks
Form the Documentation od controlpaint.Drawgrid,
I suppose you need to decide on the cell size in x- amd y-direction and pass this as a size parameter to Drawgrid:
public static void DrawGrid(
Graphics graphics,
Rectangle area,
Size pixelsBetweenDots,
Color backColor
)
for example, a 100*200 pixels square grid would be generated by
setting graphcis to the context you want to draw upon,
Setting area to the top left right and bottom parameters of your image
setting size.x to 100 and size.y to 200
setting color to any color you like.
Update
Something like this should do.
Rectangle myRect = new System.drawings.Rectangle();
myRect.Location := new System.Drawing.Point(0,0);
myRect.Height = 50;
myRect.Width = 50;
Drawgrid(FromImage(yourImage), mygrid , yourImage.Size, System.Drawing.Color.Black);
Disclaimer: i don't develope in c#, so above code is not tested for anything. I just picked stuff from the documentation (msdn).
I am trying to take a screenshot of an application and I would like to make the parts of the rectangle that are not part of the applications region be transparent. So for instance on a standard windows application I would like to make the rounded corners transparent.
I wrote a quick test application which works on on XP (or vista/windows 7 with aero turned off):
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
// Just find a window to test with
IntPtr hwnd = FindWindowByCaption(IntPtr.Zero, "Calculator");
WINDOWINFO info = new WINDOWINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
GetWindowInfo(hwnd, ref info);
Rectangle r = Rectangle.FromLTRB(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
IntPtr hrgn = CreateRectRgn(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
GetWindowRgn(hwnd, hrgn);
// fill a rectangle which would be where I would probably
// write some mask color
g.FillRectangle(Brushes.Red, r);
// fill the region over the top, all I am trying to do here
// is show the contrast between the applications region and
// the rectangle that the region would be placed in
Region region = Region.FromHrgn(hrgn);
region.Translate(info.rcWindow.Left, info.rcWindow.Top);
g.FillRegion(Brushes.Blue, region);
}
When I run this test app on XP (or Vista/Windows 7 with Aero off), I get something like this, which is great because I can eek an xor mask out of this that can be used later with BitBlt.
removed dead Imageshack link - Screenshot
Here is the problem, on Vista or Windows 7 with Aero enabled, there isn't necessarily a region on the window, in fact in most cases there isn't. Can anybody help me figure out some way to build a mask like this on these platforms?
Here are some of the approaches I have already tried...
1. Using the PrintWindow function: This doesn't work because it gives back a screenshot taken of the window with Aero off and this window is a different shape from the window returned with Aero on
2 Using the Desktop Window Manager API to get a full size thumbnail: This didn't work because it draws directly to the screen and from what I can tell you can't get a screenshot directly out of this api. Yeah, I could open a window with a pink background, show the thumbnail, take a screenshot then hide this temporary window but thats a horrible user experience and a complete hack I would rather not have my name on.
3. Using Graphics.CopyFromScreen or some other pinvoke variant of this: This doesn't work because I can't assume that the window I need information from is at the top of the z-order on the screen.
Right now, the best solution I can think of is to special case Aero on Windows 7 and Vista to manually rub out the corners by hard coding some graphics paths I paint out but this solution would suck since any application that performs custom skinning will break this.
Can you think of another or better solution?
If you are here, thanks for taking time to read this post, I appreciate any help or direction that you can offer!
If you are looking for a finished application, there is 7capture, which captures also the translucency, so images can be saved to PNG format for later compositing.
EDIT:
The original question and comments indicate you are looking to produce a region on Windows Vista/7 that you can then use to mask out parts the captured image, as is done with Windows XP and non-Aero UIs. Using a region is not going to give you the result you are looking for, since the window outline is not computed as a region, but as an image with variable transparency - RGBA. The Alpha channel in that image is your mask, but it's not an on-off mask like a region, but a gradual mask with a range of values from pixels being fully included to being fully masked out.
Although it uses undocumented APIs, the code at http://spazzarama.wordpress.com/2009/02/12/screen-capture-with-vista-dwm/ will capture to a RGBA buffer which you can then use to render or save the image with the shadow and other translucency effects intact.
In DwmCapture.cs Change
BackBufferFormat = Format.X8R8G8B8
to
BackBufferFormat = Format.A8R8G8B8
(X8->A8)
And you should then be able to access both the usual RGB data plus transparency from the captured buffer. This can then be saved as a PNG or other format with alpha-channel for composing.
Removed idea that is terrible but would have been awesome back in the '90s
You say that using the DWM API only allows you to capture directly to the screen... could you create a window offscreen (say, X = -100000px, Y = -100000px) but visible (maybe even hidden?) and draw the screenshot to it? Since when using the DWM each window has a backing texture, I'm thinking it might still get drawn fine even though the target isn't directly onscreen.
Also, if you want to go the DirectX route and access the actual DX texture backing the window, I found a few leads that might help (especially the first link):
http://spazzarama.wordpress.com/2009/02/12/screen-capture-with-vista-dwm/
http://channel9.msdn.com/forums/TechOff/251261-Help-Getting-the-shared-window-texture-out-of-DWM-/
http://web.archive.org/web/20080625183653/http://www.aeroxp.org/board/index.php?showtopic=6286
http://www.youtube.com/watch?v=hRTgFTMnT_U
Using Graphics.CopyFromScreen or some other pinvoke variant of this:
This doesn't work because I can't
assume that the window I need
information from is at the top of the
z-order on the screen.
If you know which window you need the information from, can you bring it to the front, call Graphics.CopyFromScreen, and then reset its z-index? I know from experience that Aero does odd things when items are in the background in order to make their glass interface work correctly (partial rendering etc). This may not be great UX; however, it would be a special case and used only when Aero is turned on.
You can take a look at the source code of AeroShot, as described on the main page, it can capture rounded edges and with the Aero Glass transparency effect and save it to a PNG file. It's written in C#.