Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import sys
- import os
- from PySide6.QtWidgets import (
- QApplication, QMainWindow, QMessageBox, QLineEdit,
- QPushButton, QTreeWidget, QTreeWidgetItem, QComboBox, QLabel
- )
- from PySide6.QtUiTools import QUiLoader
- from PySide6.QtCore import Slot, QObject # Import QObject jika diperlukan
- # Import backend Anda, SAMA SEKALI TIDAK BERUBAH
- from perpustakaan_backend import Perpustakaan, Pustakawan, StatusItem, StatusTransaksi
- class MainWindow(QMainWindow):
- """
- Kelas utama yang memuat .ui file dan menghubungkan logika (slots).
- Ini menggantikan kelas AppPerpustakaan dari app_gui.py.
- """
- def __init__(self):
- super().__init__()
- # 1. Muat file .ui
- loader = QUiLoader()
- # Tentukan path. Asumsi .ui file ada di folder yang sama
- path = os.path.join(os.path.dirname(__file__), "perpustakaan_ui.ui")
- self.ui = loader.load(path, self) # Simpan sebagai self.ui
- # --- TAMBAHKAN BARIS INI UNTUK MENAMPILKAN JENDELA ---
- self.ui.show()
- # --------------------------------------------------
- # 2. Inisialisasi Backend (sama seperti app_gui.py)
- try:
- # Sesuaikan path jika perlu
- nama_file_db = "perpus_data.pkl"
- self.perpustakaan_utama = Perpustakaan(nama_file_db)
- except Exception as e:
- QMessageBox.critical(self, "Startup Error", f"Gagal memuat data: {e}")
- self.perpustakaan_utama = Perpustakaan(nama_file_db)
- self.pustakawan_andi = Pustakawan("P-001", "Andi")
- # Inisialisasi data awal (sama)
- if not self.perpustakaan_utama.daftar_item:
- print("INFO: Menambahkan data item awal untuk demo...")
- self.pustakawan_andi.tambah_item_ke_koleksi(self.perpustakaan_utama, "buku", "BK-001", "OOP Python", pengarang="Dr. Inovatif")
- self.pustakawan_andi.tambah_item_ke_koleksi(self.perpustakaan_utama, "majalah", "MGZ-001", "Quanta", edisi="Okt 2025")
- self.pustakawan_andi.tambah_item_ke_koleksi(self.perpustakaan_utama, "buku", "BK-002", "Sains Data", pengarang="Prof. Analitika")
- # 3. Temukan Widget (menggunakan findChild)
- # Tab 1 - Form Member
- self.entry_nama = self.ui.findChild(QLineEdit, "entry_nama")
- self.entry_alamat = self.ui.findChild(QLineEdit, "entry_alamat")
- self.tombol_submit_member = self.ui.findChild(QPushButton, "tombol_submit_member")
- # Tab 1 - Form Item
- self.combo_tipe_item = self.ui.findChild(QComboBox, "combo_tipe_item")
- self.entry_item_id = self.ui.findChild(QLineEdit, "entry_item_id")
- self.entry_item_judul = self.ui.findChild(QLineEdit, "entry_item_judul")
- self.label_khusus = self.ui.findChild(QLabel, "label_khusus")
- self.entry_khusus = self.ui.findChild(QLineEdit, "entry_khusus")
- self.tombol_submit_item = self.ui.findChild(QPushButton, "tombol_submit_item")
- # Tab 1 - Tree Koleksi
- self.tombol_refresh_daftar_koleksi_item = self.ui.findChild(QPushButton, "tombol_refresh_daftar_koleksi_item")
- self.tree_buku = self.ui.findChild(QTreeWidget, "tree_buku")
- # Tab 1 - Tree Member
- self.tombol_refresh_member = self.ui.findChild(QPushButton, "tombol_refresh_member")
- self.tombol_riwayat_member = self.ui.findChild(QPushButton, "tombol_riwayat_member")
- self.tree_member = self.ui.findChild(QTreeWidget, "tree_member")
- # Tab 1 - Tree Riwayat
- self.label_riwayat_member = self.ui.findChild(QLabel, "label_riwayat_member")
- self.tree_riwayat = self.ui.findChild(QTreeWidget, "tree_riwayat")
- # Tab 2 - Peminjaman (KOREKSI: QLineEdit -> QComboBox)
- self.combo_pinjam_member_id = self.ui.findChild(QComboBox, "entry_pinjam_member_id")
- self.combo_pinjam_item_id = self.ui.findChild(QComboBox, "entry_pinjam_item_id")
- self.tombol_pinjam = self.ui.findChild(QPushButton, "tombol_pinjam")
- # Tab 2 - Pengembalian (KOREKSI: QLineEdit -> QComboBox)
- self.combo_kembali_trx_id = self.ui.findChild(QComboBox, "entry_kembali_trx_id")
- self.tombol_kembali = self.ui.findChild(QPushButton, "tombol_kembali")
- # Tombol Bawah
- self.tombol_simpan = self.ui.findChild(QPushButton, "tombol_simpan")
- # 4. Hubungkan Signals ke Slots (Callbacks)
- # Format: widget.signal.connect(self.fungsi_callback)
- self.tombol_submit_member.clicked.connect(self.daftar_member_baru)
- self.tombol_submit_item.clicked.connect(self.tambah_item_baru)
- self.combo_tipe_item.currentTextChanged.connect(self.on_tipe_item_changed) # Menggantikan .bind()
- self.tombol_refresh_daftar_koleksi_item.clicked.connect(self.refresh_daftar_buku)
- self.tombol_refresh_member.clicked.connect(self.refresh_daftar_member)
- self.tombol_riwayat_member.clicked.connect(self.tampilkan_riwayat_terpilih)
- self.tombol_pinjam.clicked.connect(self.lakukan_peminjaman)
- self.tombol_kembali.clicked.connect(self.lakukan_pengembalian)
- self.tombol_simpan.clicked.connect(self.simpan_dan_keluar)
- # 5. Refresh data awal
- self.refresh_daftar_buku()
- self.refresh_daftar_member()
- # BARU: Panggil fungsi untuk mengisi combobox
- self.refresh_combobox_member()
- self.refresh_combobox_item_tersedia()
- self.refresh_combobox_transaksi_aktif()
- # Set kolom TreeView agar stretch (opsional tapi bagus)
- self.tree_buku.header().setStretchLastSection(True)
- self.tree_member.header().setStretchLastSection(True)
- self.tree_riwayat.header().setStretchLastSection(True)
- # ==============================================================================
- # SLOTS (CALLBACK FUNCTIONS) - Diterjemahkan dari Tkinter ke PySide6
- # ==============================================================================
- @Slot()
- def daftar_member_baru(self):
- print("DEBUG: Tombol Daftar Member Ditekan")
- # 1. Ambil data -> .get() diganti .text()
- nama = self.entry_nama.text()
- alamat = self.entry_alamat.text()
- # 2. Validasi input
- if not nama or not alamat:
- # messagebox.showwarning -> QMessageBox.warning
- QMessageBox.warning(self, "Input Tidak Lengkap", "Nama dan Alamat tidak boleh kosong!")
- return
- # 3. Panggil logika backend (TIDAK BERUBAH)
- try:
- member_baru = self.pustakawan_andi.lakukan_pendaftaran(self.perpustakaan_utama, nama, alamat)
- # 4. Beri umpan balik
- QMessageBox.information(self, "Pendaftaran Berhasil",
- f"Member baru berhasil ditambahkan!\n"
- f"Nama: {member_baru.nama}\n"
- f"ID: {member_baru.member_id}")
- # 5. Kosongkan form -> .delete(0, tk.END) diganti .clear()
- self.entry_nama.clear()
- self.entry_alamat.clear()
- # 6. Refresh daftar member
- self.refresh_daftar_member()
- # BARU: Refresh juga combobox member
- self.refresh_combobox_member()
- except Exception as e:
- QMessageBox.critical(self, "Pendaftaran Gagal", f"Terjadi error: {e}")
- @Slot()
- def refresh_daftar_buku(self):
- # Hapus data lama -> tree.delete(tree.get_children()) diganti .clear()
- self.tree_buku.clear()
- # Ambil data baru dari backend
- for item in self.perpustakaan_utama.daftar_item:
- info = item.get_info()
- # Buat item tree baru -> .insert() diganti QTreeWidgetItem
- tree_item = QTreeWidgetItem([info["ID"], info["Judul"], info["Status"]])
- self.tree_buku.addTopLevelItem(tree_item)
- @Slot()
- def refresh_daftar_member(self):
- self.tree_member.clear()
- for member in self.perpustakaan_utama.daftar_member:
- tree_item = QTreeWidgetItem([member.member_id, member.nama, member._alamat])
- self.tree_member.addTopLevelItem(tree_item)
- @Slot()
- def lakukan_peminjaman(self):
- # KOREKSI: Ambil data dari Combobox
- member_id_full = self.combo_pinjam_member_id.currentText()
- item_id_full = self.combo_pinjam_item_id.currentText()
- if not member_id_full or not item_id_full:
- QMessageBox.warning(self, "Input Tidak Lengkap", "ID Member dan ID Item harus dipilih.")
- return
- # KOREKSI: Ekstrak ID dari string (format: "ID - Nama")
- try:
- member_id = member_id_full.split(' - ')[0]
- item_id = item_id_full.split(' - ')[0]
- except Exception:
- QMessageBox.critical(self, "Format Salah", "Format data di combobox salah.")
- return
- try:
- trx_baru = self.pustakawan_andi.lakukan_peminjaman(self.perpustakaan_utama, member_id, item_id)
- QMessageBox.information(self, "Peminjaman Berhasil",
- f"Transaksi {trx_baru.transaksi_id} sukses.\n"
- f"Item '{trx_baru.item.judul}' dipinjam oleh {trx_baru.member.nama}.")
- # KOREKSI: .clear() diganti .setCurrentIndex(-1) untuk reset pilihan
- self.combo_pinjam_member_id.setCurrentIndex(-1)
- self.combo_pinjam_item_id.setCurrentIndex(-1)
- self.refresh_daftar_buku()
- # BARU: Refresh combobox item (karena ada yg dipinjam) dan transaksi
- self.refresh_combobox_item_tersedia()
- self.refresh_combobox_transaksi_aktif()
- except Exception as e:
- QMessageBox.critical(self, "Peminjaman Gagal", f"Terjadi error: {e}")
- @Slot()
- def lakukan_pengembalian(self):
- # KOREKSI: Ambil data dari Combobox
- trx_id_full = self.combo_kembali_trx_id.currentText()
- if not trx_id_full:
- QMessageBox.warning(self, "Input Tidak Lengkap", "ID Transaksi harus dipilih.")
- return
- # KOREKSI: Ekstrak ID dari string
- try:
- trx_id = trx_id_full.split(' - ')[0]
- except Exception:
- QMessageBox.critical(self, "Format Salah", "Format data di combobox salah.")
- return
- try:
- # Logika validasi (TIDAK BERUBAH)
- transaksi = self.perpustakaan_utama.cari_transaksi(trx_id)
- if not transaksi:
- raise Exception(f"Transaksi {trx_id} tidak ditemukan.")
- if transaksi.status not in (StatusTransaksi.AKTIF, StatusTransaksi.TERLAMBAT):
- raise Exception(f"Transaksi {trx_id} sudah tidak aktif/selesai.")
- denda = transaksi.hitung_denda()
- # Lakukan pengembalian (TIDAK BERUBAH)
- self.pustakawan_andi.lakukan_pengembalian(self.perpustakaan_utama, trx_id)
- pesan_denda = f"Denda: Rp {denda:,.2f}" if denda > 0 else "Tidak ada denda."
- QMessageBox.information(self, "Pengembalian Berhasil",
- f"Transaksi {trx_id} sukses dikembalikan.\n{pesan_denda}")
- # KOREKSI: .clear() diganti .setCurrentIndex(-1) untuk reset pilihan
- self.combo_kembali_trx_id.setCurrentIndex(-1)
- self.refresh_daftar_buku()
- # BARU: Refresh combobox item (karena ada yg kembali) dan transaksi
- self.refresh_combobox_item_tersedia()
- self.refresh_combobox_transaksi_aktif()
- self.tampilkan_riwayat_terpilih(auto_refresh=True)
- except Exception as e:
- QMessageBox.critical(self, "Pengembalian Gagal", f"Terjadi error: {e}")
- @Slot()
- def tampilkan_riwayat_terpilih(self, auto_refresh=False):
- # Mengambil item terpilih -> .focus() diganti .currentItem()
- selected_item = self.tree_member.currentItem()
- if not selected_item:
- if not auto_refresh:
- QMessageBox.warning(self, "Pilihan Kosong", "Pilih salah satu member dari tabel untuk melihat riwayat.")
- return
- # Mengambil data dari item terpilih -> .item(id)['values'] diganti .text(col_index)
- member_id = selected_item.text(0)
- member_nama = selected_item.text(1)
- member = self.perpustakaan_utama.cari_member(member_id)
- if not member:
- QMessageBox.critical(self, "Error", f"Data member {member_id} tidak ditemukan di backend.")
- return
- # Update label -> .config(text=...) diganti .setText(...)
- self.label_riwayat_member.setText(f"Menampilkan riwayat untuk: {member_nama} (ID: {member_id})")
- self.tree_riwayat.clear()
- riwayat = member.get_riwayat_peminjaman(self.perpustakaan_utama)
- if not riwayat:
- item = QTreeWidgetItem(["", "Tidak ada riwayat peminjaman.", "", "", "", ""])
- self.tree_riwayat.addTopLevelItem(item)
- return
- for trx in riwayat:
- item = trx.item
- denda = trx.hitung_denda() if trx.status == StatusTransaksi.TERLAMBAT else trx._denda
- # Buat list string untuk data
- data_row = [
- trx.transaksi_id,
- item.judul,
- trx._tgl_pinjam.strftime('%Y-%m-%d'),
- trx._tgl_kembali.strftime('%Y-%m-%d'),
- trx.status.value,
- f"Rp{denda:,.2f}"
- ]
- tree_item = QTreeWidgetItem(data_row)
- self.tree_riwayat.addTopLevelItem(tree_item)
- @Slot()
- def on_tipe_item_changed(self, tipe_terpilih):
- """Mengubah label form berdasarkan pilihan Combobox."""
- if tipe_terpilih == "Buku":
- self.label_khusus.setText("Pengarang:")
- elif tipe_terpilih == "Majalah":
- self.label_khusus.setText("Edisi:")
- self.entry_khusus.clear()
- @Slot()
- def tambah_item_baru(self):
- print("DEBUG: Tombol Tambah Item Ditekan")
- tipe = self.combo_tipe_item.currentText() # .get() -> .currentText()
- item_id = self.entry_item_id.text()
- judul = self.entry_item_judul.text()
- khusus = self.entry_khusus.text()
- if not all([tipe, item_id, judul, khusus]):
- QMessageBox.warning(self, "Input Tidak Lengkap", "Semua field harus diisi!")
- return
- kwargs = {}
- if tipe == "Buku":
- kwargs['pengarang'] = khusus
- elif tipe == "Majalah":
- kwargs['edisi'] = khusus
- try:
- self.pustakawan_andi.tambah_item_ke_koleksi(
- self.perpustakaan_utama,
- tipe.lower(),
- item_id,
- judul,
- **kwargs
- )
- QMessageBox.information(self, "Penambahan Berhasil", f"{tipe} '{judul}' berhasil ditambahkan ke koleksi.")
- self.entry_item_id.clear()
- self.entry_item_judul.clear()
- self.entry_khusus.clear()
- self.refresh_daftar_buku()
- # BARU: Refresh combobox item
- self.refresh_combobox_item_tersedia()
- except Exception as e:
- # KOREKSI: Seharusnya .critical() bukan .clear()
- QMessageBox.critical(self, "Penambahan Gagal", f"Terjadi error: {e}")
- # --- FUNGSI HELPER BARU UNTUK COMBOBOX ---
- @Slot()
- def refresh_combobox_member(self):
- """Mengisi combobox member dengan data (ID - Nama)."""
- self.combo_pinjam_member_id.clear() # Hapus item lama
- try:
- member_list = [f"{m.member_id} - {m.nama}" for m in self.perpustakaan_utama.daftar_member]
- self.combo_pinjam_member_id.addItems(member_list)
- self.combo_pinjam_member_id.setCurrentIndex(-1) # Kosongkan pilihan
- except Exception as e:
- print(f"ERROR: Gagal refresh combobox member: {e}")
- @Slot()
- def refresh_combobox_item_tersedia(self):
- """Mengisi combobox item dengan item yang TERSEDIA (ID - Judul)."""
- self.combo_pinjam_item_id.clear() # Hapus item lama
- try:
- item_list = [f"{i.item_id} - {i.judul}" for i in self.perpustakaan_utama.daftar_item if i.status == StatusItem.TERSEDIA]
- self.combo_pinjam_item_id.addItems(item_list)
- self.combo_pinjam_item_id.setCurrentIndex(-1) # Kosongkan pilihan
- except Exception as e:
- print(f"ERROR: Gagal refresh combobox item: {e}")
- @Slot()
- def refresh_combobox_transaksi_aktif(self):
- """Mengisi combobox transaksi dengan transaksi AKTIF (ID - Judul Item)."""
- self.combo_kembali_trx_id.clear() # Hapus item lama
- try:
- trx_list = [
- f"{t.transaksi_id} - ({t.item.judul} oleh {t.member.nama})"
- for t in self.perpustakaan_utama.daftar_transaksi
- if t.status == StatusTransaksi.AKTIF or t.status == StatusTransaksi.TERLAMBAT
- ]
- self.combo_kembali_trx_id.addItems(trx_list)
- self.combo_kembali_trx_id.setCurrentIndex(-1) # Kosongkan pilihan
- except Exception as e:
- print(f"ERROR: Gagal refresh combobox transaksi: {e}")
- @Slot()
- def simpan_dan_keluar(self):
- try:
- self.perpustakaan_utama.simpan_data()
- QMessageBox.information(self, "Sukses", "Data berhasil disimpan!")
- self.ui.close() # .destroy() diganti .close()
- # --- PERBAIKAN: Tambahkan baris ini ---
- # Ini akan memberi tahu app.exec() untuk berhenti,
- # yang akan mengakhiri script.
- QApplication.instance().quit()
- except Exception as e:
- QMessageBox.critical(self, "Gagal Menyimpan", f"Terjadi error: {e}")
- # --- Titik Mulai Eksekusi ---
- if __name__ == "__main__":
- app = QApplication(sys.argv)
- window = MainWindow()
- # .ui file sekarang sudah di-show() di dalam __init__
- sys.exit(app.exec())
Add Comment
Please, Sign In to add comment