Qt是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写所有平台无差别运行更提供了几乎所有开发过程中需要用到的工具。如今Qt已被运用于超过70个行业、数千家企业支持数百万设备及应用。本文将为大家展示如何制作一个带有半透明背景的圆形窗口。将背景设置为半透明的小部件将对所有未绘制的像素透明并且背景将通过不透明度低于100%绘制的像素发光没有绘制的像素也不会接收任何鼠标输入这可用于自定义顶级小部件的形状。在大多数窗口系统中设置某些窗口标志将导致窗口装饰标题栏、窗口框架、按钮被禁用从而允许创建特殊形状的窗口。在这个示例中我们使用这个特性来创建一个包含模拟时钟的圆形窗口。由于这个示例的窗口没有提供File菜单或关闭按钮因此我们提供了一个带有Exit条目的上下文菜单以便可以关闭该示例单击窗口上方的鼠标右键来打开此菜单。ShapedClock类定义ShapedClock类基于AnalogClock示例中定义的AnalogClock类整个类定义如下class ShapedClock : public QWidget { Q_OBJECT public: ShapedClock(QWidget *parent nullptr); QSize sizeHint() const override; protected: void mouseMoveEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void paintEvent(QPaintEvent *event) override; private: QPoint dragPosition; };paintEvent()现在半透明背景时钟面上绘制模拟时钟此外我们实现了sizeHint()这样就不必显示地调整小部件的大小。由于包含时钟小部件的窗口将没有标题栏因此我们提供了mouseMoveEvent()和mousePressEvent()的实现来允许在屏幕上拖动时钟dragPosition变量使我们能够跟踪用户最后单击小部件的位置。ShapedClock类实现ShapedClock构造函数设置一个计时器并将其连接到小部件的update()槽。此外我们向小部件添加了一个操作当右键单击小部件时该操作将通过上下文菜单自动变为可用。ShapedClock::ShapedClock(QWidget *parent) : QWidget(parent, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint) { setAttribute(Qt::WA_TranslucentBackground); QTimer *timer new QTimer(this); connect(timer, QTimer::timeout, this, QOverload::of(ShapedClock::update)); timer-start(1000); QAction *quitAction new QAction(tr(Exit), this); quitAction-setShortcut(tr(CtrlQ)); connect(quitAction, QAction::triggered, qApp, QCoreApplication::quit); addAction(quitAction); setContextMenuPolicy(Qt::ActionsContextMenu); setToolTip(tr(Drag the clock with the left mouse button.\n Use the right mouse button to open a context menu.)); setWindowTitle(tr(Shaped Analog Clock)); }我们通过设置 Qt::WA_TranslucentBackground 小部件属性来请求透明窗口通过在窗口管理器上设置Qt::FramelessWindowHint 标志来通知窗口管理器该窗口不使用窗口框架来装饰。因此我们需要为用户提供一种在屏幕上移动时钟的方法。鼠标按钮事件被传递给mousePressEvent()处理程序void ShapedClock::mousePressEvent(QMouseEvent *event) { if (event-button() Qt::LeftButton) { dragPosition event-globalPosition().toPoint() - frameGeometry().topLeft(); event-accept(); } }如果在小部件上按下鼠标左键我们将以全局屏幕坐标记录小部件框架的左上角位置即使隐藏时与鼠标单击发生点之间的位移。如果用户按住左键移动鼠标将使用此位移。由于我们对事件进行了操作因此通过调用它的accept()函数来接受它。如果鼠标移动到小部件上则调用mouseMoveEvent()处理程序。void ShapedClock::mouseMoveEvent(QMouseEvent *event) { if (event-buttons() Qt::LeftButton) { move(event-globalPosition().toPoint() - dragPosition); event-accept(); } }如果在移动鼠标时按住左键则小部件的左上角将移动到通过从全局坐标中的当前光标位置减去dragPosition给出的位置。如果我们拖动小部件也接受事件。paintEvent()函数主要与模拟时钟示例中描述的相同另外我们使用QPainter::drawEllipse()来绘制一个圆形的钟面将画笔的不透明度降低到90%并使用调色板的默认背景色。void ShapedClock::paintEvent(QPaintEvent *) { static const QPoint hourHand[4] { QPoint(5, 14), QPoint(-5, 14), QPoint(-4, -71), QPoint(4, -71) }; static const QPoint minuteHand[4] { QPoint(4, 14), QPoint(-4, 14), QPoint(-3, -89), QPoint(3, -89) }; static const QPoint secondsHand[4] { QPoint(1, 14), QPoint(-1, 14), QPoint(-1, -89), QPoint(1, -89) }; const QColor hourColor(palette().color(QPalette::Text)); const QColor minuteColor(palette().color(QPalette::Text)); const QColor secondsColor(palette().color(QPalette::Accent)); int side qMin(width(), height()); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.translate(width() / 2, height() / 2); painter.scale(side / 200.0, side / 200.0); painter.setPen(Qt::NoPen); painter.setBrush(palette().window()); painter.setOpacity(0.9); painter.drawEllipse(QPoint(0, 0), 98, 98); painter.setOpacity(1.0); QTime time QTime::currentTime(); painter.setPen(Qt::NoPen); painter.setBrush(hourColor); painter.save(); painter.rotate(30.0 * ((time.hour() time.minute() / 60.0))); painter.drawConvexPolygon(hourHand, 4); painter.restore(); for (int i 0; i 12; i) { painter.drawRect(73, -3, 16, 6); painter.rotate(30.0); } painter.setBrush(minuteColor); painter.save(); painter.rotate(6.0 * time.minute()); painter.drawConvexPolygon(minuteHand, 4); painter.restore(); painter.setBrush(secondsColor); painter.save(); painter.rotate(6.0 * time.second()); painter.drawConvexPolygon(secondsHand, 4); painter.drawEllipse(-3, -3, 6, 6); painter.drawEllipse(-5, -68, 10, 10); painter.restore(); painter.setPen(minuteColor); for (int j 0; j 60; j) { painter.drawLine(92, 0, 96, 0); painter.rotate(6.0); } }最后为小部件实现sizeHint()以便在它第一次显示时给出一个合理的默认大小QSize ShapedClock::sizeHint() const { return QSize(200, 200); }