My overall goal is to render a second (or third, fourth...) mouse cursor. To this end, I have created a frameless, topmost, transparent window. I can draw on this window (I have 4 buttons on it to show that it's properly covering the whole desktop) - but when I click on the taskbar, it is brought to the top and overlays my buttons and drawn line.
How can I keep my window above the taskbar?
Alternatively, is there a way that I can draw on the "final" version of the screen?
Here's the code from my .Designer.cs file:
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.BackColor = System.Drawing.Color.White;
this.CausesValidation = false;
this.ClientSize = new System.Drawing.Size(332, 332);
this.ControlBox = false;
this.Controls.Add(this.button4);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Screen";
this.ShowIcon = false;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.WindowsDefaultBounds;
this.TopMost = true;
this.TransparencyKey = System.Drawing.Color.White;
Without analysing the exact motivation of doing this and whether this approach is the best way through, you should note that the taskbar's behaviour is equivalent to the one of any other window: TopMost can be used without any restriction. On the other hand, it is considered outside the "WorkingArea" and thus, depending upon the properties you are using, it might be ignored. Take a look at the sample codes below to understand this better.
Main Form covering all the available space above the taskbar:
this.ClientSize = new System.Drawing.Size(Screen.PrimaryScreen.WorkingArea.Width, Screen.PrimaryScreen.WorkingArea.Height);
this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Left, Screen.PrimaryScreen.WorkingArea.Top);
Main Form covering the whole available space of the screen:
this.ClientSize = new System.Drawing.Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Left, Screen.PrimaryScreen.WorkingArea.Top);
Thus, you can locate your form on top of the taskbar without any problem by bearing the mind that it represents the difference between WorkingArea and Bounds of the screen.
CLARIFICATION: this answer highlights what might be the reason for the taskbar to be treated differently than any other part of the screen. It does not imply that you have to make your form as big as the whole screen to put it over the taskbar; you can put it over the taskbar whenever you want with an as small size as you wish. What you have to bear in mind is that WorkingArea does not provide the whole dimensions of the screen, but just the area ABOVE the taskbar; if you want to bring the taskbar into consideration, consider Bounds.
I'll go with varocarbas answer,but there is something that i want to add which i think might be useful.
A few things are there that i guess may be helpful,when i read your question the first idea that struck my mind was to create a GlobalHook to monitor message WM_CBT,this message is send to GlobalHook procedure when the system is about to Maximize,Minimize,Restore or Focus a Window.When any hook is trapped you can override any required events to block that window from becoming the topmost window,thus giving your Form a chance to remain the topmost Window.This method will be highly helpful if it worked as i am expecting.
If you are interested in this, here are the methods that are required to make a GlobalHook work.
SetWindowsHookEx(),used to tell the system to create a GlobalHook.
HookProc,Represents the method called when a hook catches a monitored event.
HookType,Enumerates the valid hook types passed into a call to SetWindowsHookEx.
CallNextHook.If using interoperability is messy,try this open source library that contains WindowsAPI functions in a managed wrapper.Hope this helps you,meanwhile i'm also trying to get the stuff working for you.
I've been struggling for a few hours with this same problem. I thought of a nice solution: just change the bottom padding of the form dynamically whenever the form is maximized.
If Me.WindowState = FormWindowState.Maximized then
Dim pd As New Padding
pd.Left = Me.Padding.Left
pd.Right = Me.Padding.Right
pd.Top = Me.Padding.Top
pd.Bottom = Me.Height - Screen.PrimaryScreen.WorkingArea.Height
Me.Padding = pd
end if
This way the form is not above the taskbar, but at least your controls are!
Note: in designing your forms you can leave the bottom-padding 0.
If you want your form to be able to minimize/normal resize, then you may want to reset the bottom padding to 0 in another form event.
I actually found the solution about 15 minutes after I posted. (Isn't that always the way? Research for hours, but as soon as you ask for help, you figure it out on your own. :)
I have an event that is calling my code with position updates. If I simply call "BringToFront" in this event, it works just fine. The event is called many times per second, but if I throttle my behavior back to 1/4 second, it still works great.
Related
I am trying to make an openGL window a child to my windows forms application.
This is the creation of the windows forms which happens by default in the Form1.Designer.cs
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.ActiveCaptionText;
this.ClientSize = new System.Drawing.Size(1333, 594);
this.Controls.Add(this.Sim);
this.Controls.Add(this.Camera);
this.Controls.Add(this.comboBox1);
this.Controls.Add(this.pictureBox1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)
(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
Glut.glutcreateSubWindow(int win, int x, int y, int width, int height);
The glutcreateSubWindow takes the parent value as an int and I am having a hard time trying to convert this.Name = "Form1"; to an int that I can use to refer the name of the form as the parent.
I can be out on the blue here and doing this the wrong way by trying to convert the string name to the specified parent slot.
Is there another way to specify the form as the parent in this context?
Definitely you should not try to convert "Form 1" to an int, the integer the framework expects there is a GLUT window identifier, you should havfe retrieved and stored one when you create a GLUT top level window, and then you can creat a subwindow of it.
see this article and scroll down to see clear explanation of all the code, it shows you all steps you need to implement: https://www.codeproject.com/Articles/20107/GLUT-Subwindow-Template
I have no experience with glut, but I may know a different approach that might do the trick.
To make a Windows.Forms.Form a parent you will need a Child that is also a System.Windows.Forms.Form (or implement a subclass).
In the past I needed at DirectX overlay in a windows form. And because this is a different API I couldn't add this to a Windows.Forms.Form.
I solved this by implementing a System.Windows.Forms.UserControl (you could implement a System.Windows.Forms.Form or add your custom control to it)
When the control was initialized I Created the Overlay on top of it (you know the corners of your control or window)
So basically I had an empty windows control with a DirectX window on top of it, that followed the control and resized with it (int the resize and move events of the control I changed, or reconstructed my overlay to move with it.)
You could do the same, make a windows.from that has a border less (no title bar) glut window on top that reacts to the Windows.Forms Events.
This is only possible if you can make a border less Window in Glut, or draw in a kind of rectangular overlay on screen. I don't know if this is possible with Glut.
If this answer isn't helpful in your situation, please tell me and I will delete this answer. I'm just trying to offer a workaround because I've had a similar problem in the past.
I'm trying to move the form instead of resizing it while I'm resizing if the right button is down.
Resize event:
if (rightMouseDown)
{
this.SetDesktopLocation(MousePosition.X - this.Width, MousePosition.Y - this.Height);
this.MaximumSize = new System.Drawing.Size(this.Width, this.Height);
this.MinimumSize = new System.Drawing.Size(this.Width, this.Height);
}
Global mouse event:
bool rightMouseDown;
private void HoldMouse(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right && e.Clicks != 1)
{
rightMouseDown = true;
}
else if (e.Button == MouseButtons.Right)
{
rightMouseDown = false;
this.MaximumSize = new System.Drawing.Size(0, 0);
this.MinimumSize = new System.Drawing.Size(100, 100);
}
}
At the moment when I click the right button it freezes because the MaximumSize is constant, therefore I can't resize the form.
e.cancel would be awesome if it would work but I can't use that.
I'm able to capture the mouse events with a global one, the form events doesn't work weirdly.
I Got it working but only when the window's width is minimum and it goes to it's original width after the right mouse button goes up.
This is due to setting it to the default size. How can I keep the window in the changed size without setting it to MaximumSize 0,0?
First of all, I would suggest that you do not move the form while the right button is down, because this is highly non-standard and therefore likely to be perceived as highly peculiar by anyone trying to use your app. To be more specific, nobody is ever going to try either moving or resizing your form with the right mouse button, so:
if that's the only way you offer for moving your form, then nobody will ever be able to move your form.
if you also offer other ways of moving your form, then why bother with offering this way too?
Secondly, I would like to propose that this is most probably an X-Y problem meaning that you probably have some other issue, which you have told us nothing about, you think that you might address it by moving-by-right-click, then you discover that moving-by-right-click does not work for you, and you come here asking how to get moving-by-right-click to work. Why don't you begin by describing the real issue?
Thirdly, if you really want to proceed with moving your form by right-click, that's not how to do it.
First, you need to detect when the right mouse button is pressed. There are events for this. They work. If they don't work for you, that's not a reason to be doing other weird things instead. The statement "I'm not able to capture the mouse click with the Mouse events" is utterly bizarre, because a) it is a wrong use of the term "capture"; mouse capture is a very specific thing, (more about it later,) so please refrain from using it in other contexts, and b) if you cannot accomplish something, then that should be the subject of a stackoverflow question on its own. You cannot be trying utterly bizarre things because your attempts to do the right things failed.
So, once you have gotten detection of the right mouse click to work, then you need to set up mouse capture. (Look it up, search for "SetCapture".) That's what guarantees that you can keep receiving mouse move events, and finally a mouse-up event, even though the mouse has moved outside of your form while you were dragging it.
I would like to create an application that have a small window displayed at the bottom corner of desktop. On startup, the window shall be very small and ideally, just a couple of pixels in width.
Here is the code I used to do it:
public partial class DurationT64 : Form
{
private Size fullSize;
private Point fullPos;
private Point compactPos;
public DurationT64()
{
InitializeComponent();
var workingArea = Screen.PrimaryScreen.WorkingArea;
this.MinimumSize = new Size(0, this.Height);
this.MaximumSize = new Size(this.Width, this.Height);
// fullPos: the window location when it is in full size form.
fullPos = new Point(workingArea.Right - this.Width, workingArea.Bottom - this.Height);
this.Location = fullPos;
// fullSize: the size of the windown when it is in full size form.
fullSize = new Size(this.Width, this.Height);
this.Size = fullSize;
// compactPos: the window location when it is in compact size form.
compactPos = new Point(workingArea.Right - 30, fullPos.Y);
this.Width = 1;
this.Location = compactPos;
}
}
As you can see that in this example, I intended to create a window of just 1 pixel in width, placed closed to the right edge of the primary monitor.
However, I realized that the window doesn't go as small as I was expected. It goes down to 20 pixels wide but no less than that. Please refer to this screen capture image below for example:
an image shows that the window is wider than it suppose to be
I did some research regards to this problem and noticed that there was a solution proposed by Zach Johnson (#zach-johnson) back in 2009. Here is the link to it Overcome OS Imposed Windows Form Minimum Size Limit.
However, nether methods proposed in that link (the intercepting WM_ message one proposed by Zach and the SetBoundsCore one proposed by #Ace) works for me.
Can anyone please give me some solution to this question? Preferably, a solution purely based on C#/Winform and does not rely on native Win32 window message loop, if possible.
Many thanks!
It is rather straight-forward, Winforms ensures that the window cannot be made smaller than the system-imposed minimum size of a window, exposed as the SystemInformation.MinWindowTrackSize property in .NET. This is a "safety" setting, it ensures that the user cannot make the window too small when he resizes it, thus losing control over it. Same consideration applies to code.
Bypassing this limit requires no magic, you need to do two things:
Set the FormBorderStyle property to None so the user cannot resize the window.
Set the size after the window is created. The Load event is best.
Some comments about your existing code: be careful about tinkering with the Width/Height/Size properties, you are doing too much of it in your constructor and it cannot work correctly. In the constructor they don't yet match the actual size of the window. And will not be close at all on modern machines with high-resolution monitors, auto-scaling to match the DPI of the video adapter is important today. You have to postpone until the window is created and scaling is complete, the Load event is the proper place for code like this. One of the few reasons to actually use Load.
And note that your Location property calculation is inadequate, it does not consider the location of the taskbar. It doesn't work on my machine, I like the taskbar on the right.
Minimum repro:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
}
protected override void OnLoad(EventArgs e) {
this.Width = 1;
base.OnLoad(e);
}
}
Do keep in mind that you'll need hawk-eyes to find it back on the screen :)
I've got an app which will run on two different devices - one with a screen size of 240x320, the other 480x640.
For all forms bar one the VS generated code is fine:
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.AutoScroll = true;
For one form i'm capturing a signature. I'm doing this by a panel with a graphics handler; capturing mouse down and move events; this generates a list of vector points which I can draw lines with.
On the smaller res screen this is fine. On the higher res, I can't display my lines.. and I think this is because the panel is beyond the windows form size.
The form is created with a size of 240 x 268; a standard size I think - i've not manually set it, VS does this for me.
In order to get the panel in the right spot on the high res device, the co-ordinates are 3, 290; ie, 290 is past 268. Also the width of the panel is 448 which is somewhat larger than 240.
I'm using .net 2.0 (can't use later). I think I need to resize the form to make it larger but I do want to keep the existing re-sizing for the other controls on the form.
I'm not sure how to do this.
Make the form dock to fill, then use the Anchor properties to ensure controls inside the form resize as expected.
If you want the option of customizing how an individual control resizes, then DONT set the anchor properties on it, and instead handle the Resize event and perform custom resizing/repositioning within code there.
eg
private void form_Resize(object sender, EventArgs e)
{
// Center the control without changing width. Other controls are anchored.
this.control.Left = (this.Width - this.control.Width) / 2;
}
I'm writing this answer for the benefit of those who may have a similar problem in the future. PaulG pointed me in the right direction but I found the root cause to be something else.
The PDA project i've got uses "FormFactor WindowsMobile 6 Classic" which has a default size of 240 x 268.
Changing this to "Windows Mobile 6 Professional VGA" created a much larger form size.
This allowed me to get things positioned correctly for the larger size; then AutoScaleMode to DPI; and manually resizing the panel smaller made it all work.
IE, going from larger to smaller was easy; I didn't get smaller to larger working.
Every time I open my form, it defaults to 328x192. I'll change it to 328x170, save my project, close my project, then reopen it.
All of a sudden, my form is back to 328x192 instead of the size I saved it as (328x170).
I went into my Form.Designer.cs and tried adding this line of code:
this.Size = new System.Drawing.Size(328, 170);
And still, when I reopen the project, the form is at 328x192. I don't know where this value is coming from and it's driving me crazy. The weird part about this problem is that it seems to occur randomly, where I will get that extra margin on the bottom of my form. I'm worried this will slip into production because even when I save it to the correct dimensions, when I reopen it, it's back to the wrong dimensions.
Needless to say, GUI errors make my work look 1000% worse no matter how things are under the hood.
Do not edit the designer-generated code. The designer doesn't save the Size property, it isn't a good measure for the size of the form. The height of the caption bar of the form is determined by user preference. It saves the ClientSize property instead. That's an important one since it determines how much room is available to controls.
It isn't otherwise obvious what made the size revert. Could be something as simple as forgetting to check-in the changes which then lead you on the wild Size goose chase.
Have you tried setting the size on the form from codebehind?
EDIT - as in:
public Form1()
{
InitializeComponent();
this.Size = new System.Drawing.Size(328, 170);
}
I suspect you might be somehow changing the form size from an active designer window.
If you set the code manually after the initialization of the form the designer won't be able to affect that.
Unless someone is messing with you :)
The difference (of 22) could be the header. I've checked one of my WinForms projects and it has this line in the .designer.cs file:
this.ClientSize = new System.Drawing.Size(292, 273);
while the size being set at 300 x 300 in the properties dialog. The difference being the border and the header dimensions.
Have you got a line that sets this and if so try altering those values instead.
Is it possible that you have the MinimumSize set? Or maybe the AutoSize property is set to true. Either of these properties could cause your window to ignore the Size property in certain scenerios.
Otherwise, I think this.ClientSize is the property you need to look at in the Designer file. These values are the size of the client area (minus the window border).