繁体   English   中英

如何防止弹出窗体超出屏幕区域?

[英]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 的WidthHeight - 与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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM