tags:

views:

97

answers:

2

I have a panel that may or may not be within other panels. I'm trying to work out the visible bounds of that panel. I thought the GetWindowRect or the GetClientRect would do the trick but no joy.

To test this I've created a form with a panel and at multiline text box. The panel is bigger than the form (i.e. it stretches below the bottom of the form)

So if my form is 300 by 300. And the Panel is located at 10,10 and is 100 by 500 I want something that will tell me that the visible area is 100, 290 (assuming the 0,0 relative starting point for the panel which would be at 10,10 over all.

Does such a method exist?

I have tried a few different methods like getting the parent handle of the panel i'm interested in and testing that but I can't always be sure the direct parent will be the one that determines the visibility.

Here is the code of the test application I wrote to test GetWindowRect or the GetClientRect:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace clientRectTest
{
public partial class Form1 : Form
{
    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public Int32 left;
        public Int32 top;
        public Int32 right;
        public Int32 bottom;

        public static RECT FromRectangle(Rectangle rectangle)
        {
            RECT win32rect = new RECT();
            win32rect.top = rectangle.Top;
            win32rect.bottom = rectangle.Bottom;
            win32rect.left = rectangle.Left;
            win32rect.right = rectangle.Right;
            return win32rect;
        }
    }

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
    [DllImport("user32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr hWnd);


    public Form1()
    {
        InitializeComponent();
        this.AutoScrollMinSize = new Size(250, 500);

    }


    protected override void OnMouseClick(MouseEventArgs e)
    {
        NewLine("Click Location: " + e.Location.ToString());
        base.OnMouseClick(e);
    }

    protected override void OnResize(EventArgs e)
    {
        this.textBox1.Text = "Panel Size" + this.panel1.Size.ToString();

        NewLine( "Form Size" + this.Size.ToString());
        //  NewLine("Panel PARENT Client Rectangle: " + getPanelClientRectangle(this.panel1.Parent.Handle));


        NewLine("Panel Client Rectangle: " + getPanelClientRectangle(this.panel1.Handle));
        NewLine("Panel Window Rectangle: " + getPanelWindowRectangle(this.panel1.Handle));
        NewLine("Panel Window Bounts: " + this.panel1.Bounds.ToString());


        NewLine("Panel DC Client Rectangle: " + getPanelDCClientRectangle(this.panel1.Handle));
        NewLine("Panel DC Window Rectangle: " + getPanelDCWindowRectangle(this.panel1.Handle));

        NewLine("Panel Location: " + this.panel1.Location.ToString());


        base.OnResize(e);
    }

    private string getPanelDCClientRectangle(IntPtr handle)
    {
        string cr = string.Empty;

        RECT r1 = new RECT();
        IntPtr dc = GetWindowDC(handle);
        GetClientRect(dc, out r1);

        cr = r1.left.ToString() + ", " + r1.top.ToString() + ", " + r1.right.ToString()
         + ", " + r1.bottom.ToString();
        Point thisLocation = this.Location;

        return cr;
    }

    private string getPanelDCWindowRectangle(IntPtr handle)
    {
        string cr = string.Empty;

        RECT r1 = new RECT();
        IntPtr dc = GetWindowDC(handle);
        GetWindowRect(dc, out r1);

        cr = r1.left.ToString() + ", " + r1.top.ToString() + ", " + r1.right.ToString()
         + ", " + r1.bottom.ToString();
        Point thisLocation = this.Location;

        return cr;
    }

    private string getPanelWindowRectangle(IntPtr handle)
    {
        string cr = string.Empty;

        RECT r1 = new RECT();

        GetWindowRect(handle, out r1);

        cr = r1.left.ToString() + ", " + r1.top.ToString() + ", " + r1.right.ToString()
         + ", " + r1.bottom.ToString();
        Point thisLocation = this.Location;

        return cr;
    }

    private string getPanelClientRectangle(IntPtr handle)
    {
        string cr = string.Empty;

        RECT r1 = new RECT();

        GetClientRect(handle, out r1);

        cr = r1.left.ToString() + ", " + r1.top.ToString() + ", " + r1.right.ToString()
         + ", " + r1.bottom.ToString();
        Point thisLocation = this.Location;

        return cr;
    }

    private void NewLine(string p)
    {
        this.textBox1.Text += Environment.NewLine + p;
    }
}
}

EDIT: more information found:

I think the line this.AutoScrollMinSize = new Size(250, 500); was messing up my results. This seemed to make the panel 500 even though it wasn't displaying 500. Will redo some of my test cases. I wouldn't have expeced this line to cause problems.

+1  A: 

You should be able to use the DisplayRectangle property of the panel to get the rectangle that is currently being displayed. This property is implemented in Control, but is overriden by ScrollableControl (the parent of System.Windows.Forms.Panel)

davisoa
Yeah, I treid that as well, it gave me the same results as the Client Rectangle. so this is still too big.
AidanO
A: 

This is what I came up with in the end:

WinSDK.RECT parentRect = new WinSDK.RECT();
            WinSDK.RECT intersectRect = new WinSDK.RECT();

            Rectangle parentRectangle = new Rectangle();
            Rectangle intersectRectangle = new Rectangle();

            // Get the current Handle.
            IntPtr currentHandle = this.Handle;

            // Get next Parent Handle.
            IntPtr parentHandle = WinSDK.GetParent(this.Handle);

            // Get the Rect for the current Window.
            WinSDK.GetWindowRect(this.Handle, out intersectRect);

            // Load Current Window Rect into a System.Drawing.Rectangle
            intersectRectangle = new Rectangle(intersectRect.left, intersectRect.top, intersectRect.right - intersectRect.left, intersectRect.bottom - intersectRect.top );

            // Itterate through all parent windows and get the overlap of the visible areas to find out what's actually visible.
            while (parentHandle != IntPtr.Zero)
            {
                // Get the Rect for the Parent Window.
                WinSDK.GetWindowRect(parentHandle, out parentRect);
                parentRectangle = new Rectangle(parentRect.left, parentRect.top, parentRect.right - parentRect.left, parentRect.bottom - parentRect.top);

                // Get the intersect between the current and parent window.
                intersectRectangle.Intersect(parentRectangle);

                // Set up for next loop.
                currentHandle = parentHandle;
                parentHandle = WinSDK.GetParent(currentHandle);
            }

            return intersectRectangle;
AidanO