如何防止弹出窗体超出屏幕区域?
How to prevent a popup Form from exceeding screen area?
我正在使用 Forms 构建一个两列的自定义上下文菜单布局。
我将自定义上下文菜单的形式 class 命名为 ContextMenu
.
我创建了一个标志函数来检查它是否在调用时超出设备屏幕尺寸。
仅超出设备屏幕的长度或高度等个别情况有效。
但是,当涉及到超过设备屏幕的长度和高度时,它不知何故不起作用。我试图在控制台中打印值以进行检查(example)。打印的值是正确的,但由于某种原因,它没有进入 switch
案例。
我是否遗漏了代码中的任何地方?
下面是标志函数。 case 3
无效(example)。
//exceed screen flag function
private Point processContextMenuFormLocation(ContextMenu theContextMenu, int screenExceedFlag, Point mouseCoor)
{
//local form coordinate
int formXCoor;
int formYCoor;
switch (screenExceedFlag)
{
case 1: //if exceed right boundary
formXCoor = (mouseCoor.X) - (contextMenuObj.Width); //move context menu to the left
formYCoor = mouseCoor.Y; //no need changes
//after exceedFlag, set where context menu position is
theContextMenu.Location = new Point(formXCoor, formYCoor);
break;
case 2: //if exceed bottom boundary
formXCoor = (mouseCoor.X); //no need changes
formYCoor = (mouseCoor.Y) - (contextMenuObj.Height); //move context menu to the top
theContextMenu.Location = new Point(formXCoor, formYCoor);
break;
case 3: //if exceed right & bottom boundary
formXCoor = (mouseCoor.X) - (contextMenuObj.Width); //move context menu to the left
formYCoor = (mouseCoor.Y) - (contextMenuObj.Height); //move context menu to the top
theContextMenu.Location = new Point(formXCoor, formYCoor);
break;
case -1: //if exceeded nothing
theContextMenu.Location = new Point(mouseCoor.X, mouseCoor.Y);
break;
}
//return the new location of context menu
return theContextMenu.Location;
}
下面是调用上面函数的事件处理器:
//mouse up event handler
private void richTextBox1_MouseUp(object sender, MouseEventArgs e)
{
//set default CM closed so that won't open concurrently
richContextStrip.Visible = false;
if (e.Button == MouseButtons.Right)
{
IsKeyUp((int)MouseButtons.Right); //set rmbIsUp = true
//here because the rmb event handler is above this
bool canDisplay = contextMenuDisplayFlag(ctrlIsDown, rmbIsUp); //get ctrl and rmb flag status
if (canDisplay)
{
//to process whether custom context menu was opened beyond screen area or not
exceedScreenFlag = isBeyondScreen(Cursor.Position.X, Cursor.Position.Y, contextMenuObj.Width, contextMenuObj.Height);
//obtain mouse coordinates
Point theMouseCoor = new Point(Cursor.Position.X, Cursor.Position.Y);
//exceed screen flag function
Point formLocation = processContextMenuFormLocation(contextMenuObj, exceedScreenFlag, theMouseCoor);
//center the cursor at context menu
Point cursorLocation = processContextMenuCursorLocation(contextMenuObj, formLocation);
displayCustomContextMenu(contextMenuObj, formLocation, cursorLocation);
toolStripStatusLabel1.Text = "Custom context menu opened!";
}
else //if ctrl key is not pressed
{
richContextStrip.Visible = true;
toolStripStatusLabel1.Text = "Default context menu opened!";
}
}
}
您可能要考虑由MouseEventArgs.Location
返回当前鼠标指针位置。您只需要使用 [Control].PointToScreen() 方法将此值转换为屏幕坐标。
然后将初始位置 - 加上 Popup 的 Width
和 Height
- 与 Screen.FromControl([Control]).WorkingArea 返回的值进行比较,并验证 Popup 是否包含在此范围内。
如果不是,则从 WorkingArea
左右边界中减去 Popup 的 Width
and/or Height
。
像这样:
请注意,这些措施不包括表单的不可见边框。与屏幕两侧的距离为 14~16 像素。如果您喜欢更紧的位置
,请调整它
private void someControl_MouseUp(object sender, MouseEventArgs e)
{
var f = new Form() { Width = 400, Height = 400, StartPosition = FormStartPosition.Manual };
f.Location = SetPopupLocation(Screen.FromControl(this), f, (sender as Control).PointToScreen(e.Location));
f.Show();
}
private Point SetPopupLocation(Screen screen, Form form, Point initPosition)
{
var p = new Point();
var wrkArea = screen.WorkingArea;
p.X = wrkArea.Right - (initPosition.X + form.Width);
p.Y = wrkArea.Bottom - (initPosition.Y + form.Height);
p.X = p.X < 0 ? wrkArea.Right - form.Width : initPosition.X;
p.Y = p.Y < 0 ? wrkArea.Bottom - form.Height : initPosition.Y;
return p;
}
您的应用需要 DpiAware 才能接收可靠的测量值和坐标。
请参阅
中的注释
我正在使用 Forms 构建一个两列的自定义上下文菜单布局。
我将自定义上下文菜单的形式 class 命名为 ContextMenu
.
我创建了一个标志函数来检查它是否在调用时超出设备屏幕尺寸。
仅超出设备屏幕的长度或高度等个别情况有效。
但是,当涉及到超过设备屏幕的长度和高度时,它不知何故不起作用。我试图在控制台中打印值以进行检查(example)。打印的值是正确的,但由于某种原因,它没有进入 switch
案例。
我是否遗漏了代码中的任何地方?
下面是标志函数。 case 3
无效(example)。
//exceed screen flag function
private Point processContextMenuFormLocation(ContextMenu theContextMenu, int screenExceedFlag, Point mouseCoor)
{
//local form coordinate
int formXCoor;
int formYCoor;
switch (screenExceedFlag)
{
case 1: //if exceed right boundary
formXCoor = (mouseCoor.X) - (contextMenuObj.Width); //move context menu to the left
formYCoor = mouseCoor.Y; //no need changes
//after exceedFlag, set where context menu position is
theContextMenu.Location = new Point(formXCoor, formYCoor);
break;
case 2: //if exceed bottom boundary
formXCoor = (mouseCoor.X); //no need changes
formYCoor = (mouseCoor.Y) - (contextMenuObj.Height); //move context menu to the top
theContextMenu.Location = new Point(formXCoor, formYCoor);
break;
case 3: //if exceed right & bottom boundary
formXCoor = (mouseCoor.X) - (contextMenuObj.Width); //move context menu to the left
formYCoor = (mouseCoor.Y) - (contextMenuObj.Height); //move context menu to the top
theContextMenu.Location = new Point(formXCoor, formYCoor);
break;
case -1: //if exceeded nothing
theContextMenu.Location = new Point(mouseCoor.X, mouseCoor.Y);
break;
}
//return the new location of context menu
return theContextMenu.Location;
}
下面是调用上面函数的事件处理器:
//mouse up event handler
private void richTextBox1_MouseUp(object sender, MouseEventArgs e)
{
//set default CM closed so that won't open concurrently
richContextStrip.Visible = false;
if (e.Button == MouseButtons.Right)
{
IsKeyUp((int)MouseButtons.Right); //set rmbIsUp = true
//here because the rmb event handler is above this
bool canDisplay = contextMenuDisplayFlag(ctrlIsDown, rmbIsUp); //get ctrl and rmb flag status
if (canDisplay)
{
//to process whether custom context menu was opened beyond screen area or not
exceedScreenFlag = isBeyondScreen(Cursor.Position.X, Cursor.Position.Y, contextMenuObj.Width, contextMenuObj.Height);
//obtain mouse coordinates
Point theMouseCoor = new Point(Cursor.Position.X, Cursor.Position.Y);
//exceed screen flag function
Point formLocation = processContextMenuFormLocation(contextMenuObj, exceedScreenFlag, theMouseCoor);
//center the cursor at context menu
Point cursorLocation = processContextMenuCursorLocation(contextMenuObj, formLocation);
displayCustomContextMenu(contextMenuObj, formLocation, cursorLocation);
toolStripStatusLabel1.Text = "Custom context menu opened!";
}
else //if ctrl key is not pressed
{
richContextStrip.Visible = true;
toolStripStatusLabel1.Text = "Default context menu opened!";
}
}
}
您可能要考虑由MouseEventArgs.Location
返回当前鼠标指针位置。您只需要使用 [Control].PointToScreen() 方法将此值转换为屏幕坐标。
然后将初始位置 - 加上 Popup 的 Width
和 Height
- 与 Screen.FromControl([Control]).WorkingArea 返回的值进行比较,并验证 Popup 是否包含在此范围内。
如果不是,则从 WorkingArea
左右边界中减去 Popup 的 Width
and/or Height
。
像这样:
请注意,这些措施不包括表单的不可见边框。与屏幕两侧的距离为 14~16 像素。如果您喜欢更紧的位置
private void someControl_MouseUp(object sender, MouseEventArgs e)
{
var f = new Form() { Width = 400, Height = 400, StartPosition = FormStartPosition.Manual };
f.Location = SetPopupLocation(Screen.FromControl(this), f, (sender as Control).PointToScreen(e.Location));
f.Show();
}
private Point SetPopupLocation(Screen screen, Form form, Point initPosition)
{
var p = new Point();
var wrkArea = screen.WorkingArea;
p.X = wrkArea.Right - (initPosition.X + form.Width);
p.Y = wrkArea.Bottom - (initPosition.Y + form.Height);
p.X = p.X < 0 ? wrkArea.Right - form.Width : initPosition.X;
p.Y = p.Y < 0 ? wrkArea.Bottom - form.Height : initPosition.Y;
return p;
}
您的应用需要 DpiAware 才能接收可靠的测量值和坐标。
请参阅