WhiteAtelier Archives
Another side of life, Behind the real.
2020-03-02 19:59:15 - Category : PySide
【PySide2】QTableViewとModelの作り方 - その2 編集可能に

テーブルデータの編集ができるようにする

前回までに、QTableViewにデータを表示するところまではできました。

しかし、現状はテーブル内のデータを編集することができません。今回の目標として、 テーブルからデータの値を編集できるようになる ことを目指します。

CustomDataの編集

カスタムデータクラスを少し編集して、データをセットできるような関数を作ります。

今回のCustomDataはdataclassになっていますので、単純にメンバ変数に代入するだけで良いのですが、「与えられた値をバリデートし、正しければ代入する」ということをやりたかったので、このクラスを以下のように改造しました。

@dataclasses.dataclass
class CustomData:
    name: str
    age: int
    country: str

    def toList(self) -> list:
        return [self.name, self.age, self.country]

    @classmethod
    def toHeaderList(cls) -> List[str]:
        return ["NAME", "AGE", "COUNTRY"]

    def validateAndSetName(self, name) -> bool:
        if str(name) != "":  # Non-empty string is OK.
            self.name = str(name)
            return True
        return False

    def validateAndSetAge(self, age) -> bool:
        try:
            val_int = int(age)
            if val_int >= 0:  # int, and greater than 0 or equal 0 is OK.
                self.age = val_int
                return True
        except ValueError:
            pass  # Non-integer value is invalid.
        return False

    def validateAndSetCountry(self, country) -> bool:
        if str(country) in ["USA", "Japan", "US", "Russia", "Canada"]:  # Only 5 countries
            self.country = str(country)
            return True
        return False

前回から増えているところは、

  • validateAndSetName(...)
    • 空文字でなければOK
  • validateAndSetAge(...)
    • 0以上のint(整数)であればOK
  • validateAndSetCountry(...)
    • "USA", "Japan", "US", "Russia", "Canada"のいずれかであればOK

の3つの関数です。バリデーターが「正常な値」と判断する基準は、関数名の下に記したとおりです。

SimpleTableModelの編集

さて、ここからはいよいよモデルの編集を行っていきます。

追加するメソッド

今回追加するメソッドは次の2つです。

  • setData(self, index: QModelIndex, value, role: int) -> bool
  • flags(self, index: QModelIndex) -> Qt.ItemFlags

setData(self, index: QModelIndex, value, role: int) -> bool

この関数は、QTableViewの編集状態が終了したタイミングで呼び出されます。indexで指定された項目の、roleに対する値をvalueに更新するよ」という感じです。

今回は、roleQt.EditRoleというロールにのみ対応します。

また、与えられた値valueが受理できないような値の場合は、関数の戻り値としてFalseを返すと、変更が破棄され、変更前の状態に戻ります。よって、バリデータにかけて、失敗した場合はFalseを返し、テーブル上の値をもとに戻すようにしています。

def setData(self, index: QModelIndex, value, role: int) -> bool:
        # Returning true means the value was accepted.
        if index.isValid() and role == Qt.EditRole:
            if index.column() == 0:
                return self.custom_data[index.row()].validateAndSetName(value)
            elif index.column() == 1:
                return self.custom_data[index.row()].validateAndSetAge(value)
            elif index.column() == 2:
                return self.custom_data[index.row()].validateAndSetCountry(value)

        return False  # Not Accepted.

flags(self, index: QModelIndex) -> Qt.ItemFlags

この関数は、指定されたindexの要素に対する、フラグを宣言できます。フラグとは具体的に、「選択可能」や、「要素が有効である」「編集可能である」といったものです。立てるフラグが複数ある場合は、それらをビットOR演算子である|で繋げて値を戻します。

今回は、「要素が有効」「選択可能」「編集可能」の3つのフラグを立てます。

def flags(self, index: QModelIndex) -> Qt.ItemFlags:
        if index.isValid():
            return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable

        return Qt.NoItemFlags

完成

実際に動かしてみましょう。

TaroをNagatoに変更

セルをダブルクリックすることで編集ができるようになります。

年齢を50歳に

年齢の欄も、同じように編集できますが

年齢を文字列で指定することはできない

年齢の欄に文字列を入れてEnterを押すと、変更は反映されずに50歳のままとなります。

国をMyCountryに変更することもできない

国の欄に「MyCountry」と指定しても、これらは有効な「国」として登録されていないため、Enterを押すことで元の「Japan」に戻されます。

全コード

次回

この表に、次は要素の追加と削除を実装したいと思います。