KABAFORCEGeliştirici KabaOS'u edinin
Önizleme · 0.6.0 — dil 1.0 öncesidir; sözdizimi ve kütüphane değişebilir. Buradaki her örnek derlenerek sınanır.

10. Arayüz (GUI) uygulaması

Pencereli uygulamalar pencere bloğuyla yazılır. Arayüz bildirimseldir: ne görüneceğini yazarsınız, nasıl çizileceğini dil halleder.

Bu sayfadaki örnekler belge testinde derlenir ama çalıştırılmaz — pencere açmak ekran gerektirir. Derlenmeleri, yazılanların gerçekten geçerli olduğunu gösterir.

⚠️ Arayüz uygulamaları sistemin arayüz kütüphanelerini kullanır (KabaOS'ta kurulu gelir). Konsol/servis/web programları bunlara ihtiyaç duymaz.

Hazır iskelet: kabalang yeni <ad> --gui (13. sayfa).

En küçük pencere

KabaLang
kullan kaba.arayuz

pencere AnaPencere:
    baslik = "KabaOS Hoş Geldiniz"
    genislik = 400
    yukseklik = 250

    etiket AdEtiketi:
        metin = "Lütfen adınızı girin:"

    girdi AdGirdisi:
        ipucu = "Buraya yazın..."

    dugme SelamDugmesi:
        metin = "Selam Ver"
        tiklandiginda:
            eger AdGirdisi.metin == "":
                mesaj_kutusu("Hata", "Lütfen önce adınızı yazın!")
            degilse:
                mesaj_kutusu("Merhaba", "Hoş geldin " + AdGirdisi.metin + "!")

Yapı şudur:

  • pencere Ad: — pencerenin kendisi; baslik, genislik, yukseklik, tema, simge özellikleri.
  • İçeride bileşenler: tur Ad: ve altında özellikleri.
  • Bileşenin altında olay bloğu: tiklandiginda: vb. Gövdesi sıradan KabaLang kodudur.
  • Bileşene başka yerden Ad.ozellik diye erişilir (AdGirdisi.metin, DurumCubugu.deger).

Bileşenler

Dilin tanıdığı 15 bileşen türü:

Bileşen Ne işe yarar
etiket salt okunur yazı
dugme tıklanabilir düğme
girdi tek satırlık metin kutusu
metin_alani çok satırlı metin kutusu
onay_kutusu işaret kutusu (secili)
acilir_liste açılır seçim kutusu
liste · tablo · agac liste / tablo / ağaç görünümü
ilerleme_cubugu yüzde göstergesi (deger)
kaydirici sürgü
grafik canlı çizgi grafiği
resim görsel
sekme_kutusu sekmeli kap (sekme "Ad":)
durum_cubugu pencere altı durum satırı

Olaylar dört tanedir: tiklandiginda · degistiginde · cift_tiklandiginda · secildiginde.

⚠️ Tanımadığı bir özelliği yazarsanız derleyici onu okumaz. Örneğin gorunur / etkin diye bir özellik yoktur (ölçüldü) — yazarsanız hiçbir şey olmaz. Mantık değerleri noktasız yazılır: secili = dogru.

Yerleşim: yatay_kutu / dikey_kutu

KabaLang
kullan kaba.arayuz
kullan kaba.sistem

pencere SistemPaneli:
    baslik = "Sistem Paneli"
    genislik = 620
    yukseklik = 420
    tema = "koyu"

    etiket BaslikEtiketi:
        metin = "KabaOS Sistem Durumu"
        stil = "font-size: 15px; font-weight: bold; color: #7aa2f7;"

    yatay_kutu ButonSatiri:
        dugme CekirdekBtn:
            metin = "Çekirdek Bilgisi"
            tiklandiginda:
                SonucKutusu.metin = sistem.komut("uname -srm")
                DurumCubugu.deger = 50

        dugme TemizleBtn:
            metin = "Temizle"
            tiklandiginda:
                SonucKutusu.temizle()
                DurumCubugu.deger = 0

    ilerleme_cubugu DurumCubugu:
        deger = 0

    metin_alani SonucKutusu:
        salt_okunur = dogru

yatay_kutu bileşenleri yan yana, dikey_kutu alt alta dizer; iç içe yazılabilirler.

Kart kutusu, yazı hizası, açılır listede sıra

yatay_kutu / dikey_kutu bir stil alabilir: zemin, kenarlık, köşe yarıçapı ve dolgu kutunun arkasına çizilir — "kart" görünümü. Dolgu ve kenarlık kalınlığı kutunun iç kenarı olur. Kutunun stili sabit metindir (bağlanmaz, çalışırken yazılmaz); iki temada da okunsun diye yarı saydam renk (rgba(…)) iyi sonuç verir. Kutunun başka özelliği okunmaz.

etiket stilinde text-align: left | center | right her satırı hizalar (sayı sütunları sağa, rozet yazısı ortaya).

acilir_liste.secili_sira seçili öğenin sırasıdır (0'dan); okunur ve yazılır — programdan seçim yapmanın yolu budur (aralık dışı değer yok sayılır).

KabaLang
kullan kaba.arayuz

pencere Kartlar:
    baslik = "Kart"
    genislik = 360
    yukseklik = 220

    dikey_kutu Kart:
        stil = "background: rgba(127, 140, 160, 0.10); border: 1px solid rgba(127, 140, 160, 0.3); border-radius: 12px; padding: 14px;"
        acilir_liste Secim:
            secenekler = ["Bir", "İki", "Üç"]
        etiket Sayi:
            metin = "12,5 ms"
            stil = "text-align: right;"
        dugme SonBtn:
            metin = "Sonuncuyu seç"
            tiklandiginda:
                Secim.secili_sira = 2
                Sayi.metin = "sıra " + metin(Secim.secili_sira)

Sekmeler ve zamanlayıcı

zamanlayici <süre>ms: bloğu belirtilen aralıkla kendiliğinden çalışır — canlı gösterge yapmanın yolu budur.

KabaLang
kullan kaba.arayuz
kullan kaba.sistem

izinler:
    ag_erisim = yanlis

pencere CanliPanel:
    baslik = "Canlı Saat"
    genislik = 460
    yukseklik = 280
    tema = "koyu"

    sekme_kutusu AnaSekmeler:
        sekme "Saat":
            etiket SaatEtiketi:
                metin = "00:00:00"
                stil = "font-size: 34px; font-weight: bold; color: #9ece6a;"

        sekme "Sistem":
            etiket BellekEtiketi:
                metin = "Bellek: —"

    zamanlayici 1000ms:
        SaatEtiketi.metin = zaman.saat()
        BellekEtiketi.metin = "Bellek: " + sistem.bellek()

izinler: — uygulamanın hak beyanı

Pencere dosyasının başındaki izinler: bloğu uygulamanın neye ihtiyacı olduğunu bildirir; kabalang derle bu beyandan ikilinin yanına KabaOS AppArmor profilini (<ikili>.apparmor) kendiliğinden yazar.

izinler:
    ag_erisim = yanlis
    dosya_yazma = "~/Belgeler"

Blok pencere gövdesinin içine de yazılabilir; o zaman gövde bir girinti daha derin olur.

Tanınan anahtarlar (kanonik küme: cekirdek/izin_denetimi.py, IZIN_ANAHTARLARI):

Anahtar Değer Ne yapar
ag_erisim dogru / yanlis profildeki network inet kuralı
surec_calistirma dogru / yanlis sistem.komut çağrılarının beyanı
dis_cagri dogru / yanlis FFI (dis fonksiyon) — beyanı ZORUNLU
dosya_yazma yol (~/... ya da /...) profildeki rw kuralının kökü

Blok kuralları — hepsi derleme zamanında denetlenir:

  • Gövdedeki her satır anahtar = deger biçimindedir. Başka bir satır derleme hatasıdır. ⚠️ Eskiden = içermeyen tek bir satır bloğu sessizce kapatıyor ve ondan sonraki bütün izinler AppArmor profiline hiç girmiyordu; derleme yine yeşil yanıyordu (ölçüldü 2026-09-26, kapı cekirdek/test_izinler_blogu.py).
  • Boş satır ve # yorumu bloğu kapatmaz; gövdenin ortasına yazılabilir.
  • Bilinmeyen anahtar hatadır. dosya_yaz gibi bir yazım hatası eskiden sessizce yok sayılıyordu: kullanıcı istediği izni almadığını hiç öğrenmiyordu.
  • Mantıksal izinlerin değeri yalnız dogru ya da yanlis olabilir (tırnaklı yazım da geçerlidir: "yanlis"). true · evet · 1 kabul edilmez — denetçi ile profil üreteci bu değerlerde birbirine zıt karar veriyordu.
  • dosya_yazma mutlak ya da ev dizini yolu ister. ⚠️ dosya_yazma = "" eskiden profile /** rw, yazıyordu — yani bütün dosya sistemine yazma hakkı, ve apparmor_parser o profili geçerli buluyordu. dosya_yazma = yanlis ise göreli bir yol üretip profili sözdizimsel olarak bozuyordu (profil hiç yüklenmiyor). İzin istemiyorsanız satırı silin, yanlis yazmayın.
  • Aynı anahtarı çelişkili iki değerle beyan etmek hatadır.

Hazır iletişim kutuları

KabaLang
kullan kaba.arayuz

pencere Kutular:
    baslik = "İletişim kutuları"
    genislik = 320
    yukseklik = 180

    dugme BilgiBtn:
        metin = "Bilgi"
        tiklandiginda:
            mesaj_kutusu("Bilgi", "İşlem tamamlandı")

    dugme UyariBtn:
        metin = "Uyarı"
        tiklandiginda:
            uyari_kutusu("Uyarı", "Disk doluyor")

    dugme HataBtn:
        metin = "Hata"
        tiklandiginda:
            hata_kutusu("Hata", "Bağlantı kurulamadı")

İkiz dosya mimarisi: ana.ui + ana.kbl

Büyüyen bir arayüzü koddan ayırabilirsiniz. Görsel tasarım .ui dosyasına, davranış aynı adlı .kbl dosyasına yazılır; derleyici ikisini birleştirir.

Önce ana.ui:

```kabalang dosya:ana.ui pencere DemoPencere: baslik = "İkiz mimari" genislik = 480 yukseklik = 300 tema = "koyu"

etiket lbl_durum:
    metin = "Sistem Durumu: Çevrimiçi"

dugme TestBtn:
    metin = "Bildirim Gönder"

Sonra `ana.kbl` — yalnız olay işleyicileri:

```kabalang
kullan kaba.arayuz
kullan kaba.sistem

TestBtn.tiklandiginda:
    sistem.bildirim("Demo", "Uygulama çalışıyor!")
    lbl_durum.metin = "Son bildirim: " + zaman.saat()

İki yön arasında geçiş komutları vardır:

Komut Ne yapar
kabalang birlestir ana.kbl .ui içeriğini kaynağın içine alır (tek dosya)
kabalang ayir ana.kbl Arayüzü kaynaktan .ui dosyasına çıkarır

Canlı bağlama

Bir pencere: bloğu masaüstü uygulamasına derlenir. Özellik değerleri bağlama olarak ele alınır: bir değer başka bir bileşenin özelliğine dayanıyorsa, o özellik değiştiğinde kendiliğinden yenilenir.

2026-10-18: --qml (Plasma apleti / QML penceresi çıktısı) kaldırıldı; tek çıktı LLVM ile derlenen yerel ikilidir.

ornekler/03-arayuz/07_canli_baglama.kbl bunu gösterir. Şu satır

etiket SelamEtiketi:
    metin = "Merhaba " + AdGirdisi.metin

canlıdır. Yani girdiye yazmak etiketi gerçekten değiştirir.

Bu 2026-09-26'da değişti. Öncesinde masaüstü çıktısı değeri yalnız kuruluş anında bir kez atıyordu ve bildirimsel özellikler donuk kalıyordu.

Hangi kaynaklar canlı — kuralın tamamı

Bir bağlamada hedef.ozellik = f(kaynak.ozellik) iki ayrı yetenek gerekir ve bunları karıştırmamak önemlidir:

  • Hedefin yalnız yazılabilir olması gerekir — okunabilen 11 bileşen türünün hepsi yazılabilir. Yani ilerleme_cubugu, etiket, dugme gibi türler pekâlâ bağlama HEDEFİ olabilir.
  • Kaynağın haber verebilmesi gerekir. İki yol vardır ve ikisi birlikte tüm türleri kapsar:
Kaynak nasıl değişir Haber yolu Türler
Kullanıcı değiştirir olay (degistiginde / secildiginde) girdi · metin_alani · kaydirici · onay_kutusu · acilir_liste · liste · tablo
Yalnız program değiştirir programın her yazması etiket · dugme · ilerleme_cubugu · grafik (+ yukarıdakiler programla yazıldığında)

Kullanıcı bir etiketi klavyeyle değiştiremez; değeri ancak programın yaptığı bir yazmayla değişir (E.metin = …, L.ekle(…), Tb.satir_ekle(…), grafiğe veri eklemek) ve her yazma bağlamalara haber verir. Bu yüzden girdi → etiket → etiket zinciri de canlıdır.

Bilinen tek boşluk: mantık (dogru/yanlis) özellikleri bağlanamaz — secili = OtekiKutu.secili yazımı yanlis yazar ve güncellenmez. Derleyici bunu uyarı olarak söyler, sessiz kalmaz; bugünkü karşılığı kaynağın degistiginde: işleyicisinde atama yapmaktır.

Bağlama döngüleri — neden çökmüyoruz

a: b + "!" ve b: a + "?" gibi ıraksayan bir bağlama döngüsünün durağan bir çözümü yoktur. KabaLang böyle bir döngüyü iki katmanda yakalar ve program çökmez:

  1. Derleme anı — döngü bulunur ve uyarı basılır:

⚠ satır 11: bağlama döngüsü: L.metin → L.metin ▸ bu halkadaki bir özellik çalışma anında KESİLECEK ve güncellenmeyecek. ▸ döngüyü kırın: yönlerden birini `degistiginde:` olay işleyicisine taşıyın.

Derleme başarısız olmaz: döngü uyarıyla geçer ve program çalışır.

  1. Çalışma anı — yalnız program koşarken oluşan halkalar için ikinci bir koruma vardır. Kesilen bağlama bir kez bildirilir ve kalıcı olarak durdurulur:

kaba: bağlama döngüsü kesildi — "L.metin" kendi değerine dolaylı olarak bağlı. ▸ bu özellik artık güncellenmeyecek; döngüyü kaynakta kırın.

İki koruma birbirinin yedeği değildir: derleme anı denetimi dolaylı halkaları yakalar, çalışma anı koruması ise ancak program koşarken ortaya çıkan halkaları.

degistiginde: yolu da hâlâ geçerli

Bağlama, olay işleyicisini geçersiz kılmaz. Bir özelliği koşullu ya da yan etkili güncellemek istiyorsanız işleyici yazmaya devam edin:

KabaLang
kullan kaba.arayuz

pencere CanliOrnek:
    baslik = "Canlı bağlama"
    genislik = 420
    yukseklik = 200

    girdi AdGirdisi:
        metin = "dünya"
        ipucu = "Adınızı yazın..."
        degistiginde:
            SelamEtiketi.metin = "Merhaba " + AdGirdisi.metin

    etiket SelamEtiketi:
        metin = "Merhaba dünya"
        stil = "font-size: 18px; font-weight: bold;"

⚠️ Aynı özelliğe hem bildirimsel değer hem işleyici yazarsanız BAĞLAMA KAZANIR. İşleyici yine çalışır, ama bağlama değeri en son yazar ve ekranda onun sonucu kalır:

girdi G:
    metin = "dünya"
    degistiginde:
        E.metin = "OLAY:" + G.metin      # ← koşar, ama üzerine yazılır

etiket E:
    metin = "BAGLAMA:" + G.metin         # ← kazanan

Ölçüm: G.metin = "AYSE" sonrası E.metin = BAGLAMA:AYSE. İşleyici sessizce yutulmaz — koşar, sonucu ezilir. Bir özelliği işleyiciyle yönetmek istiyorsanız o özelliğe bildirimsel bir değer vermeyin (ya da sabit bir değer verin).

yineleyici — veriye göre bileşen üretme

Aynı bileşeni elle N kez yazmak yerine bir kez yazıp modele göre çoğaltırsınız. QML'deki Repeaterın karşılığıdır.

KabaLang
kullan kaba.arayuz

pencere Liste:
    baslik = "Yineleyici"
    genislik = 320
    yukseklik = 240

    dikey_kutu:
        yineleyici ["Ali", "Veli", "Ayşe"]:
            etiket:
                metin = oge

        yineleyici 3:
            etiket:
                metin = "satır " + metin(sira)

Gövdede iki ad tanımlıdır:

Ad Ne
oge o anki öğe. Model bir sayı ise öğe sıranın kendisidir (QML'de modelData da öyledir)
sira 0 tabanlı sıra numarası

İkisi de rezerve değildir: sira = 3 yazan kodunuz derlenmeye devam eder, oge/sira yalnız bir yineleyici gövdesinde bu anlama gelir (belgeler/14-anahtar-sozcukler.md).

Model yazımı

Yazım Çalışır mı
yineleyici 7: ✔ sabit tekrar
yineleyici ["a", "b"]: ✔ tek satırlık dizi sabiti
yineleyici [ … ]: (çok satır) ✔ satır ]: ile kapanır
yineleyici liste: · yineleyici kopru.kisiler: ✘ UYGULANMADI — aşağı bakın

Gövdedeki bileşenler adsızdır

etiket:          ← doğru
etiket Satir:    ← HATA

Gövde her öğe için yeniden üretildiği için bir ad N bileşene verilmiş olurdu; bu yüzden gövdede ad yazmak açık bir derleme hatasıdır.

Kimlikler kendiliğinden üretilir: adsiz_etiket_1, adsiz_etiket_2, … (adsiz_ öneki bildirimlerde rezervedir). Tek bir adlı bileşen istiyorsanız onu gövdenin dışına yazın.

UYGULANMADI: canlı model

yineleyici <değişken>: ya da yineleyici <nesne>.<alan>: bugün çalışmıyor ve sessizce düşmüyor — konumu ve bugünkü alternatifini söyleyen bir hata alırsınız.

Bildirimsel bağlama yineleyici ile sorunsuz birleşir: çoğaltılan her bileşen kendi canlı bağlamasını alır.

girdi G:
    metin = "dunya"
dikey_kutu:
    yineleyici ["A", "B"]:
        etiket:
            metin = oge + ":" + G.metin

G.metin çalışma anında "AYSE" olduğunda iki etiket de güncellenir (E1=A:AYSE · E2=B:AYSE).

Eksik olan başka bir şey: bağlama bir özelliğin değerini canlı yapar, canlı model ise bileşenlerin kendisini çalışma anında modele göre yaratıp silmeyi ister. Arayüz kitaplığında bileşen silme ve bağlamaları geri alma bugün yoktur; ikisi birlikte ele alınacak.

Sabit model (sayı ya da tek/çok satırlı dizi sabiti) bugün çalışır; veriye göre liste dolduran arayüzlerin bir kısmı böylece hemen yazılabiliyor, kalanı ise sessizce yanlış çalışmak yerine açıkça "henüz yok" diyor.

Bugünkü alternatif (çalıştığı ölçülmüş): öğe sayısı çalışma anında değişiyorsa bileşen üretmeyin — içeriği değişen bir bileşen kullanın: liste ya da tablo. L.ekle(...), L.sil(0), Tb.satir_ekle([...]) ve Tb.satir_sil(0) gerçekten çalışır, yani modeliniz değiştiğinde yüzeyi yeniden doldurabilirsiniz. Öğe sayısı sabit, yalnız değerleri değişiyorsa yineleyici + bildirimsel bağlama bunu bugün zaten yapıyor (yukarıdaki ölçüm). Kısaca: yineleyici bileşen üretir (sayı derleme anında bellidir); liste/tablo içeriğini çalışma anında değiştirir.

Masaüstüne kurmak

Uçbirim
kabalang masaustu ana.kbl        # KDE menü kısayolu (.desktop)
kabalang demet ana.kbl --kur     # .kapp uygulama demeti üretir ve kurar

Sonraki adım

11. Servis (daemon) uygulaması