I would like to know how to build an screenmate.
Something like this:
Example # 1:
http://www.youtube.com/watch?v=SHvDOPkGQqE
Example # 2:
http://www.youtube.com/watch?v=5tHpmeZseIs
Example # 3:
http://www.viddler.com/explore/myvirtuallady/videos/5/
I guess that there has to be a way to do it, but I don't know how.
Can this be done using some Microsoft frameworks? Maybe with C#?
To draw the screenmate itself you can use a normal Form that has no border and a TransparencyKey color to make the background transparent. You can then draw the animation by overriding OnPaint().
To get it to react to other windows like in the first video is a bit trickier, and requires some pinvoke into user32.dll. The function FindWindow gets the handles of other windows and GetWindowRect will let you get their position and sizes so you can write some code that makes the screen mate react to them.
Related
I am about to write a main menu for a Windows Forms application.
Rather than trying to explain my goal with a wall of text i made a quick(ugly) paint sketch:
As you can see here i want the Group Controls to automatically scale with their content(similar to the wrap_content attribute in android) and fit underneath each other if possible.
If anyone knows how to achieve this or even has a sample where he already did achieve it, that would help me massively!
thanks, Felix.
This is the cursor I want to use. It has a little plus sign below the arrow:
When I try to set the current cursor in my Windows Forms app, I do this (and it works):
Cursor.Current = Cursors.WhateverCursor;
The available cursors can be seen here. Notably, I do not see one like I want.
How can I get that little plus sign cursor?
This is the list again, in case that link dies:
AppStarting
Arrow
Cross
Default
Hand
Help
HSplit
IBeam
No
NoMove2D
NoMoveHoriz
NoMoveVert
PanEast
PanNE
PanNorth
PanNW
PanSE
PanSouth
PanSW
PanWest
SizeAll
SizeNESW
SizeNS
SizeNWSE
SizeWE
UpArrow
VSplit
WaitCursor
The system cursors only get you so far. For more you need to use an external resource..
You should create a proper cursor file (somefile.cur) and then assign it to the current cursor:
Cursor myCursor = new Cursor(yourCursorfile);
Cursor = myCursor;
To create it do use a nice application; I found Greenfish to work OK (although their own icon looks like crap ;-)
Make sure to avoid colors, as the above code won't work with colors, afaik.
Here is an example I used in one of my projects..
If you want to use it for a drag and drop operation (which is generally where this kind of cursor shows up) check out DragDropEffects, I think that's what you're looking for.
I just started to use Gtk# today, and I'm astonished how few Documentation and exampleprojects are out there. Anyways I wanted to ask, does anybody know how to add a backgroundimage to a window or a widget?
Or I don't know is it possible to stack multiple widgets over each other beacause, because then it would be quite easy.
Gtk.Window is for the GUI, for background images you need to use Graphics i.e you need to access the underlying GdkWindow . In Gtk# simply use
Gtk.Window mwin = new Gtk.Window();
Gdk.Window gwin = mwin.GdkWindow;
then use Gdk.Pixbuf to set the background image. Here's a link that may be helpful, it is in PHP-GTK, but it shouldn't be too hard to convert to C#.
http://www.kksou.com/php-gtk2/articles/place-a-background-image-in-GtkWindow.php
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.
I'm making a .NET 3.5 app with a form that draws a partially transparent black background. I'm overriding OnPaintBackground to accomplish this:
protected override void OnPaintBackground( PaintEventArgs e )
{
using ( Brush brush = new SolidBrush( Color.FromArgb( 155, Color.Black ) ) )
{
e.Graphics.FillRectangle( brush, e.ClipRectangle );
}
}
It works, but occasionally the form draws over itself without clearing the screen, making the transparency darker than it should be. I've tried playing with Graphics.Flush() and Graphics.Clear(), but it either doesn't help or completely removes transparency. Any suggestions?
Edit:
Here's what it looks like, after starting the app on the left, and after the form redraws itself a few times (in response to tabbing from one control to another) on the right:
Transparency Issue http://www.quicksnapper.com/files/5085/17725729384A10347269148_m.png
Edit 2:
I was trying a few things out this morning and noticed that when the desktop behind the transparent portions change, it's not actually being redrawn. For example, if I open Task Manager and put it behind the window, you don't see it refreshing itself. This makes sense with what I've been seeing with the transparency levels. Is there a function to make Windows redraw the area behind your window?
Edit 3:
I've tried changing a few properties on the form, but they all result in the form drawing non-transparent black:
this.AllowTransparency = true;
this.DoubleBuffered = true;
this.Opacity = .99;
I'm going to try creating a separate window for the transparent portion as overslacked mentioned, but any other ideas are still welcome.
I think I would call this expected behavior, actually. What I would do is render my background to an in-memory bitmap and, in the paint event, copy that to the form (basic double-buffering).
If I'm way off base, could you post a screenshot? I don't know that I'm imagining what you're describing correctly.
EDIT:
I'm wondering about your use of OnPaintBackground... pre-.NET, if you were doing double-buffering you'd catch and ignore the WM_ERASKBKGND message (to prevent flicker), render your image to an offscreen buffer, and copy from the buffer to the screen on WM_PAINT. So, try changing from the OnPaintBackground to OnPaint.
I haven't done too much of this kind of thing in .NET, but I had a pretty good handle on it before; I just don't know if it'll translate well or not!
EDIT 2:
Marc, the more I think about what you're trying to do, the more problems appear. I was going to suggest creating a background thread dedicated to capturing the screen and rendering it darkened; however, in order to remove your own form you'd have to set the visibility to false which would create other problems....
If you're unwilling to give up, I would suggest creating two windows and "binding" them together. Create a semi-opaque window (by setting opacity) for your background window, and create a second "normal" window for the foreground. Use SetWindowRgn on the foreground window to cut away the background and position them on top of each other.
Good luck!
Is Graphics.CompositingMode set to CompositingMode.SourceCopy? That should cause painting the background twice to be equivalent to painting it once, since it will replace the existing alpha/color data instead of compositing over it.