我正在使用 Python 2.7 和 PySide(Qt 包装器)开发一个 GUI 应用程序。
我想让标注小部件浮动在其他小部件上方(类似于工具提示),但不使用标准工具提示框架,该框架基本上为小部件分配工具提示并在悬停时显示它。
我想即时启动它们的显示和控制位置(相对于下面的小部件)、大小和内容,并销毁它们。
是否可以简单地覆盖基本的 QWidget 并将其显示在应用程序之上?
在这里询问并查看了很多其他地方之后,我发现这可以使用一个简单的 QWidget 子类来实现,该子类显示为顶级窗口,没有框架并使用一些 QRegion 技巧来创建标注。
这是我创建的代码,以防有人需要这样的东西:
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()