Arsip Bulanan: Agustus 2013

Qt Creator – Qwt, Pustaka Pengganti TeeChart untuk Simulasi Realtime Signal Plotting di Linux (Contoh Program Osiloskop)


Bismillahirrahmanirrahim.

Di luar pemrograman kemarin, sering saya tidak melakukan penulisan kode. Sering saya ingin mencoba examples yang disediakan oleh Qt. Kemarin saya menginstal pustaka Qwt dari repo (karena ketertarikan besar saya untuk mencari pengganti TeeChart di Linux) dan baru hari ini tahu kalau Qwt sama seperti Qt Creator, sama-sama membawa example programs siap pakai. Saya tahu dari mencari bagaimana real time plotting dengan Qwt. Pokoknya grafik sinyal output harus dinamis dan bisa berubah-ubah sesuai input. Eh, pada suatu forum disebut Oscilloscope Example milik Qwt. Lho, memangnya ada? Saya coba cari dengan locate di bash Ubuntu saya dan ketemu. Letaknya di /usr/share/doc/libqwt-doc/examples/. Di situ ada banyak sekali folder example programs. Nah, salah satunya bernama oscilloscope. Saya salin folder itu ke Publik dan membukanya dengan Qt Creator. Ini hasilnya.

qwt-osiloskopa

Hasilnya sungguh realtime seperti TeeChart. Bahkan bisa jadi ini lebih baik. Beranimasi, sinyalnya dinamis, bergerak terus, dan sinyal berubah-ubah sesuai data yang dimasukkan saat runtime. Saya sendiri sangat kaget saat berhasil mengompilasi Osiloskop ini di Qt Creator. Mirip sekali dengan Osiloskop di dunia nyata dan yang sangat menggembirakan adalah akhirnya saya temukan pengganti TeeChart di Linux. Saya sangat gembira malam ini, walhamdulillah.

qwt-osiloskop1a

Apa yang dimaksud dengan realtime? Ya mudahnya, output akan berubah sesuai input yang dimasukkan pada saat itu juga. Lihat, perhatikan knob bundar Amplitude. Saya perkecil maka bentuk sinyal juga menyusut. Persis Osiloskop aslinya. Kalau yang di bawah ini, perhatikan knob Frequency. Saya perkecil, sinyal menjadi renggang tidak lagi mampat. Sungguh persis Osiloskop aslinya. Yang paling penting, ini membuktikan bahwa kita bisa membuat simulasi realtime signal plotting dengan menggunakan pustaka di Linux. Jadi tidak hanya di Windows saja dengan pustaka TeeChart dan IDE Microsoft Visual Studio yang kedua-duanya komersial melainkan juga di Linux bisa bahkan Qwt selaku pustaka dan Qt Creator selaku IDE sama-sama gratis bahkan open source. Suatu keberuntungan buat kita.

qwt-osiloskop2a

Untuk Siapa Tulisan Ini?

  1. Peneliti/pelajar yang ingin membuat aplikasi simulasi real time plotting di Linux.
  2. Peneliti/pelajar yang ingin pengganti TeeChart yang gratis dan open source di Linux.
  3. Programer yang butuh pustaka untuk aplikasi simulasi Biorhytm atau komputasi medikal yang lain.

Behind The Scene Tulisan Ini

TeeChart

Gara-gara TeeChart. Saya sendiri tidak tahu menahu gambar di atas ini program untuk apa. Namun yang paling penting, program ini menayangkan grafik sinyal-sinyal secara dinamis. Lalu kita bisa memasukkan angka-angka di kotak putih sebelah kanan itu dan sinyal-sinyalnya sungguh bisa berubah-ubah. Ini dinamakan simulasi. Dan ini dilakukan dengan bahasa C, pada Microsoft Visual C++, dengan pustaka charting yang bernama Steema TeeChart. Saya bisa mengatakannya karena saya sempat melihat sendiri orang yang membuat program ini. Satu hal saja yang saya pikirkan kala itu (mungkin 4 bulan lalu) bahwa saya harus temukan pengganti TeeChart untuk Linux. Harus bisa dibuat simulasi serupa (tentunya yang realtime bukan yang statis) di Linux. Namun kala itu saya belum tahu sama sekali adanya pustaka-pustaka untuk plotting di Linux.

Selama ini, sejak sebelum posting Qt pertama saya di sini, saya mencari pustaka-pustaka pengganti TeeChart untuk Linux. Cukup sulit menemukannya walau sudah saya temukan calon-calonnya:

  1. OpenGL (saya sudah tahu sebelum keinginan mencari itu ada, tetapi terlalu sulit)
  2. Matplotlib http://matplotlib.sourceforge.net/
  3. GNUplot http://www.gnuplot.info/
  4. QCustomPlot http://qcustomplot.com/ (paling menarik buat saya)
  5. wxPlot http://wxcode.sourceforge.net/showcomp.php?name=wxPlot
  6. wxMathPlot http://wxmathplot.sourceforge.net/
  7. libgraph http://savannah.nongnu.org/projects/libgraph/‎
  8. koolplot http://koolplot.codecutter.org/
  9. EasyBMP http://easybmp.sourceforge.net/‎
  10. plotutils http://gnu.org/s/plotutils/
  11. plplot http://plplot.sourceforge.net
  12. wxArt2d http://wxart2d.org/moin/WxArt2dScreenShots
  13. MathGL http://mathgl.sourceforge.net/
  14. Scidavis http://scidavis.sourceforge.net/ (bukan pustaka)
  15. DISLIN http://www.dislin.de/
  16. wxChart http://wxcode.sourceforge.net/components/wxchart/
  17. PyQtGraph http://www.pyqtgraph.org/
  18. GUIQwt https://code.google.com/p/guiqwt/
  19. Chaco http://code.enthought.com/projects/chaco/gallery.php
  20. Qwt http://qwt.sourceforge.net/ (sebenarnya masih ada yang lain, hanya saja yang saya temukan cuma sekian).

Supaya nyata, ini saya sertakan skrinsot jadi salah satu pustaka (PyQtGraph, open source):

pyqtgraph-plotting

Serta satu lagi, yakni Matplotlib (open source):

Dan harus saya sebut juga laman yang mengantarkan saya kepada semua pustaka plotting yang ada:

  1. http://stackoverflow.com/questions/296199/is-there-any-out-of-the-box-2d-3d-plotting-library-for-c
  2. http://wiki.python.org/moin/NumericAndScientific/Plotting
  3. http://qt-project.org/forums/viewthread/14819 (mengantar saya pada QCustomPlot)

Yang saya pikirkan kala membuka semua laman itu hanyalah: “ini bisa realtime apa tidak?“. Soalnya saya ingin yang realtime bukan yang statis. Akhirnya semua ini berakhir pada Qwt setelah saya melihat dua laman ini:

  1. http://www.swharden.com/blog/2013-05-08-realtime-data-plotting-in-python/ (gara-gara ini saya semangat lagi mencari setelah saya anggap sudah mustahil, saya melihat Qt Designer di sana dan kaget sekali)
  2. http://codingexodus.blogspot.com/2013/01/getting-started-with-qwt.html (saya coba dan berhasil)

Hasilnya saya cari keterangan soal Qwt dan alhamdulillah ternyata jawabannya ada di dalam examples milik Qwt. Supaya nyata juga, ini skrinsot folder oscilloscope asli milik Qwt.

resized_qwt-osiloskop5

Kode

Ada satu hal penting setelah mengimpor satu folder oscilloscope ke dalam Qt Creator. Anda harus menambahkan satu baris kode ini di dalam .pro Anda.

CONFIG += qwt

atau dipastikan Qt Creator Anda error karena tidak bisa menemukan letak header-header Qwt. Saya menggunakan Qt Creator 4.8 pada Ubuntu 12.04 dan error kalau tidak ada baris ini. Setelah ditulis baru jalan programnya seperti skrinsot pertama. Mudah sekali, bukan?

Unduh Kode Sumber

Tautan: http://otodidak.freeserver.me/tarball/oscilloscope.tar.gz
Ukuran: 8 KB

Kesimpulan

Qwt adalah pustaka Qt untuk realtime signal plotting pengganti TeeChart di Linux. Bisa digunakan untuk sinyal sinus biasa sampai simulasi Osiloskop.

Penutup

Semoga tulisan ini bermanfaat untuk Anda sekalian.

Iklan

Qt Creator – Tip Trik Efisien Memrogram C++ dalam IDE Edisi 2


Bismillahirrahmanirrahim.

Ini posting di luar pemrograman, lanjutan yang kemarin. Kali ini temanya cuma dua yakni soal duplicate line dan skema warna kode.

Duplicate Line

Ini sangat berguna kala ada beratus baris yang polanya sama. Daripada harus Ctrl+C lalu Ctrl+V, mending Ctrl+D. Jadi, letakkan kursor di satu baris lalu Ctrl+D maka baris tersebut langsung dikopi di bawahnya. Serta, kalau ada sekian baris yang dipilih, lalu Ctrl+D dijalankan, maka seluruh baris tersebut diduplikat di bawahnya. Ini fitur yang saya temukan di aplikasi Geany dan AutoIt IDE. Sangat berguna dan sangat memangkas waktu. Begini skrinsotnya biar lebih jelas.

Sebelum Ctrl+D:

ngite-ketujuh18

Setelah Ctrl+D 3 kali:

ngite-ketujuh19

Cara mengaturnya ada pada Tools > Options > Environment > TAB Keyboard > cari string CopyLineDown. Lihat gambar ini.

ngite-ketujuh17

Skema Warna Kode

Mungkin seseorang cocok dengan skema warna gelap macam ini dibanding yang putih biasanya. Ternyata Qt Creator menyediakannya (seperti Kate). Bagaimana cara mengaturnya?

resized_ngite-ketujuh14

Tools > Text Editor > TAB Font & Colors > Vim (dark). Tersedia pilihan Intellij IDEA juga. Dan Anda bisa mengkustomisasinya sekehendak Anda.

resized_ngite-ketujuh15
Semoga ini bermanfaat.

Pemrograman Qt 6 – Membuat Program GUI Sederhana Menggunakan Sebanyak Mungkin Kelas (QStackedLayout, QPushButton, QLabel, QComboBox, dan Lainnya)


Bismillahirrahmanirrahim.

Alhamdulillah. Setelah kemarin saya menuai keberhasilan layering sebagaimana yang saya harap, kini saatnya berlatih memperluas program yang sudah bisa layering dengan macam-macam kelas yang saya belum kenal. Ini untuk memperlancar membuat program. Di sini saya membuat satu program dengan 4 layer. Setiap layer diwakili oleh satu tombol. Bedanya, kali ini saya unggah kode sumbernya lengkap di dalam paket ZIP. Silakan diunduh dan dibuka di Qt Creator Anda. Semoga ini bermanfaat.

Mockup

compressed_resized_SAM_6254

Tidak seperti biasanya, saya kali ini menggambar mockup-nya dahulu di kertas. Ini penting karena akan susah sekali program ditulis kalau harus mengimajinasikan semuanya. Lebih mudah kalau digambar dulu desainnya lalu nanti tinggal menulis kode sesuai gambar. Lakukan ini juga kala Anda ingin membuat program besar.

Wujud Program yang Diinginkan

ngite-ketujuh

Saya cinta http://ilmoe.com

ngite-ketujuh1 ngite-ketujuh2 ngite-ketujuh3

Daftar Kelas Qt yang Dipakai

  1. QVBoxLayout
  2. QHBoxLayout
  3. QStackedLayout
  4. QFrame
  5. QPushButton
  6. QComboBox
  7. QLabel
  8. QPixmap
  9. QRadioButton

Daftar Method Qt yang Dipakai

  1. setReadOnly (baru)
  2. setText (baru)
  3. setPixmap (baru)
  4. addWidget
  5. setAlignment (baru)
  6. addLayout
  7. setContentsMargins (baru)
  8. addItem (baru)
  9. setLayout
  10. setFrameShape
  11. setFrameShadow
  12. setLayout
  13. connect
  14. setCurrentIndex

Qt Creator dalam Kode

resized_ngite-ketujuh10 resized_ngite-ketujuh11

ngite-ketujuh6

Kode Program

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog();

    QVBoxLayout     *layoututama;
    QVBoxLayout     *layouta;
    QVBoxLayout     *layoutb;
    QVBoxLayout     *layoutc;
    QVBoxLayout     *layoutd;
    QHBoxLayout     *layoute;
    QHBoxLayout     *layoutf;

    QFrame          *frameutama;
    QFrame          *framea;
    QFrame          *frameb;
    QFrame          *framec;
    QFrame          *framed;

    QLabel          *labela;
    QLabel          *labelagambar;
    QLabel          *labelb;
    QLabel          *labelc;
    QLabel          *labeld;

    QPushButton     *tombola;
    QPushButton     *tombolb;
    QPushButton     *tombolc;
    QPushButton     *tombold;

    QPushButton     *tombolgga;         //gg = gak guna
    QPushButton     *tombolgga1;
    QPushButton     *tombolggb;
    QPushButton     *tombolggb1;

    QTextEdit       *textedit;

    QRadioButton    *radioa;
    QRadioButton    *radiob;
    QRadioButton    *radioc;
    QRadioButton    *radiod;

    QComboBox       *comboa;
    QComboBox       *combob;
    QComboBox       *comboc;
    QComboBox       *combod;

    QStackedLayout  *stack;

public slots:
    void            gantia();
    void            gantib();
    void            gantic();
    void            gantid();

private:

};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"                     //IDE yang dipakai adalah Qt Creator
#include "ui_mainwindow.h"                  //https://malsasa.wordpress.com

Dialog::Dialog()
{

    //deklarasi semua objek dahulu

    layoututama     =   new     QVBoxLayout;        //layout
    layouta         =   new     QVBoxLayout;
    layoutb         =   new     QVBoxLayout;
    layoutc         =   new     QVBoxLayout;
    layoutd         =   new     QVBoxLayout;
    layoute         =   new     QHBoxLayout;
    layoutf         =   new     QHBoxLayout;

    framea          =   new     QFrame;             //frame
    frameb          =   new     QFrame;
    framec          =   new     QFrame;
    framed          =   new     QFrame;

    labela          =   new     QLabel;             //label
    labelagambar    =   new     QLabel;
    labelb          =   new     QLabel;
    labelc          =   new     QLabel;
    labeld          =   new     QLabel;

    tombola         =   new     QPushButton("1");   //pushbutton
    tombolb         =   new     QPushButton("2");
    tombolc         =   new     QPushButton("3");
    tombold         =   new     QPushButton("4");

    tombolgga       =   new     QPushButton("GGA"); //pushbutton gak guna
    tombolgga1      =   new     QPushButton("GGA 1");
    tombolggb       =   new     QPushButton("GGB");
    tombolggb1      =   new     QPushButton("GGB 1");

    radioa          =   new     QRadioButton("RADIO 1");    //radio button
    radiob          =   new     QRadioButton("RADIO 2");
    radioc          =   new     QRadioButton("RADIO 3");
    radiod          =   new     QRadioButton("RADIO 4");

    textedit        =   new     QTextEdit("<span style="text-decoration: underline;"><i><b>INI ADALAH TEXTEDIT</b></i></span>");      //QTextEdit bisa mem-parsing HTML
    textedit->setReadOnly(true);

    comboa          =   new     QComboBox;                  //combo box
    combob          =   new     QComboBox;
    comboc          =   new     QComboBox;
    combod          =   new     QComboBox;

    stack           =   new     QStackedLayout;             //primadona kita

    //SELESAI DEKLARASI PEMBUATAN OBJEK
    //deklarasi labela dengan tulisan

    labela->setText("<b>INI HALAMAN 1</b>");        //GILA, Qt bisa mem-parsing HTML dalam string dalam parameter sekalipun
    labelb->setText("<i>INI HALAMAN 2</i>");        //Qt benar-benar enak
    labelc->setText("<span style="text-decoration: underline;">INI HALAMAN 3</span>");        //tag yang diterima <b> <i> <span style="text-decoration: underline;">
    labeld->setText("<span style="color: red;">INI HALAMAN 4</span>");      //hanya QLabel dan QTextEdit saja, kelas lain tidak menerima HTML

    //deklarasi gambar untuk labelagambar

    labelagambar->setPixmap(QPixmap(":/gambar/download.png"));      //ditemukan pada 23 Agustus 2013
    //sumber: http://qt-project.org/forums/viewthread/15365
    //ternyata cuma begini saja deklarasinya, gak usah kelas QImage atau QPixmap atau QPicture sama sekali

    //deklarasi pengisian layouta dengan item-item halaman 1

    layouta->addWidget(labela);
    layouta->setAlignment(labela, Qt::AlignHCenter);
    layouta->addWidget(labelagambar);
    layoutf->addWidget(tombolgga);
    layoutf->addWidget(tombolgga1);
    layouta->addLayout(layoutf);
    layouta->setContentsMargins(1,1,1,55);          //ukuran terakhir adalah margin vertikal bawah

    //deklarasi pengisian layoutb dengan item-item halaman 2

    layoutb->addWidget(labelb);
    layoutb->setAlignment(labelb, Qt::AlignHCenter);
    layoutb->addWidget(textedit);
    layoutb->addWidget(tombolggb);
    layoutb->addWidget(tombolggb1);

    //deklarasi pengisian layoutc dengan item-item halaman 3

    layoutc->addWidget(labelc);
    layoutc->setAlignment(labelc, Qt::AlignTop);
    layoutc->setAlignment(labelc, Qt::AlignHCenter);
    layoutc->addWidget(radioa);
    layoutc->setAlignment(radioa, Qt::AlignTop);
    layoutc->setAlignment(radioa, Qt::AlignHCenter);
    layoutc->addWidget(radiob);
    layoutc->setAlignment(radiob, Qt::AlignTop);
    layoutc->setAlignment(radiob, Qt::AlignHCenter);
    layoutc->addWidget(radioc);
    layoutc->setAlignment(radioc, Qt::AlignTop);
    layoutc->setAlignment(radioc, Qt::AlignHCenter);
    layoutc->addWidget(radiod);
    layoutc->setAlignment(radiod, Qt::AlignTop);
    layoutc->setAlignment(radiod, Qt::AlignHCenter);
    layoutc->setContentsMargins(1,1,1,111);         //ini harus ada

    //deklarasi pengisian layoutd dengan item-item halaman 4

    layoutd->addWidget(labeld);
    layoutd->setAlignment(labeld, Qt::AlignHCenter);
    layoutd->addWidget(comboa);
    layoutd->addWidget(combob);
    layoutd->addWidget(comboc);
    layoutd->addWidget(combod);
    layoutd->setContentsMargins(1,1,1,111);

        //begini cara mengisi item-item combo box
        //kalau pakai addItems tambah bingung karena
        //harus pakai objek List, jika tidak maka gagal

        comboa->addItem("KUCING");      //ingat, addItem bukan addItems
        comboa->addItem("AYAM");
        comboa->addItem("SAPI");

        combob->addItem("JERUK");
        combob->addItem("STROBERI");
        combob->addItem("APEL");

        comboc->addItem("BAYAM");
        comboc->addItem("KANGKUNG");
        comboc->addItem("KUBIS");

        combod->addItem("MERICA");
        combod->addItem("GARAM");
        combod->addItem("BAWANG PUTIH");

    //kemudian deklarasi pemasangan antara frame dengan layout

    framea->setLayout(layouta);
    frameb->setLayout(layoutb);
    framec->setLayout(layoutc);
    framed->setLayout(layoutd);

    //deklarasi frame agar terlihat wujudnya

    framea->setFrameShape(QFrame::StyledPanel);
    frameb->setFrameShape(QFrame::StyledPanel);
    framec->setFrameShape(QFrame::StyledPanel);
    framed->setFrameShape(QFrame::StyledPanel);

    framea->setFrameShadow(QFrame::Raised);
    frameb->setFrameShadow(QFrame::Raised);
    framec->setFrameShadow(QFrame::Raised);
    framed->setFrameShadow(QFrame::Raised);

    //memasukkan objek sebagai layer

    stack->addWidget(framea);
    stack->addWidget(frameb);
    stack->addWidget(framec);
    stack->addWidget(framed);

    //mengisi layoute dengan tombol-tombol supaya bisa horizontal persis mockup

    layoute->addWidget(tombola);
    layoute->addWidget(tombolb);
    layoute->addWidget(tombolc);
    layoute->addWidget(tombold);

    //memasukkan layout kecil ke dalam layout utama

    layoututama->addLayout(stack);
    layoututama->addLayout(layoute);

    //memasang layoututama ke dalam Dialog

    setLayout(layoututama);

    //memberi fungsi untuk setiap tombol

    connect(tombola, SIGNAL(clicked()), this, SLOT(gantia()));      //A semua
    connect(tombolb, SIGNAL(clicked()), this, SLOT(gantib()));      //B semua
    connect(tombolc, SIGNAL(clicked()), this, SLOT(gantic()));      //C semua
    connect(tombold, SIGNAL(clicked()), this, SLOT(gantid()));      //D semua
    //cara baca kode ini: kalau tombol c diklik, maka Dialog memanggil fungsi gantic
    //receiver-nya harus "this", tidak boleh "Dialog", tidak juga "stack"

}

//deklarasi fungsi-fungsi untuk tombol

void Dialog::gantia()
{
    stack->setCurrentIndex(0);
}

void Dialog::gantib()
{
    stack->setCurrentIndex(1);
}

void Dialog::gantic()
{
    stack->setCurrentIndex(2);          //jika Dialog memanggil fungsi ini, maka
}                                       //stack layer nomor 2 akan maju ke depan

void Dialog::gantid()
{
    stack->setCurrentIndex(3);
}

Analisis Kode Program

mainwindow.h

Tidak ada yang berbeda dari posting nomor 5 kemarin. Pokoknya, semua objek harus dideklarasikan di sini dahulu karena akan digunakan dalam layer dan ada fungsi yang memanggil fungsi di luar tubuhnya.

mainwindow.cpp

Di sini banyak yang penting dan berbeda. Yang sama dengan kemarin adalah deklarasi ulang semua kelas yang sudah dideklarasikan tetapi bentuk deklarasi harus pendek namaObjeknya = new NamaKelasnya; tanpa tanda pointer (*) dan tanpa NamaKelas depan. Yang berbeda dari kemarin karena adanya kelas-kelas baru semisal QTextEdit (untuk menulis teks), QLabel, QPixmap, dan lain-lain, di antaranya:

QTextEdit

textedit        =   new     QTextEdit("<u><i><b>INI ADALAH TEXTEDIT</b></i></u>");
textedit->setReadOnly(true);

Inilah deklarasi objek QTextEdit. Sama saja dengan kelas yang lain. Ajaibnya, ia menerima HTML di dalam string di dalam parameter dan mem-parsing-nya saat runtime. Ini sangat mengesankan saya bahwa Qt melakukan hal yang sangat memudahkan saya memformat nantinya. Kalau begini, mungkin saya bisa menulis ulang Otodidak dalam Qt dengan memasukkan gambar sekaligus tulisan (dan tulisan itu bisa miring bisa tebal) di dalam satu kotak saja. Qt bisa mem-parsing HTML untuk QTextEdit.

Maksud dari method setReadOnly adalah menjadikan objeknya QTextEdit nanti tidak bisa ditulisi lagi. Hanya bisa dibaca saja. Itu kalau diset nilainya true. Perhatikan, apa-apa method yang mengubah perilaku suatu objek, seringkali namanya diawali dengan set. Jadi, kita akan lebih cepat kerja dengan Qt Creator kala mencari method karena tahu tanda-tandanya.

QLabel

labela->setText("<b>INI HALAMAN 1</b>");
labelb->setText("<i>INI HALAMAN 2</i>");
labelc->setText("<u>INI HALAMAN 3</u>");
labeld->setText("<font color='red'>INI HALAMAN 4</font>");

Ini pengisian teks untuk QLabel. Digunakanlah method setText milik QLabel. Ajaibnya lagi, parameter string di dalam QLabel menerima HTML dan mem-parsing-nya ketika runtime. Ini pun sangat menguntungkan saya. Saya bisa mewarnai dan membagaimanakan tulisan dalam label sesuka saya. Ini akan sangat membantu untuk kita membentu UI dan UX yang baik untuk aplikasi. Ini (wallahu a’lam) belum saya temukan kala menggunakan Java platform (Netbeans).

QPixMap

labelagambar->setPixmap(QPixmap(":/gambar/download.png"));

Ini adalah tindakan mengisi QLabel dengan gambar. Tentu gambar sudah diimpor terlebih dahulu ke dalam proyek. Lihat posting sebelumnya untuk cara mengimpor gambar. Caranya ternyata dengan method setPixmap miliknya QLabel. Lalu di dalam parameternya dipanggillah QPixmap dengan parameter lagi berupa string, yang string itu berisi path ke gambar yang diimpor. Gambarnya adalah banner http://ilmoe.com, website favorit saya.

QVBoxLayout & QHBoxLayout

layouta->addWidget(labela);
layouta->setAlignment(labela, Qt::AlignHCenter);
layouta->addWidget(labelagambar);
layoutf->addWidget(tombolgga);
layoutf->addWidget(tombolgga1);
layouta->addLayout(layoutf);
layouta->setContentsMargins(1,1,1,55);

Ini meskipun sudah Anda ketahui semuanya, masih penting karena menata objek-objek ke dalam layout. Di sini yang berlaku sebagai layout vertikal adalah layouta dan yang horizontal itu layoutf. Yang vertikal untuk judul dan gambar, yang horizontal untuk dua tombol GG. Lihat foto mockup di atas pada HALAMAN 1.

Yang unik di sini adalah method setAlignment milik QVBoxLayout. Di dalam parameternya ada dua buah isi. Yang pertama adalah objek/widget, dan yang kedua adalah kode alignment (perataan). Isi yang pertama ini adalah labela dan Qt::AlignHCenter. Maksud kode ini adalah jadikan labela itu Center secara horizontal, pada layouta. Seperti ini juga untuk objek-objek lain. Inilah cara kita untuk menata supaya objek-objek dalam layout itu rapi. Kalau tidak begini, lihat saja. Nanti objek-objek Anda bisa awut-awutan letaknya.

Method setContensMargins ini saya gunakan untuk menarik semua objek ke atas. Karena jika tidak begitu, semua objek terlihat turun mendekati garis paling bawah. Ini tidak rapi. Makanya saya kasih angka 55 supaya ada jarak antara objek paling bawah dengan garis frame bawah. Hasilnya HALAMAN 1 terlihat rapi. Semua objek berada pas di tengah-tengah frame.

QComboBox

comboa->addItem("KUCING");
comboa->addItem("AYAM");
comboa->addItem("SAPI");

combob->addItem("JERUK");
combob->addItem("STROBERI");
combob->addItem("APEL");

comboc->addItem("BAYAM");
comboc->addItem("KANGKUNG");
comboc->addItem("KUBIS");

combod->addItem("MERICA");
combod->addItem("GARAM");
combod->addItem("BAWANG PUTIH");

Inilah cara untuk mengisi tiap-tiap combo box dengan opsi. Hasilnya bisa dilihat pada skrinsot berikut:

ngite-ketujuh9

Untuk kode-kode setelah baris 118 ini, walhamdulillah sudah saya tulis keterangannya pada posting nomor 5.

Rangkuman

  1. Kelas yang bisa meng-handle HTML adalah QLabel dan QTextEdit (yang lainnya belum diketahui). Yang jelas, QPushButton tidak bisa meng-handle HTML.
  2. Memasukkan gambar ke dalam QLabel sangat mudah, tidak usah membuat objek baru. Cukup deklarasikan: label->setPixmap(QPixmap(“:/prefix/namagambar.png”);.
  3. Ukuran horizontal layer pada semua layer pada QStackedLayout mengikuti ukuran isi layer terpanjang.
  4. Kode-kode alignment untuk parameter kedua dalam setAlignment milik QVBoxLayout/QHBoxLayout adalah Qt::AlignCenter, Qt::AlignHCenter, Qt::AlignVCenter, Qt::AlignJustify, Qt::AlignBottom, Qt::AlignRight, dan Qt::AlignLeft. Bisa dipilih sendiri dengan Qt Creator.

Unduh

Kode Sumberhttp://otodidak.freeserver.me/tarball/Embrio-B.tar.gz
Ukuran: 34 KB

Pemrograman Qt 5 – QStackedLayout dan QPushButton untuk Layering (setCurrentIndex)


Bismillahirrahmanirrahim.

Satu bulan saya mencari cara mengganti layer (bahasa teknisnya mengganti indeks dari QStackedLayout) dengan klik pada QPushButton. Kemarin maksimal baru bisa berganti dengan QComboBox. Alhamdulillah, penantian itu usai dan saya senang sekali. Mengapa? Karena jika ini sudah berhasil dilakukan, maka semua proses pengerjaan program yang saya inginkan akan lancar insya Allah. Bagaimana lagi? Program saya sebetulnya hanya berisi hal ini nantinya. Sekarang saatnya saya beberkan programnya.

Wujud Program yang Diinginkan

ngite-kelima

ngite-kelima1

Penjelasan: pokoknya, tampilan program harus berubah menjadi tampilan lain jika diklik tombol. Di sini, ada frame-frame yang ditumpuk jadi layer. Kalau tombol 1 diklik, maka frame 1 tampil di atas sedangkan frame 2 di bawah. Sebaliknya pula demikian. Ini yang saya sebut layering.

Daftar Kelas Qt yang Dipakai

  1. QVBoxLayout
  2. QFrame
  3. QPushButton
  4. QStackedLayout (primadona tulisan ini)
  5. QLabel

Daftar Method Qt yang Dipakai

  1. addWidget
  2. setLayout
  3. addLayout
  4. setCurrentIndex (primadonanya primadona ini)
  5. stacksatu
  6. stackdua
  7. setFrameShape
  8. setFrameShadow
  9. setFixedSize

Qt Creator dalam Kode

mainwindow.cpp

ngite-kelima2

mainwindow.h

ngite-kelima3

Kode Program

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtGui>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog();
    QVBoxLayout *layoututama;
    QVBoxLayout *layouta;
    QVBoxLayout *layoutb;
    QFrame      *framea;
    QFrame      *frameb;
    QStackedLayout *stackia;
    QPushButton *tombola;
    QPushButton *tombolb;
    QPushButton *tombolpengatur;
    QPushButton *tombolpengutar;
    QLabel      *labela;
    QLabel      *labelb;

public slots:
    void stacksatu();
    void stackdua();

private:

};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

Dialog::Dialog()
{
    layoututama = new QVBoxLayout;
    layouta     = new QVBoxLayout;
    layoutb     = new QVBoxLayout;
    framea      = new QFrame;
    frameb      = new QFrame;
    stackia     = new QStackedLayout;
    labela      = new QLabel("FRAME 1");
    labelb      = new QLabel("FRAME 2");

    tombola     = new QPushButton("1");
        tombola->setFixedSize(88,88);
    tombolb     = new QPushButton("2");
        tombolb->setFixedSize(66,66);
    tombolpengatur = new QPushButton("SATU");
        tombolpengatur->setFixedSize(88,33);
    tombolpengutar = new QPushButton("DUA");
        tombolpengutar->setFixedSize(88,33);

    layouta->addWidget(labela);
    layouta->addWidget(tombola);
    framea->setLayout(layouta);
        framea->setFrameShape(QFrame::StyledPanel);
        framea->setFrameShadow(QFrame::Raised);

    layoutb->addWidget(labelb);
    layoutb->addWidget(tombolb);
    frameb->setLayout(layoutb);
        frameb->setFrameShape(QFrame::StyledPanel);     //shape = styledpanel
        frameb->setFrameShadow(QFrame::Raised);         //shadow = raised

    stackia->addWidget(framea);
    stackia->addWidget(frameb);

    layoututama->addLayout(stackia);        //bukan addWidget tetapi addLayout
    layoututama->addWidget(tombolpengatur);
    layoututama->addWidget(tombolpengutar);

    setLayout(layoututama);

    connect(tombolpengatur, SIGNAL(clicked()), this, SLOT(stacksatu()));
    connect(tombolpengutar, SIGNAL(clicked()), this, SLOT(stackdua()));

}

void Dialog::stacksatu()
{
    stackia->setCurrentIndex(0);
}

void Dialog::stackdua()
{
    stackia->setCurrentIndex(1);
}

Analisis Kode Program

HEADER

Kali ini saya tidak bisa mengabaikan HEADER begitu saja. Berkas mainwindow.h menjadi penting pada program ini. Mengapa? Ini berkaitan dengan slot dan fungsi yang dipakai. Pada berkas ini, yang paling penting yang harus diperhatikan adalah deklarasi. Lihat, deklarasi objek-objek ini sangat penting dan harus ada:

    QVBoxLayout    *layoututama;
    QVBoxLayout    *layouta;
    QVBoxLayout    *layoutb;
    QFrame         *framea;
    QFrame         *frameb;
    QStackedLayout *stackia;
    QPushButton    *tombola;
    QPushButton    *tombolb;
    QPushButton    *tombolpengatur;
    QPushButton    *tombolpengutar;
    QLabel         *labela;
    QLabel         *labelb;

Ingat, mereka harus dideklarasikan dalam mainwindow.h. Mereka harus ada di bawah lingkupan public:. Jangan dipikirkan antara nama tombol pengatur dengan pengutar. Sama saja. Yang penting lagi, bahkan paling pentingnya adalah ini:

public slots:
    void stacksatu();
    void stackdua();

Mengapa penting? Karena dua buah slot ini akan dipakai untuk menggerakkan QStackedLayout supaya mengubah indeksnya. Alias, ganti tampilan. Dan slot ini harus dideklarasikan di lingkup public slots:, tidak bisa ditaruh pada private karena slot ini berjalan antarfungsi. Kalau dibuat private, maka ia hanya berjalan di dalam satu fungsi yang sama. Yang dimaksud antarfungsi adalah fungsi besar Dialog(), stacksatu/stackdua itu sendiri, dan fungsi khusus setCurrentIndex() milik objek QStackedLayout yang semuanya ada di dalam mainwindow.cpp. Intinya, yang diinginkan dengan ini adalah, jika ada tombol diklik maka fungsi stacksatu() dipanggil, dan di dalam fungsi stacksatu() tersebut dipanggillah fungsi setCurrentIndex(). Perhatikan, objek QStackedLayout berada di dalam fungsi Dialog(), tidak di dalam stacksatu(). Ini hanya bisa dilakukan jika stacksatu bertipe public. Demikian juga dengan stackdua().

Oh iya, pada program kali ini, area private: dibiarkan kosong. Sudah, jangan dipikirkan.

CPP

Khusus untuk mainwindow.cpp, ada sesuatu yang sangat berbeda dengan 4 tulisan Qt sebelumnya. Apa yang beda? Deklarasi objek-objek yang dipangkas. Lihat:

    layoututama = new QVBoxLayout;
    layouta     = new QVBoxLayout;
    layoutb     = new QVBoxLayout;
    framea      = new QFrame;
    frameb      = new QFrame;
    stackia     = new QStackedLayout;
    labela      = new QLabel("FRAME 1");
    labelb      = new QLabel("FRAME 2");

    tombola     = new QPushButton("1");
        tombola->setFixedSize(88,88);
    tombolb     = new QPushButton("2");
        tombolb->setFixedSize(66,66);
    tombolpengatur = new QPushButton("SATU");
        tombolpengatur->setFixedSize(88,33);
    tombolpengutar = new QPushButton("DUA");
        tombolpengutar->setFixedSize(88,33);

Yang sangat perlu diperhatikan adalah pergantian pola dari:

QNamaKelas *namaObjek = new QNamaKelas;

menjadi bentuk deklarasi objek yang terpangkas demikian:

namaObjek = new QNamaKelas;

Perhatikan. Deklarasi awal QNamaKelas tidak dipakai lagi. Juga tidak dipakai lagi tanda pointer (*). Langsung ditulis nama objek yang diinginkan lalu tetap ditulis nama kelas di akhir deklarasi (sebelah kanan tanda ‘=’). Mengapa dipakai deklarasi model begini? Karena kita sudah mendeklarasikan secara umum pada header. Dan karena saya kemarin satu bulan memakai pola yang pertama untuk deklarasi dalam mainwindow.cpp ini, satu bulan pula saya gagal mengerjakan kode ini. Setelah diganti dengan deklarasi baru ini, dan ditambahi sedikit kode, alhamdulillah berhasil.

Yang paling penting dari berkas CPP kali ini adalah kode connect ini:

connect(tombolpengatur, SIGNAL(clicked()), this, SLOT(stacksatu()));
connect(tombolpengutar, SIGNAL(clicked()), this, SLOT(stackdua()));

Inilah kunci dari berkas CPP ini, yang satu bulan saya cari kode yang benarnya bagaimana. Ternyata beginilah menulis kodenya. Inti kode di atas adalah

objek, SIGNAL(fungsi()), objek, SLOT(fungsi())

yang diterjemahkan dalam konteks program 5 ini menjadi

tombol, SIGNAL(clicked()), this, SLOT(stacksatu())

Maksud this adalah kelas yang tulisan this ini ada di dalamnya. Maka this merujuk pada Dialog. Makna kode connect ini adalah jika ada tombol yang terkena perlakuan clicked() (maksudnya, diklik), maka kelas Dialog memanggil fungsi stacksatu(). Itulah maksudnya. Dan ini sangat krusial, tidak boleh diganti kata this menjadi Dialog atau kata Dialog(), atau tidak juga boleh diganti menjadi stackia walaupun aslinya yang ingin dilakukan dengan kode connect() ini hanyalah mengganti indeks milik stackia saja. Nyatanya, harus demikianlah caranya.

Kemudian, kode yang harus ada meskipun kecil sekali adalah ini:

void Dialog::stacksatu()
{
    stackia->setCurrentIndex(0);
}

void Dialog::stackdua()
{
    stackia->setCurrentIndex(1);
}

Maksud semua potongan kode ini hanyalah bagaimana caranya dari tombol dikirim perintah ke QStackedLayout untuk mengubah indeksnya. Sudah, begitu saja. Hanya saja untuk itu, harus ada fungsi khusus sebagai SLOT yang dipanggil di dalam connect, yang di dalam fungsi khusus itu akan dipanggil fungsi asli milik QStackedLayout sehingga sanggup mengubah indeksnya. Jadi ada fungsi di dalam fungsi. Itu terjadi dalam kode fungsi stacksatu/stackdua di atas. Perhatikan, stackia->setCurrentIndex(1); itulah kodenya. Untuk bisa mengganti setCurrentIndex ini harus kita lakukan demikian panjang pengodean. Namun jika dilihat ulang secara keseluruhan, ealah, ternyata kode kita ini sangatlah pendek. Mudah untuk dilakukan.

Hasil Akhir

ngite-kelima1

ngite-kelima

 

Alhamdulillah, berhasil. Kalau sudah bisa begini, semua sisa pengerjaan akan menjadi sangat-sangat ringan.

 

Rangkuman

  1. Fungsi connect untuk menggerakkan QStackedLayout dengan QPushButton harus disandarkan receiver SLOT-nya pada kelas tertinggi yakni Dialog, dengan kata ganti this. Khas OOP.
  2. Mengubah nilai setCurrentIndex miliknya QStackedLayout itu dilakukan dengan membuat satu fungsi baru yang di dalam fungsi itu baru dipanggillah setCurrentIndex. Tidak bisa secara langsung setCurrentIndex dipanggil di dalam connect.
  3. Deklarasi objek di dalam CPP jika objek itu sudah dideklarasikan di H, maka tidak diulang nama kelasnya di kiri tanda ‘=’.

Catatan Penting

Saya menyebutkan satu bulan rentang waktu pencarian ini adalah dari sini:

  1. http://qt-project.org/forums/viewthread/30461/
  2. http://stackoverflow.com/questions/17916905/change-qstackedlayout-index-with-qpushbutton-not-qcombobox

Membaca PDF Berfonta Arab di Linux


Bismillahirrahmanirrahim.

Bagaimana memperbaiki tulisan Arab yang tampil kacau dan tidak semestinya di Linux? Lihat contoh skrinsot berikut.

resized_mengatasifontarab

PDF di atas adalah Kitab Al Mulakhasul Fiqhi karya Syaikh Shalih al-Fauzan. Seluruhnya ditulis dalam aksara Arab. Saya membukanya di aplikasi Okular. Sama hasilnya jika dibuka dengan PDF reader lainnya. Jika antum melihat bentuk kekacauan yang sama di Linux antum, maka posting ini insya Allah pas untuk antum. Cara memecahkan masalah ini adalah sangat sederhana, cukup instal fonta Arab yang dipakai di dalam PDF yang kacau ketika dibaca di Linux.

1. Lihat fonta Arab apa yang dipakai dalam PDF ini. resized_mengatasifontarab5

 

Buka menu File > Properties > buka TAB Fonts. Tebak saja, tidak usah pusing. Dugaan kuat saya ada pada fonta bernama Traditional Arabic. Mengapa? Ya karena namanya Arabic.

2. Cari fonta Arab tersebut dengan Google.

resized_mengatasifontarab2

Kata kuncinya download font traditional arabic. Kalau antum belum mahir googling, silakan merujuk kemari.

3. Instal fonta .ttf yang baru diunduh dengan klik 2 kali.

resized_mengatasifontarab3

Pilih tombol Personal agar tidak usah memasukkan password.

4. Restart aplikasi pembaca PDF antum.

resized_mengatasifontarab4

 

Alhamdulillah, sudah bisa dibaca dengan benar aksara Arabnya. Tanda kalau fonta Tradidional Arabic tadi sudah beres adalah ada alamat (path) fonta yang bersangkutan /home/namaantum/.fonts/t/trado.ttf menggantikan yang sebelumnya. Al Mulakhasul Fiqhi karya Syaikh Shalih bin Fauzan al-Fauzan. Demikian juga caranya kalau antum alami masalah yang sama dengan PDF kitab-kitab para ulama yang lain. Semoga Allah limpahkan shalawat serta salam untuk Rasulullah Shallallahu ‘Alaihi Wasallam. Barakallahu fiikum.

Pemrograman Qt 4 – QStackedLayout dan QComboBox untuk Window Layering


Bismillahirrahmanirrahim.

Saya ingin membuat program yang bisa layering. Saya tidak tahu istilah resmi untuk ini tetapi bayangkanlah aplikasi GUI yang jika satu tombol diklik, maka sebagian atau seluruh isi jendela berubah jadi susunan lain. Anda sering melihatnya di aplikasi yang tidak seperti Word, tidak seperti Excel, tidak seperti Notepad, tidak seperti Firefox. Mereka statis. Anda sering melihatnya ketika Anda menginstal aplikasi di Windows. Jika Anda klik Next/Back, sebagian isi jendela berubah. Yang seperti itu yang saya inginkan. Kali ini saya berhasil membuatnya dengan memanfaatkan QStackedLayout dan QComboBox. Sayang, saya hanya bisa memakai QComboBox bukan QPushButton, padahal yang saya maukan adalah QPushButton. Tetapi tidak apa. Ini insya Allah menambah pengetahuan kita dalam membuat aplikasi Qt.

Wujud Program yang Diinginkan

ngite-keempat ngite-keempat1

Pokoknya, tampilan dari satu jendela berubah total jika saya memilih salah satu opsi tampilan dari 4 yang ada. Sederhana saja. Saya hanya memasukkan tombol dalam setiap QFrame yang masing-masing QFrame itu bisa dipanggil ke atas (makanya saya kasih nama layering) dengan combo box.

Daftar Kelas Qt yang Dipakai

  1. QDialog = dipakai untuk membuat jendela tertinggi
  2. QVBoxLayout = dipakai untuk membuat kontainer yang menampung setiap blok/grup dari tombol
  3. QPushButton = dipakai untuk membuat tombol
  4. QFrame = dipakai untuk menggantikan QGroupBox dalam hal menampung tombol-tombol jadi satu blok/grup.
  5. QStackedLayout = dipakai untuk membentuk layer–layer tampilan yang setiap layernya bisa berisi widget apa saja.
  6. QComboBox = dipakai untuk mewakili masing-masing layer dan untuk switching antarlayer.

Daftar Method Qt yang Dipakai

  1. addWidget -> dipakai oleh QVBoxLayout, QStakedLayout
  2. setMinimumSize -> dipakai oleh QFrame
  3. setLayout -> dipakai oleh QFrame dan QDialog
  4. setMaximumWidth -> dipakai oleh QPushButton
  5. setFrameShadow -> dipakai oleh QFrame untuk membentuk bayangan; opsi-opsinya adalah QFrame::Raised, QFrame::Sunken, dan QFrame::Plain
  6. addItem -> dipakai oleh QStackedLayout untuk membuat opsi-opsi yang bisa diklik. Persis saat Anda memilih font di Word.
  7. setFrameShape -> dipakai oleh QFrame untuk membentuk wujud panel apakah itu timbul atau tenggelam; opsi-opsinya adalah QFrame::StyledPanel [dipakai oleh default-nya Qt Creator GUI Builder], QFrame::Box
  8. connect -> dipakai di antara QComboBox dengan QStackedLayout.

Qt Creator dan Kode

ngite-keempat2

Kode Program

Sama saja dengan ngite kemarin, hanya ada mainwindow.cpp yang paling penting. Jika bingung dengan kode Qt, silakan merujuk ke tulisan Qt sebelum ini.

#include "mainwindow.h"
#include "ui_mainwindow.h"

Dialog::Dialog()
{
    QVBoxLayout *mainlayout     =   new QVBoxLayout;
    QVBoxLayout *layouta        =   new QVBoxLayout;
    QVBoxLayout *layoutb        =   new QVBoxLayout;
    QVBoxLayout *layoutd        =   new QVBoxLayout;
    QPushButton *tombola        =   new QPushButton("A");
    QPushButton *tombolb        =   new QPushButton("B");
    QPushButton *tombolc        =   new QPushButton("C");
    QPushButton *tombold        =   new QPushButton("D");
    QFrame      *framea         =   new QFrame;
    QFrame      *frameb         =   new QFrame;
    QFrame      *framed         =   new QFrame;
    QStackedLayout *stackia     =   new QStackedLayout;
    QComboBox   *combo          =   new QComboBox;

    combo->addItem(tr("A"));
    combo->addItem(tr("B"));
    combo->addItem(tr("C"));
    combo->addItem(tr("D"));

    tombold->setFixedSize(55,55);

    layouta->addWidget(tombola);
    layoutb->addWidget(tombolb);
    layoutd->addWidget(tombold);

    framea->setLayout(layouta);
    frameb->setLayout(layoutb);
    framea->setMinimumSize(88,88);
    frameb->setMinimumSize(88,88);
    framed->setLayout(layoutd);

    //membentuk frame
    framea->setFrameShape(QFrame::StyledPanel);
    framea->setFrameShadow(QFrame::Raised);
    frameb->setFrameShape(QFrame::StyledPanel);
    frameb->setFrameShadow(QFrame::Raised);
    framed->setFrameShape(QFrame::StyledPanel);
    framed->setFrameShadow(QFrame::Raised);

    //mengecilkan ukuran tombol c
    tombolc->setMaximumWidth(33);

    stackia->addWidget(framea);
    stackia->addWidget(frameb);
    stackia->addWidget(tombolc);
    stackia->addWidget(framed);

    mainlayout->addLayout(stackia);

    mainlayout->addWidget(combo);
    setLayout(mainlayout);

    connect(combo, SIGNAL(activated(int)), stackia, SLOT(setCurrentIndex(int)));
}

Analisis Kode Program

Sedikit saja sebenarnya yang istimewa dari program ke-4 ini. Cukup tahu hal ini maka Anda bisa memodifikasi program menjadi lebih istimewa.

SATU

combo->addItem(tr("A"));
combo->addItem(tr("B"));
combo->addItem(tr("C"));
combo->addItem(tr("D"));

Gunanya untuk menambahkan opsi-opsi pada combo box.

DUA

connect(combo, SIGNAL(activated(int)), stackia, SLOT(setCurrentIndex(int)));

Ini sangat istimewa. Inilah inti dari pemrograman Qt yakni SIGNAL dan SLOT. Method connect() ini adalah suatu penghubung antara objek yang mengeluarkan SIGNAL dan objek yang menerimanya yaitu memiliki SLOT. Ini maksudnya jika suatu objek mengeluarkan SIGNAL tertentu maka objek satunya melakukan fungsi tertentu. Itu saja. Dan inilah yang saya pakai untuk mengendalikan layer di dalam QStackedLayout dengan menggunakan QComboBox. Kita pun pasti akan menggunakannya dalam mengendalikan objek lainnya dengan tombol atau dengan objek lainnya pula. Karena itu, inilah inti dari pemrograman Qt.

combo -> objek dari QComboBox
stackia -> objek dari QStakedLayout

Hasil Akhir

ngite-keempat

Rangkuman

  1. Layering dilakukan dengan QStackedLayout karena ia mengakomodasi frame-frame sebagai layer dan mampu mengatur susunannya yang kita lihat dengan SLOT setCurrentIndex().
  2. Layer-layer di dalam QStackedLayout bisa diatur mana yang terlihat dengan mengaturnya dari QComboBox dengan menghubungkan mereka berdua memakai connect().
  3. Sementara yang saya tahu, hanya QComboBox yang mampu mengatur layer dalam QStackedLayout dan QPushButton belum berhasil mengaturnya. Anda bisa melihat buktinya di sini dan di sini. Tampaknya, QStackedLayout ingin selalu dberi masukan berupa integer sementara QPushButton tidaklah seperti QComboBox yang mengeluarkan nilai integer untuk setiap opsi yang kita tentukan. Misalnya yaa, A itu 1, B itu 2, C itu 3, dan seterusnya seperti kode di atas.