Callback adalah tempat app kita benar-benar hidup: di sinilah klik tombol berubah menjadi komputasi, dan komputasi berubah menjadi tampilan yang diperbarui. Tetapi callback juga sumber bug yang khas — eksekusinya dipicu dari luar, urutannya tidak selalu kita kendalikan, dan satu galat yang tidak ditangkap cukup untuk membekukan alur app. Chapter ini membedah anatomi callback, event data, pola handler bersama, dan strategi mengisolasi logikanya. Cakupannya:

  • anatomi callback (app, event) dan event data yang tersedia
  • urutan eksekusi dan masalah UI yang membeku
  • menangkap galat di dalam callback dengan try-catch + uialert
  • pola dispatch: satu handler untuk banyak sumber

Anatomi Callback #

Callback App Designer selalu memakai satu bentuk tanda tangan — dua argumen, urutannya tetap:

matlab
function ButtonPushed(app, event)
    % app   : objek app — pintu ke seluruh properti dan komponen
    % event : event data — informasi tentang kejadian yang baru terjadi
    app.Label.Text = "Memproses...";
    hasil = hitung(app.EditField.Value);
    app.Label.Text = sprintf("Hasil: %.2f", hasil);
end

Argumen app menggantikan kebutuhan variabel global: seluruh state dan komponen bisa dibaca karena callback adalah method dari class app itu sendiri. Argumen event membawa data kejadian — isinya bergantung jenis event:

EventCallbackIsi event yang berguna
ButtonPushedButtonPushedFcnminimal — sumber diketahui dari app
ValueChangedValueChangedFcnevent.PreviousValue — nilai sebelum perubahan
Jendela ditutupCloseRequestFcnminimal — cukup untuk mencegah/izin menutup

Nilai terkini komponen justru tidak perlu diambil dari event — kita membacanya langsung dari komponennya (app.EditField.Value), karena saat callback berjalan nilai komponen sudah diperbarui. Data event.PreviousValue berguna untuk kebutuhan khusus seperti mencatat riwayat perubahan.

Urutan Eksekusi dan UI yang Membeku #

Mekanisme di balik layar: event loop MATLAB menjalankan callback satu per satu — callback berikutnya menunggu callback sekarang selesai. Konsekuensinya praktis: loop panjang di dalam callback (misalnya optimasi 10.000 iterasi tanpa jeda) membuat app terasa membeku — klik tombol lain tidak diproses, jendela tidak digambar ulang. Solusi resminya sederhana: sisipkan drawnow secara berkala di dalam loop panjang agar MATLAB sempat memproses antrean event dan memperbarui tampilan. Untuk loop yang sangat cepat, drawnow limitrate membatasi frekuensi pembaruan supaya tidak memperlambat komputasi.

Selama pemrosesan panjang, matikan sementara komponen pemicunya supaya pengguna tidak menumpuk event:

matlab
function ProsesButtonPushed(app, event)
    app.ProsesButton.Enable = "off";   % cegah klik ganda
    try
        app.HasilLabel.Text = "Memproses...";
        drawnow
        app.data = prosesBerat(app.data);
        app.HasilLabel.Text = "Selesai";
    catch galat
        uialert(app.UIFigure, galat.message, "Galat Saat Memproses", ...
            Icon="error");
    end
    app.ProsesButton.Enable = "on";    % aktifkan kembali
end

Mari kita bedah baris-baris kode di atas:

  1. Baris 2 (app.ProsesButton.Enable = "off"): properti Enable (bukan Enabled) menonaktifkan tombol — pengguna tidak bisa memicu callback yang sama saat pemrosesan berjalan.
  2. Baris 4 (drawnow): satu pemanggilan di titik yang tepat memberi MATLAB kesempatan menggambar ulang label dan memproses event lain.
  3. Baris 6 (prosesBerat(app.data)): komputasi berat didelegasikan ke method/fungsi terpisah — callback tetap pendek dan mudah dibaca.
  4. Baris 7-9 (catch galat + uialert): galat apa pun di dalam blok try ditangkap lalu ditampilkan sebagai dialog modal di depan jendela app — pengguna melihat pesan yang jelas, bukan teks galat mentah di Command Window.
  5. Baris 11 (Enable = "on"): tombol diaktifkan kembali di akhir; karena berada setelah try-catch, pemulihan terjadi meskipun terjadi galat.

Sintaks uialert di atas terverifikasi dari dokumentasi resmi: uialert(fig, message, title) menampilkan dialog modal dengan ikon error secara bawaan; argumen Icon bisa diubah ke "warning", "info", atau "success".

Hindari Duplikasi: Helper dan Handler Bersama #

Aturan praktisnya: callback adalah koordinator, bukan pelaksana. Callback membaca komponen, memanggil fungsi kerja, lalu menulis hasilnya — komputasi murni dipindahkan ke fungsi terpisah sehingga bisa dipanggil dari banyak callback dan, penting bagi kita, diuji tanpa GUI. Berkas contoh.m di folder chapter ini mendemonstrasikan pola lengkapnya: mula-mula berkas membangun daftar komponen bertag (naik, turun, ganda, set_nilai), lalu satu handler bersama melayani semuanya, memilah aksi lewat Tag, dan menangkap galat dengan try-catch:

matlab
state = struct('nilai', 10);
fprintf('state awal: nilai=%g\n', state.nilai);

aksi = { ...
    'naik',      ''; ...
    'ganda',     ''; ...        % tombol tanpa handler: cabang otherwise
    'set_nilai', '7'; ...
    'set_nilai', 'tujuh'; ...   % memicu galat, ditangkap try-catch
    'turun',     ''};

for k = 1:size(aksi, 1)
    evt = struct('tipe', 'ButtonPushed', ...
        'data', struct('nilaiLama', state.nilai, 'teks', aksi{k, 2}));
    sumber = cariKomponen(komponen, aksi{k, 1});
    state = buttonPushedFcn(sumber, evt, state);
end
fprintf('state akhir: nilai=%g\n', state.nilai);

Mari kita bedah baris-baris kode di atas:

  1. Baris 1 (state = struct(...)): state digantikan struct — nilai adalah satu-satunya data yang dimutasi handler.
  2. Baris 4-10 (aksi = {...}): lima event disusun sebagai pasangan Tag + muatan teks; baris keempat sengaja berisi "tujuh" untuk memicu jalur galat.
  3. Baris 12-15 (evt = struct(...)): event dibangun sebagai struct berisi tipe dan data — nilaiLama berperan seperti event.PreviousValue di callback asli.
  4. Baris 16 (buttonPushedFcn(...)): handler bersama dipanggil dengan tiga bahan yang sama persis dengan callback nyata: sumber (komponen bertag), event, dan state.

Di dalam buttonPushedFcn (lihat berkas lengkapnya), switch sumber.Tag memilih aksi; aksi set_nilai memanggil str2double() lalu error() ketika hasilnya NaN — dan try-catch di lapisan handler menangkapnya sebelum menghentikan program, persis peran uialert di app sungguhan.

Output yang Dihasilkan:

text
state awal: nilai=10
[ButtonPushed] Tag=naik      nilai 10 -> 11
[ButtonPushed] Tag=ganda     belum punya aksi, diabaikan
[ButtonPushed] Tag=set_nilai nilai 11 -> 7
[ButtonPushed] Tag=set_nilai galat ditangkap: input "tujuh" bukan angka
[ButtonPushed] Tag=turun     nilai 7 -> 6
state akhir: nilai=6

Perhatikan dua baris kunci di output: tombol ganda yang belum punya aksi hanya diabaikan (cabang otherwise), dan galat input "tujuh" ditangkap tanpa menghentikan event berikutnya — tombol turun tetap diproses dan state akhir tetap konsisten.

Ringkasan #

Callback App Designer memakai tanda tangan (app, event): app membuka akses ke seluruh state dan komponen, event membawa data kejadian seperti event.PreviousValue pada ValueChangedFcn. Event loop menjalankan callback satu per satu, sehingga komputasi panjang perlu drawnow dan penonaktifan tombol (Enable = "off") agar app tetap responsif. Galat di dalam callback dibungkus try-catch dan dilaporkan lewat uialert. Terakhir, logika handler dipisah dari UI: pola dispatch Tag → aksi di contoh.m membuktikan bahwa handler bersama, jalur galat, dan pemulihan state semuanya bisa dirancang dan diuji tanpa satu jendela pun.