Reputation: 3222
I'm working on a GUI application using Python 2.7 and PySide (Qt wrapper).
I want to have callout widgets floating above other widgets (similar to tool tips), but without using the standard tooltip framework, which basically assigns a tool tip for a widget and displays it on hover.
I would like to initiate their display and control position (relative to the widget below), size, and content on the fly as well as destroy them.
Is it possible to simply override a basic QWidget and show it on top of the application?
Upvotes: 1
Views: 253
Reputation: 3222
After asking here and looking at a lot of other places, I found that this can be implemented using a simple QWidget subclass which is shown as a top level window, without a frame and using some QRegion tricks to create the callout.
Here is the code I created, in case someone needs something like that:
from PySide.QtCore import *
from PySide.QtGui import *
import sys
def createMask(size):
w=size.width()
h=size.height()
img=QImage(size, QImage.Format_MonoLSB)
qp=QPainter()
qp.begin(img)
qp.fillRect(QRect(QPoint(0, 0), size), QColor(255,255,255))
path=QPainterPath()
path.moveTo(0, h-1)
path.lineTo(w-1,0)
path.lineTo(h-1, 0)
path.lineTo(0, h-1)
qp.fillPath(path, QBrush(QColor(0, 0, 0)))
qp.end()
return img
def createRoundedRectRegion(rect, radius):
r=QRegion(rect.adjusted(radius, 0, -radius, 0))
r|=QRegion(rect.adjusted(0, radius, 0, -radius))
r|=QRegion(rect.left(), rect.top(), 2*radius, 2*radius, QRegion.Ellipse)
r|=QRegion(rect.right()-2*radius, rect.top(), 2*radius, 2*radius, QRegion.Ellipse)
r|=QRegion(rect.left(), rect.bottom()-2*radius, 2*radius, 2*radius, QRegion.Ellipse)
r|=QRegion(rect.right()-2*radius, rect.bottom()-2*radius, 2*radius, 2*radius, QRegion.Ellipse)
return r
def createRegion(bubbleSize, pointSize, offset):
r=createRoundedRectRegion(QRect(QPoint(0, 0), bubbleSize), 10)
t=QRegion(QPixmap(createMask(pointSize)))
t.translate(offset, bubbleSize.height())
r|=t
return r
class Callout(QWidget):
def __init__(self, text, parent=None):
super(Callout, self).__init__(parent)
w=100+len(text)*5
self.setMinimumSize(w, 100)
self.setMaximumSize(w, 100)
self.text=text
self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setMask(createRegion(QSize(w, 50), QSize(75, 50), 75))
def paintEvent(self, event):
qp=QPainter()
qp.begin(self)
qp.fillRect(0, 0, self.width(), 200, QColor(192, 192, 192))
qp.drawText(QRect(0, 0, self.width(), 50), Qt.AlignCenter, self.text)
qp.end()
def main():
app=QApplication(sys.argv)
w=Callout('Bla Bla Bla')
w.move(200, 100)
w.show()
app.exec_()
if __name__ == '__main__':
main()
Upvotes: 1