5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

OpenSiv3D で Windows のポップアップメニューを表示したい

Posted at

概要

OpenSiv3D で、Windows のポップアップメニュー(コンテキストメニュー/ショートカットメニュー)を表示し、クリックされた項目を取得します。

image.png

開発環境

  • Windows 11
  • Visual Studio 2022
  • OpenSiv3D 0.6.11

どうやるか

OpenSiv3D には Windows のメニューを扱う機能がないので、Win32API を使います。

メニューを表示する基本的な流れは次のとおりです:

  • LoadMenu 関数で、リソースからメニューをロードする
  • GetSubMenu 関数でサブメニューを取得する
  • TrackPopupMenu 関数でメニューを表示する

ただし、OpenSiv3D アプリは次のようにスレッドが分かれています:

  • THREAD #0: ウィンドウプロシージャが実行されるスレッド
  • THREAD #1: Main 関数が実行されるスレッド(メインスレッド)

(参照:https://github.com/Siv3D/OpenSiv3D/blob/main/Siv3D/src/Siv3D-Platform/WindowsDesktop/Siv3D/Siv3DMain.cpp

そのためか、メインスレッドからの TrackPopupMenu の実行は失敗してしまいます。

なので、メニューのロード~表示までの一連の流れをウィンドウプロシージャのスレッドで行うことにします。具体的な流れは、次のようになります:

  1. SetWindowLongPtr 関数で、ウィンドウプロシージャを自前のものに変更する
  2. メニューを表示したいときは、あらかじめ決めておいたメッセージ(WM_USER + 適当な数値 など)をウィンドウに送る。ウィンドウプロシージャはそのメッセージを受けてメニューのロード~表示を行う
  3. メニューがクリックされると、ウィンドウプロシージャに WM_COMMAND メッセージが送られる。ウィンドウプロシージャは PostThreadMessage 関数でその内容をメインスレッドに送る
  4. メインスレッドでは 3. で送られたメッセージを GetMessage 関数で取得する

ソースコード

メニューの編集方法

Visual Studio のリソースビューからメニューリソースを編集する際、OpenSiv3D のプロジェクトにはじめから入っている Resource.rc に対してメニューを追加すると、もともとの内容がぐちゃぐちゃになってしまうので(何かやりかたが悪い?)、メニュー用に Resource2.rc などとして別ファイルを追加して、これを編集するのが良いと思います。

image.png

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?