Skip to content

Instantly share code, notes, and snippets.

@ydm
Last active December 22, 2015 03:39
Show Gist options
  • Save ydm/6411957 to your computer and use it in GitHub Desktop.
Save ydm/6411957 to your computer and use it in GitHub Desktop.
Python translation of Qxt (Qt extension framework) tooltips. More information about LibQxt and QxToolTip refer to http://dev.libqxt.org/libqxt/wiki/Home
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from __future__ import print_function
from __future__ import unicode_literals
import sys
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt
# This is a Python translation of qxttooltip: http://dev.libqxt.org/libqxt/
class ToolTipPrivate(QtGui.QWidget):
FLAGS = Qt.ToolTip
def __init__(self):
app = QtGui.QApplication.instance()
super(ToolTipPrivate, self).__init__(app.desktop(), self.FLAGS)
self.currentParent = None
self.currentRect = QtCore.QRect()
self.tooltips = {}
self.setWindowFlags(self.FLAGS)
self.vbox = QtGui.QVBoxLayout(self)
self.setPalette(self.palette())
self.setWindowOpacity(
self.style().styleHint(
QtGui.QStyle.SH_ToolTipLabel_Opacity, None, self
) / 255.0
)
self.layout().setMargin(self.style().pixelMetric(
QtGui.QStyle.PM_ToolTipLabelFrameWidth, None, self
))
def show(self, pos, tooltip, parent, rect):
assert tooltip and parent, \
'Bad values: tooltip={}, parent={}'.format(tooltip, parent)
if not self.isVisible():
if QtGui.QApplication.desktop().isVirtualDesktop():
scr = QtGui.QApplication.desktop().screenNumber(pos)
else:
scr = QtGui.QApplication.desktop().screenNumber(self)
self.setParent(QtGui.QApplication.desktop().screen(scr))
self.setWindowFlags(self.FLAGS)
self.setToolTip(tooltip)
self.currentParent = parent
self.currentRect = rect
self.move(self.calculatePos(scr, pos))
super(ToolTipPrivate, self).show()
def setToolTip(self, tooltip):
for i in range(self.vbox.count()):
item = self.layout().takeAt(i)
if item.widget():
item.widget().hide()
self.vbox.addWidget(tooltip)
tooltip.show()
def enterEvent(self, event):
self.hideLater()
def paintEvent(self, event):
return super(ToolTipPrivate, self).paintEvent(event)
# Use Qxt's implementation and feel the mysticism of C++
painter = QtGui.QStylePainter()
opt = QtGui.QStyleOptionFrame()
opt.initFrom(self)
painter.drawPrimitive(QtGui.QStyle.PE_PanelTipLabel, opt)
def hideLater(self):
self.currentRect = QtCore.QRect()
if self.isVisible():
QtCore.QTimer.singleShot(0, self.hide)
def calculatePos(self, scr, eventPos):
if sys.platform == 'darwin':
screen = QtGui.QApplication.desktop().availableGeometry(scr)
else:
screen = QtGui.QApplication.desktop().screenGeometry(scr)
p = eventPos + QtCore.QPoint(2, 24 if sys.platform == 'win32' else 16)
s = self.sizeHint()
if p.x() + s.width() > screen.x() + screen.width():
p.setX(p.x() - (4 + s.width()))
if p.y() + s.height() > screen.y() + screen.height():
p.setY(p.y() - (24 + s.height()))
if p.y() < screen.y():
p.setY(screen.y())
if p.x() + s.width() > screen.x() + screen.width():
p.setX(screen.x() + screen.width() - s.width())
if p.x() < screen.x():
p.setX(screen.x())
if p.y() + s.height() > screen.y() + screen.height():
p.setY(screen.y() + screen.height() - s.height())
return p
class ToolTip(QtCore.QObject):
_instance = None
@classmethod
def instance(cls):
if cls._instance is None:
cls._instance = ToolTip()
return cls._instance
def __init__(self):
self.tooltips = {}
self.tooltipInstance = ToolTipPrivate()
super(ToolTip, self).__init__()
app = QtGui.QApplication.instance()
app.installEventFilter(self)
def eventFilter(self, obj, event):
t = event.type()
if t in (QtCore.QEvent.KeyPress, QtCore.QEvent.KeyRelease):
pass # TODO
elif t in (QtCore.QEvent.Leave,
QtCore.QEvent.WindowActivate,
QtCore.QEvent.WindowDeactivate,
QtCore.QEvent.MouseButtonPress,
QtCore.QEvent.MouseButtonRelease,
QtCore.QEvent.MouseButtonDblClick,
QtCore.QEvent.FocusIn,
QtCore.QEvent.FocusOut,
QtCore.QEvent.Wheel):
self.tooltipInstance.hideLater()
elif t == QtCore.QEvent.MouseMove:
pos = event.pos()
if (not self.tooltipInstance.currentRect.isNull()
and not self.tooltipInstance.currentRect.contains(pos)):
self.tooltipInstance.hideLater()
elif t == QtCore.QEvent.ToolTip:
if obj in self.tooltips:
tooltip, area = self.tooltips[obj]
if area.isNull() or area.contains(event.pos()):
self.show(event.globalPos(), tooltip, obj, area)
# return super(ToolTip, self).eventFilter(obj, event)
return False
def show(self, pos, tooltip, parent, rect):
if rect is None:
rect = QtCore.QRect()
self.tooltipInstance.show(pos, tooltip, parent, rect)
def hide(self):
self.tooltipInstance.hide()
def setToolTip(self, parent, tooltip, rect=None):
assert parent
if tooltip:
# Set
tooltip.hide()
self.tooltips[parent] = (tooltip,
QtCore.QRect() if rect is None else rect)
else:
# Remove
if parent not in self.tooltips:
print(
'Warning! parent {} not in ToolTipPrivate.tooltips dict'.
format(parent),
file=sys.stderr
)
else:
del self.tooltips[parent]
def main():
class Window(QtGui.QWidget):
def __init__(self):
""""""
super(Window, self).__init__()
self.resize(400, 100)
self.initUi()
def onButton1Click(self):
ToolTip.instance().hide()
def onButton2Click(self):
pass
def initUi(self):
layout = QtGui.QVBoxLayout()
button1 = QtGui.QPushButton('Hello!')
button1.clicked.connect(self.onButton1Click)
button2 = QtGui.QPushButton('World!')
button2.clicked.connect(self.onButton2Click)
ToolTip.instance().setToolTip(
button1, QtGui.QLabel('Clicking me should hide this tooltip!'))
ToolTip.instance().setToolTip(
button2, QtGui.QLabel('Clicking me shouldn\'t do anything'))
layout.addWidget(button1)
layout.addWidget(button2)
self.setLayout(layout)
app = QtGui.QApplication(sys.argv)
w = Window()
w.show()
app.exec_()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment