GTK4 - Python İle ColumnView Performansı

GTK4 ve Python kullanarak Columnview içeren bir arayüz geliştiriyordum. Sütun sayısının artması, verilerin modele eklenme performansını önemli ölçüde düşürüyor. Örnek olarak verdiğim aşağıdaki kodda 5 sütunlu bir verinin modele eklenmesi yaklaşık 0.0978 saniye sürüyor. 4 sütunlu iken bu değer 0.0763 saniye oluyor. 2 sütunlu iken yaklaşık 0.0435 saniye oluyor. Sistem Gözlem Merkezi gibi bir uygulama, İşlemler (Processes) sekmesinde 25 kadar sütuna sahip olabiliyor. Arayüzün hissedilir oranda donmasına sebep oluyor. Ama satır sayısının artması performansı bu kadar etkilemiyor. Örnekteki 300 sayısını 3000 yapılarak deneyebilirsiniz.

Her bir satır verisinin (işlem, servis, vb.) GObject nesnesi olarak Gio.Liststore’a eklenme süresini azaltmanın bir yolu var mıdır?
Modele ekleme işlemi “splice” metodu kullanılarak yapılıyor.

Basit bir kod örneği:

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gio, GObject

class User(GObject.Object):
    __gtype_name__ = 'User'
    name = GObject.Property(type=str)
    email = GObject.Property(type=str)
    city = GObject.Property(type=str)
    car = GObject.Property(type=str)
    country = GObject.Property(type=str)

    def __init__(self, name, email, city, car, country):
        super().__init__()
        self.name = name
        self.email = email
        self.city = city
        self.car = car
        self.country = country

class AppWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        super().__init__(application=app, title="ColumnView", default_width=600, default_height=400)

        self.model = Gio.ListStore(item_type=User)
        self.selection_model = Gtk.SingleSelection(model=self.model)
        column_view = Gtk.ColumnView(model=self.selection_model)

        self.add_column(column_view, "Name", "name")
        self.add_column(column_view, "E-mail", "email")
        self.add_column(column_view, "City", "city")
        self.add_column(column_view, "Car", "car")
        self.add_column(column_view, "Country", "country")

        scrolled = Gtk.ScrolledWindow(child=column_view)
        self.set_child(scrolled)

        self.load_data()


    def add_column(self, column_view, title, prop_name):
        factory = Gtk.SignalListItemFactory()

        factory.connect("setup", lambda factory, item: item.set_child(Gtk.Label(xalign=0)))
        
        def on_bind(factory, list_item):
            label = list_item.get_child()
            user = list_item.get_item()
            label.set_label(getattr(user, prop_name))

        factory.connect("bind", on_bind)

        col = Gtk.ColumnViewColumn(title=title, factory=factory)
        column_view.append_column(col)

    def load_data(self):
        new_items = []
        for i in range(1500):
            new_items.append(User(name=f"User {i}", email=f"user{i}@example.com", city="city123", car="car123", country="country 123"))
        import time;time1=time.time()
        self.model.splice(0, 0, new_items)
        print(time.time()-time1)

def on_activate(app):
    win = AppWindow(app)
    win.present()

app = Gtk.Application(application_id='com.example.abcd')
app.connect('activate', on_activate)
app.run(None)

Hocam selamlar, ColumnView yerine GridView’i bir denediniz mi?

Normalde Factory mantığında nesneler ekranda gözüktüğü kadar oluşturulup ekrandan çıkınca yerini diğer nesnelere bırakır. Yani örneğin 10 tane elemanlık bir ekran varsa list’te 1000 veri de olsa her zaman 10 widget var olur.

Sizin senaryoda tahminim ColumnView bu görünürlüğü sadece satır bazlı kontrol ediyor olabilir, dolayısıyla gözükecek satır sayısı örneğin 10 olduğu için 1500 satır da olsa sorun olmayabiliyor, fakat 10 satırın tüm sütunları gözükse de gözükmese de eklendiği için performansı düşürüyor olabilir.

Tabi bu ön bir tahmin, test edip denemedim, ama GridView’in işinizi çözeceğini ve satır eklemedeki rahatlığı sütunda da sağlayacağını, gözükmeyen sütunların performansa etkisi olmayacağını öngörüyorum.

https://lazka.github.io/pgi-docs/#Gtk-4.0/classes/GridView.html#Gtk.GridView.set_factory

Test edip sonuçlarını da paylaşabilirseniz sizin senaryodaki gibi bir program yazacaklar için için de faydalı olmuş olur.

Yanıtınız için teşekkürler. Anlattığınız ekranda görünen kadarını işleme mantığının farkındayım.
Ama GridView görünüşü daha farklı bir widget galiba. Daha çok galeri görünümüne sahip bir arayüz sunuyor. Attığınız ikinci linkteki bilgiye göre de column ekleme-çıkarma için bir metod sunmuyor. Column diye bahsettiği metodlarda yan yana kaç kutucuk gelebileceği bilgisi giriliyor/alınıyor ve türü integer. Aşağıya örnek bir tane gridview uygulaması resmi atıyorum:

Evet aslında tam beklediğiniz şekilde çalışan bir widget değil.

Eğer illa 30 column göstermek istiyorsanız GridView veya ListView gibi widgetleri temel alıp kendi özel widget’inizi implement etmeniz gerekebilir. Örneğin her satırın kendi içinde bir listview, ve tüm satırların da bir listview olduğu senaryo gibi.

Bir diğer seçenek, 25-30 tane sütunlu bir tasarım yerine, 4-5 tane temel değerleri gösterip, detaylar için satıra sağ tık > detaylar menüsüyle açılan popup’ta göstermek olabilir.

İkinci önerinizi (detayların ayrı bir yerde gösterilmesi) düşüneceğim. Ayrıca uygulamayı şu haliyde GTK3/4 karışımı halinde mi bırakmalı yoksa yeni bir arayüzle mi hazırlamak gerekli düşüneceğim.

Uzun süre önce tkinter ile uygulamanın bir kısmını tasarlamıştım. Orada da ayrı sorunlar var. Tooltip desteği olmayan bir kütüphane. Window tanımlayarak tooltip veya popover menu gibi şeyler yapmak gerekiyor. Treeview’deki sürükle-bırak gibi çok temel şeyleri bile elle geliştirmek gerekiyor. Yazılarda blur varmış gibi gözüküyor. Ekran ölçeklendirmesi değişince sorun çıkıyor vb.
Tema ile şu anki görünümüne yakın bir hale geldi. Örnek bir resim:

Hocam benim beğendiğim ve Linux’ta native hissettiren görünüme sahip iki sistem gözlemcisi uygulaması var:

Mission Center:

ve

Resources:

Bu ikisi şık, modern, responsive ve adaptive bir görünüme sahip libadwaita ile. Yani uygulamanın boyutunu küçültürseniz, örneğin mobil görünüm gibi, uygulamanın arayüzü de ona adapte oluyor.


Bu da ileride linux bir telefon çıkarıldığında, ki bu yönde çalışmalar epey var ve bu tarz şeyler bunun zeminini oluşturuyor, yoksa düz bir gtk uygulaması direkt telefonda verimli çalışamaz, sizin uygulamanız hem pc hem mobilde de kullanılabilir manasına gelecek.

Dolayısıyla bu tarz tasarım kararlarını bir kullanıcı olarak epey önemsiyorum. Tkinter gibi basit bir şey yerine GTK4 + Libadwaita ile adaptive ve modern bir tasarım çizgisiyle ilerlemek daha iyi olacaktır.

Son olarak QT6 hakkındaki düşüncelerinizi de dinlemek isterim. Bildiğim kadarıyla ikisi de donanım hızlandırmayı (GPU acceleration) destekliyor. Linux’da ve Windows’ta kullanıcı kitlesi, iki kütüphanenin kullanım kolaylığı, gelişmişlikleri, vb. İş ilanlarında QT’ye denk geldiğim oldu. Ama GTK istenen ilan gördüğümü hatırlamıyorum.

Basit bir ölçüm var bu konuda:

Eğer cross platform çalışacak bir uygulama yazıyorsam: Qt

Eğer sadece Linux’ta çalışacak, mac’e ve windows’a çıkarmayı düşünmediğim bir uygulama yazıyorsam GTK.

Nasıl Windows’un native’i .Net, macos’in swift ve swiftui, Linux’un da Gtk diyebiliriz.

En güzeli her platformun kendi native aracını kullanmak.

Fakat örneğin localsend gibi her yerde çalışmasını planladığınız bir uygulama için Qt veya Flutter gibi platformlar daha uygun olacaktır.

Teşekkürler vakit ayırdığınız için.