27

私がプログラミングを始めたとき (約 10 年以上前)、次の 3 つのことに驚かされました。

  • コンパイラ/インタプリタ (当時、私はそれらを「自分のプログラムを機能させるプログラム」として知っていました。多くの場合、「それらが何であれ」という修飾子が後に続きます)
  • コード エディター
  • フォーム デザイナー

当時、私はそれらすべてを人生の事実として受け入れていました。専用プログラムは自作できましたが、「自分のプログラムを動かすプログラム」、コードエディタやフォームエディタは神々が作ったもので、いじるわけにはいきませんでした。

その後、大学に進学し、形式言語処理のコースを受講しました。形式文法、パーサー、抽象構文木などを学習した後。コンパイラ、インタープリタ、コード エディタに関するすべての魔法はすぐになくなりました。コンパイラーとインタープリターは、正気で単純な方法で作成できます。構文を強調表示するコード エディターに必要な正気でないものは、Windows API のハックだけでした。

しかし、今日に至るまで、フォーム エディターは私にとって謎のままです。フォーム デザイナを作成するために必要な技術的知識が不足しているか、またはそのような知識はあるが、フォーム デザイナを実装するためにそれを使用する方法を見つけることができません。

Visual C++ と MFC を使用して、これまでで最高のフォーム デザイナーに触発されたフォーム デザイナーを実装したいと思います。

Visual Basic 6 のフォーム デザイナー

特に、私が最も気に入っている 2 つの機能を模倣したいと思います。

  • 設計中のフォームはコンテナー内にあります。したがって、コンテナのサイズを適切なサイズに変更するだけで、画面の領域をあまり浪費することなく、任意の大きさのフォームを設計できます。

  • 「グリッドに合わせる」オプションを使用すると、プロフェッショナルな外観のユーザー インターフェイスを設計する際のストレスが大幅に軽減されます。実際、Visual Basic のフォーム デザイナーを使用してプロフェッショナルな外観のユーザー インターフェイスを作成することは、実際には簡単で、楽しく、楽しいものです。私のような左脳のプログラマーにとっても。

そこで、次の質問があります。

  1. フォームがコンテナー内にあるフォーム デザイナーを作成するにはどうすればよいですか? 設計されているフォームは、別のウィンドウ内に含まれる実際のウィンドウですか? それとも、フォーム デザイナーが「手作業で」描いたモックアップですか?

  2. Windows API および/または MFC には、「選択可能な」項目を簡単に作成できる関数、クラスが含まれていますか (選択されている場合は小さな白または青のボックスで囲まれ、これらのいずれかによって「つかまれる」場合はサイズ変更可能です)。エッジ")?

  3. 「グリッドに合わせる」機能を実装するにはどうすればよいですか?

4

3 に答える 3

30

ここでの両方の答えは良いですが、私が本当に興味深いと思う部分を省略しました (直接尋ねなかったが、とにかく興味があるかもしれないいくつかを含む)。

コントロールの描画

理想的には、先に進んでコントロールの通常のインスタンスを作成するだけです。ボタンのようなものが欲しいですか?実際のボタンを作成します。トリッキーなことは、ボタンのように動作するのを止めることです: 実際に「クリック」するのではなく、クリックして移動のためにアクティブにする必要があります。

これに対処する 1 つの方法 - 問題のコントロールが 'HWND ベース' (たとえば、ボタン、編集、静的、リストボックス、ツリービューなどの標準ウィンドウ セット) であると仮定すると、コントロールを作成してからサブクラス化することです。それ - すなわち。wndproc を SetWindowLongPtr(GWLP_WNDPROC, ...) でオーバーライドして、デザイナー コードがマウスとキーボードの入力をインターセプトし、それを使用して移動を開始できるようにします。たとえば、マウス入力を実際のボタン コードに渡す代わりに、代わりに「クリック」イベントとして解釈します。

サブクラス化の別の方法は、ボタンの上に非表示のウィンドウを配置して入力をキャプチャすることです。入力をインターセプトするという同じ考え方ですが、実装が異なります。

上記は、マネージド (VB.Net、C#) コントロールとアンマネージド (C/C++) コントロールの両方に適用されます。どちらも本質的にストック ウィンドウ HWND です。マネージ バージョンには、基になるアンマネージ コントロールに渡すマネージ ラッパー コードが含まれているだけです。

.Net VB より前に使用されていた古い (事前に管理されたコード) ActiveX コントロールは、まったく別の球技でした。ActiveX コンテナーとその中の ActiveX コントロールの間にはかなり複雑な関係があり、プロパティ、イベント、描画などのネゴシエーションなどを処理する多くの COM インターフェイスがあります。(ActiveX コントロールが入力を受け取り、独自の HWND を持たずにそれ自体を描画できるようにする一連のインターフェイスのイベントがあります。) ただし、この複雑さから得られる利点の 1 つは、ActiveX コントロールには明示的な「デザイン モード」があることです。そのため、コントロールはその場合に適切に応答することを認識し、手順全体に協力できます。

フォーム自体...

したがって、基本的にコントロールは通常のコントロールです。では、フォーム自体は通常のフォームであると思いますか? - ほとんど。私の知る限り、デザイナーの子である別の HWND ベースのウィンドウです (そのため、クリップされ、その中でスクロールできます)。しかし、デザイナーはここで少し「不正行為」をしていると思います。通常、Windows は実際のトップレベル ウィンドウのタイトルバーと最小/最大ボタンのようなフレームしか描画しないためです。彼らがここで使用している正確なテクニックはわかりませんが、いくつかのオプションには以下が含まれる可能性があります。Windows の外観を模倣するために手動でペイントする。Windows の「テーマ」API を使用して、タイトルバーの断片に使用されるグラフィック要素にアクセスし、好きな場所にペイントできるようにします。または、おそらく可能性は低いですが、ウィンドウを「MDI子ウィンドウ」として設定します

ドラッグ可能なハンドル

ここでの最も簡単なアプローチは、デザイナーが、他のすべての要素の上にある、タイトル バーのない小さな正方形のポップアップ ウィンドウを 8 つ作成することです。これらのウィンドウは、クリックされると適切なサイズ変更コードを開始します。ユーザーがコントロールからコントロールへとクリックするとき、ドラッグ ハンドル ウィンドウを現在アクティブなコントロールに移動するだけです。(上記のすべてにおいて、Windows 自体が誰がクリックされたかを把握していることに注意してください。実際にマウスの座標を要素の四角形の座標と比較して、自分で計算する必要はありません。)

保存と再作成

アンマネージ C/C++ で使用される単純な Windows システム コントロールの場合は、比較的簡単です。コントロールと場所を記述する、よく知られたテキスト ベースのファイル形式 (.rc) があります。デザイナーにそれ (およびおそらく resource.h ファイルも) を吐き出させると、完了です。どの C/C++ プロジェクトでも、これらのファイルを取得してコンパイルできます。マネージ コード (C#、VB.Net) には、もう少し複雑なスキームですが、基本的な考え方は同じです。つまり、マネージド ツールが期待するスタイルで記述を書き出すと、マネージド ツールは喜んでそれをコンパイルして使用します。

(ActiveX コントロールは、ご想像のとおり、まったく別の話です。私が認識している標準形式はありません。そのため、データを使用するフォーム エディターとランタイムは密接に結びついています。 .Net VB6 より前のフォーム エディターは、VB だけが使用できるフォームを作成します。

フォームの再作成に関しては、.rc ファイルがある場合、ダイアログ リソースにコンパイルされます。Windows には、それらを再作成するためのサポートが組み込まれています。同様に、マネージ コード サポート ライブラリは、特定の形式からフォームを再作成する方法を知っています。どちらも基本的に説明を解析し、アイテムごとに適切なクラスの要素を作成し、適切なスタイル、テキスト、およびその他のプロパティを指定どおりに設定します。自分でできないことは何もしていません。単なるヘルパー ユーティリティ コードです。

フォーカスの処理

コンテナー内の HWND のコレクションについては、「テスト」モードであるか実際のアプリで実際に実行されているかに関係なく、フォームの作成を Windows または Winforms に処理させるかどうか、または各 HWND を自分で作成したかに関係なく、次の方法でタブ サポートを追加できます。メッセージ ループでIsDialogMessageを呼び出す: 詳細については、MSDN ページの備考セクションを参照してください。(WinForms はこれを行うことができますが、実際には独自のフォーカス処理を行うため、視覚的なスタッキング Z オーダーから独立したタブ オーダーを持つことができると思います。)

その他の探索事項...

Spy++ アプリ (SDK の一部、Visual Studio と共にインストール) と友達になりましょう。マネージドまたはアンマネージドの HWND を使用して何かを行う場合は、このツールの使用方法を知っておくことをお勧めします。Windows の任意の UI をポイントして、ツリーからどのように構築されるかを確認できます。さまざまなタイプの HWND。それを VB デザイナに向けて、実際に何が起こっているかを確認してください。(ツールバーの「双眼鏡」アイコンをクリックし、目的のウィンドウに十字線をドラッグします。)

また、デザイナーが吐き出すリソース ファイルも見てください。フォーム デザイナで微調整、移動、または編集できるものはすべて、これらのリソース ファイルのどこかにある項目に対応しています。それらのコピーを作成し、いくつかの設定を微調整してから、2 つのセットをファイル比較して、変更点を確認します。ファイル内のいくつかを手動で変更してみて (ほぼすべてテキストだと思います)、リロードして、デザイナーが変更を反映しているかどうかを確認してください。

その他の注意事項...

上記の多くは Windows に固有のものです。特に、Windows 独自のビルディング ブロック (HWND) を使用しているため、Windows 自体に難しい作業の一部を任せることができます。これにより、コントロール自体を再利用する機能が提供されます。設計時にモックアップを作成する必要がありません。他のコントロールへの入力をインターセプトして、動きやその他の必要なアクションをクリックしたり、自分で位置計算を行うことなくクリックされたコントロールを特定したりできます。これが、内部で HWND を使用しない他の UI フレームワーク (Flash など) のデザイナーである場合、代わりにそのフレームワークの独自の内部機能を使用して同様の作業を行う可能性があります。

また、少なくとも最初のうちは、パレット内のコントロールの数を小さな有限セットに制限すると、はるかに簡単になります。コントロールをドラッグできるようにしたい場合 - たとえば。サードパーティのもの、または別のプロジェクトで使用したもの; 通常、最初にそのコントロールが使用可能であることをデザイナーが認識できるように、そのコントロールを「登録」する何らかの方法が必要です。また、ツールバーでどのアイコンを使用しているか、その名前は何か、どのプロパティをサポートしているかなどを発見する何らかの方法が必要になる場合もあります。

楽しく探検しましょう!

于 2011-04-04T04:52:29.697 に答える
6

通常の GUI とほとんど同じようにフォーム デザイナーを実装します。ドラッグできるもの (ウィジェット)、クリックできるもの (ボタン)、選択できるもの (配置されたウィジェット) があります。


Q: では、GUI でウィンドウを表示するにはどうすればよいですか?
A: あなたはそれを簡単に描きます。

Q: では、そのウィンドウ内に物を保管するにはどうすればよいですか?
A: 「親」オブジェクトの境界に対してチェックします。フォーム デザイナーは小さなゲームのようなものであり、親子関係によって接続されたすべてのウィジェットを保持するシーン グラフを持っていると言えます。

Q: では、GUI でどのように選択しますか?
A: 現在のマウスの位置をクリックして、すべての (近くにある) ウィジェットの境界に対して確認します (四分木のように、シーン グラフはここでのみ役立ちます)。

Q: ウィジェットをグリッド上に配置するにはどうすればよいですか?
A: グリッドの配置について、簡単な例を挙げてみましょう。実際の解像度は100pxx 軸上にあり、グリッドの解像度は x 軸のみにしたいとします10px28pxここで、実際の解像度でウィジェットを移動するとします。グリッドの解像度を取得するには、単純に で割り10、 を取得2.8し、丸め、最後にウィジェット3タイルを x に移動します。ここで重要なのは丸めです。グリッドの移動が の場合のみ>= ?.5、次のタイルにスナップします。それ以外の場合は、単純に古いものにとどまります。


これが、フォーム デザイナーを開始する方法についての一般的なヒントになることを願っています。楽しむ。:)
(PS: 特定の WinAPI/MFC 関数/クラスについてはわかりません。申し訳ありません。)

于 2011-04-03T23:20:04.490 に答える
2

@Xeoがすでに言ったことに1つか2つのポイントを追加するだけです:

まず第一に、いいえ、すべてのコンテンツを自分で描くとは限りません通常の設計段階では、基本的にはコントロールのように見えるものを描画するだけですが、(少なくとも IIRC) テスト モードでフォームを「実行」することもできます (確かに VC++ ダイアログ デザイナーは実行します。VB はより原始的でしたが) 、その特定の機能もあったと思います)。テスト モードは、コードを (必然的に) 添付する前にフォームを「実行」できるときでした。ボタンをクリックしても (たとえば)、周囲のプログラムでは何もしませんが、コントロール自体は通常どおり動作します。 -- 通常どおりボタンをクリックすると、編集コントロールで編集できるようになります。

これは、コントロールを実際にインスタンス化し、正しい位置、サイズ、およびプロパティを伝えることによって行われます。ActiveX コントロールはこれをかなりサポートしており、以前の "Windows カスタム コントロール" も同様でしたが、洗練度はかなり劣っていました。コントロールの観点からは、入力の受信、親への通知の送信など、通常とまったく同じように機能しています。変更された唯一のことは、親が受信した通知のほとんどをほとんど無視することですが、コントロールはそうではありません。それはよくわからない。

これを行うには、2 つの基本的な方法があります。1 つは、自分でコントロールのコレクションをその位置、サイズなどとともに作成し、 CreateWindow(またはCreateWindowExなど) を使用して正しいクラスのウィンドウを作成することです。これには、比較的簡単に処理できますが、すべてのタブ処理がユーザーに任されているという欠点があります。

もう 1 つの可能性はDLGTEMPLATE、ダイアログ ボックスに関するデータを保持する構造体とDLGITEMTEMPLATES、個々のコントロールのデータを保持する構造体を作成し、最終的に使用CreateDialogIndirectして、これらの仕様を持つダイアログ ボックスを作成し、それらのコントロールを保持することです。面倒ですが、うまくいきます。完了すると、コントロール間のタブ移動が自動的に処理されます (どちらの方法でも同じ Windows コードで作成されるため、他のダイアログと同じように機能します)。

第 2 に、この C++ にタグを付けたので、実際にダイアログ エディターを実装している CodeProjectのコードを確認することをお勧めします。いくつかの商用のものほど洗練されていませんが、これはかなり完全なフォーム/ダイアログ エディターであり、あなたが求めてきたほとんどの機能を備えています。

于 2011-04-04T02:08:18.727 に答える