Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building a Customizable Mini Clock Widget with Qt

Tech May 17 1

Window Structure Analysis

Creating miniature widgets like those found in trading platforms requires understanding three core components:

  • Window Frame: The outer boundary that enables resizing functionality
  • Title Bar: Custom implementation replacing native Windows title bar
  • Client Area: The content region where custom widget are displayed

Interactive Window Resizing

The key to creating resizable mini-widgets lies in overriding mouse event handlers to detect edge interactions and modify window dimensions accordingly.

class ResizableWidget : public QWidget {
protected:
    void mousePressEvent(QMouseEvent* event) override;
    void mouseMoveEvent(QMouseEvent* event) override;
    void mouseReleaseEvent(QMouseEvent* event) override;
};

Cursor State Management

Determining weather the cursor is positioned over a resizeable edge requires checking boundary conditions:

void CustomWidget::updateEdgeDetection(const QPoint& mousePos) {
    QRect widgetRect = rect();
    int edgeThreshold = 5;
    
    bool atLeft = mousePos.x() <= edgeThreshold;
    bool atRight = mousePos.x() >= widgetRect.width() - edgeThreshold;
    bool atTop = mousePos.y() <= edgeThreshold;
    bool atBottom = mousePos.y() >= widgetRect.height() - edgeThreshold;
    
    // Corner detection combinations
    topLeftCorner = atTop && atLeft;
    topRightCorner = atTop && atRight;
    bottomLeftCorner = atBottom && atLeft;
    bottomRightCorner = atBottom && atRight;
    
    canResize = atLeft || atRight || atTop || atBottom;
}

Dynamic Cursor Appearance

Based on edge detection results, the cursor appearance changes to indicate available resize directions:

void CustomWidget::adjustCursor(const QPoint& position) {
    updateEdgeDetection(position);
    
    if (topLeftCorner || bottomRightCorner) {
        setCursor(Qt::SizeFDiagCursor);
    } else if (topRightCorner || bottomLeftCorner) {
        setCursor(Qt::SizeBDiagCursor);
    } else if (atLeft || atRight) {
        setCursor(Qt::SizeHorCursor);
    } else if (atTop || atBottom) {
        setCursor(Qt::SizeVerCursor);
    } else {
        unsetCursor();
    }
}

Window Dimension Adjustment

Resizing calculations use the initial press position as reference point to maintain consistent behavior:

void CustomWidget::handleResize(QMouseEvent* event) {
    QPoint currentGlobal = event->globalPos();
    QPoint offset = currentGlobal - pressStartPosition;
    
    QRect newGeometry = initialGeometry;
    
    if (atLeft) newGeometry.setLeft(newGeometry.left() + offset.x());
    if (atRight) newGeometry.setRight(newGeometry.right() + offset.x());
    if (atTop) newGeometry.setTop(newGeometry.top() + offset.y());
    if (atBottom) newGeometry.setBottom(newGeometry.bottom() + offset.y());
    
    setGeometry(newGeometry);
}

Clock Display Implementation

The clock widget features dynamic text scaling based on window size using QPainter transformations.

Layout Structure

A simple vertical arrangement contains the time display and date information:

// Create separator line
QFrame* separator = new QFrame();
separator->setFrameShape(QFrame::HLine);
separator->setStyleSheet("color: #474F57;");

// Setup layout
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(timeDisplay);
layout->addWidget(separator);
layout->addWidget(dateDisplay);
setLayout(layout);

Scalable Text Rendering

The core innovation uses scene transformation to achieve smooth font scaling:

void ScalableTextLabel::paintEvent(QPaintEvent* event) {
    QWidget::paintEvent(event);
    
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    
    QFont font = painter.font();
    font.setPixelSize(14);
    painter.setFont(font);
    
    // Calculate optimal scale factor
    double scaleFactor = qMin(width(), height()) / 100.0;
    
    // Center and scale drawing area
    painter.translate(width() / 2, height() / 2);
    painter.scale(scaleFactor, scaleFactor);
    
    // Measure text dimensions
    int textWidth = painter.fontMetrics().horizontalAdvance(displayText);
    int textHeight = painter.fontMetrics().height();
    
    // Draw centered text
    QRect textRect(-textWidth/2, -textHeight/2, textWidth, textHeight);
    painter.drawText(textRect, displayText);
}

Real-time Updates

A timer updates the display every second with current time information:

// Initialize update timer
QTimer* updateTimer = new QTimer(this);
connect(updateTimer, &QTimer::timeout, this, &ClockWidget::refreshTime);
updateTimer->start(1000);

void ClockWidget::refreshTime() {
    QDateTime currentTime = QDateTime::currentDateTime();
    
    // Update time display
    timeLabel->setText(currentTime.toString("HH:mm:ss"));
    
    // Update date display  
    QString dateString = QString("Beijing(CN) %1")
                        .arg(currentTime.toString("yyyy/MM/dd"));
    dateLabel->setText(dateString);
    
    // Trigger repaint
    update();
}

Tags: qt

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.