全螢幕 OpenGL 本質是**無邊框、無標題、覆蓋全螢幕的彈出式視窗** + **切換顯示解析度**。只需在視窗類別的 CreateParams 中修改樣式並設定尺寸即可。
void __fastcall TMyGLForm::CreateParams(TCreateParams &Params) {
TForm::CreateParams(Params);
Params.Style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
// WS_POPUP: 無標題列、無邊框、不在工作列顯示
// WS_CLIPCHILDREN/WS_CLIPSIBLINGS: 防止子視窗/同層視窗繪圖衝突,OpenGL 必備
}
void __fastcall TMyGLForm::CreateParams(TCreateParams &Params) {
TForm::CreateParams(Params);
Params.Style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
ChangeResolution(800, 600); // 切換顯示模式
Params.Width = 800;
Params.Height = 600;
Params.X = Params.Y = 0; // 左上角對齊螢幕原點
}
bool ChangeResolution(DWORD w, DWORD h) {
DEVMODE dm = {0};
dm.dmSize = sizeof(DEVMODE);
LONG i = 0, modeSwitch;
// 1. 列舉顯示模式,尋找符合寬高且 16 位元色深的模式
do {
modeSwitch = EnumDisplaySettings(NULL, i++, &dm);
} while (modeSwitch &&
(dm.dmBitsPerPel != 16 || dm.dmPelsWidth != w || dm.dmPelsHeight != h));
if (!modeSwitch) return false; // 找不到支援模式
// 2. 嘗試套用
modeSwitch = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
if (modeSwitch != DISP_CHANGE_SUCCESSFUL) {
// 3. 兼容舊驅動:嘗試不指定刷新率
dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
dm.dmBitsPerPel = 16;
dm.dmPelsWidth = w;
dm.dmPelsHeight = h;
modeSwitch = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
}
return modeSwitch == DISP_CHANGE_SUCCESSFUL;
}
關鍵點:
CDS_FULLSCREEN:標記為全螢幕模式切換,離開程式自動恢復原解析度。DEVMODE(含刷新率),失敗則退回最小欄位集合。dmBitsPerPel = 32)。
void __fastcall TMyGLForm::FormClose(TObject *Sender, TCloseAction &Action) {
ChangeDisplaySettings(NULL, 0); // 還原系統預設模式
}
若工作列設定「永遠在最上層」,全螢幕視窗底部會露出一條白線。解決:
FormStyle = fsStayOnTop(Always On Top),覆蓋工作列。SetWindowPos(Handle, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE)。TForm,覆寫 CreateParams、FormClose。FormCreate 初始化 OpenGL RC(wglCreateContext、wglMakeCurrent、設定投影矩陣)。FormPaint 或計時器中渲染 OpenGL 場景,SwapBuffers。SetFullscreenState(TRUE) 原生全螢幕,效能最佳。