在移动和调整大小时,表单叠加层显示在表单后面
Form overlay showing behind form on move and resize
我已经设置了一个自定义控件作为加载叠加层,叠加层是一个带有图片框的表单,用于显示图像。
当叠加层显示它就位并且位于调用它的主窗体前面时,这看起来很棒。但是,当用户移动表单或调整表单大小时,表单会回到主表单。
当主窗体移动或调整大小时,覆盖窗体移动和调整大小没有问题,但在完成调整大小或移动后,窗体落后于主窗体。如何在不使用 TopMost 的情况下将覆盖表单返回顶部?
我使用
从主窗体调用以下代码
LoadingControl p = new LoadingControl(dataGridView1, this);
p.Show();
叠加形式:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class LoadingControl : Form
{
private Color BackgroundColour = Color.Black;
private double BackgroundOpacity = 0.50;
private Image LoadingImage = APPNAME.Properties.Resources.loading_120x128;
private Form Mainform;
private Control MainControl;
public LoadingControl(Control parent, Form frm)
{
MainControl = parent;
Mainform = frm;
SetupForm();
Size = parent.ClientSize;
Location = parent.PointToScreen(Point.Empty);
Mainform.Move += AdjustPosition;
MainControl.SizeChanged += AdjustPosition;
}
private void SetupForm()
{
FormBorderStyle = FormBorderStyle.None;
BackColor = BackgroundColour;
Opacity = BackgroundOpacity;//0.50;
ShowInTaskbar = false;
StartPosition = FormStartPosition.Manual;
PictureBox pbox = new PictureBox {Image = LoadingImage, Parent = this};
pbox.Width = pbox.Image.Width;
pbox.Height = pbox.Image.Height;
pbox.Left = (Width/2) - (pbox.Width/2);
pbox.Top = (Height/2) - (pbox.Height/2)-10;
pbox.Anchor = AnchorStyles.None;
Controls.Add(pbox);
}
public void SetLoadingImage(Image img)
{
LoadingImage = img;
}
public void SetBackgroundColour(Color col)
{
BackgroundColour = col;
}
public void SetOpacity(double Opa)
{
BackgroundOpacity = Opa;
}
private void AdjustPosition(object sender, EventArgs e)
{
//TopMost = true;
BringToFront();
ClientSize = MainControl.ClientSize;
Location = MainControl.PointToScreen(Point.Empty);
//Mainform.Activate();
//TopMost = false;
BringToFront();
Focus();
//MakeTopMost(this);
}
}
无论您调用 BringToFront()
多少次,它都不会将您的表单移动到活动表单之上。 BringToFront()
不会使控件成为顶级控件,也不会引发 Paint 事件。
修复它的方法太多了。 IMO 的最佳方法是让您的加载控件成为主窗体的子控件,而不是将它们分开,并且您必须在每次移动或调整大小后手动定位控件。
另一种方法是更改控件 window 的 z 顺序并在每次移动、调整大小或 maximize/minimize 事件引发后激活它。
这可以通过一些 p 调用来实现:
public void FocusForm()
{
// force window to have focus
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const uint SW_SHOW = 5;
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(this.Handle);
ShowWindow(this.Handle, SW_SHOW);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(this.Handle);
ShowWindow(this.Handle, SW_SHOW);
}
this.Activate();
}
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
我用它来将我的主要 window 设置为最上面的,所以你可能想在最后失去 Activate()
调用。
我必须说,即使这可能对你有用[我还没有完全测试它的移动和调整大小],我建议你修改你的代码并把加载将窗体作为主窗体的子控件。
编辑:
如果需要透明控件可以勾选accepted answer to this SO question。我不能 post 这里的代码,因为我不想谎称这是我的代码。
我已经设置了一个自定义控件作为加载叠加层,叠加层是一个带有图片框的表单,用于显示图像。
当叠加层显示它就位并且位于调用它的主窗体前面时,这看起来很棒。但是,当用户移动表单或调整表单大小时,表单会回到主表单。
当主窗体移动或调整大小时,覆盖窗体移动和调整大小没有问题,但在完成调整大小或移动后,窗体落后于主窗体。如何在不使用 TopMost 的情况下将覆盖表单返回顶部?
我使用
从主窗体调用以下代码LoadingControl p = new LoadingControl(dataGridView1, this);
p.Show();
叠加形式:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class LoadingControl : Form
{
private Color BackgroundColour = Color.Black;
private double BackgroundOpacity = 0.50;
private Image LoadingImage = APPNAME.Properties.Resources.loading_120x128;
private Form Mainform;
private Control MainControl;
public LoadingControl(Control parent, Form frm)
{
MainControl = parent;
Mainform = frm;
SetupForm();
Size = parent.ClientSize;
Location = parent.PointToScreen(Point.Empty);
Mainform.Move += AdjustPosition;
MainControl.SizeChanged += AdjustPosition;
}
private void SetupForm()
{
FormBorderStyle = FormBorderStyle.None;
BackColor = BackgroundColour;
Opacity = BackgroundOpacity;//0.50;
ShowInTaskbar = false;
StartPosition = FormStartPosition.Manual;
PictureBox pbox = new PictureBox {Image = LoadingImage, Parent = this};
pbox.Width = pbox.Image.Width;
pbox.Height = pbox.Image.Height;
pbox.Left = (Width/2) - (pbox.Width/2);
pbox.Top = (Height/2) - (pbox.Height/2)-10;
pbox.Anchor = AnchorStyles.None;
Controls.Add(pbox);
}
public void SetLoadingImage(Image img)
{
LoadingImage = img;
}
public void SetBackgroundColour(Color col)
{
BackgroundColour = col;
}
public void SetOpacity(double Opa)
{
BackgroundOpacity = Opa;
}
private void AdjustPosition(object sender, EventArgs e)
{
//TopMost = true;
BringToFront();
ClientSize = MainControl.ClientSize;
Location = MainControl.PointToScreen(Point.Empty);
//Mainform.Activate();
//TopMost = false;
BringToFront();
Focus();
//MakeTopMost(this);
}
}
无论您调用 BringToFront()
多少次,它都不会将您的表单移动到活动表单之上。 BringToFront()
不会使控件成为顶级控件,也不会引发 Paint 事件。
修复它的方法太多了。 IMO 的最佳方法是让您的加载控件成为主窗体的子控件,而不是将它们分开,并且您必须在每次移动或调整大小后手动定位控件。
另一种方法是更改控件 window 的 z 顺序并在每次移动、调整大小或 maximize/minimize 事件引发后激活它。
这可以通过一些 p 调用来实现:
public void FocusForm()
{
// force window to have focus
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const uint SW_SHOW = 5;
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(this.Handle);
ShowWindow(this.Handle, SW_SHOW);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(this.Handle);
ShowWindow(this.Handle, SW_SHOW);
}
this.Activate();
}
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
我用它来将我的主要 window 设置为最上面的,所以你可能想在最后失去 Activate()
调用。
我必须说,即使这可能对你有用[我还没有完全测试它的移动和调整大小],我建议你修改你的代码并把加载将窗体作为主窗体的子控件。
编辑:
如果需要透明控件可以勾选accepted answer to this SO question。我不能 post 这里的代码,因为我不想谎称这是我的代码。