在MDi窗體嵌入子窗體後不顯示選單欄
背景:
由於之前做的一個程式的功能全部都是放在一個介面上的,有一個功能能夠在資料庫查詢資料,並返回到介面上,資料量比較小的時候還好,但是資料量多了,導致它阻塞的其他執行緒,經過一系列討論之後,決定將一個介面換成一個主介面加多個子介面。
實施:
多個子介面遷移完成之後,使用下面的方法將其放置的主介面中(先將主窗體的IsMdiContainer設定為true,不然會報錯)
Form frm = new SssForm();
foreach (Form childForm in MdiChildren)
{
if (childForm != CccForm)
{
childForm.Close();
}
}
this.CccForm.Visible = false;
frm.MdiParent = this;
frm.Show();
frm.WindowState = FormWindowState.Maximized;
然後在主窗體和子窗體的屬性那裡把ControlBox屬性設定為false,然後測試發現主窗體一開始是沒有選單欄的,但是開啟子窗體之後就會在主窗體的右上角顯示出選單欄
查閱了一些網上的辦法去改變其他屬性值,但是測試之後發現沒有用,有說用pannel的,但是我的這個程式需要在Mdi中實現,就沒有去實踐了,後面就去問gpt4了,最後用gpt4給的方法實現了
這個方法是重寫WndProc,在獲取到子窗體需要重新計算大小時,直接告訴系統我們只需要計算工作區,而不需要把選單欄加入進來,這裡微軟的官方文件裡面也有寫到[(https://learn.microsoft.com/zh-cn/windows/win32/winmsg/wm-nccalcsize)]
以下是程式碼實現:
protected override void WndProc(ref Message m)
{
const int WM_NCCALCSIZE = 0x0083;
const int WM_NCHITTEST = 0x0084;
switch (m.Msg)
{
case WM_NCCALCSIZE:
// 當窗體的大小需要重新計算時,系統會傳送WM_NCCALCSIZE訊息
// 這裡可以修改訊息的處理,以改變窗體非客戶區的大小
// 如果wParam是TRUE(非零),則指示客戶區大小需要重新計算
// 透過簡單地返回0,我們可以告訴Windows我們已處理訊息,不需要預設的非客戶區
// 這實際上會移除所有的非客戶區,包括邊框和標題欄
if (m.WParam.ToInt32() != 0)
{
// 返回0表示我們處理了這個訊息,不再需要預設的處理
// 這將去除非客戶區,包括標題欄和邊框
m.Result = IntPtr.Zero;
return;
}
break;
case WM_NCHITTEST:
// 可以在這裡處理滑鼠事件,例如檢測滑鼠是否在我們自定義的標題欄區域內
// 這對於新增拖動行為等自定義互動是有用的
base.WndProc(ref m);
if ((int)m.Result == 0x01) // HTCLIENT
{
// 可以修改m.Result來改變滑鼠的行為,例如使其支
// m.Result = (IntPtr)2; // HTCAPTION 表示標題欄,允許拖動窗體
}
return;
}
base.WndProc(ref m);
}
然後根據我想要的功能給它簡單的最佳化了一些
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0083 && m.WParam.ToInt32() != 0)
{
m.Result = IntPtr.Zero;
return;
}
base.WndProc(ref m);
}
效果圖: