Auf dieser Seite

Durchscheinender Hintergrund

Das Beispiel zeigt, wie man ein rundes Fenster mit einem durchscheinenden Hintergrund erstellt.

Durchsichtige Uhr, die über den Text gelegt ist

Widgets, deren Hintergrund als durchscheinend festgelegt ist, sind für alle nicht gezeichneten Pixel transparent, und der Hintergrund scheint durch Pixel hindurch, die mit einer Deckkraft von weniger als 100 % gezeichnet wurden. Pixel, die überhaupt nicht gezeichnet werden, erhalten auch keine Mauseingaben. Dies kann genutzt werden, um die Formen von Widgets der obersten Ebene anzupassen. Bei den meisten Fenstersystemen führt das Setzen bestimmter Fensterflags dazu, dass die Fensterdekoration (Titelleiste, Fensterrahmen, Schaltflächen) deaktiviert wird, wodurch Fenster mit speziellen Formen erstellt werden können. In diesem Beispiel nutzen wir diese Funktion, um ein kreisförmiges Fenster zu erstellen, das eine Analoguhr enthält.

Da das Fenster in diesem Beispiel weder über ein Menü „ File “ noch über eine Schaltfläche zum Schließen verfügt, stellen wir ein Kontextmenü mit dem Eintrag „ Exit “ bereit, damit das Beispiel geschlossen werden kann. Klicken Sie mit der rechten Maustaste auf das Fenster, um dieses Menü zu öffnen.

Definition der Klasse „ShapedClock“

Die Klasse „ ShapedClock “ basiert auf der im Beispiel „Analog Clock “ definierten Klasse „ AnalogClock “. Die vollständige Klassendefinition ist nachfolgend aufgeführt:

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;
};

Die Implementierung von ` paintEvent()` zeichnet eine analoge Uhr auf einem halbtransparenten Hintergrund (dem Zifferblatt). Zusätzlich implementieren wir ` sizeHint()`, damit wir die Größe des Widgets nicht explizit anpassen müssen.

Da das Fenster, das das Uhr-Widget enthält, keine Titelleiste hat, stellen wir Implementierungen für ` mouseMoveEvent()` und ` mousePressEvent()` bereit, damit die Uhr auf dem Bildschirm verschoben werden kann. Mit der Variablen ` dragPosition ` können wir verfolgen, wo der Benutzer zuletzt auf das Widget geklickt hat.

Implementierung der Klasse `ShapedClock`

Der Konstruktor „ ShapedClock “ richtet einen Timer ein und verbindet ihn mit dem Slot „update()“ des Widgets. Außerdem fügen wir dem Widget eine Aktion hinzu, die automatisch über ein Kontextmenü verfügbar wird, wenn man mit der rechten Maustaste auf das Widget klickt.

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("E&xit"), this);
    quitAction->setShortcut(tr("Ctrl+Q"));
    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"));
}

Wir fordern ein transparentes Fenster an, indem wir das Widget-Attribut „ Qt::WA_TranslucentBackground “ setzen. Wir teilen dem Fenstermanager mit, dass das Widget nicht mit einem Fensterrahmen versehen werden soll, indem wir das Flag „ Qt::FramelessWindowHint “ für das Widget setzen. Daher müssen wir dem Benutzer eine Möglichkeit bieten, die Uhr auf dem Bildschirm zu verschieben.

Mausklick-Ereignisse werden an den Handler „ mousePressEvent() “ weitergeleitet:

void ShapedClock::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        dragPosition = event->globalPosition().toPoint() - frameGeometry().topLeft();
        event->accept();
    }
}

Wird die linke Maustaste über dem Widget gedrückt, erfassen wir die Verschiebung in globalen (Bildschirm-)Koordinaten zwischen der Position oben links am Rahmen des Widgets (auch wenn dieser ausgeblendet ist) und dem Punkt, an dem der Mausklick erfolgte. Diese Verschiebung wird verwendet, wenn der Benutzer die Maus bewegt, während er die linke Taste gedrückt hält. Da wir auf das Ereignis reagiert haben, akzeptieren wir es durch Aufruf der Funktion ` accept()`.

Die Position des Schiebers relativ zum Zifferblatt

Der ` mouseMoveEvent() `-Handler wird aufgerufen, wenn die Maus über das Widget bewegt wird.

void ShapedClock::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        move(event->globalPosition().toPoint() - dragPosition);
        event->accept();
    }
}

Wird die linke Maustaste während der Bewegung gedrückt gehalten, wird die obere linke Ecke des Widgets an die Position verschoben, die sich ergibt, wenn „ dragPosition “ von der aktuellen Cursorposition in globalen Koordinaten abgezogen wird. Wenn wir das Widget ziehen, nehmen wir das Ereignis ebenfalls an.

Die Funktion „ paintEvent() “ entspricht im Wesentlichen der im Beispiel „Analog Clock“ beschriebenen. Die einzige Ergänzung besteht darin, dass wir mit „ QPainter::drawEllipse()“ ein rundes Zifferblatt zeichnen. Wir reduzieren die Deckkraft des Zeichners auf 90 % und verwenden die Standard-Hintergrundfarbe der Palette.

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);

    {
        QPainterStateGuard guard(&painter);
        painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
        painter.drawConvexPolygon(hourHand, 4);
    }

    for (int i = 0; i < 12; ++i) {
        painter.drawRect(73, -3, 16, 6);
        painter.rotate(30.0);
    }

    painter.setBrush(minuteColor);

    {
        QPainterStateGuard guard(&painter);
        painter.rotate(6.0 * time.minute());
        painter.drawConvexPolygon(minuteHand, 4);
    }

    painter.setBrush(secondsColor);

    {
        QPainterStateGuard guard(&painter);
        painter.rotate(6.0 * time.second());
        painter.drawConvexPolygon(secondsHand, 4);
        painter.drawEllipse(-3, -3, 6, 6);
        painter.drawEllipse(-5, -68, 10, 10);
    }

    painter.setPen(minuteColor);

    for (int j = 0; j < 60; ++j) {
        painter.drawLine(92, 0, 96, 0);
        painter.rotate(6.0);
    }
}

Abschließend implementieren wir die Funktion ` sizeHint() ` für das Widget, damit es beim ersten Anzeigen eine angemessene Standardgröße erhält:

QSize ShapedClock::sizeHint() const
{
    return QSize(200, 200);
}

Beispielprojekt @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.