開発当初、Form->Show()で表示して、Form->Hide()で隠していたのだが、これがなんだかあいまいで、最前面に来ることがあったり、起動時点での最前面に来たりした。また、フォーカスも、奪ったり奪わなかったりと、実にファジーな動作で頭を悩ませてくれた。Form->Visible = true; を用いても同様。
初期の仕様では、『上から2番目に表示する』という仕様にしていたのだが、SetActiveWindow(), SetForeGroundWindow(), BringWindowToTop(), SetWindowPos()のどれを用いても、2番目に来たり来なかったり、最前面に来たり来なかったり、起動時点での最前面に来たり来なかったり、とガッカリな動作。
そこで、仕様を変更して、『最前面に来るが、即座にフォーカスを(元いたフォーカスに)返す』という仕様にした。GetForegroundWindow()で、『時報時計』のForm->Show()が呼ばれた瞬間に最前面にいるアプリのハンドルを取得でき、そのハンドルを引数にSetForegroundWindow()に与えれば元に戻る、ということで、これでできたかと思ったのだが、これがエラーは出さないが正常に動作しないことがチョクチョクあるという、これまたファジーな挙動。基本的に俺用のソフトだったので、キー入力中(IME動作中)にフォーカスを奪うなど言語道断という考えで作っていたので、このファジーな挙動によって、時報時計にフォーカスが奪われるのは我慢ならなかった。
ふてくされて放置していたのだが、ふと、『Windows Live Messenger』の『メンバーがオンラインになったらアラートを表示する』はどうなっているのかが気になった。普段、鬱陶しいのでそんな機能はオフにしているのだが、これを見てみた。そしたら、『最前面に表示されるが、フォーカスは奪わない』という仕様だった。
俺が作っていたときも、それを目標に作っていたのだが、実際には『一瞬、時報時計がフォーカスを奪うが、すぐ元のアプリに返す』という挙動だった。この2つの違いは大きい。
これに気づいたら、あとは楽勝だった。少し調べると、SetWindowPos()の第7引数
UINT uFlags // ウィンドウ位置のオプションには、SWP_NOSENDCHANGINGというフラグがある。MSDNの説明では、
ウィンドウに WM_WINDOWPOSCHANGING メッセージが送られないようにします。と、何を言っているのか分からないことが書いてある。いちおう、CWnd::OnWindowPosChanging()などで更に説明があるが、読んでもサッパリ分からない。まぁ、頭の悪い説明や、俺の悪い頭は置いといて、とにかく、SetWindowPos()の第7引数にSWP_NOSENDCHANGINGを指定すると、フォーカスはそのままで、Zオーダーのみを最前面に渡すことができた。ただし、先にForm->Show()してしまうとマズいらしく、うまく動かない。
SetWindowPos( Form->Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOSENDCHANGING | SWP_SHOWWINDOW );とすれば、正常動作が望める。
Form_Main->Visible = true;
ということで、キモはSWP_NOSENDCHANGINGだった。最前面に表示されるが、フォーカスは奪わない方法について言及している検索結果は少なかったので、TIPSとして、価値があるであろうと判断。ここに、載せておく。
お役に立てて何よりです。
開発がんばってくださいねー。
お世話になります。
VB.NET2010で
普段、VBのフォームを最小化しておいて
時間が経過すると(何かのタイミング)フォームを普通の状態にして
( FormWindowState.Normal)
PCモニターの右上にメッセージ表示するプログラムの作成を考えています。
職場で以下を記載しましたら
エラーになったのですが
環境が違ったでしょうか?
お手数おかけしますがよろしくお願いします。
SetWindowPos( Form->Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOSENDCHANGING | SWP_SHOWWINDOW );
Form_Main->Visible = true;
私の書いたコードは、C++Builderのコードです。
VB.NETというと、Visual Basicですから、言語が異なります。
言語が違いますので、コードをそのまま流用することはできないでしょう。
「VB 最前面 フォーカス」とかで検索すれば、ヒットするかもしれません。
また、VBとC#のコードを併記して説明しているサイトも多いですから、「C# 最前面 フォーカス」とかで検索しても、VBの説明に辿りつけるかもしれません。
お力になれず申し訳ないですが、参考になれば。