我一直在嘗試多種方法使一個視窗成為焦點并位于其他視窗之上。
我試過了SetForegroundWindow()
,,,BringWindowToTop()
。SetActiveWindow()
這些都不是始終如一的。
我怎樣才能簡單地使我想要成為焦點的視窗成為所有其他視窗的頂部并獲得焦點?為什么這么難?
uj5u.com熱心網友回復:
SetForegroundWindow()
是更改前臺視窗的正確方法,但呼叫的執行緒SetForegroundWindow()
必須滿足某些條件才能“作業”。如果不符合條件,則視窗的任務欄按鈕會閃爍。這是設計使然。這是為了保護用戶免受應用程式竊取焦點的影響,您應該尊重這一點。
也可以看看:
- 前臺激活權限就像愛情:不能偷,必須給你
- 如果兩個程式都這樣做了怎么辦?
uj5u.com熱心網友回復:
您的行程需要滿足一些條件才能設定前景視窗。
這是為了防止應用程式竊取焦點——這是一種非常糟糕的用戶體驗。
想象一下,您正在寫一封電子郵件,而您的應用程式認為現在是將一個視窗推到前臺的好時機。當你突然打字時,焦點視窗會立即改變,你的按鍵現在將被發送到你的程式而不是郵件程式。這不僅會導致各種破壞(您按下的鍵現在被發送到您的程式,因此熱鍵可能會被觸發,對話框被關閉等......) - 而且對用戶來說也是一個非常令人沮喪的體驗(尤其是對于技術不那么好的人)。
這就是為什么SetForegroundWindow()
& 類似的功能有時不會將您的視窗推到前臺,但仍然報告成功的原因。不過,您的視窗仍會在任務欄中閃爍,因此用戶知道您的應用程式中發生了一些事情。
設定前景視窗
需要滿足的SetForegroundWindow()
作業條件的確切串列在檔案中有詳細說明:
系統限制哪些行程可以設定前臺視窗。
只有當下列條件之一為真時,行程才能設定前臺視窗:
- 該行程是前臺行程。
- 該行程由前臺行程啟動。
- 行程收到最后一個輸入事件。
- 沒有前臺行程。
- 正在除錯前臺行程。
- 前景未鎖定(請參閱LockSetForegroundWindow)。
- 前臺鎖定超時已過期(參見
SPI_GETFOREGROUNDLOCKTIMEOUT
SystemParametersInfo )。- 沒有選單處于活動狀態。
當用戶正在使用另一個視窗時,應用程式不能將一個視窗強制到前臺。相反,Windows 會閃爍視窗的任務欄按鈕以通知用戶。
1這就是防止上面詳述的郵件程式示例發生的原因。
滿足這些條件的行程也可以通過呼叫與另一個行程“共享”其設定前臺視窗的權限AllowSetForegroundWindow()
設定活動視窗
SetActiveWindow()
僅當目標視窗附加到您的訊息佇列并且您的應用程式視窗之一當前是前臺視窗時才有效。
激活一個視窗。該視窗必須附加到呼叫執行緒的訊息佇列。
如果系統激活視窗時其應用程式處于前臺,則該視窗將被置于前臺(Z-Order 的頂部) 。
將視窗置頂
BringWindowToTop()
是 的便利函式SetWindowPos()
,同樣具有相同的限制:
如果應用程式不在前臺,而應該在前臺,則它必須呼叫SetForegroundWindow函式。
要使用SetWindowPos將視窗置于頂部,擁有該視窗的行程必須具有SetForegroundWindow權限。
使用 UI 自動化
既然您提到您需要此功能來實作可訪問性工具,那么您可以通過以下方式使用UI 自動化來完成此操作:
為簡單起見,此示例使用準系統 COM,但如果您愿意,當然可以使用例如wil
更類似于 C 的 API。
#include <uiautomation.h>
bool MoveWindowToForeground(IUIAutomation* pAutomation, HWND hWnd) {
// retrieve an ui automation handle for a given window
IUIAutomationElement* element = nullptr;
HRESULT result = pAutomation->ElementFromHandle(hWnd, &element);
if (FAILED(result))
return false;
// move the window into the foreground
result = element->SetFocus();
// cleanup
element->Release();
return SUCCEEDED(result);
}
int main()
{
// initialize COM, only needs to be done once per thread
CoInitialize(nullptr);
// create the UI automation object
IUIAutomation* pAutomation = nullptr;
HRESULT result = CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, IID_IUIAutomation, reinterpret_cast<LPVOID*>(&pAutomation));
if (FAILED(result))
return 1;
// move the given window into the foreground
HWND hWnd = FindWindowW(nullptr, L"Calculator");
MoveWindowToForeground(pAutomation, hWnd);
// cleanup
pAutomation->Release();
CoUninitialize();
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/491587.html
上一篇:是否有一種獨立于平臺的方法來檢查檔案路徑是否是Haskell中根目錄的某種表示?
下一篇:重命名具有相同名稱的多個檔案