QListViewに右クリックメニューを作る!!

QListViewなどView系を使っていると、このViewに右クリックメニューを追加したい!っと思うことが多々あります。シンプルですが、こんな感じかと思います。

こんな風にできると、コピーや、削除といったことがやりやすくなりますねっ!(*´ω`*)

早速、QListViewをベースにご紹介したいと思います!(`・ω・´)ゞ

クラスの骨格

まずは、QListViewを継承したクラスを用意します。

from PySide import QtCore
from PySide import QtGui

class ListView(QtGui.QListView):
	def __init__(self, *args, **kwargs):
		super(ListView, self).__init__(*args, **kwargs)

右クリックメニューを追加する準備

QListViewなどに右クリックメニューを追加するポイントなのが「setContextMenuPolicy」です。PySide(Qt)では、右クリックメニューのことを「ContextMenu」と言います。

setContextMenuPolicy」に「QtCore.Qt.CustomContextMenu」を設定すると「オリジナルのメニューを使うぜ!」っとなります。

from PySide import QtCore
from PySide import QtGui

class ListView(QtGui.QListView):
	def __init__(self, *args, **kwargs):
		super(ListView, self).__init__(*args, **kwargs)
		
		self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)

次に、CustomContextMenuの処理を追加します。これはSignal&Slotで実装することができちゃいます(*´ω`*)

右クリックメニューのSignalは「customContextMenuRequested」になります。引数に、マウスの右クリックされた位置が渡されます。

from PySide import QtCore
from PySide import QtGui

class ListView(QtGui.QListView):
	def __init__(self, *args, **kwargs):
		super(ListView, self).__init__(*args, **kwargs)
		
		self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
		self.customContextMenuRequested.connect(self.contextMenu)
		
	def contextMenu(self, point):
		pass

右クリックメニューの実装

ここでは、for文を使って、簡単に5つのメニュー項目を作ります。QMenuのインスタンスを作り、addActionするのが簡単かと思います。メニューの作り方は通常のメニューづくりと同じです。

from PySide import QtCore
from PySide import QtGui

class ListView(QtGui.QListView):
	def __init__(self, *args, **kwargs):
		super(ListView, self).__init__(*args, **kwargs)
		
		self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
		self.customContextMenuRequested.connect(self.contextMenu)
		
	def contextMenu(self, point):
		menu = QtGui.QMenu(self)
		
		for i in range(5):
			action = QtGui.QAction('Menu%s' % i, self)
			menu.addAction(action)
		
		menu.exec_(self.mapToGlobal(point))

最後が今まで違うメニュー作りになります。

まず、QMenuの「exec_()」を実行しないと表示されません。。。その時に、表示する位置を指定するわけなのですが、引数で渡された位置「pos」は、座標がローカル空間?なので、位置がズレてしまいます。(;´∀`)

View系の「mapToGlobal」を使ってグローバル空間に変換すると位置がズレなくなります!

ちなみに、、、

「menu.exec_()」ではなく、「menu.show()」を使うと、表示する位置が思ったところに来ませんのでご注意ください(;´∀`)