如何在 Qt QML TableView 单元格中绘制圆圈? [英] How do I draw a circle in a Qt QML TableView cell?

查看:118
本文介绍了如何在 Qt QML TableView 单元格中绘制圆圈?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的示例项目 here 演示了这个问题.

I have a simple sample project here which demonstrate the problem.

我在下面包含了我认为相关的来源,但其余的可以在上面的项目链接中找到,或者我可以编辑并包含更多有用的内容.

I've included below what I believe is the relevant source, but the remainder is available in the project link above or I can edit and include more if useful.

根据一些研究,似乎我需要在我的数据函数中使用 Qt::DecorationRole 并在列为 1 时返回一个图像.但是,这部分代码永远不会执行.关于角色概念如何与 Qt QML TableView 配合使用,我遗漏了一些重要且明显的内容.

Based on some research, it appears that I need to use the Qt::DecorationRole in my data function and return an image when the column is 1. However, that part of the code is never executed. I am missing some important and obvious about how the role concept works with Qt QML TableView's.

我需要更改什么才能在第 1 列(平均年龄)中画一个圆圈?如果 age <,我希望这个圆圈是红色的13,如果<则为黄色35,否则为绿色.

What do I need to change so I can draw a circle in Column 1 (average age)? I'd like this circle to be red if the age < 13, yellow if < 35, and green otherwise.

main.qml

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import Qt.labs.qmlmodels 1.0

import Backend 1.0

ApplicationWindow
{
  id:      root
  visible: true

  width:  768
  height: 450

  minimumWidth:  768
  minimumHeight: 450

  property string backendReference: Backend.objectName

  TableView
  {
    id: tableView

    columnWidthProvider: function( column )
    {
      return 100;
    }

    rowHeightProvider: function( column )
    {
      return 23;
    }

    anchors.fill: parent
    topMargin:    columnsHeader.implicitHeight

    model: Backend.modelResults.list

    ScrollBar.horizontal: ScrollBar {}
    ScrollBar.vertical:   ScrollBar {}

    clip: true

    delegate: DelegateChooser {
//      role: "type"

      DelegateChoice {
        roleValue: "decoration"

        Rectangle
        {
          color: 'red'

          anchors.fill: parent
        }
      }

      DelegateChoice {
//        roleValue: "display"

        Rectangle
        {
          Text
          {
            text: display
            anchors.fill: parent
            anchors.margins: 10
            color: 'black'
            font.pixelSize: 15
            verticalAlignment: Text.AlignVCenter
          }
        }
      }

    }

//        Rectangle
//    {
//      Text
//      {
//        text: display
//        anchors.fill: parent
//        anchors.margins: 10
//        color: 'black'
//        font.pixelSize: 15
//        verticalAlignment: Text.AlignVCenter
//      }
//    }

    Rectangle // mask the headers
    {
      z: 3

      color: "#222222"

      y: tableView.contentY
      x: tableView.contentX

      width:  tableView.leftMargin
      height: tableView.topMargin
    }

    Row
    {
      id: columnsHeader
      y:  tableView.contentY

      z: 2

      Repeater
      {
        model: tableView.columns > 0 ? tableView.columns : 1

        Label
        {
          width:  tableView.columnWidthProvider(modelData)
          height: 35

          text: Backend.modelResults.list.headerData( modelData, Qt.Horizontal )

          font.pixelSize:    15
          padding:           10
          verticalAlignment: Text.AlignVCenter

          background: Rectangle
          {
            color: "#eeeeee"
          }
        }
      }
    }

    ScrollIndicator.horizontal: ScrollIndicator { }
    ScrollIndicator.vertical: ScrollIndicator { }
  }
}

modeldata.cpp

#include "modeldata.h"

//
// ModelList
//
ModelList::
ModelList( QObject* parent )
    : QAbstractTableModel (parent )
{
//  mRoleNames = QAbstractTableModel::roleNames();
//  mRoleNames.insert( 1, QByteArray( "type" ) );

}



int
ModelList::
rowCount(const QModelIndex &) const
{
   int size = mList.size();

   return size;
}



int
ModelList::
columnCount( const QModelIndex & ) const
{
   return 2;
}




QVariant
ModelList::
data( const QModelIndex& index, int role ) const
{
    const ModelItem modelItem = mList.at( index.row() );

    QVariant result = QVariant();

    if ( role == Qt::DisplayRole )
    {
        if ( index.column() == 0 )
        {
          result = QVariant( QString( modelItem.population ) );
        }
        else
        {
          result = QVariant( QString::number( modelItem.averageAge ) );
        }
    }

    if ( role == Qt::DecorationRole )
    {
        qDebug() << "decorate 1";
    }

    return result;
}



QVariant
ModelList::
headerData( int section, Qt::Orientation orientation, int role ) const
{
    if ( section == 0 )
        return QVariant( QString( "Population" ) );
    else
        return QVariant( QString( "Average Age" ) );
}



int
ModelList::
size() const
{
    return mList.size();
}



const QList<ModelItem>&
ModelList::
list() const
{
    return mList;
}



void
ModelList::
removeAt( int index )
{
    if ( index < 0 || index >= mList.size() )
        return;

    beginRemoveRows( QModelIndex(), index, index );
    mList.removeAt( index );
    endRemoveRows();

    emit sizeChanged();
}



void
ModelList::
add( const QString& population, const int averageAge )
{
    ModelItem item;

    item.population = population;
    item.averageAge = averageAge;

    add( item );
}

QHash<int, QByteArray>
ModelList::
roleNames() const
{
  return {
    { Qt::DisplayRole, "display" },
    { Qt::DecorationRole, "decorations" }
  };

//  return this->mRoleNames;
}



void
ModelList::
add(const ModelItem& item)
{
    const int index = mList.size();

    beginInsertRows( QModelIndex(), index, index );
    mList.append( item );
    endInsertRows();

    emit sizeChanged();
}



void
ModelList::
reset()
{
    if ( mList.isEmpty() )
        return;

    beginRemoveRows( QModelIndex(), 0, mList.size() - 1 );
    mList.clear();
    endRemoveRows();

    emit sizeChanged();
}



//
// ModelResults
//
ModelResults::ModelResults(QObject* parent)
    : QObject(parent)
{
    mList = new ModelList( this );

    qRegisterMetaType<ModelItem>("ModelItem");
}

ModelList* ModelResults::list() const
{
    return mList;
}

void ModelResults::reset()
{
    mList->reset();
}

推荐答案

我已经能够在平均年龄字段中绘制正确的圆圈.

I have been able to get the correct circle drawn in the averageAge field.

我的 ModelItem 看起来像:

My ModelItem looks like:

struct ModelItem
{
    Q_GADGET

    Q_PROPERTY( QString population MEMBER population )
    Q_PROPERTY( int averageAge MEMBER averageAge )
    Q_PROPERTY( bool selected MEMBER selected )

public:

    enum class Role {
      Selection = Qt::UserRole,
      ColumnType,
      ColorValue
    };
    Q_ENUM(Role)

    QString population;
    int     averageAge;
    bool    selected    { false };

    bool operator!=( const ModelItem& other )
    {
        return other.population != this->population
            || other.averageAge != this->averageAge;
    }

};

这里的重点是 ColumnType 和 ColorValue 角色的定义.

The key point here is the definition of the ColumnType and ColorValue Role.

我的自定义角色需要一个 roleNames 函数

I needed a roleNames function for my custom role

QHash<int, QByteArray>
ModelList::
roleNames() const
{
  return {
    { Qt::DisplayRole, "display" },
    { int( ModelItem::Role::Selection ), "selected" },
    { int( ModelItem::Role::ColumnType ), "type" },
    { int( ModelItem::Role::ColorValue ), "colorValue" }
  };
}

自定义角色需要由 roleNames 提供并具有字符串type";和颜色值"指定.

The custom roles needed to be supplied by roleNames and have the strings "type" and "colorValue" specified.

我的数据函数看起来像:

My data function looks like:

QVariant
ModelList::
data( const QModelIndex& index, int role ) const
{
    const ModelItem modelItem = mList.at( index.row() );

    QVariant result = QVariant();

    if ( role == Qt::DisplayRole )
    {
        if ( index.column() == 0 )
        {
          result = QVariant( QString( modelItem.population ) );
        }
        else
        {
          result = QVariant( QString::number( modelItem.averageAge ) );
        }
    }

    if ( role == int( ModelItem::Role::Selection ) )
    {
        result = QVariant( QString( modelItem.selected ? "#eeeeee" : "white" ) );
    }

    if ( role == int( ModelItem::Role::ColumnType ) )
    {
      if ( index.column() == 0 )
        result = QVariant( QString( "stringValue" ) );
      else
        result = QVariant( QString( "colorValue" ) );
    }

    if ( role == int( ModelItem::Role::ColorValue ) )
    {
      QString color;

      if ( modelItem.averageAge < 13 )
        color = "red";
      else if ( modelItem.averageAge < 35 )
        color = "yellow";
      else
        color = "green";

      result = QVariant( color );
    }

    qDebug() << role << " " << result;

    return result;
}

这里的一个关键点是,当使用角色 ColumnType 时,我会返回该列是 stringValue 还是 colorValue.

A key point here is that when the role ColumnType is used, I return whether or not the column is a stringValue or a colorValue.

另外,当使用角色ColorValue时,我查看modelItem的averageAge并返回一个包含要使用的颜色的字符串.

Additionally, when the role ColorValue is used, I look at the averageAge of the modelItem and return a string containing the color to be used.

最后一部分是让 QML 使用自定义角色.

The final piece is to have the QML use the custom roles.

delegate: DelegateChooser
{
  role: "type"

  DelegateChoice
  {
    roleValue: "colorValue"

    delegate: Rectangle
    {
      color: selected

      Rectangle
      {
        color: colorValue

        width: parent.height
        height: parent.height

        radius: width * 0.5;

        anchors.horizontalCenter: parent.horizontalCenter;
      }

      MouseArea
      {
        anchors.fill: parent

        onClicked:
        {
          var idx = Backend.modelResults.list.index( row, column )

          console.log( "Clicked cell: ", idx.row, " ", Backend.modelResults.list.data( idx ) )

          Backend.modelResults.list.select( idx.row );
        }
      }
    }
  }

  DelegateChoice
  {
    delegate: Rectangle
    {
      color: selected

      Text
      {
        text: display
        anchors.fill: parent
        anchors.margins: 10
        color: 'black'
        font.pixelSize: 15
        verticalAlignment: Text.AlignVCenter
      }

      MouseArea
      {
        anchors.fill: parent

        onClicked:
        {
          var idx = Backend.modelResults.list.index( row, column )

          console.log( "Clicked cell: ", idx.row, " ", Backend.modelResults.list.data( idx ) )

          Backend.modelResults.list.select( idx.row );
        }
      }
    }
  }
}

首先,对于 DelegateChooser,角色由我们自定义的类型"指定.角色.系统知道用这个角色调用我们的数据函数.当数据函数返回colorValue"时,基于roleValue是colorValue"选择第一个DelegateChoice.第二个 DelegateChoice 没有 roleValue,因为它似乎需要一个默认的 DelegateChoice 和stringValue".是默认值.

First, for the DelegateChooser, the role is specified by our custom "type" role. The system knows to call our data function with this role. When the data function returns "colorValue", the first DelegateChoice is selected based because the roleValue is "colorValue". The second DelegateChoice does not have a roleValue because it appears there needs to be a default DelegateChoice and "stringValue" is the default.

其次,colorValue"委托选择已定义 color: colorValue.这会导致系统再次调用具有 ColorValue 角色的数据函数,然后返回单元格的正确颜色.

Second, the "colorValue" delegate choice has defined color: colorValue. This causes the system to again call the data function with the ColorValue role and it then returns the correct color for the cell.

示例项目已更新.

欢迎对此解决方案提出改进建议.

Suggested improvement to this solution are welcome.

这篇关于如何在 Qt QML TableView 单元格中绘制圆圈?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆