What I would like to do is to simply display a Texture2D on the screen, the screen needs to be transparent as well. I already have a section of code I found which can make the window borderless.
IntPtr hWnd = this.Window.Handle;
var control = System.Windows.Forms.Control.FromHandle(hWnd);
var form = control.FindForm();
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
When put into the Initialize() method, this successfully makes the window borderless.
however, when I use a GraphicsDevice.Clear(Color.Transparent); in my Draw all it results in is a black square in the middle of my screen.
Is there a way to change the opacity of the background at all? Is there anything else I can try to fix this?
Some things I heard of were to take a screenshot of the background and display it on the screen via backbuffer, however I can't find any solutions that successfully implement that.
EDIT: Here is the draw method, while rather simple
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Transparent);
spriteBatch.Begin();
{
spriteBatch.Draw(tex, parameters, Color.White );
}
spriteBatch.End();
base.Draw(gameTime);
}
I also found I can change the forms opacity via form.opacity = 0; but that makes the texture transparent as well.
Related
i have a class that draws waveforms of audio. I'm drawing it in OnPaint function. Now i need to draw a line that shows where on the waveform we are at current moment. I can calculate the position but when i try to draw it i need to call Invalidate() and that forces form to redraw all that waveform chart data (a lot of points).
So is there a way to put some transparent element over this one and then call Invalidate() only on that element? i was trying with picture box but no sucess...
//main form
private void timer100ms_Tick(object sender, EventArgs e)
{
customWaveViewer1.currentPosition = (int)((stream.Position / (float)stream.Length) * customWaveViewer1.Width);
customWaveViewer1.overlayLabel.Invalidate(false);
}
//drawing function in my class
private void overlayLabelInvalidate(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0));
e.Graphics.DrawLine(pen, currentPosition, 0, currentPosition, this.Height);
}
//constructor
public CustomWaveViewer()
{
InitializeComponent();
this.DoubleBuffered = true;
this.PenColor = Color.DodgerBlue;
this.PenWidth = 1;
overlayLabel = new PictureBox();
overlayLabel.Size = new System.Drawing.Size(this.Width, this.Height);
overlayLabel.Location = new Point(this.Left, this.Top);
overlayLabel.Visible = true;
overlayLabel.BackColor=Color.FromArgb(0,0,0,0);
overlayLabel.Paint += new System.Windows.Forms.PaintEventHandler(this.overlayLabelInvalidate);
Controls.Add(overlayLabel);
}
Actually what you are saying is not exactly true.
In the painteventargs there is a rectangle indicating the small portion of the window that needs to be repainted.
Also when you invalidate, you don't necessarily need to invalidate the whole form.
In your case you might want to invalidate only the old and new position of the marker that indicates where you are in the waveform.
So in your algorithm of your paint method, it is really up to you to make it efficient and only paint that part of the window that really needs repainting and to skip the part that does not need repainting.
It really can make a huge difference.
To make it even more look professional, set double buffering on.
No need to hastle with bitmaps of the whole image you have yourself, that is just what double buffering is all about, and forms can do it for you.
I copied following excerpt from https://msdn.microsoft.com/en-us/library/windows/desktop/dd145137(v=vs.85).aspx
BeginPaint fills a PAINTSTRUCT structure with information such as the dimensions of the portion of the window to be updated and a flag indicating whether the window background has been drawn. The application can use this information to optimize drawing. For example, it can use the dimensions of the update region, specified by the rcPaint member, to limit drawing to only those portions of the window that need updating. If an application has very simple output, it can ignore the update region and draw in the entire window, relying on the system to discard (clip) any unneeded output. Because the system clips drawing that extends outside the clipping region, only drawing that is in the update region is visible.
In this case there is no simple output and taking this into account is adviced.
I am not saying that creating a bitmap will not work. I am saying that optimizing your drawing logic will solve it just as well.
The information above still stands as windows forms is built on top of the old win32 api.
I’m working on a little overlay for Diablo 3 (For personal use only!)
I want just to draw a Text string (We’ll see later for font) in the middle of the screen.
But with XNA I cannot find how to put background to transparent…
My code so far is :
GraphicsDevice.Clear(new Color(0, 0, 0, 255));
spriteBatch.Begin();
spriteBatch.DrawString(font, this.TestToShow, new Vector2(23, 23), Color.White);
spriteBatch.End();
So I only need 1 thing: make this black transparent!
You do not seem to understand what GraphicsDevice.Clear(Color) does.
XNA opens a Windows Window and draws with DirectX into it.
GraphicsDevice.Clear(Color) clears the buffer drawn with DirectX, but doesn't have anything to do with the window.
To make the window transparent, you have to modify the underlaying window.
To do that you have to first add references to System.WIndows.Forms and System.Drawing.
In the Constructor of your Game1 class, you do the following:
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IntPtr hWnd = Window.Handle;
System.Windows.Forms.Control ctrl = System.Windows.Forms.Control.FromHandle(hWnd);
System.Windows.Forms.Form form = ctrl.FindForm();
form.TransparencyKey = System.Drawing.Color.Black;
}
Let's go through this line by line:
Well, the first two are auto generated and we don't care about these.
IntPtr hWnd = Window.Handle;
This line gets you the pointer to the underlaying Window that is registered in Windows.
System.Windows.Forms.Control ctrl = System.Windows.Forms.Control.FromHandle(hWnd);
This line gets the WindowsForms-Control in the given Window.
System.Windows.Forms.Form form = ctrl.FindForm();
This line gets you the Form to which the Control belongs to.
form.TransparencyKey = System.Drawing.Color.Black;
This last line sets the key-Color, that identifies one single Color-value to not be drawn at all. I used Black, but you could also choose CornflowerBlue.
This makes your window internally transparent for that Color. I suggest you should choose the same Color as your clear-Color.
Two things to note:
Best practice is to cache your Form so you can set the TransparencyKey from anywhere.
You can also make your Window borderless this way:
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
Hope I could help.
Edit:
I just realized this was asked years ago and had no answer. So feel free to use this, if you stumble upon it.
When I set the position of my game window using form.DesktopLocation(new Point(X, Y);, it works, but then XNA automatically resets it to the center of the screen. I tried googling and looking on stack overflow, but I can't seem to figure out how to prevent it centering. Any ideas?
Here's my code manipulating the GraphicsDevice, GraphicsDeviceManager, and the Form controlling the game:
// in the initialiser
window = (Form)Form.FromHandle(Window.Handle);
GraphicsDeviceManager = new GraphicsDeviceManager(this);
// in the draw method
g.PreferredBackBufferWidth = Width;
g.PreferredBackBufferHeight = Height;
g.ApplyChanges();
f.DesktopLocation = new System.Drawing.Point(X, Y);
And that's literally everything. I tried setting the desktop location more than once each frame, before and after the g.ApplyChanges(), and that doesn't change anything.
However, just now, I tried removing the g.ApplyChanges() and it doesn't do it anymore. Odd. Why would running a g.ApplyChanges() before changing the form only sometimes recenter the form AFTER I positioned the form?
There is no solution to this question.
XNA automatically resets the position of the window to the center of the screen on g.ApplyChanges, and whenever it hits another window-related operation, such as resizing, or moving the window from one monitor to another.
This is a problem in XNA, not with XNA code. XNA was written with no way to prevent this because their focus is on content, not windows. Therefore, if you want greater control over your forms, it's a better idea to not use XNA at all, or use XNA's output in a form you set up.
I am inserting advertising on a windows phone 7 app.
this is where i create the drawable add:
AdComponent.Initialize("test_client");
Microsoft.Xna.Framework.Rectangle rect = new Microsoft.Xna.Framework.Rectangle(0, 0, 480, 80);
//rect.Location= (20,20);
drawableAd = AdComponent.Current.CreateAd("Image480_80", rect, true);
drawableAd.AdRefreshed += new EventHandler(drawableAd_AdRefreshed);
drawableAd.ErrorOccurred += new EventHandler<Microsoft.Advertising.AdErrorEventArgs>(drawableAd_ErrorOccurred);
and this is where i draw it on the OnDraw method:
AdComponent.Current.Draw();
what i am trying to do is make it come to the front, because i draw other components on the OnDraw method and even though i draw the add in the end, it still goes behind all the other components
i figured it out, i was drawing it inside the spriteBatch together with the other components when in fact you have to draw it after the spriteBatch.End(); thanks for the help anyway
So i'm trying to make a nice rounded switch that when clicked it will slide either left or right to basically turn something on or off (it could be used for other things). I have a rectangle version working somewhat ok (i have a few tweaks in mind that I want to make for it) but the problem I'm running into is by using rounded rectangles. I made a few classes to help my self in this. I have one called RoundRectanglePath. Using the Create method I give it a Rectangle (or x,y,w,h) and a radius for the corners and it returns a closed GraphicsPath that I can then use Graphics.[Fill|Draw]Path with. I then have a RoundRectangle class which is a just a control that acts very similar to a Label. I found that if I override the OnPaintBackground and not send the event to the base, but instead paint a rectangle the same color as it's Parent.BackColor than I get the illusion that the control is really round. (as a related side note I allow transparent)
For my RoundMovableSwitch class I use 2 RoundRectanglePaths to split the Control in half. The left is a green Color and the right is Pink (thinking about it now I could have just used a horizontal LinearGradient brush...ooops oh well) I then draw the string On and Off on opposing sides. To that control I add a RoundRectangle. When the user clicks on either the RoundRectangle or the MoveableSwitch the Control then moves the RoundRectangle left or right 1 pixel at a time. The movement works great. The problem I am having is this. The outside Edge of the RoundRectangle is the correct Transparent color. The inside edge is the wrong color. See RoundMovingSwitch 1 and 2 in picture below. Once I get the code working correctly I'll go back and reorganize the code a bit more.
The code is hosted on GitHub: Here
"The problem I am having is this. The outside Edge of the RoundRectangle is the correct Transparent color. The inside edge is the wrong color."
Not sure I understand the problem...
Are you trying to get rid of the blue corners that are outside the rounded edges?
If so, then try this in RoundRectangle:
public RoundRectangle()
{
this.ResizeRedraw = true;
this.VisibleChanged += new EventHandler(RoundRectangle_VisibleChanged);
}
private bool RegionSet = false;
void RoundRectangle_VisibleChanged(object sender, EventArgs e)
{
if (this.Visible && !RegionSet)
{
RegionSet = true;
var r = new RectangleEx(this.ClientRectangle);
var path = RoundRectanglePath.Create(r.ToRectangle(), this.Radius, this.Corners);
this.Region = new Region(path);
}
}
*If the size of the control changes then you should reset the Region() property to the new size.
Edit: To make it reset the Region when the size changes:
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
var r = new RectangleEx(this.ClientRectangle);
var path = RoundRectanglePath.Create(r.ToRectangle(), this.Radius, this.Corners);
this.Region = new Region(path);
}