Docking Window Inside Another Window

Docking Window inside another Window

The solution I have used before is to set the application window as a child of the control you want to dock it in.

using System.Diagnostics;
using System.Runtime.InteropServices;

private Process pDocked;
private IntPtr hWndOriginalParent;
private IntPtr hWndDocked;

[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

private void dockIt()
{
if (hWndDocked != IntPtr.Zero) //don't do anything if there's already a window docked.
return;
hWndParent = IntPtr.Zero;

pDocked = Process.Start(@"notepad");
while (hWndDocked == IntPtr.Zero)
{
pDocked.WaitForInputIdle(1000); //wait for the window to be ready for input;
pDocked.Refresh(); //update process info
if (pDocked.HasExited)
{
return; //abort if the process finished before we got a handle.
}
hWndDocked = pDocked.MainWindowHandle; //cache the window handle
}
//Windows API call to change the parent of the target window.
//It returns the hWnd of the window's parent prior to this call.
hWndOriginalParent = SetParent(hWndDocked, Panel1.Handle);

//Wire up the event to keep the window sized to match the control
Panel1.SizeChanged += new EventHandler(Panel1_Resize);
//Perform an initial call to set the size.
Panel1_Resize(new Object(), new EventArgs());
}

private void undockIt()
{
//Restores the application to it's original parent.
SetParent(hWndDocked, hWndOriginalParent);
}

private void Panel1_Resize(object sender, EventArgs e)
{
//Change the docked windows size to match its parent's size.
MoveWindow(hWndDocked, 0, 0, Panel1.Width, Panel1.Height, true);
}

C# Window Docking

This type of window is called an "Application Desktop Toolbar" and can be implemented via P/Invoking to the base APIs:

Duplicates:

  • How do you do AppBar docking (to screen edge, like WinAmp) in WPF?
  • How to dock an application in the Windows desktop?
  • Windows API to attach window to the left or to right of desktop
  • WPF application that claims desktop real estate similar to windows taskbar
  • How to limit bottom window full screen max y position on Windows
  • WPF Windows Docking that affects other windows in Maximized mode
  • C# Desktop App Bar (Somewhat Like a taskbar)

C# - Docked External application - Mouse events

For reference, I'm combining two answers together to one here:

Getting mouse position in c#

How to get window's position?

Using the global position of the mouse and the position of the window we can calculate the relative position of the mouse. Heres some sample code with really basic boundary handling and no real error handling for if the handle gets closed, etc. But should get you started.

First, basically a copy of the above answers bringing in windows APIs to get the window and mouse positions:

    [StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;

public static implicit operator Point(POINT point)
{
return new Point(point.X, point.Y);
}
}

[DllImport("user32.dll")]
public static extern bool GetCursorPos(out POINT lpPoint);

public static Point GetCursorPosition()
{
POINT lpPoint;
GetCursorPos(out lpPoint);

return lpPoint;
}

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindow(string strClassName, string strWindowName);

[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hwnd, ref Rect rectangle);

public struct Rect
{
public int Left { get; set; }
public int Top { get; set; }
public int Right { get; set; }
public int Bottom { get; set; }
}

Then a bit of math between the two:

    public Point GetRelativeMousePosition(IntPtr windowPtr)
{
Rect windowPostion = new Rect();
GetWindowRect(windowPtr, ref windowPostion);
var mousePosition = GetCursorPosition();

var result = new Point();
result.X = mousePosition.X - windowPostion.Left;
result.Y = mousePosition.Y - windowPostion.Top;

// set some boundaries so we can't go outside.
if (result.X < 0)
result.X = 0;

var maxWidth = windowPostion.Right - windowPostion.Left;
if (result.X > maxWidth)
result.X = maxWidth;

if (result.Y < 0)
result.Y = 0;

var maxHeight = windowPostion.Bottom - windowPostion.Top;
if (result.Y > maxHeight)
result.Y = maxHeight;

return result;
}

and then putting it all together:

    private void Sample()
{
Process[] processes = Process.GetProcessesByName("notepad");
Process lol = processes[0];
var ptr = lol.MainWindowHandle; // getting this reference is expensive. Better to store and reuse if possible.
var relativePoint = GetRelativeMousePosition(ptr);
Console.WriteLine($"relative mouse x:{relativePoint.X} y:{relativePoint.Y}");
}

Docking a WinForm inside another WinForm

Create 2 forms, Form1 and Form2. Set TopLevel property of Form2 to false. In form load for Form1 add code

private void Form1_Load(object sender, EventArgs e)
{
Form2 frm2 = new Form2();
frm2.Show();

this.Controls.Add(frm2);
}

This will include form2 in form1, you then have to set properties on form2 if you want to remove the title bar to make the form more like a Panel.

How to dock a pop-out window?

You can dock a QDockWidget on a QMainWindow or another QDockWidget.

To get the desired layout embed a sub QMainWindow on the right side of your main window, and use it as a QWidget with setWindowFlags(Qt::Widget):

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtWidgets>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QSplitter *splitter = new QSplitter(this);
splitter->setOrientation(Qt::Horizontal);
QTreeView* leftSideWidget = new QTreeView(this);

m_rightSideWindow = new QMainWindow(this);
m_rightSideWindow->setWindowFlags(Qt::Widget);
m_rightSideWindow->layout()->setContentsMargins(3, 3, 3, 3);

splitter->addWidget(leftSideWidget);
splitter->addWidget(m_rightSideWindow);

m_dockWidget1 = new QDockWidget("Dock 1", this);
m_rightSideWindow->addDockWidget(Qt::TopDockWidgetArea, m_dockWidget1);
m_dockWidget1->setTitleBarWidget(new QWidget()); // remove title bar
m_dockWidget1->setAllowedAreas(Qt::NoDockWidgetArea); // do not allow to dock
QTextEdit* textEdit1 = new QTextEdit(this); // put any QWidget derived class inside
m_dockWidget1->setWidget(textEdit1);

m_dockWidget2 = new QDockWidget("Dock 2", this);
m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget2);
m_dockWidget2->setTitleBarWidget(new QWidget());
m_dockWidget2->setAllowedAreas(Qt::NoDockWidgetArea);
QTextEdit* textEdit2 = new QTextEdit(this);
m_dockWidget2->setWidget(textEdit2);

m_dockWidget3 = new QDockWidget("Dock 3", this);
m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget3);
QTextEdit* textEdit3 = new QTextEdit(this);
m_dockWidget3->setWidget(textEdit3);

setCentralWidget(splitter);

}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionRestore_layout_triggered()
{
QList<QDockWidget*> list = findChildren<QDockWidget*>();
foreach(QDockWidget* dock, list)
{
if(dock->isFloating())
dock->setFloating(false);
m_rightSideWindow->removeDockWidget(dock);
if (dock == m_dockWidget1)
m_rightSideWindow->addDockWidget(Qt::TopDockWidgetArea, m_dockWidget1);
else
m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, dock);
dock->setVisible(true);
}
m_rightSideWindow->splitDockWidget(m_dockWidget2, m_dockWidget3, Qt::Horizontal);
}

Sample Image



Related Topics



Leave a reply



Submit