Komponen antarmuka tanpa data hanyalah gambar statis — nilai dari app muncul ketika data mengalir dari komponen ke logika, diproses, lalu dialirkan kembali ke komponen lain. Chapter ini membahas penampung data di dalam app (properti), alur baca-proses-tulis, penanganan state saat pemrosesan berjalan, dan pemisahan logika dari UI — fondasi yang membuat app bisa diuji. Cakupannya:

  • properti class app sebagai state (app.data, app.filename)
  • pola baca komponen → proses → tulis komponen
  • transisi state: menonaktifkan komponen saat pemrosesan
  • pemisahan pola model–view dan logika yang teruji

Properti App sebagai State #

Data app yang hidup lebih lama dari satu callback harus punya tempat tinggal resmi: properti class. Kita sudah melihatnya menyimpan komponen; bagian data tinggal menempel di blok yang sama:

matlab
properties (Access = public)
    UIFigure     matlab.ui.Figure
    EditField    matlab.ui.control.NumericEditField
    LabelHasil   matlab.ui.control.Label

    dataPath     char   = 'data_cuaca.csv'   % berkas data aktif
    dataTable    double = []                 % data hasil muat
    hasil        struct = struct()           % hasil analisis terakhir
end

Mari kita bedah baris-baris kode di atas:

  1. Baris 2-4: tiga properti komponen — dibuat dan dimusnahkan bersama app.
  2. Baris 6-8 (dataPath, dataTable, hasil): state aplikasi — data yang dipakai lintas callback; tanpa properti ini, setiap callback harus menghitung ulang atau saling melempar variabel lokal.
  3. Baris 6 (char + nilai awal): tipe dan nilai bawaan properti dideklarasikan sekaligus — pola yang sama dengan materi OOP.

Aturan pentingnya: satu sumber kebenaran. Jika dataTable adalah data resmi app, semua callback membaca dari sana — tidak ada callback yang diam-diam menyimpan salinannya sendiri, karena dua salinan pasti berpisah nilainya.

Pola Baca → Proses → Tulis #

Alur standar hampir semua callback berbentuk tiga langkah: baca nilai dari komponen input, serahkan ke fungsi proses, tulis hasil ke komponen output:

matlab
function KonversiButtonPushed(app, event)
    % Langkah 1: baca input dari komponen.
    suhu = app.EditFieldSuhu.Value;
    satuan = app.DropDownSatuan.Value;

    % Langkah 2: proses di fungsi terpisah (bukan di sini).
    [hasil, ok, pesan] = prosesForm( ...
        struct('suhuTeks', num2str(suhu), 'satuan', satuan));

    % Langkah 3: tulis hasil ke komponen output.
    if ok
        app.hasil = hasil;
        app.LabelHasil.Text = hasil.labelTeks;
    else
        uialert(app.UIFigure, pesan, "Input Tidak Valid", Icon="warning");
    end
end

Ketika callback di atas berjalan, hasil konversi tampil di label; jika input gagal divalidasi, dialog peringatan muncul di depan jendela app. Perhatikan pembagian kerjanya: callback tidak berisi satu rumus pun — komputasi ada di prosesForm(), dan fungsi itulah yang bisa diuji tanpa GUI (dibahas dua bagian di bawah).

Transisi State Saat Pemrosesan #

State app tidak hanya data hasil — kondisi antarmuka juga state. Pola yang lazim saat pemrosesan panjang: kunci pemicu, proses, pulihkan. app.ProsesButton.Enable = "off" mencegah klik ganda; label status berubah menjadi "Memproses..."; setelah selesai semuanya dikembalikan. Karena callback berjalan satu per satu di event loop, penonaktifan tombol adalah satu-satunya penjaga bahwa pemrosesan tidak tumpang tindih dengan dirinya sendiri.

Pembaruan banyak komponen sekaligus (label, tabel, ringkasan) tidak perlu trik khusus — cukup tulis properti-propertinya lalu biarkan MATLAB menggambar ulang jendela di kesempatan berikutnya; sisipkan drawnow bila kita ingin tampilan terbarui segera sebelum komputasi lanjut.

Menyimpan State Saat App Ditutup #

Data app lenyap saat objek app dihapus. Untuk preferensi atau data kerja, callback penutupan jendela adalah titik simpan terakhir:

matlab
function UIFigureCloseRequest(app, event)
    % Dipanggil sebelum jendela benar-benar ditutup.
    simpanPreferensi(app.dataPath, app.hasil);
    delete(app)
end

Callback CloseRequestFcn milik UIFigure dijalankan ketika pengguna menekan tombol tutup jendela — penutupan tidak terjadi otomatis; pemanggilan delete(app) yang mengakhirinya. Slot inilah tempat menulis preferensi, berkas kerja, atau konfirmasi “ada perubahan belum disimpan” sebelum app musnah.

Pemisahan Logika dari UI #

Pola model–view versi ringkas memetakan tiga peran dalam app kita:

PeranDi dalam appDi luar app (teruji)
Viewkomponen: EditField, Label, UIAxes—
Controllercallback: KonversiButtonPushedcontoh.m (alur simulasi)
Model—prosesForm(), analisisCuaca()

Fungsi model menerima struct input dan mengembalikan struct hasil — tidak menyentuh satu komponen pun, tidak memanggil uialert, tidak membaca app. Konsekuensinya: fungsi model bisa diuji di Octave seperti fungsi biasa. Inilah isi inti contoh.m:

matlab
form = { ...
    struct('suhuTeks', '25', 'satuan', 'Fahrenheit'), ...
    struct('suhuTeks', '100', 'satuan', 'Kelvin'), ...
    struct('suhuTeks', ' dua puluh ', 'satuan', 'Fahrenheit'), ...
    struct('suhuTeks', '36.6', 'satuan', 'Reamur')};

for k = 1:numel(form)
    fprintf('form %d: suhuTeks="%s" satuan="%s"\n', ...
        k, form{k}.suhuTeks, form{k}.satuan);
    [hasil, ok, pesan] = prosesForm(form{k});
    if ok
        fprintf('   -> Tulis komponen: Label.Text = "%s"\n', ...
            hasil.labelTeks);
    else
        fprintf('   -> Tampilkan uialert: %s\n', pesan);
    end
end

Mari kita bedah baris-baris kode di atas:

  1. Baris 1-5 (form = {...}): empat kasus input dibungkus struct — dua valid, satu berisi teks dengan spasi tepi dan kata bukan angka, satu memakai satuan yang tidak dikenal.
  2. Baris 7-10 (for k = 1:numel(form)): loop memainkan peran callback yang dipicu berulang: baca input → panggil prosesForm() → tulis keluaran.
  3. Baris 11-17 (if ok ... else ...): dua jalur keluaran persis seperti callback nyata — label diperbarui saat valid, uialert diganti fprintf saat gagal.

Di dalam prosesForm() (berkas lengkap), fungsi mengerjakan tiga tahap bersih: sanitasi strtrim() + konversi str2double() dengan cek NaN, komputasi switch per satuan, lalu pembentukan labelTeks dengan sprintf() — semuanya tanpa menyentuh UI.

Output yang Dihasilkan:

text
form 1: suhuTeks="25" satuan="Fahrenheit"
   -> Tulis komponen: Label.Text = "77.0 Fahrenheit"
form 2: suhuTeks="100" satuan="Kelvin"
   -> Tulis komponen: Label.Text = "373.1 Kelvin"
form 3: suhuTeks=" dua puluh " satuan="Fahrenheit"
   -> Tampilkan uialert: "dua puluh" bukan angka
form 4: suhuTeks="36.6" satuan="Reamur"
   -> Tampilkan uialert: satuan "Reamur" tidak dikenal

Ringkasan #

Data app hidup di properti class (dataPath, dataTable, hasil) sebagai satu sumber kebenaran lintas callback. Alur callback mengikuti pola baca → proses → tulis: nilai komponen dibaca, komputasi didelegasikan ke fungsi model, hasil ditulis ke komponen output atau dilaporkan lewat uialert. State antarmuka (tombol nonaktif, label status) ikut dikelola saat pemrosesan berjalan, dan CloseRequestFcn menjadi titik simpan terakhir sebelum delete(app). Pemisahan model dari view dibuktikan di contoh.m: prosesForm() mengubah struct menjadi struct dan lolos uji Octave, sementara versi GUI-nya tinggal menempelkan fungsi itu ke callback.