いわゆるオブジェクトにカーソルがあたるとHelpが表示される「Tooltip」ですが
PySideデフォルトのTooltipは非常に使いにくいので、自前で作ってみます。
実行結果はこんな感じになります。
やりたい事は、
- 指定のItem範囲にマウスカーソルが入ったら
- painterで作った描画のTooltipを表示して
- 範囲外にでたら消す
ようにします。
大分コードが長いですが、せっかくなので全部貼り。
とりあえず全コード貼ると長いので全部は
https://snippets.cacher.io/snippet/c58f263509ee12c0155f
ここにUPしました。
今回は主にカスタムTooltip部分と、Item部分をまとめ。
上のコードのうち、ポイントになるのが表示されるTooltip部分。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 | class MyPopup(QtWidgets.QDialog):
def __init__(self, text="", width=200, height=100, positionOffset=10, parent=None):
super(MyPopup, self).__init__(parent)
self._text = text
self.color = [0, 0, 255]
self.tooltipWidth = width
self.tooltipHeight = height
self.positionOffset = positionOffset
# 枠を消して、透明にする
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.positionUpdate()
def setText(self, text):
self._text = text
self.update()
def getText(self):
return self._text
def positionUpdate(self):
pos = QtGui.QCursor().pos()
self.setGeometry(pos.x() + self.positionOffset,
pos.y() + self.positionOffset,
self.tooltipWidth,
self.tooltipHeight)
def paintEvent(self, event):
painter = QtGui.QPainter(self)
pen = QtGui.QPen(QtGui.QColor(*self.color), 8)
bg_color = QtGui.QColor(*self.color)
painter.setPen(pen)
painter.setBrush(bg_color)
rect = QtCore.QRect(0, 0, self.geometry().width(), self.geometry().height())
painter.drawRoundedRect(rect, 20, 20)
# 文字を描画
painter.setFont(QtGui.QFont(u'メイリオ', 20, QtGui.QFont.Bold, False))
painter.setPen(QtCore.Qt.white)
painter.drawText(QtCore.QPoint(10, 30), self.getText())
|
このポイントは setWindowFlagsで設定している QtCore.Qt.FramelessWindowHint と、
ウィンドウを透明にする QtCore.Qt.WA_TranslucentBackground の2つです。
試しにこの2つをOFFにすると
こんな感じになってしまい、非常に残念な感じになってしまいます。
もう1つのポイントはウィンドウを表示する位置について。
ウィンドウ位置は setGeometry() で指定できるのですが、これをマウスカーソル位置とイコールにすると
作成したUI側にフォーカスが移ってしまうらしく、色々と挙動がおかしくなります。
ので、ある程度マウスから外した所にだしたほうが安全です。
Itemを作る
次に GraphicsItemを継承したカスタムのItemを作ります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 | class BaseNodeItem(QtWidgets.QGraphicsItem):
def __init__(self, parent=None):
super(BaseNodeItem, self).__init__(parent)
self._width = 200
self._height = 100
self.color = [255, 0, 0]
self.tooltip = None
self.tooltipText = "hogehoge"
self.setAcceptHoverEvents(True)
self.setFlags(self.ItemIsSelectable | self.ItemIsMovable)
def boundingRect(self):
return QtCore.QRectF(0.0, 0.0, self._width, self._height)
def paint(self, painter, option, widget):
margin = 20
rect = self.boundingRect()
dis_rect = QtCore.QRectF(rect.left() - (margin / 2),
rect.top() - (margin / 2),
rect.width() + margin,
rect.height() + margin)
pen = QtGui.QPen(QtGui.QColor(*self.color), 8)
bg_color = QtGui.QColor(*self.color)
painter.setPen(pen)
painter.setBrush(bg_color)
painter.drawRoundedRect(dis_rect, 5, 5)
def hoverEnterEvent(self, e):
self.tooltip = MyPopup("hogehogefugafuga", parent=self.window())
self.tooltip.show()
def hoverMoveEvent(self, e):
if self.tooltip is not None:
self.tooltip.positionUpdate()
def hoverLeaveEvent(self, e):
self.tooltip.close()
self.tooltip = None
|
こちらのポイントは hover###Event になっている3つ。
その名の通り、マウスがItemの上に入った時・入ってる間・出たときに呼ばれる関数です。
ので、
- 入った時にPopup用Windowを作り
- 入ってる間Positionを更新し
- 出たら閉じる
ようにします。
ですが、これだけだとHoverイベントが発生してくれないので
| self.setAcceptHoverEvents(True)
|
HoverEventをOnにしてあげます。
今回はテスト用なのでものすごいアレなPopupですが、
paintEvent内でちゃんと描画さえ書いてあげれば表示までのラグなどもなく
好きな感じでToolTipを出せるようになります。
ついでに、枠消してカスタム描画なUIも同じような方法で作れるので
いわゆる普通のWindowsのUIからも卒業できそう。
参考