1.用意するネタ |
Form1に、ツールバーコントロール、テキストボックスなど、それと、(実行時は非表示ですが)フレームコントロール(またはピクチャーボックス)を貼り付けます。 そして、Form2には何も貼り付けず、ウィンドウスタイル(BorderStyle)を"4 - ツールボックス固定"にします。 ツールバーのAlignプロパティは"1"にしておいても大丈夫です。成功すると、右のような状態にすることができます。「ダブルクリックすると...?」と表示されているラベルコントロールは、Alignプロパティを"1"にしたピクチャーボックスの中に貼り付けています。 この図では、ツールバーコントロールのみに対象を絞っていますが、応用すれば、VBのドッキングウィンドウのように、テキストボックスやツリービューコントロール、それらの複合体(ピクチャーボックスをコンテナにすることによってできます)をドッキングしたり切り離したりすることができます。 ただ、MFCにあるような移動中に枠を描いたり、かっこいい(?)動作をさせようとするには、残念ながらもっと修行が必要です。(きっとメッセージフックなどを使えばできるでしょう。) |
2.親子関係を変える |
Dim OldParent_hwnd As Long OldParent_hwnd = SetParent(Toolbar1.hwnd, Form2.hwnd) 最初、単純にこれだけでいいと思ってました。多分、掲示板に刺激されて試された方がいれば、この段階でおかしなことに気付いたはずです。 この時、他にAlignプロパティが"1"のコントロール(上の図ではピクチャーボックス)があれば、どうなるでしょう? ピクチャーボックスの位置が変わりません。ツールバーはForm2に移ってしまっているのに、Form1ではツールバーの高さ分だけ、透明なコントロールが占有しているのです。これでは使い物になりませんね。理由は、Alignプロパティを実現する機能がWindowsに備わっていないからです。この処理をVBが独自で行っているからだと思われます。 ではむりやりAlignを解除して、親フォームを変えてみましょう。SetParent()の前に、Toolbar1.Alignを"0"に設定するだけです。どうでしょう? 「透明コントロール」は消えました。しかし、ちょっとツールバーがおかしいみたいです。Alignが0だからです。と言うことは、サイズ調整はForm2_Resize()で手動で行わないといけません。 ここでフレームコントロールの出番です。 Set Toolbar1.Container = Frame1 とすることによって、ツールバーのコンテナがフォームからフレームに移ります。つまり、Alignプロパティは一旦解除(=0)されます。しかし、この状態でSetParent()を実行すると、不思議なことに、上の図のようになるではないですか。 戻す時も簡単ですね。逆をすればいいのです。コンテナをフレームからフォームに移し、SetParent()を実行するのです。 |
3.注意すること |
この動作をさせる時、注意しておかなければならないのは「フォーカスの移動」です。上の図で実験中に分かったことですが、ツールバー上に配置されたコントロールがアクティブの時、Form1をクリックしても、Form1はアクティブになってくれません。 Form1をクリックすることによって、Form1がアクティブになります。しかし、Form1でフォーカスを持っているのは見かけ上Form2にあるツールバーの中のコントロールです。Form1がアクティブになると、そのコントロールがアクティブになり、同時に、その親であるForm2が結果的に再びアクティブになるのです。サンプルプロジェクトで確かめてください。 Form1_Active()において、ツールバー分離時の対策について、何らかのコードを組む必要があります。上の図では、例えばText1.SetFocusとすることでこの現象は防ぐことができます。ただ、ツールバー上のコントロールがアクティブでなく、「ツールバーコントロール」がアクティブの時、この現象は起こりませんので、ツールバーにコントロールを乗せない時はこの措置は必要ありません。 |
4.ウィンドウのスタイルを変える |
ここではツールバーに限って書いているので直接は関係ありませんが、先に書いた「フォーカスの移動」の問題を解決後(現時点で自分でも解決法が見つかりません)、複合体を分離した時にVBのドッキングウィンドウのようにタイトルバーを付けたい、とお思いの方に。 SetWindowLong()を使用します。GWL_STYLE, GWL_EXSTYLEの場合、まず、GetWindowLong()で元からあるスタイルを取得したあと、Or や Xor でスタイルを追加・削除する方法が基本です。 Dim Style As Long Style = GetWindowLong(Form1.hwnd, GWL_STYLE) Style = Style Xor WS_CAPTION ' タイトルバーを消す SetWindowLong Form1.hwnd, GWL_STYLE, Style この関数はスタイルの変更に関してあまり危険ということはないので、上の定数を使っていろいろと試してみてください。複合体のコンテナ(ピクチャーボックス)にタイトルバーを付けた後、それを親フォームの中で最大化します。そうするとVBのドッキングウィンドウのようになります。 |
5.メッセージフックでもっときれいに |
タイトルバーを付けました。しかし、動いてしまいます。ここでメッセージフックです(Movableプロパティはないので)。 サブクラス化し、WM_NCMOUSEDOWNメッセージを横取りし、そのメッセージのパラメータにあるヒットテストコード(どこにマウスポインタがあるか)にことごとく「別の場所」の値を代入すればいいのです。 自分でもあまりやっておらず、詳しく書けませんので各個人の責任で探求していってください。その結果新発見があれば、掲示板・メールでお知らせください。 つづ・・・く? ※ この事に関しては研究した後、また別の機会に続編Tipsを載せるつもりでいます。が、載せないかもしれません。 |