Implementación de Estilos Personalizados en QTreeView mediante Dibujado Propio con QPainter

Este artículo aborda la personalización de la apariencia de QTreeView en Qt, un widget de vista de árbol, mediante la sobreescritura de eventos de dibujado y el uso de QPainter. Aunque las hojas de estilo de Qt ofrecen algunas opciones, a menudo es necesario un control más detallado para lograr efectos visuales específicos. A continuación, se descirben los pasos clave para implementar un diseño único, incluyendo el color de fondo, el estilo de las celdas y la gestión de interacciones con el ratón.

Establecer el Color de Fondo del Widget

Se comienza sobrescribeindo el evento de pintura para dibujar un fondo personalizado y manejar estados vacíos.


void CustomTreeView::paintEvent(QPaintEvent* paintEvent)
{
    QPainter renderer(viewport());
    renderer.setPen(Qt::NoPen);
    renderer.setBrush(QColor(35, 40, 48));
    renderer.drawRect(viewport()->rect());

    int totalItems = dataModel->rowCount(rootIndex());
    if (totalItems == 0) {
        QFont displayFont("Segoe UI");
        displayFont.setPointSize(10);
        renderer.setFont(displayFont);
        renderer.setPen(QColor(140, 145, 155));
        renderer.drawText(viewport()->width() / 2 - 80, viewport()->height() / 2, 160, 30, Qt::AlignCenter, "Sin elementos disponibles");
        return;
    }

    QTreeView::paintEvent(paintEvent);
}

Dibujar el Estilo de las Celdas

Cada fila se dibuja personalizadamente mediante la sobrescritura del método drawRow, gestionando diferentes estados visuales.


void CustomTreeView::drawRow(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
{
    if (!modelIndex.isValid())
        return;

    painter->save();
    painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    QString itemPath = dataModel->filePath(modelIndex);
    QFileInfo fileInfo(itemPath);
    QRect cellRect = option.rect;

    bool isActive = false, isHighlighted = false, isNormal = true;
    if (itemPath == selectedFilePath) {
        isHighlighted = true;
        isNormal = false;
    } else if (modelIndex == currentIndex()) {
        isActive = true;
        isNormal = false;
    }

    int baseIndentation = calculateIndentation(modelIndex);

    if (isNormal) {
        painter->setBrush(QColor(35, 40, 48));
        painter->setPen(Qt::NoPen);
        painter->drawRect(cellRect);
    } else if (isHighlighted && !fileInfo.isDir()) {
        painter->setBrush(QColor(45, 50, 58));
        painter->setPen(Qt::NoPen);
        painter->drawRect(cellRect);
    } else if (isActive) {
        painter->setBrush(QColor(40, 45, 53));
        painter->setPen(Qt::NoPen);
        painter->drawRect(cellRect);
    }

    drawIcon(painter, cellRect, modelIndex, baseIndentation, fileInfo);
    drawTextContent(painter, cellRect, modelIndex, baseIndentation);
    drawExpansionIndicator(painter, cellRect, modelIndex, fileInfo);

    painter->restore();
}

Las funciones auxiliares como calculateIndentation, drawIcon, drawTextContent y drawExpansionIndicator encapsulan la lógica específica para mayor claridad.

Gestionar Eventos del Ratón para Interacción

Se sobrescriben los eventos de clic y doble clic para controlar la selección y la expansión de nodos.


void CustomTreeView::mousePressEvent(QMouseEvent* mouseEvent)
{
    QTreeView::mousePressEvent(mouseEvent);
    QModelIndex clickedIndex = indexAt(mouseEvent->pos());
    if (!clickedIndex.isValid())
        return;

    QString clickedPath = dataModel->filePath(clickedIndex);
    QFileInfo info(clickedPath);
    if (!info.isDir())
        return;

    QRect expandArea(10, 0, 16, rowHeight(clickedIndex));
    if (!expandArea.contains(mouseEvent->pos().x(), mouseEvent->pos().y() % rowHeight(clickedIndex)))
        return;

    QDir directory(clickedPath);
    if (directory.isEmpty())
        return;

    if (isExpanded(clickedIndex))
        collapse(clickedIndex);
    else
        expand(clickedIndex);
}

void CustomTreeView::mouseDoubleClickEvent(QMouseEvent* mouseEvent)
{
    QModelIndex indexUnderMouse = indexAt(mouseEvent->pos());
    if (indexUnderMouse != currentIndex())
        return;

    QString path = dataModel->filePath(indexUnderMouse);
    if (!dataModel->isDir(indexUnderMouse)) {
        selectedFilePath = path;
    }

    update();
    QTreeView::mouseDoubleClickEvent(mouseEvent);
}

Estas implementaciones permiten una interacción personalizada, como selecccionar archivos con doble clic y expandir carpetas con clic en áreas específicas.

Al combinar estas técnicas, se logra un control completo sobre la apariencia y el comportamiento de QTreeView, adaptándolo a requisitos visuales avanzados sin depender únicamente de las hojas de estilo estándar.

Etiquetas: QTreeView QPainter Qt C++ Personalización de Widgets

Publicado el 6-22 03:10