0
点赞
收藏
分享

微信扫一扫

QTabelView结合QSqlQueryModel使用时刷新一行数据的方法

寒羽鹿 2022-04-13 阅读 122
qt

一、先说结论吧,QT官方应该是不完全支持这种操作的。

是不完全支持,不是完全不支持。

以下代码是官方文档的示例,在需要修改数据时,继承了一个QSqlQueryModel类,并定义了自己的setData函数,其中setData修改数据的时候,是直接操作数据库对数据源做修改的;而操作完之后调用的refresh()函数也是在此处现场定义的,是重新执行了一遍select。整个代码中不涉及对原有的model对象中的值的修改,而是直接把model通过查询整体刷新掉了。

在做比较粗放的查询的时候,这样自然是没有问题,但是如果你像我一样,需求中,查询是包含一些筛选条件的,而你要修改的值恰好是筛选条件之一,那么修改后重新执行原来的查询并不能让某一行的值发生变化,反而会让这一行从结果中被筛掉,这就会导致比较差的交互体验。那有没有办法解决这个问题呢?敢写文章出来自然是有的,只是办法比较笨,而且会损失一些性能。请继续往下看。

  bool EditableSqlModel::setData(const QModelIndex &index, const QVariant &value, int /* role */)
  {
      if (index.column() < 1 || index.column() > 2)
          return false;

      QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(), 0);
      int id = data(primaryKeyIndex).toInt();

      clear();

      bool ok;
      if (index.column() == 1) {
          ok = setFirstName(id, value.toString());
      } else {
          ok = setLastName(id, value.toString());
      }
      refresh();
      return ok;
  }

  void EditableSqlModel::refresh()
  {
      setQuery("select * from person");
      setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
      setHeaderData(1, Qt::Horizontal, QObject::tr("First name"));
      setHeaderData(2, Qt::Horizontal, QObject::tr("Last name"));
  }

  bool EditableSqlModel::setFirstName(int personId, const QString &firstName)
  {
      QSqlQuery query;
      query.prepare("update person set firstname = ? where id = ?");
      query.addBindValue(firstName);
      query.addBindValue(personId);
      return query.exec();
  }

  bool EditableSqlModel::setLastName(int personId, const QString &lastName)
  {
      QSqlQuery query;
      query.prepare("update person set lastname = ? where id = ?");
      query.addBindValue(lastName);
      query.addBindValue(personId);
      return query.exec();
  }

二、还是要从需求入手,我们的需求本质上不是修改model,而是要让当前页面的某些值被修改后,重新刷新页面时,整个页面要呈现的行与修改前是一样的。

所以笨办法是这样的,还是从refresh函数入手,在重新执行查询的时候,把当前页面的所有主键记录下来然后重新查询一遍,代码见下。

PS:这个函数随便叫什么,refresh不是qsqlquerymodel类里面声明过的。

PS2:没必要非得在setdata函数里面调用,事实上我修改值也是直接另起炉灶的,setdata函数直接注释掉了,反正要拼接sql语句,不如拼接点通用性高的出来,有几列写几个set实在太麻烦了(当然也可能是我段位太低)。修改完之后调用一下这个refresh就好。

PS3:其实这个函数甚至没必要写成成员函数,详见注释。


    bool refresh()
    {
        bool ok;
        QStringList ID_list;
        int temp_count = this->rowCount();
        if (temp_count < 1 )
            return false;
        else
        {
            QSqlQuery tmp;
            //把当前model中页面内所有的主键记录下来,在我这里是mould_ID
            for (int i = 0; i < temp_count; i++)
            {
                ID_list.insert(i, this->index(i, 0).data().toString());
            }
            string tmp_sql = "select * from Mould_main where mould_ID = '" + ID_list[0].toStdString() + "' ";
            if (temp_count == 1)
            {
                tmp.prepare(QString::fromStdString(tmp_sql + " order by mould_serial"));
            }
            else if (temp_count > 1)
            {
                //通过循环将所有主键作为查询条件拼接成一句超长sql进行查询
                //注意我后面拼接的排序语句,要使得页面相比原来不发生任何变化,排序规则要保持一致。
                //如果存在其他排序或允许用户自己设置排序的话,这个函数也可以不写成成员函数,在需要传参的地方定义、调用也是可以的。
                //题外话,也不知道sql语句有没有长度上限,拼接的时候string真的比QString好用
                
                for (int j = 1; j < temp_count; j++)
                {
                    tmp_sql = tmp_sql + " or mould_ID = '" + ID_list[j].toStdString() + "' ";
                }
                tmp.prepare(QString::fromStdString(tmp_sql + " order by mould_serial"));
            }
            ok = tmp.exec();
            this->setQuery(tmp);
        }
        return ok;
    }

三、

举报

相关推荐

0 条评论