[英]How to prevent a popup Form from exceeding screen area?
我正在使用 Forms 构建一个两列自定义上下文菜单布局。
我将自定义上下文菜单的窗体 class 命名为ContextMenu
。
我创建了一个标志 function 来检查它是否在调用时超过设备屏幕尺寸。
单个情况,如仅超出设备屏幕的长度或高度。
然而,当涉及到超过设备屏幕的长度和高度时,它不知何故不起作用。 我试图在控制台中打印值以进行检查(示例)。 打印的值是正确的,但由于某种原因,它没有进入它的switch
case。
我错过了代码中的任何地方吗?
下面是标志 function。 case 3
不起作用(示例)。
//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;
}
下面是事件处理程序,它调用上面的 function:
//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
和/或Height
。
像这样:
请注意,这些措施不包括表单的不可见边框。 与屏幕两侧的距离为 14~16 像素。 如果您喜欢更紧的,请调整它 position
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 才能接收可靠的测量和坐标。
请参阅将SetWindowPos 与多个监视器一起使用中的说明
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.