繁体   English   中英

如何获取任务栏的位置和大小?

[英]How do I get the taskbar's position and size?

我想知道如何获取任务栏占据的矩形(底部、顶部、左侧和右侧)。 我该如何在 C# 中执行此操作?

    private enum TaskBarLocation { TOP, BOTTOM, LEFT, RIGHT}

    private TaskBarLocation GetTaskBarLocation()
    {
        TaskBarLocation taskBarLocation = TaskBarLocation.BOTTOM;
        bool taskBarOnTopOrBottom = (Screen.PrimaryScreen.WorkingArea.Width == Screen.PrimaryScreen.Bounds.Width);
        if (taskBarOnTopOrBottom)
        {
            if (Screen.PrimaryScreen.WorkingArea.Top > 0) taskBarLocation = TaskBarLocation.TOP;
        }
        else
        {
            if (Screen.PrimaryScreen.WorkingArea.Left > 0)
            {
                taskBarLocation = TaskBarLocation.LEFT;
            }
            else
            {
                taskBarLocation = TaskBarLocation.RIGHT;
            }
        }
        return taskBarLocation;
    }

它实际上比上面显示的要复杂得多。 一方面,任务栏不必在主屏幕上,它可以拖到任何屏幕上。 另一方面,理论上每个给定屏幕的每个边缘都可以停靠一些东西。 上面的代码错误地假设找到停靠在一条边上的东西排除了所有其他边。

任务栏的位置可以明确地从边界与工作区域得出的唯一方法是,如果所有屏幕中只有一个边缘有东西停靠在它上面。

下面的函数返回一个矩形数组,每个矩形代表一个停靠的任务栏,并将计数写入其 byref 参数。 如果该计数为 1,则返回数组的元素 0 为任务栏占用的 Rectangle。 如果大于 1,是时候猜测了?

Public Function FindDockedTaskBars(ByRef DockedRectCounter As Integer) As Rectangle()
    Dim TmpScrn As Screen = Nothing
    Dim LeftDockedWidth As Integer = 0
    Dim TopDockedHeight As Integer = 0
    Dim RightDockedWidth As Integer = 0
    Dim BottomDockedHeight As Integer = 0
    Dim DockedRects(Screen.AllScreens.Count * 4) As Rectangle

    DockedRectCounter = 0

    For Each TmpScrn In Screen.AllScreens
        If Not TmpScrn.Bounds.Equals(TmpScrn.WorkingArea) Then
            LeftDockedWidth = Math.Abs(Math.Abs(TmpScrn.Bounds.Left) - Math.Abs(TmpScrn.WorkingArea.Left))
            TopDockedHeight = Math.Abs(Math.Abs(TmpScrn.Bounds.Top) - Math.Abs(TmpScrn.WorkingArea.Top))
            RightDockedWidth = (TmpScrn.Bounds.Width - LeftDockedWidth) - TmpScrn.WorkingArea.Width
            BottomDockedHeight = (TmpScrn.Bounds.Height - TopDockedHeight) - TmpScrn.WorkingArea.Height

            If LeftDockedWidth > 0 Then
                DockedRects(DockedRectCounter).X = TmpScrn.Bounds.Left
                DockedRects(DockedRectCounter).Y = TmpScrn.Bounds.Top
                DockedRects(DockedRectCounter).Width = LeftDockedWidth
                DockedRects(DockedRectCounter).Height = TmpScrn.Bounds.Height
                DockedRectCounter += 1
            End If
            If RightDockedWidth > 0 Then
                DockedRects(DockedRectCounter).X = TmpScrn.WorkingArea.Right
                DockedRects(DockedRectCounter).Y = TmpScrn.Bounds.Top
                DockedRects(DockedRectCounter).Width = RightDockedWidth
                DockedRects(DockedRectCounter).Height = TmpScrn.Bounds.Height
                DockedRectCounter += 1
            End If
            If TopDockedHeight > 0 Then
                DockedRects(DockedRectCounter).X = TmpScrn.WorkingArea.Left
                DockedRects(DockedRectCounter).Y = TmpScrn.Bounds.Top
                DockedRects(DockedRectCounter).Width = TmpScrn.WorkingArea.Width
                DockedRects(DockedRectCounter).Height = TopDockedHeight
                DockedRectCounter += 1
            End If
            If BottomDockedHeight > 0 Then
                DockedRects(DockedRectCounter).X = TmpScrn.WorkingArea.Left
                DockedRects(DockedRectCounter).Y = TmpScrn.WorkingArea.Bottom
                DockedRects(DockedRectCounter).Width = TmpScrn.WorkingArea.Width
                DockedRects(DockedRectCounter).Height = BottomDockedHeight
                DockedRectCounter += 1
            End If
        End If
    Next
    Return DockedRects
End Function

或者对于那些喜欢 C# 的人...(注意:此移植代码未经测试)

using System.Drawing;
using System.Windows.Forms;

public Rectangle[] FindDockedTaskBars(ref int DockedRectCounter)
{
    int LeftDockedWidth = 0;
    int TopDockedHeight = 0;
    int RightDockedWidth = 0;
    int BottomDockedHeight = 0;
    Rectangle[] DockedRects = new Rectangle[Screen.AllScreens.Count() * 4]; 

    DockedRectCounter = 0;
    foreach (Screen TmpScrn in Screen.AllScreens)
    {
        if (!TmpScrn.Bounds.Equals(TmpScrn.WorkingArea))
        {
            LeftDockedWidth = Math.Abs(Math.Abs(TmpScrn.Bounds.Left) - Math.Abs(TmpScrn.WorkingArea.Left));
            TopDockedHeight = Math.Abs(Math.Abs(TmpScrn.Bounds.Top) - Math.Abs(TmpScrn.WorkingArea.Top));
            RightDockedWidth = (TmpScrn.Bounds.Width - LeftDockedWidth) - TmpScrn.WorkingArea.Width;
            BottomDockedHeight = (TmpScrn.Bounds.Height - TopDockedHeight) - TmpScrn.WorkingArea.Height;

            if (LeftDockedWidth > 0)
            {
                DockedRects[DockedRectCounter].X = TmpScrn.Bounds.Left;
                DockedRects[DockedRectCounter].Y = TmpScrn.Bounds.Top;
                DockedRects[DockedRectCounter].Width = LeftDockedWidth;
                DockedRects[DockedRectCounter].Height = TmpScrn.Bounds.Height;
                DockedRectCounter += 1;
            }

            if (RightDockedWidth > 0)
            {
                DockedRects[DockedRectCounter].X = TmpScrn.WorkingArea.Right;
                DockedRects[DockedRectCounter].Y = TmpScrn.Bounds.Top;
                DockedRects[DockedRectCounter].Width = RightDockedWidth;
                DockedRects[DockedRectCounter].Height = TmpScrn.Bounds.Height;
                DockedRectCounter += 1;
            }
            if (TopDockedHeight > 0)
            {
                DockedRects[DockedRectCounter].X = TmpScrn.WorkingArea.Left;
                DockedRects[DockedRectCounter].Y = TmpScrn.Bounds.Top;
                DockedRects[DockedRectCounter].Width = TmpScrn.WorkingArea.Width;
                DockedRects[DockedRectCounter].Height = TopDockedHeight;
                DockedRectCounter += 1;
            }
            if (BottomDockedHeight > 0)
            {
                DockedRects[DockedRectCounter].X = TmpScrn.WorkingArea.Left;
                DockedRects[DockedRectCounter].Y = TmpScrn.WorkingArea.Bottom;
                DockedRects[DockedRectCounter].Width = TmpScrn.WorkingArea.Width;
                DockedRects[DockedRectCounter].Height = BottomDockedHeight;
                DockedRectCounter += 1;
            }
        }
    }
    return DockedRects;
}

根据David 的回答,这里有一个更好的实现,它使用 P/Invoke 来正确确定任务栏的位置和大小。 到目前为止,我所知道的唯一限制是,当多个监视器设置为以扩展模式显示时,它不会返回正确的边界。

包含所有后续更新的代码可在https://git.io/v9bCx作为要点获得。

/******************************************************************************
 * Name:        Taskbar.cs
 * Description: Class to get the taskbar's position, size and other properties.
 * Author:      Franz Alex Gaisie-Essilfie
 *              based on code from https://winsharp93.wordpress.com/2009/06/29/find-out-size-and-position-of-the-taskbar/
 *
 * Change Log:
 *  Date        | Description
 * -------------|--------------------------------------------------------------
 *  2017-05-16  | Initial design
 */

using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace System.Windows.Forms
{
    public enum TaskbarPosition
    {
        Unknown = -1,
        Left,
        Top,
        Right,
        Bottom,
    }

    public static class Taskbar
    {
        private enum ABS
        {
            AutoHide = 0x01,
            AlwaysOnTop = 0x02,
        }

        ////private enum ABE : uint
        private enum AppBarEdge : uint
        {
            Left = 0,
            Top = 1,
            Right = 2,
            Bottom = 3
        }

        ////private enum ABM : uint
        private enum AppBarMessage : uint
        {
            New = 0x00000000,
            Remove = 0x00000001,
            QueryPos = 0x00000002,
            SetPos = 0x00000003,
            GetState = 0x00000004,
            GetTaskbarPos = 0x00000005,
            Activate = 0x00000006,
            GetAutoHideBar = 0x00000007,
            SetAutoHideBar = 0x00000008,
            WindowPosChanged = 0x00000009,
            SetState = 0x0000000A,
        }

        private const string ClassName = "Shell_TrayWnd";
        private static APPBARDATA _appBarData;

        /// <summary>Static initializer of the <see cref="Taskbar" /> class.</summary>
        static Taskbar()
        {
            _appBarData = new APPBARDATA
            {
                cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA)),
                hWnd = FindWindow(Taskbar.ClassName, null)
            };
        }

        /// <summary>
        ///   Gets a value indicating whether the taskbar is always on top of other windows.
        /// </summary>
        /// <value><c>true</c> if the taskbar is always on top of other windows; otherwise, <c>false</c>.</value>
        /// <remarks>This property always returns <c>false</c> on Windows 7 and newer.</remarks>
        public static bool AlwaysOnTop
        {
            get
            {
                int state = SHAppBarMessage(AppBarMessage.GetState, ref _appBarData).ToInt32();
                return ((ABS)state).HasFlag(ABS.AlwaysOnTop);
            }
        }

        /// <summary>
        ///   Gets a value indicating whether the taskbar is automatically hidden when inactive.
        /// </summary>
        /// <value><c>true</c> if the taskbar is set to auto-hide is enabled; otherwise, <c>false</c>.</value>
        public static bool AutoHide
        {
            get
            {
                int state = SHAppBarMessage(AppBarMessage.GetState, ref _appBarData).ToInt32();
                return ((ABS)state).HasFlag(ABS.AutoHide);
            }
        }

        /// <summary>Gets the current display bounds of the taskbar.</summary>
        public static Rectangle CurrentBounds
        {
            get
            {
                var rect = new RECT();
                if (GetWindowRect(Handle, ref rect))
                    return Rectangle.FromLTRB(rect.Left, rect.Top, rect.Right, rect.Bottom);

                return Rectangle.Empty;
            }
        }

        /// <summary>Gets the display bounds when the taskbar is fully visible.</summary>
        public static Rectangle DisplayBounds
        {
            get
            {
                if (RefreshBoundsAndPosition())
                    return Rectangle.FromLTRB(_appBarData.rect.Left,
                                              _appBarData.rect.Top,
                                              _appBarData.rect.Right,
                                              _appBarData.rect.Bottom);

                return CurrentBounds;
            }
        }

        /// <summary>Gets the taskbar's window handle.</summary>
        public static IntPtr Handle
        {
            get { return _appBarData.hWnd; }
        }

        /// <summary>Gets the taskbar's position on the screen.</summary>
        public static TaskbarPosition Position
        {
            get
            {
                if (RefreshBoundsAndPosition())
                    return (TaskbarPosition)_appBarData.uEdge;

                return TaskbarPosition.Unknown;
            }
        }

        /// <summary>Hides the taskbar.</summary>
        public static void Hide()
        {
            const int SW_HIDE = 0;
            ShowWindow(Handle, SW_HIDE);
        }

        /// <summary>Shows the taskbar.</summary>
        public static void Show()
        {
            const int SW_SHOW = 1;
            ShowWindow(Handle, SW_SHOW);
        }

        private static bool RefreshBoundsAndPosition()
        {
            //! SHAppBarMessage returns IntPtr.Zero **if it fails**
            return SHAppBarMessage(AppBarMessage.GetTaskbarPos, ref _appBarData) != IntPtr.Zero;
        }

        #region DllImports

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);

        [DllImport("shell32.dll", SetLastError = true)]
        private static extern IntPtr SHAppBarMessage(AppBarMessage dwMessage, [In] ref APPBARDATA pData);

        [DllImport("user32.dll")]
        private static extern int ShowWindow(IntPtr hwnd, int command);

        #endregion DllImports

        [StructLayout(LayoutKind.Sequential)]
        private struct APPBARDATA
        {
            public uint cbSize;
            public IntPtr hWnd;
            public uint uCallbackMessage;
            public AppBarEdge uEdge;
            public RECT rect;
            public int lParam;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
    }
}
private enum TaskBarLocation { TOP, BOTTOM, LEFT, RIGHT } 

private TaskBarLocation GetTaskBarLocation()
{
  //System.Windows.SystemParameters....
  if (SystemParameters.WorkArea.Left > 0) 
    return TaskBarLocation.LEFT;
  if (SystemParameters.WorkArea.Top > 0)
    return TaskBarLocation.TOP;
  if (SystemParameters.WorkArea.Left == 0 
    && SystemParameters.WorkArea.Width < SystemParameters.PrimaryScreenWidth) 
      return TaskBarLocation.RIGHT;
  return TaskBarLocation.BOTTOM;
}

这是 C# 中Mark McGinty的答案。

此代码将所有任务栏作为矩形列表返回:

  • 0 矩形表示任务栏被隐藏;
  • 1个矩形是任务栏的位置;
  • 2+ 非常罕见,这意味着我们有多个显示器,并且我们没有使用Extend these displays来创建单个虚拟桌面。

适用于各种情况

它适用于:

  • Windows 7(几乎可以肯定适用于 Windows 8.1 和 Windows 10)。
  • 所有设置组合。

在此处输入图像描述

C# 代码

public static List<Rectangle> FindDockedTaskBars()
{
    List<Rectangle> dockedRects = new List<Rectangle>();
    foreach (var tmpScrn in Screen.AllScreens)
    {
        if (!tmpScrn.Bounds.Equals(tmpScrn.WorkingArea))
        {
            Rectangle rect = new Rectangle();

            var leftDockedWidth = Math.Abs((Math.Abs(tmpScrn.Bounds.Left) - Math.Abs(tmpScrn.WorkingArea.Left)));
            var topDockedHeight = Math.Abs((Math.Abs(tmpScrn.Bounds.Top) - Math.Abs(tmpScrn.WorkingArea.Top)));
            var rightDockedWidth = ((tmpScrn.Bounds.Width - leftDockedWidth) - tmpScrn.WorkingArea.Width);
            var bottomDockedHeight = ((tmpScrn.Bounds.Height - topDockedHeight) - tmpScrn.WorkingArea.Height);
            if ((leftDockedWidth > 0))
            {
                rect.X = tmpScrn.Bounds.Left;
                rect.Y = tmpScrn.Bounds.Top;
                rect.Width = leftDockedWidth;
                rect.Height = tmpScrn.Bounds.Height;
            }
            else if ((rightDockedWidth > 0))
            {
                rect.X = tmpScrn.WorkingArea.Right;
                rect.Y = tmpScrn.Bounds.Top;
                rect.Width = rightDockedWidth;
                rect.Height = tmpScrn.Bounds.Height;
            }
            else if ((topDockedHeight > 0))
            {
                rect.X = tmpScrn.WorkingArea.Left;
                rect.Y = tmpScrn.Bounds.Top;
                rect.Width = tmpScrn.WorkingArea.Width;
                rect.Height = topDockedHeight;
            }
            else if ((bottomDockedHeight > 0))
            {
                rect.X = tmpScrn.WorkingArea.Left;
                rect.Y = tmpScrn.WorkingArea.Bottom;
                rect.Width = tmpScrn.WorkingArea.Width;
                rect.Height = bottomDockedHeight;
            }
            else
            {
                // Nothing found!
            }

            dockedRects.Add(rect);
        }
    }

    if (dockedRects.Count == 0)
    {
        // Taskbar is set to "Auto-Hide".
    }

    return dockedRects;
}   

这是一个使用带有 wpf 和多屏支持的 winforms 的简单示例:

Screen sc = Screen.FromHandle(new WindowInteropHelper(this).Handle);
            if (sc.WorkingArea.Top > 0)
            {
                // TASKBAR TOP
            }
            else if (sc.WorkingArea.Left != sc.Bounds.X)
            {
                // TASKBAR LEFT
            }
            else if ((sc.Bounds.Height - sc.WorkingArea.Height) > 0)
            {
                // TASKBAR BOTTOM
            }
            else if (sc.WorkingArea.Right != 0)
            {
                // TASKBAR RIGHT
            }
            else
            {
                // TASKBAR NOT FOUND
            }
[StructLayout(LayoutKind.Sequential)]
public struct RECT { public Int32 left; public Int32 top; public Int32 right; public Int32 bottom; }
[StructLayout(LayoutKind.Sequential)]
public struct APPBARDATA { public UInt32 cbSize; public IntPtr hWnd; public UInt32 uCallbackMessage; public UInt32 uEdge; public RECT rc; public IntPtr lParam; }
[DllImport("shell32.dll")]
public static extern IntPtr SHAppBarMessage(UInt32 dwMessage, ref APPBARDATA pData);

private void Form1_Load(object sender, EventArgs e)
{
    APPBARDATA msgData = new APPBARDATA();
    msgData.cbSize = (UInt32)Marshal.SizeOf(msgData);
    // get taskbar position
    SHAppBarMessage((UInt32)0x00000005, ref msgData);
    RECT taskRect = msgData.rc;
    Console.WriteLine("top:" + taskRect.top + "; left:" + taskRect.left + "; bottom:" + taskRect.bottom + "; right:" + taskRect.right);
    Console.WriteLine("width:" + (taskRect.right - taskRect.left) + "; height:" + (taskRect.bottom - taskRect.top));
}

输出:顶部:1040; 左:0; 底部:1080; 右:1920 宽度:1920; 高度:40

这是获取任务栏高度的方法(使用 WPF)

int PSBH = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height
int TaskBarHeight = PSBH - System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;

如果要考虑dpi

int PSH = SystemParameters.PrimaryScreenHeight;
int PSBH = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
double ratio = PSH / PSBH;
int TaskBarHeight = PSBH - System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
TaskBarHeight *= ratio;

我不想这么说,但是在使用无 WindowStyle 时设置窗口大小的最佳和最一致的方法之一是创建一个临时窗口,该窗口被创建、最大化、记录宽度和高度,然后被销毁。

    private (double height, double width) GetVirtualWindowSize()
    {
        Window virtualWindow = new Window();
        virtualWindow.Show();
        virtualWindow.WindowState = WindowState.Maximized;
        double returnHeight = virtualWindow.Height;
        double returnWidth = virtualWindow.Width;
        virtualWindow.Close(); 

        return (returnHeight, returnWidth);
    }

然后,您可以使用元组中返回的值设置窗口的 MaxHeight 和 MaxWidth 属性。 这个“牺牲”窗口将使用标准窗口框架,因此 Windows 知道如何正确最大化它,从而每次都返回准确的值。

您可以在启动时执行此操作,这样您只需处理一次窗口创建,或者您可以在每次最大化时重新检查尺寸。

我知道它不漂亮,并且有一个短暂的闪光。 但它总是对我有用,无论任务栏在哪里,无论缩放,以及自应用程序启动以来发生的变化。

这将适用于 Windows 和 macOS。 它也适用于多台显示器。 照原样,它适用于电子应用程序,但您可以轻松了解发生了什么。

type TaskBarPos int

const (
    UNKNOWN TaskBarPos = -1
    LEFT    TaskBarPos = 0
    RIGHT   TaskBarPos = 1
    TOP     TaskBarPos = 2
    BOTTOM  TaskBarPos = 3
)

type Rect struct {
    top    int
    bottom int
    width  int
    height int
    left   int
    right  int
}

func (r Rect) centerX() int {
    return r.left + ((r.right - r.left) / 2)
}

func (r Rect) centerY() int {
    return r.top + ((r.bottom - r.top) / 2)
}

func taskbar(tray *js.Object) TaskBarPos {

    // Step 1 - Get relevant display
    display := screen.Call("getDisplayNearestPoint", screen.Call("getCursorScreenPoint")) // Replace with primary monitor or a secondary monitor. This line as is grabs the monitor that the mouse cursor is on.

    // Step 2 - Determine taskbar bounds relative to the display
    bounds := display.Get("bounds")
    workArea := display.Get("workArea")
    var tb *Rect

    d := Rect{
        top:    bounds.Get("y").Int(),
        bottom: bounds.Get("y").Int() + bounds.Get("height").Int(),
        width:  bounds.Get("width").Int(),
        height: bounds.Get("height").Int(),
        left:   bounds.Get("x").Int(),
        right:  bounds.Get("x").Int() + bounds.Get("width").Int(),
    }

    wa := Rect{
        top:    workArea.Get("y").Int(),
        bottom: workArea.Get("y").Int() + workArea.Get("height").Int(),
        width:  workArea.Get("width").Int(),
        height: workArea.Get("height").Int(),
        left:   workArea.Get("x").Int(),
        right:  workArea.Get("x").Int() + workArea.Get("width").Int(),
    }

    if tray != nil {
        tBounds := tray.Call("getBounds")
        tb = &Rect{
            top:    tBounds.Get("y").Int(),
            bottom: tBounds.Get("y").Int() + tBounds.Get("height").Int(),
            width:  tBounds.Get("width").Int(),
            height: tBounds.Get("height").Int(),
            left:   tBounds.Get("x").Int(),
            right:  tBounds.Get("x").Int() + tBounds.Get("width").Int(),
        }
    }

    // Step 3 - Determine Position of Taskbar
    if wa.top > d.top {
        return TOP
    } else if wa.bottom < d.bottom {
        return BOTTOM
    } else if wa.left > d.left {
        return LEFT
    } else if wa.right < d.right {
        return RIGHT
    }
    if tb == nil {
        return UNKNOWN
    }

    // Check which corner tray is closest to
    if ((*tb).top - d.top) < (d.bottom - (*tb).bottom) {
        return TOP
    }
    if ((*tb).left - d.left) < (d.right - (*tb).right) {
        return LEFT
    }
    if d.bottom-(*tb).centerY() < d.right-(*tb).centerX() {
        return BOTTOM
    }
    return RIGHT
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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