I need to know the drop shadow dimensions of a window. I tried receiving values via the GetSystemMetrics WinAPI function, but I could not find the parameter to pass over.
Any idea on how I can get this value globally (or for a single window handle)? I know that the width of a drop shadow depends on the window type (dialog/normal/and so on).
Ibwould implement this functionality using C#, but C++ would also be fine.
There is a way using the DWM API to figure out the size of the drop shadow, however, it does not work until the window is visible.
In previous versions of Windows, there was the Client Rect, and the Window Rect. But ever since Vista came out, there has been a third Rect for a window called the Extended Frame Bounds. The third rect is larger than the Client Rect and smaller than the Window Rect, and excludes the area taken up by the drop shadow.
Call DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &rect, sizeof(RECT)) to read the Extended Frame Bounds rect. This function is from <dwmapi.h>, and is
not available in Windows XP or earlier.
Note that if you call this before the window has been shown, you will get incorrect results.
EDIT:
Note that Extended Frame Bounds are in physical pixel coordinates, and are not affected by the Scaling features of Windows. You may need to convert back to virtual coordinates, or convert the virtual coordinates to physical coordinates to make them match.
As far as I know there is no way of obtaining that information. Programs such as WindowClippings solve it by taking a screenshot and cropping to the shadow dimensions afterwards.
Related
I have a winform (c#, let's say 250px by 250px) that needs to stay in one location on the screen regardless of screen resolution i.e 800x600, 1920x1080 etc. The Winform itself contains only one element - a picturebox so what's inside really doesn't matter (no need to worry about fonts, etc.). I just need it to stick in one place on the screen from one monitor to another.
Any ideas? Thanks in advance.
Could you use one of these?
1) WindowsState = Maximized (then you dont worry, it always takes whole screen)
2) StartPosition = CenterScreen (then it always shows as centered), or CenterParent to center within parent form
3) Location = in this case you would have to do some math to get screen size, your form size than based on that center it but I dont see point of using this considering that StartPosition does it already for you.
Hope that helps
Ok, so in order to get the window at a fixed location given in % of the screen size, you need the screen size (e.g. using this answer), compute the desired position, and set it as the window-location.
Since you need to do it at startup, you could do it before you show the window, or maybe best inside a Frame.Loaded event handler.
For some reason, everything I tried that was online about resolution independence doesn't really work the way I would want it to. Most of the solutions suggest a way to get the width and height and then use a class with them, but the result is always a cutoff picture(too big picture) or a picture in the top left corner with smaller height and width than those of the screen.
P.S. The game is in fullscreen, but we tried windowed and it didn't work either.
This is actually a pretty simple fix. Basically, create a RenderTarget object somewhere and do all your drawing to that object, then resize that to the screen.
Use GraphicsDevice.SetRenderTarget(target) to change the render target, then do all your drawing operations, then change it back to the back buffer afterwards by setting it to null. RenderTargets actually derive from Texture2D, so you can use it in as an argument, such as: SpriteBatch.Draw(renderTarget, Viewport.Bounds, Color.White), and this will stretch it to fit the screen.
I have made a program that reads voltage and current values of some diode curves from an xml file and draws them on screen (Just using plain 2D graphics and some simple commands like DrawCurve and stuff like that).
My main image frame is 800 by 800 pixels (you can see a smaller screenshot down below). Now I want to add a zoom function that when I hover the mouse over this image area, a flying smaller square pops up and zooms in + moves when I move the mouse over this area.
I have no idea how to approach this. Ofcourse I don't ask the full working code but please help me to get closer and closer!
For instance, can I make the zoom to work, without reading the curve data and painting real time? or there is no escape from it? How can I have a hovering image box when I move mouse over the orginal image?
Thanks!
Have you timed how long DrawCurve takes? Perhaps it's fast enough to do in real time. Don't forget, the GDI will clip the drawing primitives to the drawing area. You just need to set up a clipping rectangle as you move the mouse around.
To speed up the redraw, create the main window image (the one you pasted) as an off-screen bitmap, and just DrawImage the off-screen version to the window in the paint events. That way you reduce the impact of the DrawCurve.
Finally, to get good looking results, overload the OnPaintBackground (can't remember the name exactly but it's something like that) so it does nothing (not even call the base class) and do all your painting in the OnPaint method using a BufferedGraphics object.
Update
Your paint function might look like this:
OnPaint (...)
{
the_graphics_object.DrawImage (the background image);
the_graphics_object.Clip = new Region (new Rectangle (coords relative to mouse position));
the_graphics_object.TranslateTransform (drawing offset based on mouse position);
RenderScene (the_graphics_object, scale_factor); // draws grid and curve, etc
the_graphics_object.DrawRectangle (zoom view rectangle); // draw a frame around the zoomed view
}
This will produce a floating 'window' relative to the mouse position.
Typically, cases where redrawing can be time consuming, zooming is usually tackled by providing a "quick but ugly" implementation, alongside the "correct but slow" implementation. While the zoom operation is actively in progress (say, while the user has a slider clicked, or until a 50ms since the last change in zoom value has happened), you use the quick and ugly mode, so the user can see a preview of what the final image will be. Once they let go of the zoom slider (or whatever mechanism you provided), you can recalculate the image in detail. The quick version is usually calculated based on the original image that you are working with.
In your case, you could simply take the original image, work out the bounding box of the new, zoomed image, and scale the relevant part of the original image up to the full image size. If say 100ms has passed with no change in zoom, recalculate the entire image.
Examples of this kind of functionality are quite widespread: most fractal generators use exactly this technique, and even unrelated things like Google StreetView (which provides a very ugly distorted version of the previous image when you move around, until the actual image has downloaded).
So the default cursor is the "Arrow" cursor and the top-left of the arrow (where the point is) is the part that clicks or interacts with other controls. How can I change the pointing part to say the tail of the arrow?
What I have is a custom cursor (a bitmap image) which is a circle at 16x16 size and I want the very center of it to be the pointer. I have another custom arrow-like cursor that points downward-left also 16x16 and I want the bottom-left corner of the cursor to be the pointer. I think there's a property in the cursor class for this but I'm not sure what it's called.
This is actually specified in the CUR file format.
The CUR file format is an almost identical image file format for
non-animated cursors in Microsoft Windows. The only differences
between these two file formats are the bytes used to identify them and
the addition of a hotspot in the CUR format header; the hotspot is
defined as the pixel offset (in x,y coordinates) from the top-left
corner of the cursor image where the user is actually pointing the
mouse.
Programs that can edit CUR files generally allow you to specify the hot spot. More information can be found in this question.
What you want can't be done through code. I wanted do the same thing but it's not possible.
In fact, the Cursor class has a property called HotSpot, which is the point that you want change. However this property is readonly.
The only way to change this is at file loading (on a .cur file, I suggest you using Paint .net with Cursor and icons plugin (search over the web) to edit cursor). An important thing: the cursor must be a file and not a resource or things like that (must be a file on the file system) to load it. Remember it, I had bad times testing in other ways.
The idea that I have in mind is: edit cursor file just when you need to change the hotspot, however this require for you writing an api that allows you to change the hotspot on a cursor file. I obviusly don't know how this file is built so you must continue from here.
Hope this was useful
I want to draw directly on the desktop in C#. From searching a bit, I ended up using a Graphics object from the Desktop HDC (null). Then, I painted normally using this Graphics object.
The problem is that my shapes get lost when any part of the screen is redrawn. I tried a While loop, but it actually ends up drawing as fast as the application can, which is not the update rate of the desktop.
Normally, I would need to put my drawing code in a "OnPaint" event, but such thing does not exist for the desktop.
How would I do it?
Example code: https://stackoverflow.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c
I posted two solutions for a similar requirement here
Basically you have two options.
1- Get a graphics object for the desktop and start drawing to it. The problem is if you need to start clearing what you have previously drawn etc.
Point pt = Cursor.Position; // Get the mouse cursor in screen coordinates
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
g.DrawEllipse(Pens.Black, pt.X - 10, pt.Y - 10, 20, 20);
}
2- The second option that I provide in the link above is to create a transparent top-most window and do all your drawing in that window. This basically provides a transparent overlay for the desktop which you can draw on. One possible downside to this, as I mention in the original answer, is that other windows which are also top-most and are created after your app starts will obscure your top most window. This can be solved if it is a problem though.
For option 2, making the form transparent is as simple as using a transparency key, this allows mouse clicks etc. to fall through to the underlying desktop.
BackColor = Color.LightGreen;
TransparencyKey = Color.LightGreen;
When you draw to HDC(NULL) you draw to the screen, in an unmanaged way. As you've discovered, as soon as windows refreshes that part of the screen, your changes are overwritten.
There are a couple of options, depending upon what you want to achieve:
create a borderless, possibly
non-rectangular window. (Use
SetWindowRgn to make a window
non-rectangular.) You can make this a child of the desktop window.
subclass the desktop window. This is not straightforward, and involves
injecting a DLL into the
Explorer.exe process.
To get an OnPaint for the desktop you would need to subclass the desktop window and use your drawing logic when it receives a WM_PAINT/WM_ERASEBKGND message.
As the thread you linked to says, you can only intercept messages sent to a window of an external process using a hook (SetWindowsHookEx from a DLL).
As mentioned a transparent window is another way to do it, or (depending on the update frequency) copying, drawing and setting a temporary wallpaper (as bginfo does).
This is difficult to do correctly.
It will be far easier, and more reliable, to make your own borderless form instead.