忘却まとめ

Blenderの中級者・上級者向けの踏み込んだ情報や、アドオン・3DCGに関する情報を記事にします

ポップアップメニューの作り方 / 常に指定位置・マウス相対位置に表示する方法【Blenderアドオン開発 / Python / invoke_props_dialog】

Python

投稿日:

invoke_props_dialog()とマウスの事前移動を利用して、ポップアップメニューを常に指定位置・マウス相対位置に表示する方法を紹介する。

相対位置で、マウスの位置とかぶらないようにメニューを表示したり、
絶対位置で、作業の邪魔にならない画面端にメニューを表示したりすることができる。

Blenderのポップアップメニュー表示方法

Blenderのポップアップメニューには、 invoke_props_dialog() とinvoke_popup()がある。
それぞれ Operator の invoke の return に渡すことで、 draw に用意されたメニューが、マウス位置に表示される。

  • invoke_props_dialog()
    • OKボタンが下に表示され、OKをクリックするとexecuteが実行される。
    • オプションを調整してからなんらかの処理を実行する、という機能に便利。
  • invoke_popup()
    • マウスを画面外から離すとすぐに消える。
    • メニューを表示した後、楽に閉じたいときに便利。

ソースコード

ポップアップメニューはマウス位置に表示されるので、そのマウス位置を実行前に動かせば、メニューが表示される位置を変えることができる。
表示した後に1度だけ、マウスを元の位置に戻す処理を入れればよい。

(マウス位置が変わるので、invoke_popupにはこの方法は利用できない)

  • マウスからの相対位置
    • マウス位置を基準としたオプションの値の位置に出現させます。
  • ウィンドウからの絶対位置
    • X位置は、アクティブなエディターの左端からの位置です。
    • Y位置は、ウィンドウ全体からの位置です。
    • (X0としてもポップアップ画面が端に食い込むようにはなりません)
    • (Y位置はポップアップ画面の縦幅によっては変わります)
import bpy
from bpy.props import *
from bpy.types import Panel, Operator
 

class MISCMENU_OT_main(Operator):
	bl_idname = "miscmenu.misc_menu"
	bl_label = "Misc Menu"
	bl_description = ""
	bl_options = {'REGISTER', 'UNDO'}

	items = [
	("MOUSE","Mouse Position",""),
	("MOUSE_RELATIVE","Mouse Relative",""),
	("WINDOW_ABSOLUTE","Window Absolute","The X position is from the left edge of the active editor.\nY position is the position from the whole window"),
	]
	window_position : EnumProperty(default="WINDOW_ABSOLUTE",name="Window Position",items= items)
	loc_x : IntProperty(name="X Location",default=300)
	loc_y : IntProperty(name="Y Location",default=600)
	menu_width         : IntProperty(default=330, name = "Menu Width", description = "Width setting when menu layout is broken. \n Blender Settings-> Interface-> If 'Resolution Scale' is set to a value smaller than 1,\n  icons may be squished together so closely",min = 0)


	def invoke(self, context, event):

		# マウス位置を保存
		self.mouse_snap = False
		self.old_mouse_x = event.mouse_x
		self.old_mouse_y = event.mouse_y

		# アクティブエリアのサイズ
		a = bpy.context.area
		for r in a.regions:
			if r.type == 'WINDOW':
				win_x = r.x
				win_y = r.y
				break


		# マウスからの相対位置
		if self.window_position == "MOUSE_RELATIVE":
			bpy.context.window.cursor_warp(event.mouse_x + self.loc_x,event.mouse_y + self.loc_y)


		# Xは、エディター左上からの絶対位置
		# Yは、ウィンドウからの絶対位置(エディターのY位置の取得方法がわからなかった)
		elif self.window_position == "WINDOW_ABSOLUTE":
			bpy.context.window.cursor_warp(win_x + self.loc_x, bpy.context.window.height - self.loc_y)


		return context.window_manager.invoke_props_dialog(self, width=self.menu_width)


	def draw(self, context):
		ad_prefs = preference()
		if ad_prefs.use_dialog:
			if not self.mouse_snap: # 描画開始の最初だけ実行し、マウス位置を元に戻す
				self.mouse_snap = True
				bpy.context.window.cursor_warp(self.old_mouse_x, self.old_mouse_y)

		main_menu(self, context)


	def execute(self, context):
		return {'FINISHED'}

アドオンの制作依頼はこちら

-Python

Copyright© 忘却まとめ , 2022 All Rights Reserved Powered by STINGER.