【ITニュース解説】Selection, Modelled: Why GTK4 Puts Selection in the Model, Not the View
2026年09月29日に「Dev.to」が公開したITニュース「Selection, Modelled: Why GTK4 Puts Selection in the Model, Not the View」について初心者にもわかりやすく解説しています。
ITニュース概要
GTK4では、リストの選択状態がビューからデータモデルへ移動した。これにより、表示に依存せず選択を管理できる。単一選択モデルでは初期選択や解除の挙動に注意が必要で、設定順序が重要。複数選択モデルでは、選択変更通知の引数が実際の選択と異なるため、別途モデルに問い合わせる必要がある。一部の選択操作は単一選択モデルでは動作しない。
ITニュース解説
GTK4という新しいプログラミングツールキットでは、リストやグリッドといった画面上の要素の中からユーザーがどれかを選ぶ「選択」という機能の扱い方が根本的に変更された。以前のGTK3では、選択状態は画面に表示されるリストそのもの(View)が持っていたが、GTK4ではデータを管理する部分(Model)がその状態を持つように変わった。これは非常に重要な変更点で、選択されたアイテムの情報が、画面表示に依存せず、より独立して扱えるようになったことを意味する。例えば、リストがまだ画面に表示されていなくても、どのアイテムが選ばれているかをプログラムで設定したり確認したりできるし、画面と直接関係ないプログラムの部分からも選択状態を自由に操作できるようになる。
この新しい選択の仕組みは、GtkSelectionModelという「インターフェース」として提供される。インターフェースとは、特定の機能を持たなければならないという約束のようなものだ。このインターフェースには、GListModelという基本的なデータリストを「ラップする(包み込む)」形で、主に三つの具体的な実装が用意されている。これらは、元のデータモデルに選択という機能を追加する「デコレータ」として機能し、自身もGListModelとして振る舞う。
一つ目はNoSelectionで、これはリスト内のどのアイテムも選択できないようにする。例えば、ユーザーがただ内容を見るだけのログ表示のようなリストに使う。
二つ目はSingleSelectionで、これは一度に一つのアイテムだけを選択できるようにする。リストで人名を選んだら、その人の詳細情報が別の画面に表示されるような「マスター・ディテール」型の表示に最適だ。
三つ目はMultiSelectionで、これは複数のアイテムを同時に選択できる。複数のファイルを選んで一括で操作するような場面で使う。
SingleSelectionを使う場合、現在選択されているアイテムの「位置(インデックス)」や「データそのもの」を簡単に取得できる。例えば、選択されたアイテムが変わったときに何らかの処理をするには、選択モデルの特定のプロパティ変更を監視するだけで良い。この処理は、リストが画面に表示されていなくても実行されるため、画面要素に縛られないロジックが書ける。
しかし、SingleSelectionには少し注意が必要な挙動がある。それはautoselectとcan-unselectという二つのプロパティだ。autoselectがデフォルトでTRUEになっていると、リストにデータが一つでもあれば、自動的に最初のアイテム(0番目)が選択されてしまう。また、選択されていたアイテムがリストから消えると、自動的に別のアイテムが選択される。これにより、リストを開いたときに必ず何かが選択されている状態になる。
さらに、can-unselectがデフォルトでFALSEだと、ユーザー操作だけでなく、プログラムからでも選択を解除することができなくなる。つまり、「何かしら選ばれた状態」を強制する。
これらのプロパティを適切に設定しないと、意図せずアイテムが選択されたり、選択を解除できなかったりする問題が発生する。特に注意すべきは、autoselect(false)のような設定を、データモデルをセットするmodel(&store)より「前」に行う必要があることだ。もしmodel(&store)を先に呼んでしまうと、その時点でautoselectがデフォルトのTRUEとして働き、最初のアイテムが選択されてしまい、後からautoselect(false)にしてもその選択は解除されない。また、選択がない状態を示すGTK_INVALID_LIST_POSITIONは、符号なし32ビット整数の最大値(u32::MAX)に相当する。プログラムで数値の0と比較すると、選択が解除された状態(u32::MAX)と最初のアイテムが選択された状態(0)を混同する可能性があるため、注意が必要だ。
一方、MultiSelectionは、SingleSelectionのように「現在選択されているアイテム」を直接取得できるプロパティを持たない。複数のアイテムが選択されるため、その状態を管理する方法が異なる。
選択状態が変わったときに発火するconnect_selection_changedシグナルがあるが、その引数は「変更があった範囲」を示すだけであり、現在選択されているすべてのアイテムを教えてくれるわけではない。そのため、この引数を現在の選択状態だと誤解すると、プログラムが正しく動作しないことがある。
現在選択されているアイテムの全貌を知るには、selection()メソッドを呼び出し、GtkBitsetというオブジェクトを取得する必要がある。GtkBitsetは、選択されているアイテムのインデックスを効率的に管理する仕組みだ。このBitsetを一つ一つたどり(イテレートし)、それぞれのインデックスを使ってselection.item(p)を呼び出すことで、選択されたアイテムのデータ自体を取得できる。ここで重要なのは、元のデータモデル(store.item(p))ではなく、選択モデル(selection.item(p))に対して問い合わせることだ。将来的にフィルタリングやソート機能が追加された場合、元のデータモデルと選択モデルでのインデックスが異なる可能性があるため、この点は必ず守るべきだ。
プログラムからアイテムを選択したり解除したりするためのメソッドも提供されている。例えば、select_itemで特定のアイテムを選択したり、select_allで全てを選択したり、unselect_allで全てを解除したりできる。
select_itemメソッドには、unselect_restという真偽値の引数があり、これをTRUEにすると「他の選択を全て解除してから指定のアイテムだけを選択する」という挙動になる。これはMultiSelectionで特に重要だ。
しかし、ここにも落とし穴がある。SingleSelectionでは、これらの設定メソッドの一部(例えばselect_allやselect_rangeなど)が、コンパイルは通るものの、実際には何もしない。これらのメソッドは「処理が成功したかどうか」を真偽値で返すため、SingleSelectionに対して実行した場合、常にfalseが返ってくる。この返り値をきちんと確認しないと、意図した処理が行われないままプログラムが進行してしまう可能性がある。NoSelectionに至っては、どの選択操作も何もせずfalseを返す。
GTK4における選択モデルの変更は、アプリケーション開発において選択状態の管理をより柔軟かつ強力にするための重要なデザイン変更だ。ビューから独立した選択状態は、テストしやすく、再利用性の高いコードを書くことを可能にする。しかし、SingleSelectionのautoselectやcan-unselectプロパティの挙動、設定順序の重要性、MultiSelectionにおける選択状態の取得方法、そして各選択モデルで利用できるメソッドの違いなど、いくつかの注意すべき点が存在する。これらを理解し、適切に扱うことで、GTK4を用いた堅牢で柔軟なユーザーインターフェースを構築できるだろう。特に、選択状態の変更を監視する際には、selection_changedの引数に惑わされず、常にselection()メソッドで現在の状態を問い合わせること、そして、インデックスを使ったアイテムの取得は必ずその位置を与えてくれた選択モデルに対して行うことが重要である。これらの点を意識することで、GTK4の新しい選択モデルを効果的に活用できるようになる。