Langsung ke konten utama

PEMBUATAN PARTITURE NOTASI ANGKA LAGU (Part-2)

 PEMBUATAN PARTITURE NOTASI ANGKA LAGU (Part-2)


Tolong buatkan partitur notasi angka lagu dengan yang lebih lengkap dan kompleks.


Untuk membuat **partitur notasi angka yang lebih lengkap dan kompleks**, kita dapat memperhatikan beberapa elemen penting dalam penulisan notasi angka, seperti **tanda tempo**, **birama**, **dinamika**, dan **oktaf**. Di bawah ini adalah contoh partitur notasi angka untuk bagian dari sebuah lagu, dengan elemen-elemen tersebut diterapkan.


### Notasi Angka Lengkap dan Kompleks:


```

Judul: Contoh Lagu

Tempo: 80 BPM

Birama: 4/4

Instrumen: Piano


| 1 2 3 4 | 1 2 3 4 | 1 2 3 4 | 1 2 3 4 |

|:-------------------------|-------------------------|-------------------------|-------------------------:|

| 1 . 2 . 3 . | 5' . 5' . 6' . | 6' . 5' . 6' . | 5' . 3' . 2' . |

| Do . Re . Mi . | So' . So' . La' . | La' . So' . La' . | So' . Mi' . Re' . |


Dinamika: mf (mezzo-forte)

Instruksi: Tahan nada setiap perempat ketukan selama setengah ketukan.

```


Pada partitur di atas:

- **Angka 1 hingga 7** merepresentasikan **Do Re Mi Fa So La Si** dalam **oktaf normal**.

- **Angka dengan tanda petik (misal: `5'`)** merepresentasikan nada di **oktaf satu tingkat lebih tinggi**.

- **.** mewakili durasi atau nada yang ditahan atau diistirahatkan.

- **Dinamika** `mf` (mezzo-forte) menandakan bahwa lagu dimainkan dengan kekuatan sedang.


### Penjelasan Detail:

1. **Tempo**: Lagu dimainkan dengan **80 BPM** (Beat per Minute), artinya setiap ketukan diatur dalam kecepatan 80 ketukan per menit.

2. **Birama**: Setiap baris dibagi dalam kelompok **4 ketukan** (4/4), yang berarti ada empat nada atau istirahat per bar dalam satu siklus birama.

3. **Oktaf**: Penggunaan tanda petik (misal: `5'`) menunjukkan bahwa nada tersebut berada di **oktaf satu tingkat lebih tinggi** dari oktaf dasar.

4. **Dinamika**: `mf` berarti dinamika lagu dimainkan dengan kekuatan sedang, dan dapat diganti menjadi `p` (piano) untuk lembut, atau `f` (forte) untuk keras, jika dibutuhkan.


### Contoh Lanjutan:


```

Judul: Contoh Lagu (Lanjutan)

Tempo: 90 BPM

Birama: 4/4

Instrumen: Piano dan Drum


| 1 2 3 4 | 1 2 3 4 | 1 2 3 4 | 1 2 3 4 |

|:-------------------------|-------------------------|-------------------------|-------------------------:|

| 3 . 5 . 6 . | 1 . 2 . 3 . | 4 . 5' . 6' . | 5' . 6' . 7' . |

| Mi . So . La . | Do . Re . Mi . | Fa . So' . La' . | So' . La' . Si' . |


Dinamika: f (forte)

Instruksi: Mainkan nada dengan volume keras dan pertahankan setiap ketukan perempat untuk seluruh ketukan.

```


Pada bagian lanjutan:

- Notasi angka menunjukkan progresi dengan variasi **oktaf normal dan oktaf tinggi**.

- Dinamika `f` menandakan nada dimainkan dengan lebih keras.


### Kombinasi dengan Instrumen Kedua (Misalnya Drum):

Untuk drum atau instrumen ritmis, bisa ditambahkan baris terpisah di bawah baris melodi piano.


```

Judul: Contoh Lagu dengan Drum

Tempo: 90 BPM

Birama: 4/4

Instrumen: Piano dan Drum


| 1 2 3 4 | 1 2 3 4 | 1 2 3 4 | 1 2 3 4 |

|:-------------------------|-------------------------|-------------------------|-------------------------:|

| 3 . 5 . 6 . | 1 . 2 . 3 . | 4 . 5' . 6' . | 5' . 6' . 7' . |

| Mi . So . La . | Do . Re . Mi . | Fa . So' . La' . | So' . La' . Si' . |


| BD . SN . BD . | SN . BD . BD . | SN . BD . SN .| BD . BD . SN .|

| BassDrum . SnareDrum . | Snare . Bass . BassDrum| Snare . Bass . SnareDrum| Bass . BassDrum. Snare . |

```


Pada bagian ini:

- **BD** = **Bass Drum** dan **SN** = **Snare Drum**. Instrumen drum dimainkan dengan pola ritmis yang mengikuti progresi birama yang sama dengan piano.

- Piano memainkan melodi, sementara drum memberikan ritme yang mendukung lagu.


### Kesimpulan:

- **Notasi angka** dapat dikembangkan dengan banyak detail, termasuk tempo, dinamika, variasi oktaf, dan kombinasi instrumen.

- Untuk implementasi dalam aplikasi, notasi angka ini dapat diubah menjadi **kode MIDI** atau **frekuensi**, sehingga instrumen yang berbeda dapat menghasilkan suara yang sesuai dengan partitur.

- Notasi angka yang lengkap dan kompleks ini memudahkan untuk **pengaturan progresi**, **perubahan dinamika**, dan **penambahan instrumen** dalam aplikasi musik yang sedang dikembangkan.


Pada kode tersebut, bisakah ditambahkan entry di dalam output_text yaitu entry entry untuk judul lagu, nada dasar lagu, tanda sukat(birama) lagu, pencipta lagu,


Tentu, saya bisa membantu menambahkan **entry untuk judul lagu, nada dasar lagu, tanda sukat (birama) lagu, dan pencipta lagu** ke dalam kode Anda. Berikut ini adalah contoh bagaimana Anda bisa melakukannya. Dalam contoh ini, saya menambahkan empat `Entry` untuk informasi tersebut ke dalam layout Anda.


```python

import tkinter as tk

from tkinter import ttk


# Fungsi untuk menampilkan partitur dengan detail tambahan

def show_partitur():

    judul_lagu = judul_entry.get()

    nada_dasar = nada_entry.get()

    tanda_sukat = sukat_entry.get()

    pencipta_lagu = pencipta_entry.get()


    # Menampilkan hasil ke output_text

    output_text.delete(1.0, tk.END)

    output_text.insert(tk.END, f"Judul Lagu : {judul_lagu}\n")

    output_text.insert(tk.END, f"Nada Dasar : {nada_dasar}\n")

    output_text.insert(tk.END, f"Tanda Sukat : {tanda_sukat}\n")

    output_text.insert(tk.END, f"Pencipta Lagu : {pencipta_lagu}\n")

    output_text.insert(tk.END, "\n")

    output_text.insert(tk.END, "Partitur Notasi Angka:\n")

    output_text.insert(tk.END, "| 1 2 3 4 | 1 2 3 4 |\n")

    output_text.insert(tk.END, "| 5' . 6' . 7' . | 6' . 5' . 4' . |\n")

    output_text.insert(tk.END, "| So' . La' . Si' . | La' . So' . Fa' . |\n")


# Setup UI

root = tk.Tk()

root.title("Notasi Angka Lagu")


frame = tk.Frame(root)

frame.pack(padx=10, pady=10)


# Entry untuk judul lagu

judul_label = tk.Label(frame, text="Judul Lagu:")

judul_label.grid(row=0, column=0, padx=5, pady=5)

judul_entry = tk.Entry(frame)

judul_entry.grid(row=0, column=1, padx=5, pady=5)


# Entry untuk nada dasar lagu

nada_label = tk.Label(frame, text="Nada Dasar:")

nada_label.grid(row=1, column=0, padx=5, pady=5)

nada_entry = tk.Entry(frame)

nada_entry.grid(row=1, column=1, padx=5, pady=5)


# Entry untuk tanda sukat (birama) lagu

sukat_label = tk.Label(frame, text="Tanda Sukat (Birama):")

sukat_label.grid(row=2, column=0, padx=5, pady=5)

sukat_entry = tk.Entry(frame)

sukat_entry.grid(row=2, column=1, padx=5, pady=5)


# Entry untuk pencipta lagu

pencipta_label = tk.Label(frame, text="Pencipta Lagu:")

pencipta_label.grid(row=3, column=0, padx=5, pady=5)

pencipta_entry = tk.Entry(frame)

pencipta_entry.grid(row=3, column=1, padx=5, pady=5)


# Tombol untuk menampilkan partitur

show_button = tk.Button(frame, text="Tampilkan Partitur", command=show_partitur)

show_button.grid(row=4, columnspan=2, padx=5, pady=10)


# Output text box

output_text = tk.Text(root, height=10, width=50)

output_text.pack(padx=10, pady=10)


root.mainloop()

```

### Penjelasan Kode:

1. **Entry Fields**: Saya menambahkan empat `Entry` baru ke dalam layout:

   - `judul_entry` untuk judul lagu

   - `nada_entry` untuk nada dasar lagu

   - `sukat_entry` untuk tanda sukat (birama)

   - `pencipta_entry` untuk pencipta lagu

2. **Fungsi `show_partitur`**: Fungsi ini mengambil data dari `Entry` yang dimasukkan oleh pengguna dan menampilkannya di dalam `output_text`, bersamaan dengan partitur notasi angka yang dihasilkan.

3. **Text Widget (`output_text`)**: Ini digunakan untuk menampilkan partitur lagu, termasuk detail judul, nada dasar, tanda sukat, dan pencipta lagu.

### Cara Kerja:

- Pengguna akan memasukkan informasi ke dalam kolom **Judul Lagu**, **Nada Dasar**, **Tanda Sukat**, dan **Pencipta Lagu**.

- Setelah menekan tombol **Tampilkan Partitur**, informasi tersebut akan ditampilkan bersama dengan notasi angka partitur di dalam `Text` widget.

Apakah Anda membutuhkan penambahan fitur lain atau modifikasi lebih lanjut dari kode ini?


Nada nada yang tampil pada output_text pastikan agar bisa di edit user.


Untuk membuat nada-nada pada `output_text` dapat diedit oleh pengguna, kita perlu menampilkan bagian notasi angka secara langsung di dalam `Text` widget yang bisa diedit, tanpa batasan, agar pengguna dapat memodifikasi nada tersebut.

Berikut adalah modifikasi kode yang memungkinkan pengguna untuk mengedit nada-nada di dalam `output_text` secara langsung:


```python

import tkinter as tk

from tkinter import ttk


# Fungsi untuk menampilkan partitur dengan detail tambahan dan memungkinkan pengguna mengedit notasi

def show_partitur():

    judul_lagu = judul_entry.get()

    nada_dasar = nada_entry.get()

    tanda_sukat = sukat_entry.get()

    pencipta_lagu = pencipta_entry.get()


    # Menampilkan hasil ke output_text (editable)

    output_text.delete(1.0, tk.END) # Menghapus teks sebelumnya

    output_text.insert(tk.END, f"Judul Lagu : {judul_lagu}\n")

    output_text.insert(tk.END, f"Nada Dasar : {nada_dasar}\n")

    output_text.insert(tk.END, f"Tanda Sukat : {tanda_sukat}\n")

    output_text.insert(tk.END, f"Pencipta Lagu : {pencipta_lagu}\n")

    output_text.insert(tk.END, "\n")

    output_text.insert(tk.END, "Partitur Notasi Angka (Edit di sini):\n")

    

    # Menyisipkan partitur yang bisa diubah oleh pengguna

    output_text.insert(tk.END, "| 1 2 3 4 | 1 2 3 4 |\n")

    output_text.insert(tk.END, "| 5' . 6' . 7' . | 6' . 5' . 4' . |\n")

    output_text.insert(tk.END, "| So' . La' . Si' . | La' . So' . Fa' . |\n")


# Setup UI

root = tk.Tk()

root.title("Notasi Angka Lagu")


frame = tk.Frame(root)

frame.pack(padx=10, pady=10)


# Entry untuk judul lagu

judul_label = tk.Label(frame, text="Judul Lagu:")

judul_label.grid(row=0, column=0, padx=5, pady=5)

judul_entry = tk.Entry(frame)

judul_entry.grid(row=0, column=1, padx=5, pady=5)


# Entry untuk nada dasar lagu

nada_label = tk.Label(frame, text="Nada Dasar:")

nada_label.grid(row=1, column=0, padx=5, pady=5)

nada_entry = tk.Entry(frame)

nada_entry.grid(row=1, column=1, padx=5, pady=5)


# Entry untuk tanda sukat (birama) lagu

sukat_label = tk.Label(frame, text="Tanda Sukat (Birama):")

sukat_label.grid(row=2, column=0, padx=5, pady=5)

sukat_entry = tk.Entry(frame)

sukat_entry.grid(row=2, column=1, padx=5, pady=5)


# Entry untuk pencipta lagu

pencipta_label = tk.Label(frame, text="Pencipta Lagu:")

pencipta_label.grid(row=3, column=0, padx=5, pady=5)

pencipta_entry = tk.Entry(frame)

pencipta_entry.grid(row=3, column=1, padx=5, pady=5)


# Tombol untuk menampilkan partitur

show_button = tk.Button(frame, text="Tampilkan Partitur", command=show_partitur)

show_button.grid(row=4, columnspan=2, padx=5, pady=10)


# Output text box yang bisa di-edit oleh user

output_text = tk.Text(root, height=15, width=60)

output_text.pack(padx=10, pady=10)


root.mainloop()

```

### Penjelasan Modifikasi:

1. **`Text` Widget yang Editable**: `output_text` adalah widget `Text` yang otomatis bisa di-edit oleh pengguna. Setelah tombol **Tampilkan Partitur** ditekan, teks notasi angka yang dihasilkan dapat langsung di-edit di dalam widget ini.

2. **Menyisipkan Notasi Angka**: Pengguna bisa mengubah bagian mana pun dari notasi angka yang ditampilkan di dalam `Text` widget. Misalnya, mereka dapat mengganti nada atau struktur partitur sesuai keinginan.

### Penggunaan:

- **Judul Lagu, Nada Dasar, Tanda Sukat, dan Pencipta Lagu** diisi di dalam entry.

- Saat tombol **Tampilkan Partitur** ditekan, partitur dengan informasi judul, nada dasar, dan tanda sukat ditampilkan di dalam `output_text`.

- Pengguna dapat langsung mengedit notasi angka atau menambahkan variasi baru sesuai keperluan di dalam `Text` widget.

### Perluas Fungsi:

Jika Anda ingin menangkap hasil edit pengguna dan menyimpannya atau menggunakannya untuk tujuan lain, Anda bisa menambahkan fitur untuk mengambil teks dari `output_text` setelah user selesai mengeditnya.


Misal setelah nada nada di edit dengan menggantikan nada nada baru, tentunya harus ada tombol "save" untuk menyimpan perubahan


Untuk menambahkan tombol "Save" agar pengguna dapat menyimpan perubahan setelah mengedit nada-nada dalam partitur, kita perlu membuat fungsi yang dapat mengambil teks yang diubah dari `Text` widget, lalu menyimpannya ke dalam file atau database.

Berikut adalah modifikasi kode untuk menambahkan tombol "Save" dan menyimpan hasil perubahan pengguna ke dalam file:

### Kode dengan Fitur Simpan Perubahan:


```python

import tkinter as tk

from tkinter import filedialog, messagebox


# Fungsi untuk menampilkan partitur dengan detail tambahan dan memungkinkan pengguna mengedit notasi

def show_partitur():

    judul_lagu = judul_entry.get()

    nada_dasar = nada_entry.get()

    tanda_sukat = sukat_entry.get()

    pencipta_lagu = pencipta_entry.get()


    # Menampilkan hasil ke output_text (editable)

    output_text.delete(1.0, tk.END) # Menghapus teks sebelumnya

    output_text.insert(tk.END, f"Judul Lagu : {judul_lagu}\n")

    output_text.insert(tk.END, f"Nada Dasar : {nada_dasar}\n")

    output_text.insert(tk.END, f"Tanda Sukat : {tanda_sukat}\n")

    output_text.insert(tk.END, f"Pencipta Lagu : {pencipta_lagu}\n")

    output_text.insert(tk.END, "\n")

    output_text.insert(tk.END, "Partitur Notasi Angka (Edit di sini):\n")

    

    # Menyisipkan partitur yang bisa diubah oleh pengguna

    output_text.insert(tk.END, "| 1 2 3 4 | 1 2 3 4 |\n")

    output_text.insert(tk.END, "| 5' . 6' . 7' . | 6' . 5' . 4' . |\n")

    output_text.insert(tk.END, "| So' . La' . Si' . | La' . So' . Fa' . |\n")


# Fungsi untuk menyimpan perubahan

def save_partitur():

    # Mengambil teks yang sudah diedit oleh pengguna

    edited_text = output_text.get(1.0, tk.END).strip()


    # Menyimpan ke dalam file

    file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])

    

    if file_path:

        try:

            with open(file_path, 'w') as file:

                file.write(edited_text)

            messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")

        except Exception as e:

            messagebox.showerror("Error", f"Gagal menyimpan partitur: {e}")


# Setup UI

root = tk.Tk()

root.title("Notasi Angka Lagu")


frame = tk.Frame(root)

frame.pack(padx=10, pady=10)


# Entry untuk judul lagu

judul_label = tk.Label(frame, text="Judul Lagu:")

judul_label.grid(row=0, column=0, padx=5, pady=5)

judul_entry = tk.Entry(frame)

judul_entry.grid(row=0, column=1, padx=5, pady=5)


# Entry untuk nada dasar lagu

nada_label = tk.Label(frame, text="Nada Dasar:")

nada_label.grid(row=1, column=0, padx=5, pady=5)

nada_entry = tk.Entry(frame)

nada_entry.grid(row=1, column=1, padx=5, pady=5)


# Entry untuk tanda sukat (birama) lagu

sukat_label = tk.Label(frame, text="Tanda Sukat (Birama):")

sukat_label.grid(row=2, column=0, padx=5, pady=5)

sukat_entry = tk.Entry(frame)

sukat_entry.grid(row=2, column=1, padx=5, pady=5)


# Entry untuk pencipta lagu

pencipta_label = tk.Label(frame, text="Pencipta Lagu:")

pencipta_label.grid(row=3, column=0, padx=5, pady=5)

pencipta_entry = tk.Entry(frame)

pencipta_entry.grid(row=3, column=1, padx=5, pady=5)


# Tombol untuk menampilkan partitur

show_button = tk.Button(frame, text="Tampilkan Partitur", command=show_partitur)

show_button.grid(row=4, column=0, padx=5, pady=10)


# Tombol untuk menyimpan partitur

save_button = tk.Button(frame, text="Simpan Partitur", command=save_partitur)

save_button.grid(row=4, column=1, padx=5, pady=10)


# Output text box yang bisa di-edit oleh user

output_text = tk.Text(root, height=15, width=60)

output_text.pack(padx=10, pady=10)


root.mainloop()

```

### Penjelasan Modifikasi:

1. **Tombol "Simpan Partitur"**: Telah ditambahkan sebuah tombol **Simpan Partitur** di sebelah tombol **Tampilkan Partitur**. Ketika tombol ini ditekan, sistem akan membuka dialog untuk menyimpan teks yang ada di dalam `Text` widget.   

2. **Fungsi `save_partitur()`**:

   - **Mengambil Teks yang Diedit**: Teks yang telah diedit oleh pengguna diambil menggunakan `output_text.get(1.0, tk.END)`.

   - **Dialog Save File**: Menggunakan `filedialog.asksaveasfilename()` untuk menampilkan dialog "Save As" di mana pengguna bisa memilih nama dan lokasi file.

   - **Penyimpanan File**: Jika pengguna memilih lokasi, file tersebut akan disimpan dalam format `.txt`.

3. **Error Handling**: Ditambahkan penanganan kesalahan menggunakan `try-except` untuk memastikan jika ada kesalahan saat menyimpan file, pengguna akan menerima pesan kesalahan.

### Penggunaan:

1. **Edit Notasi Angka**: Pengguna dapat mengedit notasi angka secara langsung di dalam kotak teks `output_text`.

2. **Simpan Partitur**: Setelah mengedit, pengguna dapat menekan tombol **Simpan Partitur** dan memilih lokasi untuk menyimpan partitur tersebut dalam bentuk file teks.

3. **Menyimpan Hasil Edit**: Sistem akan memberikan notifikasi bahwa file berhasil disimpan atau jika ada masalah selama proses penyimpanan.

Dengan fitur ini, aplikasi Anda sekarang bisa menyimpan hasil edit dari notasi angka lagu secara permanen.


Pada kode tersebut, saya sudah tambahkan tombol paste_gn untuk menempelkan gugus nada terpilih pada output_text, di mana gugus nada terpilih diperoleh dari isian entry dari gn_a_bass_entry ketika tombol button_copy_gn di tekan untuk mengcopy gugus nada terpilih, lalu mempastekan ke output_text dengan cara menekan tombol paste_gn_button.

Berikut kodenya:

import tkinter as tk

from tkinter import ttk

from tkinter import messagebox

import sqlite3


# Initialize the main window

root = tk.Tk()

root.geometry("690x1390")

root.title("Arah Arus Musik Gn_Cyan_Atas dan Sub_Gn_Cyan_Atas")


# Bottom Frame

bottom_frame = tk.Frame(root, bg="#e2e2e2")

bottom_frame.pack(side=tk.TOP, fill=tk.X)


# Fungsi untuk menampilkan messagebox dan memvalidasi input level_gn

def validate_level_gn():

    try:

        level_gn = int(entry_level_gn.get())


        if level_gn in [1, 4, 7, 10]:

            messagebox.showinfo("Info", "Lanjut dengan memasukkan input ID = 1")

            set_id_entry(1)

        elif level_gn in [2, 5, 8, 11]:

            messagebox.showinfo("Info", "Lanjut dengan memasukkan input ID = 2")

            set_id_entry(2)

        elif level_gn in [3, 6, 9, 12]:

            messagebox.showinfo("Info", "Lanjut dengan memasukkan input ID = 3")

            set_id_entry(3)

        else:

            messagebox.showerror("Error", "Masukkan input yang benar.\nInput Level Gn adalah 1 hingga 12")

            reset_entries()


    except ValueError:

        messagebox.showerror("Error", "Input harus berupa angka.")

        reset_entries()


# Fungsi untuk mengatur entry ID dan mencegah input selain ID yang valid

def set_id_entry(valid_id):

    entry_id.delete(0, tk.END)

    entry_id.insert(0, valid_id)

    entry_id.config(state='readonly') # Membatasi input hanya pada ID yang valid


# Fungsi untuk mereset entries jika input level_gn tidak valid

def reset_entries():

    entry_level_gn.delete(0, tk.END)

    entry_id.config(state='normal')

    entry_id.delete(0, tk.END)


# Fungsi untuk menampilkan data ke Entry setelah pemilihan nada

def pilih_nada():

    try:

        level_gn_selected = int(entry_level_gn.get())

        id_selected = int(entry_id.get())

        progres_selected = int(progres_var.get())

        mode_selected = mode_var.get().lower()


        # Ambil data berdasarkan level_gn_selected, id_selected, progres_selected, dan mode_selected

        result = level_gn(id_selected, progres_selected, mode_selected, level_gn_selected)


        # Tampilkan data ke dalam entry

        gn_a_bass_entry.delete(0, tk.END)

        gn_a_bass_entry.insert(0, result["Gugusan_nada"])    

    

    except Exception as e:

        print("Error:", e)

        

    finally:

        # Menghapus status read-only sementara

        entry_id.config(state='normal')

        

        # Bersihkan atau reset entry dan combobox setelah tombol pilih_nada ditekan

        entry_level_gn.delete(0, 'end')

        entry_id.delete(0, 'end')

        progres_combobox.set('')

        mode_combobox.set('')       

        # Kembalikan status read-only setelah menghapus isinya

        entry_id.config(state='readonly')  

        reset_entries()         


# Fungsi untuk menerapkan pengurangan berdasarkan level_gn tanpa mempertimbangkan progres

def apply_level_adjustment(value, level_gn_selected):

    # Tentukan pengurang berdasarkan level_gn

    if level_gn_selected in [1, 2, 3]:

        pengurang = 0

    elif level_gn_selected in [4, 5, 6]:

        pengurang = 1

    elif level_gn_selected in [7, 8, 9]:

        pengurang = 2

    elif level_gn_selected in [10, 11, 12]:

        pengurang = 3


    # Sesuaikan nilai string berdasarkan pengurang

    adjusted_value = ''.join(str((int(digit) - pengurang) % 10) for digit in value if digit.isdigit())

    return adjusted_value


# Pengurangan hanya pada perubahan Level Gn, progres tidak mengubah gugusan_nada

def level_gn(id, progres_selected, mode_selected, level_gn_selected):

    conn = sqlite3.connect('DATAMUSIK.db')

    cursor = conn.cursor()


    # Query untuk pengambilan data dari tabel Gn_A_Bass

    query = """

        SELECT Gugusan_nada

        FROM Gn_A_Bass

        WHERE ID = ?

    """

    cursor.execute(query, (id,))

    data = cursor.fetchone()


    gugusan_nada = data[0]


    # Sesuaikan nilai Bass hanya berdasarkan level_gn

    gugusan_nada = apply_level_adjustment(gugusan_nada, level_gn_selected)

    

    conn.close()


    # Return hasil

    result = {

        "Gugusan_nada": gugusan_nada

    }

    return result

          

# Tambahkan tombol untuk memvalidasi level_gn

validate_button = tk.Button(bottom_frame, text="Validasi Level Gn", bg="yellow", command=validate_level_gn)

validate_button.grid(row=3, column=2, padx=0, pady=7)


# Tombol untuk memproses pemilihan nada

button_pilih_nada = tk.Button(bottom_frame, text="Pilih Nada", bg="grey", fg="white", command=pilih_nada)

button_pilih_nada.grid(row=8, column=1, padx=5, pady=5)


separator = ttk.Separator(bottom_frame, orient='horizontal')

separator.grid(row=9, column=0, sticky="ew", pady=15)


#Gugusan Nada Terpilih: "Gn_A_Bass" Terpilih 

gugusan_label = tk.Label(bottom_frame, text="Gn_A_Bass", fg="tomato")

gugusan_label.grid(row=0, column=0, padx=10, pady=5, sticky="ew")  


# Labels dan Entries

label_level_gn = tk.Label(bottom_frame, text="Level_Gn:")

label_level_gn.grid(row=3, column=0, padx=5, pady=5)

entry_level_gn = tk.Entry(bottom_frame)

entry_level_gn.grid(row=3, column=1, padx=5, pady=5)


label_id = tk.Label(bottom_frame, text="ID:")

label_id.grid(row=4, column=0, padx=5, pady=5)

entry_id = tk.Entry(bottom_frame)

entry_id.grid(row=4, column=1, padx=5, pady=5)


label_progres = tk.Label(bottom_frame, text="Progres:")

label_progres.grid(row=5, column=0, padx=5, pady=5)

progres_var = tk.StringVar()

progres_combobox = ttk.Combobox(bottom_frame, textvariable=progres_var)

progres_combobox['values'] = (1, 2, 3)

progres_combobox.grid(row=5, column=1, padx=5, pady=5)


label_mode = tk.Label(bottom_frame, text="Mode:")

label_mode.grid(row=6, column=0, padx=5, pady=5)

mode_var = tk.StringVar()

mode_combobox = ttk.Combobox(bottom_frame, textvariable=mode_var)

mode_combobox['values'] = ("Naik", "Turun")

mode_combobox.grid(row=6, column=1, padx=5, pady=5)


separator = ttk.Separator(bottom_frame, orient='horizontal')

separator.grid(row=7, column=0, sticky="ew", pady=4)


# Gugusan Nada Terpilih Field

Gn_tetpilih_label = tk.Label(bottom_frame, text="Gugusan- \n Nada Terpilih:")

Gn_tetpilih_label.grid(row=11, column=0, padx=5, pady=5)  

      

# Label dan Entry

gn_a_bass_label = tk.Label(bottom_frame, text="Bass")

gn_a_bass_label.grid(row=10, column=1, padx=10, pady=5)  

gn_a_bass_entry = tk.Entry(bottom_frame, bg="white")

gn_a_bass_entry.grid(row=11, column=1, padx=10, pady=5)


# Tombol untuk meng_cooy g

ugus nada

button_copy_gn = tk.Button(bottom_frame, text="Copy Gn", bg="grey", fg="white", command=None)

button_copy_gn.grid(row=12, column=1, padx=5, pady=5)


root.mainloop()

 

Untuk melanjutkan fitur **copy** dan **paste** gugus nada terpilih ke `output_text`, kita bisa menambahkan dua fungsi berikut:

1. **Fungsi untuk menyalin data dari entry** (saat tombol *Copy Gn* ditekan).

2. **Fungsi untuk menempelkan data** (saat tombol *Paste Gn* ditekan) ke `output_text`.

Berikut adalah pengembangan kode yang melibatkan dua fungsi tersebut:


```python

# Initialize the main window

root = tk.Tk()

root.geometry("690x1390")

root.title("Arah Arus Musik Gn_Cyan_Atas dan Sub_Gn_Cyan_Atas")


# Variable to store copied gugusan nada

copied_gugusan_nada = ""


# Fungsi untuk menampilkan messagebox dan memvalidasi input level_gn

def validate_level_gn():

    try:

        level_gn = int(entry_level_gn.get())

        if level_gn in [1, 4, 7, 10]:

            messagebox.showinfo("Info", "Lanjut dengan memasukkan input ID = 1")

            set_id_entry(1)

        elif level_gn in [2, 5, 8, 11]:

            messagebox.showinfo("Info", "Lanjut dengan memasukkan input ID = 2")

            set_id_entry(2)

        elif level_gn in [3, 6, 9, 12]:

            messagebox.showinfo("Info", "Lanjut dengan memasukkan input ID = 3")

            set_id_entry(3)

        else:

            messagebox.showerror("Error", "Masukkan input yang benar.\nInput Level Gn adalah 1 hingga 12")

            reset_entries()

    except ValueError:

        messagebox.showerror("Error", "Input harus berupa angka.")

        reset_entries()


def set_id_entry(valid_id):

    entry_id.delete(0, tk.END)

    entry_id.insert(0, valid_id)

    entry_id.config(state='readonly')


def reset_entries():

    entry_level_gn.delete(0, tk.END)

    entry_id.config(state='normal')

    entry_id.delete(0, tk.END)


def pilih_nada():

    try:

        level_gn_selected = int(entry_level_gn.get())

        id_selected = int(entry_id.get())

        progres_selected = int(progres_var.get())

        mode_selected = mode_var.get().lower()


        # Ambil data berdasarkan level_gn_selected, id_selected, progres_selected, dan mode_selected

        result = level_gn(id_selected, progres_selected, mode_selected, level_gn_selected)


        # Tampilkan data ke dalam entry

        gn_a_bass_entry.delete(0, tk.END)

        gn_a_bass_entry.insert(0, result["Gugusan_nada"])    


    except Exception as e:

        print("Error:", e)


    finally:

        entry_id.config(state='normal')

        entry_level_gn.delete(0, 'end')

        entry_id.delete(0, 'end')

        progres_combobox.set('')

        mode_combobox.set('')

        entry_id.config(state='readonly')

        reset_entries()


def apply_level_adjustment(value, level_gn_selected):

    if level_gn_selected in [1, 2, 3]:

        pengurang = 0

    elif level_gn_selected in [4, 5, 6]:

        pengurang = 1

    elif level_gn_selected in [7, 8, 9]:

        pengurang = 2

    elif level_gn_selected in [10, 11, 12]:

        pengurang = 3


    adjusted_value = ''.join(str((int(digit) - pengurang) % 10) for digit in value if digit.isdigit())

    return adjusted_value


def level_gn(id, progres_selected, mode_selected, level_gn_selected):

    conn = sqlite3.connect('DATAMUSIK.db')

    cursor = conn.cursor()


    query = """

        SELECT Gugusan_nada

        FROM Gn_A_Bass

        WHERE ID = ?

    """

    cursor.execute(query, (id,))

    data = cursor.fetchone()


    gugusan_nada = data[0]


    gugusan_nada = apply_level_adjustment(gugusan_nada, level_gn_selected)

    

    conn.close()


    result = {

        "Gugusan_nada": gugusan_nada

    }

    return result


# Fungsi untuk meng-copy gugus nada dari entry ke clipboard

def copy_gugusan_nada():

    global copied_gugusan_nada

    copied_gugusan_nada = gn_a_bass_entry.get()

    messagebox.showinfo("Info", "Gugus nada berhasil di-copy!")


# Fungsi untuk mem-paste gugus nada dari clipboard ke output_text

def paste_gugusan_nada():

    if copied_gugusan_nada:

        output_text.insert(tk.END, copied_gugusan_nada + '\n')

    else:

        messagebox.showerror("Error", "Tidak ada gugus nada yang di-copy!")


# Tambahkan tombol untuk memvalidasi level_gn

validate_button = tk.Button(bottom_frame, text="Validasi Level Gn", bg="yellow", command=validate_level_gn)

validate_button.grid(row=3, column=2, padx=0, pady=7)


button_pilih_nada = tk.Button(bottom_frame, text="Pilih Nada", bg="grey", fg="white", command=pilih_nada)

button_pilih_nada.grid(row=8, column=1, padx=5, pady=5)


separator = ttk.Separator(bottom_frame, orient='horizontal')

separator.grid(row=9, column=0, sticky="ew", pady=15)


# Gugusan Nada Terpilih: "Gn_A_Bass" Terpilih 

gugusan_label = tk.Label(bottom_frame, text="Gn_A_Bass", fg="tomato")

gugusan_label.grid(row=0, column=0, padx=10, pady=5, sticky="ew")


# Labels dan Entries

label_level_gn = tk.Label(bottom_frame, text="Level_Gn:")

label_level_gn.grid(row=3, column=0, padx=5, pady=5)

entry_level_gn = tk.Entry(bottom_frame)

entry_level_gn.grid(row=3, column=1, padx=5, pady=5)


label_id = tk.Label(bottom_frame, text="ID:")

label_id.grid(row=4, column=0, padx=5, pady=5)

entry_id = tk.Entry(bottom_frame)

entry_id.grid(row=4, column=1, padx=5, pady=5)


label_progres = tk.Label(bottom_frame, text="Progres:")

label_progres.grid(row=5, column=0, padx=5, pady=5)

progres_var = tk.StringVar()

progres_combobox = ttk.Combobox(bottom_frame, textvariable=progres_var)

progres_combobox['values'] = (1, 2, 3)

progres_combobox.grid(row=5, column=1, padx=5, pady=5)


label_mode = tk.Label(bottom_frame, text="Mode:")

label_mode.grid(row=6, column=0, padx=5, pady=5)

mode_var = tk.StringVar()

mode_combobox = ttk.Combobox(bottom_frame, textvariable=mode_var)

mode_combobox['values'] = ("Naik", "Turun")

mode_combobox.grid(row=6, column=1, padx=5, pady=5)


separator = ttk.Separator(bottom_frame, orient='horizontal')

separator.grid(row=7, column=0, sticky="ew", pady=4)


# Gugusan Nada Terpilih Field

Gn_tetpilih_label = tk.Label(bottom_frame, text="Gugusan- \n Nada Terpilih:")

Gn_tetpilih_label.grid(row=11, column=0, padx=5, pady=5)


# Label dan Entry

gn_a_bass_label = tk.Label(bottom_frame, text="Bass")

gn_a_bass_label.grid(row=10, column=1, padx=10, pady=5)

gn_a_bass_entry = tk.Entry(bottom_frame, bg="white")

gn_a_bass_entry.grid(row=11, column=1, padx=10, pady=5)


# Output Text for pasted Gugusan Nada

output_text = tk.Text(bottom_frame, height=10, width=40)

output_text.grid(row=14, column=0, columnspan=2, padx=10, pady=5)


# Tombol untuk meng-copy gugus nada

button_copy_gn = tk.Button(bottom_frame, text="Copy Gn", bg="grey", fg="white", command=copy_gugusan_nada)

button_copy_gn.grid(row=12, column=1, padx=5, pady=5)


# Tombol untuk mem-paste gugus nada ke output_text

button_paste_gn = tk.Button(bottom_frame, text="Paste Gn", bg="grey", fg="white", command=paste_gugusan_nada)

button_paste_gn.grid(row=13, column=1, padx=5, pady=5)


root.mainloop()

```

### Penjelasan:

- Fungsi `copy_gugusan_nada()` akan menyalin isi dari `gn_a_bass_entry` ke dalam variabel `copied_gugusan_nada`.

- Fungsi `paste_gugusan_nada()` akan menempelkan nilai yang sudah disalin ke dalam widget `output_text`.

- Tombol **Copy Gn** akan menyalin gugus nada dari entri, dan tombol **Paste Gn** akan mem


Fungsi fungsi copy ada pada file CRUD gn a bass.py, sedangkan fungsi fungsi paste ada file partitur notasi angka, sebaiknya ketika user menekan tombol copy_gn maka isian entry gn_a_bass_entry sudah tercooy dan langsung membuka file partitur notasi angka untuk selanjutnya mempastekan isian entry gn_a_bass_entry tersebut pada output_text, tentunya ini dengan cara mengimpor fungsi fungsi terkait dari file CRUD gn a Bass ke file partitur notasi angka. 


Untuk memenuhi permintaan Anda, berikut ini adalah panduan dan kode untuk mengimpor fungsi terkait dari file `CRUD_Gn_A_Bass.py` ke file `partitur_notasi_angka.py`. Kita akan membuat perubahan sehingga ketika tombol `copy_gn` ditekan, data di `gn_a_bass_entry` otomatis dicopy dan membuka file `partitur_notasi_angka.py`, di mana kemudian dapat dipaste ke `output_text`.

### Langkah-Langkah Implementasi:

1. **Impor fungsi dari `CRUD_Gn_A_Bass.py` ke dalam `partitur_notasi_angka.py`.**  

2. **Modifikasi tombol `copy_gn` di `CRUD_Gn_A_Bass.py` agar bisa mengcopy nilai dari `gn_a_bass_entry` dan membuka file `partitur_notasi_angka.py`.**

3. **Modifikasi di file `partitur_notasi_angka.py` untuk menerima dan mempastekan nilai yang dicopy ke dalam `output_text`.**

---


### 1. File `CRUD_Gn_A_Bass.py`

Tambahkan fungsi `copy_gn()` untuk mengcopy nilai dari `gn_a_bass_entry` dan membuka file `partitur_notasi_angka.py`.


```python

import tkinter as tk

import os # untuk membuka file partitur_notasi_angka.py


def copy_gn():

    # Ambil nilai dari entry gn_a_bass_entry

    gn_value = gn_a_bass_entry.get()


    # Simpan nilai ke clipboard (opsional)

    root.clipboard_clear()

    root.clipboard_append(gn_value)


    # Simpan nilai gn_value ke file sementara

    with open("temp_gn_value.txt", "w") as temp_file:

        temp_file.write(gn_value)

    

    # Buka file partitur_notasi_angka.py

    os.system('python partitur_notasi_angka.py')

```


Pastikan tombol `button_copy_gn` memanggil fungsi `copy_gn`:


```python

button_copy_gn = tk.Button(bottom_frame, text="Copy Gn", bg="grey", fg="white", command=copy_gn)

button_copy_gn.grid(row=12, column=1, padx=5, pady=5)

```


### 2. File `partitur_notasi_angka.py`

Modifikasi file `partitur_notasi_angka.py` untuk menerima nilai yang sudah di-copy dan mempastekannya ke `output_text`.


```python

import tkinter as tk


# Inisialisasi jendela utama

root = tk.Tk()

root.geometry("600x400")

root.title("Partitur Notasi Angka")


# Output text untuk paste hasil copy

output_text = tk.Text(root, height=10, width=50)

output_text.pack(pady=20)


# Fungsi untuk mempastekan data dari temp_gn_value.txt ke output_text

def paste_gn():

    try:

        # Buka file sementara dan baca nilai

        with open("temp_gn_value.txt", "r") as temp_file:

            gn_value = temp_file.read()

        

        # Paste gn_value ke output_text

        output_text.insert(tk.END, gn_value)

    

    except FileNotFoundError:

        output_text.insert(tk.END, "Tidak ada data yang dicopy.")


# Tombol untuk paste gugusan nada terpilih

paste_gn_button = tk.Button(root, text="Paste Gn", command=paste_gn)

paste_gn_button.pack(pady=10)


root.mainloop()

```

### 3. Penjelasan:

- **`CRUD_Gn_A_Bass.py`:**  

  Ketika tombol `copy_gn` ditekan, nilai dari entry `gn_a_bass_entry` akan dicopy dan disimpan dalam file sementara (`temp_gn_value.txt`). Kemudian, file `partitur_notasi_angka.py` akan dibuka.

- **`partitur_notasi_angka.py`:**  

  Pada file ini, fungsi `paste_gn()` membaca nilai yang disimpan di `temp_gn_value.txt` dan menempelkannya ke dalam `output_text` setelah tombol `paste_gn_button` ditekan.

Dengan ini, Anda dapat menyalin data dari entry di satu file dan secara otomatis membuka file lain untuk mempaste data tersebut.


Apa kode cara mengimpor semua fungsi dari suatu file ke file lain, misalnya pada file partitur notasi angka mengimport dari file CRUD gn a bass, ini:

import tkinter as tk

from tkinter import filedialog, messagebox

import os

from crud gn a bass import *.*


Untuk mengimpor semua fungsi dari file lain di Python, Anda bisa menggunakan sintaks `from <nama_file> import *`. Dalam konteks Anda, jika ingin mengimpor semua fungsi dari file `CRUD_Gn_A_Bass.py` ke dalam file `partitur_notasi_angka.py`, Anda cukup menulis seperti ini:


```python

from CRUD_Gn_A_Bass import *

```


Namun, ada beberapa hal yang perlu diperhatikan:


1. **Penamaan File:**

   - Nama file Python **tidak boleh** mengandung spasi atau karakter khusus (misalnya: tanda strip, titik ganda, dll). Untuk file `CRUD_Gn_A_Bass.py`, pastikan file tersebut disimpan dengan nama yang benar, misalnya: `CRUD_Gn_A_Bass.py`.


2. **Letak File:**

   - Pastikan bahwa file `CRUD_Gn_A_Bass.py` berada di direktori yang sama dengan file `partitur_notasi_angka.py`, atau atur jalur yang sesuai agar bisa diakses.


3. **Penggunaan `import *`:**

   - Menggunakan `import *` akan mengimpor **semua** fungsi, kelas, dan variabel yang ada di file `CRUD_Gn_A_Bass.py`. Jika Anda ingin hanya mengimpor fungsi tertentu, lebih baik secara eksplisit menyebutkan nama fungsinya, misalnya:

     ```python

     from CRUD_Gn_A_Bass import copy_gn, fungsi_lain

     ```


### Contoh Implementasi

Berikut contoh bagaimana mengimpor semua fungsi dari `CRUD_Gn_A_Bass.py` ke `partitur_notasi_angka.py`:


#### 1. **File `CRUD_Gn_A_Bass.py`** (Contoh)

```python

import tkinter as tk


# Contoh fungsi di CRUD_Gn_A_Bass.py

def copy_gn():

    print("Fungsi copy_gn dipanggil.")


def fungsi_lain():

    print("Fungsi lain dipanggil.")

```


#### 2. **File `partitur_notasi_angka.py`**

```python

import tkinter as tk

from tkinter import filedialog, messagebox

import os

from CRUD_Gn_A_Bass import * # Mengimpor semua fungsi dari CRUD_Gn_A_Bass


# Panggil fungsi dari CRUD_Gn_A_Bass.py

copy_gn() # Memanggil fungsi copy_gn

fungsi_lain() # Memanggil fungsi lain

```


### Kesimpulan:

- **`from CRUD_Gn_A_Bass import *`** akan mengimpor semua fungsi dari file `CRUD_Gn_A_Bass.py`.

- Pastikan nama file valid dan tidak mengandung spasi atau karakter khusus.

- Pastikan file berada di direktori yang sama atau diatur path-nya agar bisa diakses.


Kenapa ketika tombol button_copy_gn ditekan belum bisa langsung membuka file partitur_notasi_angka.py (yang bisa hanya mengcopy isian entry gn_a_bass_entry). Apakah harus kita tambahkan sebuah tombol lagi yaitu tombol button_buka_partitur = tk.Button(bottom_frame, text="Buka Partitur", bg="grey", fg="white", command=buka_partitur)

button_buka_partitur.grid(row=12, column=2, padx=5, pady=5), dengan kaitannya pada fungsi buka partitur: def buka_partitur():

    filepath = "partitur_notasi_angka.py"

    try:

        with open(filepath, 'r') as file:

            exec(file.read(), globals())

        messagebox.showinfo("Success", "File executed successfully")

    except Exception as e:

        messagebox.showerror("Error", f"Failed to execute file: {e}")     


Menambahkan tombol khusus seperti `button_buka_partitur` dengan fungsi `buka_partitur()` adalah solusi yang tepat jika Anda ingin membuka dan menjalankan file `partitur_notasi_angka.py` secara manual setelah menekan tombol "Copy". Namun, ada beberapa hal penting terkait dengan pendekatan ini, terutama dalam menjalankan file Python eksternal.


Berikut penjelasan tentang cara kerjanya dan beberapa solusi lain:


### Pendekatan 1: Menambahkan Tombol `Buka Partitur`

Jika Anda ingin menambahkan tombol tambahan untuk membuka file `partitur_notasi_angka.py`, maka kode Anda seperti yang dijelaskan sudah benar. Anda dapat menggunakan fungsi `exec()` untuk mengeksekusi file Python secara langsung, tetapi pendekatan ini memiliki beberapa kekurangan (misalnya, jika file mengandung bug atau kesalahan, eksekusi bisa gagal).


Berikut implementasi lengkapnya:


#### 1. **Menambahkan Tombol `button_buka_partitur`**

```python

import tkinter as tk

from tkinter import messagebox


def copy_gn():

    # Fungsi untuk mengcopy isian entry gn_a_bass_entry

    gn_a_bass_entry_value = gn_a_bass_entry.get()

    print(f"Isian yang di-copy: {gn_a_bass_entry_value}")


def buka_partitur():

    filepath = "partitur_notasi_angka.py"

    try:

        with open(filepath, 'r') as file:

            exec(file.read(), globals())

        messagebox.showinfo("Success", "File executed successfully")

    except Exception as e:

        messagebox.showerror("Error", f"Failed to execute file: {e}")


# Tkinter setup

root = tk.Tk()


# Entry untuk gn_a_bass

gn_a_bass_entry = tk.Entry(root)

gn_a_bass_entry.grid(row=0, column=0)


# Tombol Copy

button_copy_gn = tk.Button(root, text="Copy", command=copy_gn)

button_copy_gn.grid(row=1, column=0)


# Tombol Buka Partitur

button_buka_partitur = tk.Button(root, text="Buka Partitur", command=buka_partitur)

button_buka_partitur.grid(row=1, column=1)


root.mainloop()

```


#### 2. **Menjelaskan Fungsi**

- **`copy_gn()`**: Ini adalah fungsi yang mengambil nilai dari `gn_a_bass_entry` dan melakukan copy (dalam hal ini hanya mencetak ke terminal).

- **`buka_partitur()`**: Fungsi ini membuka file `partitur_notasi_angka.py` dan mengeksekusinya menggunakan `exec()`.

  - **Peringatan**: Menggunakan `exec()` bisa berbahaya jika tidak dilakukan dengan benar, karena akan mengeksekusi semua kode di file tersebut, termasuk error dan kode yang tidak aman.


### Pendekatan 2: Menjalankan File Eksternal Menggunakan `subprocess`

Jika Anda ingin menjalankan file `partitur_notasi_angka.py` sebagai program Python yang terpisah, menggunakan modul `subprocess` mungkin lebih aman dan lebih fleksibel daripada menggunakan `exec()`.


Berikut contohnya:


```python

import tkinter as tk

from tkinter import messagebox

import subprocess


def copy_gn():

    # Fungsi untuk mengcopy isian entry gn_a_bass_entry

    gn_a_bass_entry_value = gn_a_bass_entry.get()

    print(f"Isian yang di-copy: {gn_a_bass_entry_value}")


def buka_partitur():

    filepath = "partitur_notasi_angka.py"

    try:

        subprocess.run(["python", filepath], check=True)

        messagebox.showinfo("Success", "File executed successfully")

    except Exception as e:

        messagebox.showerror("Error", f"Failed to execute file: {e}")


# Tkinter setup

root = tk.Tk()


# Entry untuk gn_a_bass

gn_a_bass_entry = tk.Entry(root)

gn_a_bass_entry.grid(row=0, column=0)


# Tombol Copy

button_copy_gn = tk.Button(root, text="Copy", command=copy_gn)

button_copy_gn.grid(row=1, column=0)


# Tombol Buka Partitur

button_buka_partitur = tk.Button(root, text="Buka Partitur", command=buka_partitur)

button_buka_partitur.grid(row=1, column=1)


root.mainloop()

```


### Penjelasan:

- **`subprocess.run()`**: Ini menjalankan file `partitur_notasi_angka.py` sebagai proses terpisah. Hal ini lebih aman daripada menggunakan `exec()`.

- Jika ada kesalahan dalam file yang dijalankan, error akan ditampilkan dengan lebih baik.

- Pada `subprocess.run()`, pastikan Python di lingkungan Anda tersedia dalam jalur yang benar (misalnya `python` atau `python3` bergantung pada konfigurasi sistem Anda).


### Catatan Tambahan:

- Jika Anda ingin **langsung membuka file `partitur_notasi_angka.py` ketika tombol Copy ditekan**, Anda bisa menggabungkan logika kedua fungsi seperti berikut:


```python

def copy_dan_buka_partitur():

    # Copy gn_a_bass_entry

    copy_gn()

    

    # Buka partitur

    buka_partitur()


# Tombol Copy sekaligus Buka Partitur

button_copy_gn_buka = tk.Button(root, text="Copy & Buka Partitur", command=copy_dan_buka_partitur)

button_copy_gn_buka.grid(row=2, column=0)

```


Dengan ini, ketika pengguna menekan tombol, file partitur akan dibuka langsung setelah melakukan copy.


### Kesimpulan:

1. **Menambahkan tombol tambahan** untuk membuka partitur adalah solusi yang baik.

2. Menggunakan **`exec()`** bisa diterapkan, namun lebih aman menggunakan **`subprocess`** untuk menjalankan file Python eksternal.

3. Jika ingin membuka partitur langsung setelah copy, Anda bisa menggabungkan fungsionalitas copy dan buka partitur dalam satu tombol.


Kode selengkapnya untuk file partitur_notasi_angka.py adalah berikut:

import tkinter as tk

from tkinter import filedialog, messagebox


# Fungsi untuk menampilkan partitur dengan detail tambahan dan memungkinkan pengguna mengedit notasi

def show_partitur():

    judul_lagu = judul_entry.get()

    nada_dasar = nada_entry.get()

    tanda_birama = birama_entry.get()

    pencipta_lagu = pencipta_entry.get()

    arranger_lagu = arranger_entry.get()   


    # Menampilkan hasil ke output_text (editable)

    output_text.delete(1.0, tk.END) # Menghapus teks sebelumnya

    output_text.insert(tk.END, f"Judul Lagu : {judul_lagu}\n")

    output_text.insert(tk.END, f"Nada Dasar : {nada_dasar}\n")

    output_text.insert(tk.END, f"Tanda Birama : {tanda_birama}\n")

    output_text.insert(tk.END, f"Pencipta : {pencipta_lagu}\n")

    output_text.insert(tk.END, f"Arranger : {arranger_lagu}\n")

    output_text.insert(tk.END, "\n")

    output_text.insert(tk.END, "Partitur Notasi Angka (Edit di sini):\n")

    

    # Menyisipkan partitur yang bisa diubah oleh pengguna

    output_text.insert(tk.END, " \n")

    output_text.insert(tk.END, " \n")

    output_text.insert(tk.END, " \n")


# Fungsi untuk menyimpan perubahan

def save_partitur():

    # Mengambil teks yang sudah diedit oleh pengguna

    edited_text = output_text.get(1.0, tk.END).strip()


    # Menyimpan ke dalam file

    file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])

    

    if file_path:

        try:

            with open(file_path, 'w') as file:

                file.write(edited_text)

            messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")

        except Exception as e:

            messagebox.showerror("Error", f"Gagal menyimpan partitur: {e}")


# Setup UI

root = tk.Tk()

root.title("Notasi Angka Lagu")


frame = tk.Frame(root)

frame.pack(padx=10, pady=10)


# Entry untuk judul lagu

judul_label = tk.Label(frame, text="Judul Lagu:")

judul_label.grid(row=0, column=0, padx=5, pady=5)

judul_entry = tk.Entry(frame)

judul_entry.grid(row=0, column=1, padx=5, pady=5)


# Entry untuk nada dasar lagu

nada_label = tk.Label(frame, text="Nada Dasar:")

nada_label.grid(row=1, column=0, padx=5, pady=5)

nada_entry = tk.Entry(frame)

nada_entry.grid(row=1, column=1, padx=5, pady=5)


# Entry untuk tanda sukat (birama) lagu

birama_label = tk.Label(frame, text="Tanda Birama:")

birama_label.grid(row=2, column=0, padx=5, pady=5)

birama_entry = tk.Entry(frame)

birama_entry.grid(row=2, column=1, padx=5, pady=5)


# Entry untuk pencipta lagu

pencipta_label = tk.Label(frame, text="Pencipta:")

pencipta_label.grid(row=3, column=0, padx=5, pady=5)

pencipta_entry = tk.Entry(frame)

pencipta_entry.grid(row=3, column=1, padx=5, pady=5)


# Entry untuk arranger lagu

arranger_label = tk.Label(frame, text="Arranger:")

arranger_label.grid(row=4, column=0, padx=5, pady=5)

arranger_entry = tk.Entry(frame)

arranger_entry.grid(row=4, column=1, padx=5, pady=5)


# Tombol untuk menampilkan partitur

show_button = tk.Button(frame, text="Tampilkan Partitur", bg="grey", fg="white", command=show_partitur)

show_button.grid(row=5, column=0, padx=5, pady=10)


# Tombol untuk menyimpan partitur

save_button = tk.Button(frame, text="Simpan Partitur", bg="grey", fg="white", command=save_partitur)

save_button.grid(row=5, column=2, padx=5, pady=10)


# Output text box yang bisa di-edit oleh user

output_text = tk.Text(root, height=15, width=60)

output_text.pack(padx=10, pady=10)


# Fungsi untuk mempastekan data dari temp_gn_value.txt ke output_text

def paste_gn():

    try:

        # Buka file sementara dan baca nilai

        with open("temp_gn_value.txt", "r") as temp_file:

            gn_value = temp_file.read()

        

        # Paste gn_value ke output_text

        output_text.insert(tk.END, gn_value)

    

    except FileNotFoundError:

        output_text.insert(tk.END, "Tidak ada data yang dicopy.")

        

# Tombol untuk mem-paste gugus nada ke output_text

paste_gn_button = tk.Button(frame, text="Paste Gn", bg="grey", fg="white", command=paste_gn)

paste_gn_button.grid(row=5, column=1, padx=5, pady=5)        

root.mainloop()


Pada kode tolong tambahkan fungsi pengguliran semua konten agar dapat bergulir ke segala arah. Maunya kita, pengguliran ada pada semua konten isi file partitur_notasi_angka.py sehingga semua elemen GUI dapat digulir ke segala arah.


Untuk menambahkan fungsi pengguliran ke segala arah pada semua konten dalam file `partitur_notasi_angka.py`, kita dapat menggunakan widget `Canvas` yang membungkus seluruh elemen GUI dan menambahkan scrollbar horizontal maupun vertikal. Berikut adalah modifikasi kode yang diperlukan:


```python

import tkinter as tk

from tkinter import filedialog, messagebox


# Fungsi untuk menampilkan partitur dengan detail tambahan dan memungkinkan pengguna mengedit notasi

def show_partitur():

    judul_lagu = judul_entry.get()

    nada_dasar = nada_entry.get()

    tanda_birama = birama_entry.get()

    pencipta_lagu = pencipta_entry.get()

    arranger_lagu = arranger_entry.get()   


    # Menampilkan hasil ke output_text (editable)

    output_text.delete(1.0, tk.END) # Menghapus teks sebelumnya

    output_text.insert(tk.END, f"Judul Lagu : {judul_lagu}\n")

    output_text.insert(tk.END, f"Nada Dasar : {nada_dasar}\n")

    output_text.insert(tk.END, f"Tanda Birama : {tanda_birama}\n")

    output_text.insert(tk.END, f"Pencipta : {pencipta_lagu}\n")

    output_text.insert(tk.END, f"Arranger : {arranger_lagu}\n")

    output_text.insert(tk.END, "\n")

    output_text.insert(tk.END, "Partitur Notasi Angka (Edit di sini):\n")

    

    # Menyisipkan partitur yang bisa diubah oleh pengguna

    output_text.insert(tk.END, " \n")

    output_text.insert(tk.END, " \n")

    output_text.insert(tk.END, " \n")


# Fungsi untuk menyimpan perubahan

def save_partitur():

    # Mengambil teks yang sudah diedit oleh pengguna

    edited_text = output_text.get(1.0, tk.END).strip()


    # Menyimpan ke dalam file

    file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])

    

    if file_path:

        try:

            with open(file_path, 'w') as file:

                file.write(edited_text)

            messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")

        except Exception as e:

            messagebox.showerror("Error", f"Gagal menyimpan partitur: {e}")


# Setup UI

root = tk.Tk()

root.title("Notasi Angka Lagu")


# Membuat canvas untuk pengguliran

canvas = tk.Canvas(root)

canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)


# Membuat scrollbar horizontal dan vertikal

scrollbar_y = tk.Scrollbar(root, orient=tk.VERTICAL, command=canvas.yview)

scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)


scrollbar_x = tk.Scrollbar(root, orient=tk.HORIZONTAL, command=canvas.xview)

scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X)


canvas.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)


# Membuat frame yang akan diletakkan di dalam canvas

scrollable_frame = tk.Frame(canvas)


# Fungsi untuk mengatur ukuran scrollable_frame di dalam canvas

def on_frame_configure(event):

    canvas.configure(scrollregion=canvas.bbox("all"))


scrollable_frame.bind("<Configure>", on_frame_configure)


# Membuat window di dalam canvas

canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")


# Entry untuk judul lagu

judul_label = tk.Label(scrollable_frame, text="Judul Lagu:")

judul_label.grid(row=0, column=0, padx=5, pady=5)

judul_entry = tk.Entry(scrollable_frame)

judul_entry.grid(row=0, column=1, padx=5, pady=5)


# Entry untuk nada dasar lagu

nada_label = tk.Label(scrollable_frame, text="Nada Dasar:")

nada_label.grid(row=1, column=0, padx=5, pady=5)

nada_entry = tk.Entry(scrollable_frame)

nada_entry.grid(row=1, column=1, padx=5, pady=5)


# Entry untuk tanda sukat (birama) lagu

birama_label = tk.Label(scrollable_frame, text="Tanda Birama:")

birama_label.grid(row=2, column=0, padx=5, pady=5)

birama_entry = tk.Entry(scrollable_frame)

birama_entry.grid(row=2, column=1, padx=5, pady=5)


# Entry untuk pencipta lagu

pencipta_label = tk.Label(scrollable_frame, text="Pencipta:")

pencipta_label.grid(row=3, column=0, padx=5, pady=5)

pencipta_entry = tk.Entry(scrollable_frame)

pencipta_entry.grid(row=3, column=1, padx=5, pady=5)


# Entry untuk arranger lagu

arranger_label = tk.Label(scrollable_frame, text="Arranger:")

arranger_label.grid(row=4, column=0, padx=5, pady=5)

arranger_entry = tk.Entry(scrollable_frame)

arranger_entry.grid(row=4, column=1, padx=5, pady=5)


# Tombol untuk menampilkan partitur

show_button = tk.Button(scrollable_frame, text="Tampilkan Partitur", bg="grey", fg="white", command=show_partitur)

show_button.grid(row=5, column=0, padx=5, pady=10)


# Tombol untuk menyimpan partitur

save_button = tk.Button(scrollable_frame, text="Simpan Partitur", bg="grey", fg="white", command=save_partitur)

save_button.grid(row=5, column=2, padx=5, pady=10)


# Output text box yang bisa di-edit oleh user

output_text = tk.Text(scrollable_frame, height=15, width=60)

output_text.grid(row=6, column=0, columnspan=3, padx=10, pady=10)


# Fungsi untuk mempastekan data dari temp_gn_value.txt ke output_text

def paste_gn():

    try:

        # Buka file sementara dan baca nilai

        with open("temp_gn_value.txt", "r") as temp_file:

            gn_value = temp_file.read()

        

        # Paste gn_value ke output_text

        output_text.insert(tk.END, gn_value)

    

    except FileNotFoundError:

        output_text.insert(tk.END, "Tidak ada data yang dicopy.")

        

# Tombol untuk mem-paste gugus nada ke output_text

paste_gn_button = tk.Button(scrollable_frame, text="Paste Gn", bg="grey", fg="white", command=paste_gn)

paste_gn_button.grid(row=5, column=1, padx=5, pady=5)        


# Mengaitkan scrollbars dengan canvas

canvas.configure(scrollregion=canvas.bbox("all"))


root.mainloop()

```


### Penjelasan:

1. **Canvas** digunakan untuk menampung semua elemen GUI. Ini memungkinkan kita untuk menggulirkan keseluruhan konten.

2. **Scrollbars** (baik horizontal maupun vertikal) ditambahkan dan dikaitkan dengan `canvas`.

3. **Scrollable Frame** adalah frame yang diletakkan di dalam `canvas` dan diatur agar isinya bisa digulir.

4. Semua widget seperti `Label`, `Entry`, `Text`, dan `Button` dimasukkan ke dalam `scrollable_frame`.


Dengan setup ini, semua elemen GUI dapat digulirkan ke segala arah, baik secara vertikal maupun horizontal.


Kode yang ini saja dimodifikasi, semua label di hapus, dan teks label tersebut dimasukkan pada entry yang sesuai dalam Hint, lalu ukuran lembaran partiture dibatasi dibuat menurut ukuran panjang dan lebar kertas kuarto.


Baik, berikut adalah modifikasi kode yang sesuai dengan permintaan Anda:

1. **Menghapus semua Label**: Semua label dihapus dan teks label seperti "Judul Lagu", "Nada Dasar", "Tanda Birama", dll., dimasukkan sebagai **placeholder (hint)** dalam `Entry`.  

2. **Membatasi ukuran widget `Text`**: Ukuran `Text` dibatasi mengikuti ukuran kertas **kuarto** (A4) dalam satuan piksel. Ukuran kertas kuarto dalam piksel biasanya diatur sebagai 793.7 x 1122.52 piksel pada resolusi standar 72 DPI (dots per inch).

Berikut kode yang telah dimodifikasi:

### Kode Modifikasi:


```python

import tkinter as tk


# Fungsi untuk menampilkan placeholder (hint) pada Entry

def set_placeholder(entry, placeholder):

    entry.insert(0, placeholder)

    entry.config(fg='grey')

    

    def on_focus_in(event):

        if entry.get() == placeholder:

            entry.delete(0, tk.END)

            entry.config(fg='black')


    def on_focus_out(event):

        if entry.get() == "":

            set_placeholder(entry, placeholder)


    entry.bind("<FocusIn>", on_focus_in)

    entry.bind("<FocusOut>", on_focus_out)


# Fungsi untuk menampilkan partitur dengan Entry di tengah atas

def show_partitur():

    # Menghapus teks sebelumnya

    output_text.delete(1.0, tk.END)


    # Menambahkan beberapa baris kosong untuk memberi ruang di atas (untuk memusatkan Entry)

    output_text.insert(tk.END, "\n" * 2)


    # Lebar layar untuk Text widget

    text_widget_width = output_text.winfo_width()


    # Menyusun entry agar berada di tengah horizontal dengan spasi di kanan-kiri

    def center_entry(entry_widget, width):

        # Menghitung jumlah spasi yang dibutuhkan agar Entry berada di tengah

        entry_widget_width = entry_widget.winfo_reqwidth()

        space = (width - entry_widget_width) // 2

        output_text.insert(tk.END, " " * space)

        output_text.window_create(tk.END, window=entry_widget)

        output_text.insert(tk.END, "\n\n") # Spasi vertikal antar Entry


    # Membuat Entry di dalam Text widget dan menempatkannya di tengah atas

    judul_entry_in_text = tk.Entry(output_text, width=30, justify='center')

    set_placeholder(judul_entry_in_text, "Judul Lagu")

    center_entry(judul_entry_in_text, text_widget_width)

    

    nada_entry_in_text = tk.Entry(output_text, width=30, justify='center')

    set_placeholder(nada_entry_in_text, "Nada Dasar")

    center_entry(nada_entry_in_text, text_widget_width)

    

    birama_entry_in_text = tk.Entry(output_text, width=30, justify='center')

    set_placeholder(birama_entry_in_text, "Tanda Birama")

    center_entry(birama_entry_in_text, text_widget_width)

    

    pencipta_entry_in_text = tk.Entry(output_text, width=30, justify='center')

    set_placeholder(pencipta_entry_in_text, "Pencipta")

    center_entry(pencipta_entry_in_text, text_widget_width)

    

    arranger_entry_in_text = tk.Entry(output_text, width=30, justify='center')

    set_placeholder(arranger_entry_in_text, "Arranger")

    center_entry(arranger_entry_in_text, text_widget_width)


# Fungsi untuk menyimpan perubahan (contoh)

def save_partitur():

    # Contoh cara mengambil data dari Entry di dalam Text widget

    pass


# Setup UI

root = tk.Tk()

root.title("Notasi Angka Lagu")


# Ukuran kertas kuarto (A4) dalam piksel pada resolusi standar (72 DPI)

A4_WIDTH_PX = 793

A4_HEIGHT_PX = 1122


# Output text box yang bisa di-edit oleh user (dibatasi ukuran seperti kertas kuarto)

output_text = tk.Text(root, height=A4_HEIGHT_PX // 15, width=A4_WIDTH_PX // 8)

output_text.pack(padx=10, pady=10)


# Tombol untuk menampilkan partitur

show_button = tk.Button(root, text="Tampilkan Partitur", bg="grey", fg="white", command=show_partitur)

show_button.pack(padx=10, pady=5)


# Tombol untuk menyimpan partitur

save_button = tk.Button(root, text="Simpan Partitur", bg="grey", fg="white", command=save_partitur)

save_button.pack(padx=10, pady=5)


root.mainloop()

```


### Penjelasan Modifikasi:

1. **Menghapus Label**:

   - Semua `Label` dihapus, dan teks label seperti "Judul Lagu", "Nada Dasar", "Tanda Birama", dan lain-lain diubah menjadi placeholder (`hint`) dalam `Entry`.

   - Placeholder diset menggunakan fungsi `set_placeholder` agar teks default akan muncul dalam warna abu-abu, dan akan menghilang saat user mulai mengetik.

2. **Ukuran Lembaran Partitur (A4)**:

   - `Text widget` sekarang memiliki ukuran yang disesuaikan dengan ukuran kertas kuarto (A4), yaitu **793 x 1122 piksel**.

   - Pengaturan ukuran tinggi dan lebar pada widget `Text` menggunakan rasio yang mendekati ukuran A4. Dalam hal ini, kita menghitung tinggi dan lebar yang relevan dalam jumlah baris dan kolom (setiap 15 piksel untuk tinggi dan 8 piksel untuk lebar per kolom sebagai perkiraan).

### Hasil:

Ketika kode ini dijalankan, lembar partitur akan berukuran **seperti kertas kuarto** dan semua entry berada di bagian **tengah atas** dari lembar tersebut. Placeholder (hint) muncul di setiap `Entry`, menggantikan fungsi label tanpa mempengaruhi kemampuan pengguna untuk mengetik pada `Entry`.

Anda bisa mengubah rasio lebar dan tinggi jika ingin menyesuaikan ukuran lebih detail dengan ukuran kertas kuarto atau menambahkan lebih banyak fitur sesuai kebutuhan.


 Ukuran output_text ini dalam satuan apa:

# Output text box yang bisa di-edit oleh user

output_text = tk.Text(scrollable_frame, height=15, width=60)


Ukuran **`height`** dan **`width`** pada widget `Text` di tkinter diukur dalam satuan **baris teks** dan **karakter lebar**.

- **`height=15`** berarti tinggi dari `Text` widget adalah 15 baris teks.

- **`width=60`** berarti lebar dari `Text` widget adalah 60 karakter teks dalam satu baris.

Jadi, ukuran ini bukan dalam piksel, tetapi dalam jumlah baris dan jumlah karakter per baris berdasarkan ukuran font default.


ukuran kertas kuarto A4 adalah lebar 793 px dan panjang 1122 px , bila di konversikan ke ukuran baris teks dan karakter lebar maka akan sama dengan berapa?


Untuk mengonversi ukuran kertas A4 dari piksel ke satuan **baris teks** dan **karakter lebar** di tkinter, kita perlu memperhitungkan ukuran rata-rata satu karakter teks dan tinggi rata-rata satu baris teks berdasarkan font yang digunakan.


### Asumsi Umum:

Ukuran font default di tkinter adalah **`TkDefaultFont`**, dengan ukuran sekitar 12px per karakter untuk lebar, dan 18px per baris untuk tinggi (ini adalah perkiraan umum, karena ukuran font dapat bervariasi).


### Langkah 1: Mengonversi lebar

- **Lebar kertas kuarto**: 793 px.

- Jika lebar satu karakter sekitar 12px, maka:

  \[

  \text{Lebar (dalam karakter)} = \frac{793}{12} \approx 66 \text{ karakter}

  \]


### Langkah 2: Mengonversi tinggi

- **Tinggi kertas kuarto**: 1122 px.

- Jika tinggi satu baris sekitar 18px, maka:

  \[

  \text{Tinggi (dalam baris)} = \frac{1122}{18} \approx 62 \text{ baris}

  \]


### Hasil Konversi

- Lebar dalam karakter: **66 karakter**

- Tinggi dalam baris: **62 baris**


Jadi, untuk ukuran kertas kuarto (A4) di tkinter, kamu dapat menggunakan:

```python

output_text = tk.Text(scrollable_frame, height=62, width=66)

```


Kemudian ke depannya nanti partitur notasi angka yang berupa lembaran musik ini akan di print oleh user, apakah teks yang tertulis "Partitur Notasi Angka (Edit di sini):" akan tercetak juga, bukan ?, makanya teks tulisan tersebut sebaiknya bagaimana agar tidak ikut tercetak, namun tetap ada di partitur sebagai info atau instruksi bagi user. 


Agar teks seperti "Partitur Notasi Angka (Edit di sini):" tetap terlihat di antarmuka aplikasi sebagai instruksi atau informasi bagi user, namun tidak ikut tercetak ketika partitur dicetak, ada beberapa cara yang bisa diambil tergantung pada teknologi yang digunakan untuk mencetak konten.

Berikut adalah beberapa opsi untuk mencegah teks instruksi ikut tercetak:

### 1. **Pisahkan Komponen Tampilan dan Data yang Dicetak**

   - Anda bisa memisahkan **area tampilan** (misalnya `output_text`) yang digunakan user untuk mengedit dari **area yang dicetak**.

   - Saat user mengklik tombol "Print", hanya data yang relevan dicetak (misalnya, partitur dan input dari `Entry`), sementara teks seperti "Partitur Notasi Angka (Edit di sini):" tidak ikut tercetak.

   **Contoh Implementasi**:

   - Tampilkan teks instruksi di dalam widget `Label` atau sebagai bagian dari tampilan saja (di luar area yang akan dicetak).

   - Saat mencetak, ambil hanya konten partitur dari widget tertentu (seperti `Text` atau `Entry`) dan kirimkan ke fungsi cetak tanpa menyertakan label instruksi.

   **Kode Contoh**:

   ```python

   def print_partitur():

       # Fungsi yang mengambil data partitur saja, tanpa teks instruksi

       partitur_data = output_text.get("1.0", "end-1c") # Hanya ambil konten teks yang relevan       

       # Proses pengiriman 'partitur_data' ke printer (contoh sederhana)

       print(partitur_data) # Ini hanya mencetak ke konsol, ganti dengan fungsi cetak sebenarnya

   ```

   **Penjelasan**: 

   - `output_text.get("1.0", "end-1c")` mengambil seluruh konten dari widget `Text`, tanpa teks tambahan yang berada di luar area partitur.

   - Anda bisa mengolah `partitur_data` agar hanya bagian yang penting (misalnya input partitur dari user) yang dikirim ke printer.


### 2. **Gunakan Warna atau Format yang Tidak Dicetak**

   - Jika Anda ingin teks tetap berada di area yang dicetak tetapi tidak ikut tercetak, Anda bisa menggunakan **warna teks yang tidak terlihat** oleh printer atau menggunakan **tag khusus** untuk menyembunyikan elemen tersebut saat proses cetak.

   **Contoh Implementasi**:

   - Gunakan **font berwarna putih** atau dengan **transparansi tinggi** untuk teks yang tidak ingin dicetak, sehingga teks tetap terlihat di antarmuka aplikasi, namun tidak muncul saat proses pencetakan (karena tidak terlihat pada latar putih).

   **Kode Contoh**:

   ```python

   # Teks instruksi yang berwarna abu-abu agar terlihat samar dan tidak dicetak jelas

   output_text.tag_configure("instruksi", foreground="lightgray")

   output_text.insert(tk.END, "Partitur Notasi Angka (Edit di sini):", "instruksi")

   ```

   - `foreground="lightgray"` membuat teks instruksi berwarna terang, yang tetap terlihat di aplikasi namun samar ketika dicetak.


### 3. **Gunakan Area yang Tidak Dicetak untuk Instruksi**

   - Teks instruksi seperti "Partitur Notasi Angka (Edit di sini):" bisa ditempatkan di area aplikasi yang **tidak termasuk dalam area cetak**. Misalnya, menggunakan label atau teks di antarmuka aplikasi, tetapi tidak di dalam area `Text` atau partitur yang dicetak.

   **Contoh Implementasi**:

   - Tempatkan instruksi di area terpisah dari widget `Text` atau `Entry` yang berisi partitur, dan saat mencetak, hanya ambil bagian yang relevan.

   ```python

   instruksi_label = tk.Label(root, text="Partitur Notasi Angka (Edit di sini):")

   instruksi_label.pack()

   ```

   - Dengan pendekatan ini, teks instruksi hanya ada di antarmuka pengguna, bukan di area yang dicetak.


### 4. **Gunakan Layering atau Overlay**

   - Anda bisa membuat lapisan atau **overlay** untuk menampilkan teks instruksi yang hanya terlihat di antarmuka aplikasi. Teks tersebut ditempatkan di atas atau di bawah area partitur, tetapi tidak ikut dimasukkan ke dalam konten yang dicetak.

---

Jadi, untuk memastikan teks instruksi "Partitur Notasi Angka (Edit di sini):" tidak ikut tercetak, saya menyarankan untuk menggunakan opsi **1** atau **3**, yaitu memisahkan komponen tampilan (untuk instruksi) dari data yang relevan untuk dicetak, atau menggunakan widget seperti `Label` yang tidak termasuk dalam proses pencetakan.

Dengan begitu, instruksi tetap terlihat di antarmuka, namun tidak ikut dalam hasil cetakan.


Jika hasilnya di print, bagian bagian mana saja yang akan tercetak, apakah bentuk kotak EntryBox tersebut tercetak berbentuk kotak?


Jika hasil kode di-print menggunakan tombol **Simpan Partitur** yang ada dalam kode, hanya teks yang ada di dalam widget `Text` akan disimpan dan tercetak. Bagian yang tersimpan adalah teks yang dimasukkan atau diedit dalam `Text` widget (`output_text`), tetapi tidak termasuk widget `Entry` (seperti kotak input "Judul Lagu", "Nada Dasar", dll.).


Widget `Entry`, seperti kotak input untuk "Judul Lagu", "Nada Dasar", "Tanda Birama", "Arranger", dan "Pencipta", hanya menampilkan kotak teks interaktif di dalam aplikasi. Namun, ketika disimpan ke file atau di-print, widget tersebut tidak tercetak dalam bentuk kotak. Hanya **teks** yang ada dalam widget `Text` yang disimpan dan dicetak, bukan tampilan fisik widget (kotak `Entry` itu sendiri). 


Untuk menangkap isi dari `Entry` dan mencetaknya, Anda perlu memodifikasi kode agar konten dari setiap `Entry` diambil, kemudian digabungkan dan dimasukkan ke dalam `Text` widget sebelum disimpan atau diprint.


Contoh untuk menyimpan isi dari `Entry` ke dalam `Text`:


```python

def show_partitur():

    # Menghapus teks sebelumnya

    output_text.delete(1.0, tk.END)


    # Menambahkan spasi untuk menggeser Entry ke kanan

    padding = " " * 22 # 22 karakter spasi untuk menggeser entry ke kanan

    

    # Menambahkan Entry untuk Judul Lagu

    judul_entry_in_text = tk.Entry(output_text, width=30, justify='center')

    set_placeholder(judul_entry_in_text, "Judul Lagu")

    output_text.window_create(tk.END, window=judul_entry_in_text)

    

    # Menambahkan tombol untuk menyimpan entry judul ke output_text

    def save_entries_to_text():

        output_text.insert(tk.END, f"\nJudul Lagu: {judul_entry_in_text.get()}\n")

        output_text.insert(tk.END, f"Nada Dasar: {nada_entry_in_text.get()}\n")

        output_text.insert(tk.END, f"Tanda Birama: {birama_entry_in_text.get()}\n")

        output_text.insert(tk.END, f"Arranger: {arranger_entry_in_text.get()}\n")

        output_text.insert(tk.END, f"Pencipta: {pencipta_entry_in_text.get()}\n")

    

    # Menambahkan tombol untuk mengeksekusi save_entries_to_text

    save_entries_button = tk.Button(scrollable_frame, text="Simpan Entry", command=save_entries_to_text)

    save_entries_button.grid(row=7, column=0, padx=5, pady=5)


# Tambahkan fungsi ini ke dalam root.mainloop() agar bisa dipanggil

```

Dengan ini, teks dari setiap `Entry` akan ditambahkan ke dalam `Text` widget, dan ketika disimpan atau di-print, teks tersebut akan tercetak.


Sebaiknya kita menggunakan kode berikut ini saja untuk file partitur_notasi_angka.py:


import tkinter as tk

from tkinter import filedialog, messagebox


# Fungsi untuk menampilkan partitur dengan detail tambahan dan memungkinkan pengguna mengedit notasi

def show_partitur():

    judul_lagu = judul_entry.get()

    nada_dasar = nada_entry.get()

    tanda_birama = birama_entry.get()

    pencipta_lagu = pencipta_entry.get()

    arranger_lagu = arranger_entry.get()   


    # Menampilkan hasil ke output_text (editable)

    output_text.delete(1.0, tk.END) # Menghapus teks sebelumnya

    output_text.insert(tk.END, f"Judul Lagu : {judul_lagu}\n")

    output_text.insert(tk.END, f"Nada Dasar : {nada_dasar}\n")

    output_text.insert(tk.END, f"Tanda Birama : {tanda_birama}\n")

    output_text.insert(tk.END, f"Pencipta : {pencipta_lagu}\n")

    output_text.insert(tk.END, f"Arranger : {arranger_lagu}\n")

    output_text.insert(tk.END, "\n")

    output_text.insert(tk.END, "Partitur Notasi Angka :\n")

    

    # Menyisipkan partitur yang bisa diubah oleh pengguna

    output_text.insert(tk.END, " \n")

    output_text.insert(tk.END, " \n")

    output_text.insert(tk.END, " \n")


# Fungsi untuk menyimpan perubahan

def save_partitur():

    # Mengambil teks yang sudah diedit oleh pengguna

    edited_text = output_text.get(1.0, tk.END).strip()


    # Menyimpan ke dalam file

    file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])

    

    if file_path:

        try:

            with open(file_path, 'w') as file:

                file.write(edited_text)

            messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")

        except Exception as e:

            messagebox.showerror("Error", f"Gagal menyimpan partitur: {e}")


# Setup UI

root = tk.Tk()

root.title("Notasi Angka Lagu")


frame = tk.Frame(root)

frame.pack(padx=10, pady=10)


# Entry untuk judul lagu

judul_label = tk.Label(frame, text="Judul Lagu:")

judul_label.grid(row=0, column=0, padx=5, pady=5)

judul_entry = tk.Entry(frame)

judul_entry.grid(row=0, column=1, padx=5, pady=5)


# Entry untuk nada dasar lagu

nada_label = tk.Label(frame, text="Nada Dasar:")

nada_label.grid(row=1, column=0, padx=5, pady=5)

nada_entry = tk.Entry(frame)

nada_entry.grid(row=1, column=1, padx=5, pady=5)


# Entry untuk tanda sukat (birama) lagu

birama_label = tk.Label(frame, text="Tanda Birama:")

birama_label.grid(row=2, column=0, padx=5, pady=5)

birama_entry = tk.Entry(frame)

birama_entry.grid(row=2, column=1, padx=5, pady=5)


# Entry untuk pencipta lagu

pencipta_label = tk.Label(frame, text="Pencipta:")

pencipta_label.grid(row=3, column=0, padx=5, pady=5)

pencipta_entry = tk.Entry(frame)

pencipta_entry.grid(row=3, column=1, padx=5, pady=5)


# Entry untuk arranger lagu

arranger_label = tk.Label(frame, text="Arranger:")

arranger_label.grid(row=4, column=0, padx=5, pady=5)

arranger_entry = tk.Entry(frame)

arranger_entry.grid(row=4, column=1, padx=5, pady=5)


# Tombol untuk menampilkan partitur

show_button = tk.Button(frame, text="Tampilkan Partitur", bg="grey", fg="white", command=show_partitur)

show_button.grid(row=5, column=0, padx=5, pady=10)


# Tombol untuk menyimpan partitur

save_button = tk.Button(frame, text="Simpan Partitur", bg="grey", fg="white", command=save_partitur)

save_button.grid(row=5, column=2, padx=5, pady=10)


# Output text box yang bisa di-edit oleh user

output_text = tk.Text(root, height=62, width=66)

output_text.pack(padx=10, pady=10)


# Fungsi untuk mempastekan data dari temp_gn_value.txt ke output_text

def paste_gn():

    try:

        # Buka file sementara dan baca nilai

        with open("temp_gn_value.txt", "r") as temp_file:

            gn_value = temp_file.read()

        

        # Paste gn_value ke output_text

        output_text.insert(tk.END, gn_value)

    

    except FileNotFoundError:

        output_text.insert(tk.END, "Tidak ada data yang dicopy.")

        

# Tombol untuk mem-paste gugus nada ke output_text

paste_gn_button = tk.Button(frame, text="Paste Gn", bg="grey", fg="white", command=paste_gn)

paste_gn_button.grid(row=5, column=1, padx=5, pady=5)        


# Menambahkan teks instruksi di atas output_text

instruksi_label = tk.Label(frame, text="Partitur Notasi Angka (Edit di bawah sini):")

instruksi_label.grid(row=6, column=0, padx=5, pady=5)


root.mainloop()


Pada kode tolong perbaiki agar supaya semua teks label yang di luar output teks dihapus saja, dan teks tulisan label dimasukkan ke dalam masing-masing entry yang sesuai dalam hint (placeholder) dan kursor berada di tengah tengah entry agar teks dalam entry berada di tengah tengah entry masing masing.


Untuk memperbaiki kode agar teks label dihapus dan teks dimasukkan sebagai placeholder (hint) di dalam setiap entry, serta agar teks dalam entry berada di tengah-tengah, kita bisa memanfaatkan `Entry` widget dan mengatur alignment-nya menggunakan opsi `justify`. Untuk menambahkan placeholder pada widget `Entry` di tkinter, kita harus membuat sebuah fungsi untuk menampilkan placeholder secara manual karena tkinter tidak memiliki opsi `placeholder` secara bawaan.


Berikut adalah versi modifikasi kode sesuai dengan permintaan Anda:

```python

import tkinter as tk

from tkinter import filedialog, messagebox


# Fungsi untuk menampilkan placeholder pada entry

def set_placeholder(entry, placeholder_text):

    entry.insert(0, placeholder_text)

    entry.config(fg="grey")


    def on_focus_in(event):

        if entry.get() == placeholder_text:

            entry.delete(0, tk.END)

            entry.config(fg="black")


    def on_focus_out(event):

        if entry.get() == "":

            entry.insert(0, placeholder_text)

            entry.config(fg="grey")


    entry.bind("<FocusIn>", on_focus_in)

    entry.bind("<FocusOut>", on_focus_out)


# Fungsi untuk menampilkan partitur dengan detail tambahan dan memungkinkan pengguna mengedit notasi

def show_partitur():

    judul_lagu = judul_entry.get()

    nada_dasar = nada_entry.get()

    tanda_birama = birama_entry.get()

    pencipta_lagu = pencipta_entry.get()

    arranger_lagu = arranger_entry.get()


    # Menampilkan hasil ke output_text (editable)

    output_text.delete(1.0, tk.END) # Menghapus teks sebelumnya

    output_text.insert(tk.END, f"Judul Lagu : {judul_lagu}\n")

    output_text.insert(tk.END, f"Nada Dasar : {nada_dasar}\n")

    output_text.insert(tk.END, f"Tanda Birama : {tanda_birama}\n")

    output_text.insert(tk.END, f"Pencipta : {pencipta_lagu}\n")

    output_text.insert(tk.END, f"Arranger : {arranger_lagu}\n")

    output_text.insert(tk.END, "\n")

    output_text.insert(tk.END, "Partitur Notasi Angka :\n")

    

    # Menyisipkan partitur yang bisa diubah oleh pengguna

    output_text.insert(tk.END, " \n")

    output_text.insert(tk.END, " \n")

    output_text.insert(tk.END, " \n")


# Fungsi untuk menyimpan perubahan

def save_partitur():

    # Mengambil teks yang sudah diedit oleh pengguna

    edited_text = output_text.get(1.0, tk.END).strip()


    # Menyimpan ke dalam file

    file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])

    

    if file_path:

        try:

            with open(file_path, 'w') as file:

                file.write(edited_text)

            messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")

        except Exception as e:

            messagebox.showerror("Error", f"Gagal menyimpan partitur: {e}")


# Setup UI

root = tk.Tk()

root.title("Notasi Angka Lagu")


frame = tk.Frame(root)

frame.pack(padx=10, pady=10)


# Entry untuk judul lagu

judul_entry = tk.Entry(frame, justify="center")

judul_entry.grid(row=0, column=0, padx=5, pady=5)

set_placeholder(judul_entry, "Judul Lagu")


# Entry untuk nada dasar lagu

nada_entry = tk.Entry(frame, justify="center")

nada_entry.grid(row=1, column=0, padx=5, pady=5)

set_placeholder(nada_entry, "Nada Dasar")


# Entry untuk tanda sukat (birama) lagu

birama_entry = tk.Entry(frame, justify="center")

birama_entry.grid(row=2, column=0, padx=5, pady=5)

set_placeholder(birama_entry, "Tanda Birama")


# Entry untuk pencipta lagu

pencipta_entry = tk.Entry(frame, justify="center")

pencipta_entry.grid(row=3, column=0, padx=5, pady=5)

set_placeholder(pencipta_entry, "Pencipta")


# Entry untuk arranger lagu

arranger_entry = tk.Entry(frame, justify="center")

arranger_entry.grid(row=4, column=0, padx=5, pady=5)

set_placeholder(arranger_entry, "Arranger")


# Tombol untuk menampilkan partitur

show_button = tk.Button(frame, text="Tampilkan Partitur", bg="grey", fg="white", command=show_partitur)

show_button.grid(row=5, column=0, padx=5, pady=10)


# Tombol untuk menyimpan partitur

save_button = tk.Button(frame, text="Simpan Partitur", bg="grey", fg="white", command=save_partitur)

save_button.grid(row=5, column=2, padx=5, pady=10)


# Output text box yang bisa di-edit oleh user

output_text = tk.Text(root, height=62, width=66)

output_text.pack(padx=10, pady=10)


# Fungsi untuk mempastekan data dari temp_gn_value.txt ke output_text

def paste_gn():

    try:

        # Buka file sementara dan baca nilai

        with open("temp_gn_value.txt", "r") as temp_file:

            gn_value = temp_file.read()

        

        # Paste gn_value ke output_text

        output_text.insert(tk.END, gn_value)

    

    except FileNotFoundError:

        output_text.insert(tk.END, "Tidak ada data yang dicopy.")

        

# Tombol untuk mem-paste gugus nada ke output_text

paste_gn_button = tk.Button(frame, text="Paste Gn", bg="grey", fg="white", command=paste_gn)

paste_gn_button.grid(row=5, column=1, padx=5, pady=5)        


# Menambahkan teks instruksi di atas output_text

instruksi_label = tk.Label(frame, text="Partitur Notasi Angka (Edit di bawah sini):")

instruksi_label.grid(row=6, column=0, padx=5, pady=5)


root.mainloop()

```

### Penjelasan Perubahan:

1. **Placeholder (Hint)**: Setiap `Entry` sekarang memiliki fungsi placeholder yang menggantikan teks label. Placeholder ini hilang saat `Entry` diklik (ketika mendapat fokus) dan muncul kembali jika kosong. 

2. **Teks dalam Entry di Tengah**: Dengan menambahkan `justify="center"`, teks di dalam setiap `Entry` akan berada di tengah.

3. **Penghapusan Label**: Label yang sebelumnya ada di luar setiap `Entry` telah dihapus, dan teks yang relevan telah dimasukkan sebagai placeholder pada masing-masing `Entry`.

Dengan perubahan ini, antarmuka pengguna akan terlihat lebih bersih dan lebih mudah digunakan.


Kode selengkapnya adalah berikut ini:

import tkinter as tk

from tkinter import filedialog, messagebox


# Fungsi untuk menampilkan placeholder pada entry

def set_placeholder(entry, placeholder_text):

    entry.insert(0, placeholder_text)

    entry.config(fg="grey")


    def on_focus_in(event):

        if entry.get() == placeholder_text:

            entry.delete(0, tk.END)

            entry.config(fg="black")


    def on_focus_out(event):

        if entry.get() == "":

            entry.insert(0, placeholder_text)

            entry.config(fg="grey")


    entry.bind("<FocusIn>", on_focus_in)

    entry.bind("<FocusOut>", on_focus_out)


# Fungsi untuk menampilkan partitur dengan detail tambahan dan memungkinkan pengguna mengedit notasi

def show_partitur():

    judul_lagu = judul_entry.get()

    nada_dasar = nada_entry.get()

    tanda_birama = birama_entry.get()

    pencipta_lagu = pencipta_entry.get()

    arranger_lagu = arranger_entry.get()   


    # Menampilkan hasil ke output_text (editable)

    output_text.delete(1.0, tk.END) # Menghapus teks sebelumnya

    output_text.insert(tk.END, f"Judul Lagu : \n")

    output_text.insert(tk.END, f"Nada Dasar : \n")

    output_text.insert(tk.END, f"Tanda Birama : \n")

    output_text.insert(tk.END, f"Pencipta : \n")

    output_text.insert(tk.END, f"Arranger : \n")

    output_text.insert(tk.END, "\n")

    output_text.insert(tk.END, "Partitur Notasi Angka :\n")

    

    # Menyisipkan partitur yang bisa diubah oleh pengguna

    output_text.insert(tk.END, " \n")

    output_text.insert(tk.END, " \n")

    

# Fungsi untuk menyimpan perubahan

def save_partitur():

    # Mengambil teks yang sudah diedit oleh pengguna

    edited_text = output_text.get(1.0, tk.END).strip()


    # Menyimpan ke dalam file

    file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])

    

    if file_path:

        try:

            with open(file_path, 'w') as file:

                file.write(edited_text)

            messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")

        except Exception as e:

            messagebox.showerror("Error", f"Gagal menyimpan partitur: {e}")


# Setup UI

root = tk.Tk()

root.title("Notasi Angka Lagu")


frame = tk.Frame(root)

frame.pack(padx=10, pady=10)


# Entry untuk judul lagu

judul_entry = tk.Entry(frame, justify="center")

judul_entry.grid(row=0, column=1, padx=5, pady=5)

set_placeholder(judul_entry, "Judul Lagu")


# Entry untuk nada dasar lagu

nada_entry = tk.Entry(frame, justify="center")

nada_entry.grid(row=1, column=1, padx=5, pady=5)

set_placeholder(nada_entry, "Nada Dasar")


# Entry untuk tanda sukat (birama) lagu

birama_entry = tk.Entry(frame, justify="center")

birama_entry.grid(row=2, column=1, padx=5, pady=5)

set_placeholder(birama_entry, "Tanda Birama")


# Entry untuk pencipta lagu

pencipta_entry = tk.Entry(frame, justify="center")

pencipta_entry.grid(row=3, column=1, padx=5, pady=5)

set_placeholder(pencipta_entry, "Pencipta")


# Entry untuk arranger lagu

arranger_entry = tk.Entry(frame, justify="center")

arranger_entry.grid(row=4, column=1, padx=5, pady=5)

set_placeholder(arranger_entry, "Arranger")


# Tombol untuk menampilkan partitur

show_button = tk.Button(frame, text="Tampilkan Partitur", bg="grey", fg="white", command=show_partitur)

show_button.grid(row=5, column=0, padx=5, pady=10)


# Tombol untuk menyimpan partitur

save_button = tk.Button(frame, text="Simpan Partitur", bg="grey", fg="white", command=save_partitur)

save_button.grid(row=5, column=2, padx=5, pady=10)


# Output text box yang bisa di-edit oleh user

output_text = tk.Text(root, height=62, width=66)

output_text.pack(padx=10, pady=10)


# Fungsi untuk mempastekan data dari temp_gn_value.txt ke output_text

def paste_gn():

    try:

        # Buka file sementara dan baca nilai

        with open("temp_gn_value.txt", "r") as temp_file:

            gn_value = temp_file.read()

        

        # Paste gn_value ke output_text

        output_text.insert(tk.END, gn_value)

    

    except FileNotFoundError:

        output_text.insert(tk.END, "Tidak ada data yang dicopy.")

        

# Tombol untuk mem-paste gugus nada ke output_text

paste_gn_button = tk.Button(frame, text="Paste Gn", bg="grey", fg="white", command=paste_gn)

paste_gn_button.grid(row=5, column=1, padx=5, pady=5)        


# Menambahkan teks instruksi di atas output_text

instruksi_label = tk.Label(frame, text="Partitur Notasi Angka (Edit di bawah sini):")

instruksi_label.grid(row=6, column=0, padx=5, pady=5)


root.mainloop()


Pada kode tolong semua tulisan teks yang di dalam output_text dibuat agak masuk (menjorot) ke dalam, kemudian pada kode pada semua elemen dan fungsi tambahkan fungsi pengguliran ke segala arah agar supaya semua elemen GUI dan fungsi kode dapat bergulir ke segala arah.


Untuk menambahkan indentasi (penjorokan ke dalam) pada teks di dalam `output_text` dan menambahkan fitur pengguliran pada semua elemen GUI, kita bisa memodifikasi kode dengan beberapa perubahan. Berikut adalah langkah-langkahnya:


1. **Indentasi (Menjorok ke Dalam):**

   - Menambahkan spasi atau tab pada setiap baris teks yang ingin ditampilkan menjorok ke dalam.


2. **Fitur Pengguliran:**

   - Kita bisa menambahkan scrollbar vertikal dan horizontal ke widget yang dibutuhkan, seperti `output_text`.


Berikut adalah kode yang telah dimodifikasi sesuai permintaan Anda:


```python

import tkinter as tk

from tkinter import filedialog, messagebox


# Fungsi untuk menampilkan placeholder pada entry

def set_placeholder(entry, placeholder_text):

    entry.insert(0, placeholder_text)

    entry.config(fg="grey")


    def on_focus_in(event):

        if entry.get() == placeholder_text:

            entry.delete(0, tk.END)

            entry.config(fg="black")


    def on_focus_out(event):

        if entry.get() == "":

            entry.insert(0, placeholder_text)

            entry.config(fg="grey")


    entry.bind("<FocusIn>", on_focus_in)

    entry.bind("<FocusOut>", on_focus_out)


# Fungsi untuk menampilkan partitur dengan detail tambahan dan memungkinkan pengguna mengedit notasi

def show_partitur():

    # Menampilkan hasil ke output_text (editable)

    output_text.delete(1.0, tk.END) # Menghapus teks sebelumnya

    output_text.insert(tk.END, " Judul Lagu : \n")

    output_text.insert(tk.END, " Nada Dasar : \n")

    output_text.insert(tk.END, " Tanda Birama : \n")

    output_text.insert(tk.END, " Pencipta : \n")

    output_text.insert(tk.END, " Arranger : \n")

    output_text.insert(tk.END, "\n")

    output_text.insert(tk.END, " Partitur Notasi Angka :\n")

    

    # Menyisipkan partitur yang bisa diubah oleh pengguna

    output_text.insert(tk.END, " \n")

    output_text.insert(tk.END, " \n")


# Fungsi untuk menyimpan perubahan

def save_partitur():

    # Mengambil teks yang sudah diedit oleh pengguna

    edited_text = output_text.get(1.0, tk.END).strip()


    # Menyimpan ke dalam file

    file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])

    

    if file_path:

        try:

            with open(file_path, 'w') as file:

                file.write(edited_text)

            messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")

        except Exception as e:

            messagebox.showerror("Error", f"Gagal menyimpan partitur: {e}")


# Setup UI

root = tk.Tk()

root.title("Notasi Angka Lagu")


frame = tk.Frame(root)

frame.pack(padx=10, pady=10)


# Entry untuk judul lagu

judul_entry = tk.Entry(frame, justify="center")

judul_entry.grid(row=0, column=1, padx=5, pady=5)

set_placeholder(judul_entry, "Judul Lagu")


# Entry untuk nada dasar lagu

nada_entry = tk.Entry(frame, justify="center")

nada_entry.grid(row=1, column=1, padx=5, pady=5)

set_placeholder(nada_entry, "Nada Dasar")


# Entry untuk tanda sukat (birama) lagu

birama_entry = tk.Entry(frame, justify="center")

birama_entry.grid(row=2, column=1, padx=5, pady=5)

set_placeholder(birama_entry, "Tanda Birama")


# Entry untuk pencipta lagu

pencipta_entry = tk.Entry(frame, justify="center")

pencipta_entry.grid(row=3, column=1, padx=5, pady=5)

set_placeholder(pencipta_entry, "Pencipta")


# Entry untuk arranger lagu

arranger_entry = tk.Entry(frame, justify="center")

arranger_entry.grid(row=4, column=1, padx=5, pady=5)

set_placeholder(arranger_entry, "Arranger")


# Tombol untuk menampilkan partitur

show_button = tk.Button(frame, text="Tampilkan Partitur", bg="grey", fg="white", command=show_partitur)

show_button.grid(row=5, column=0, padx=5, pady=10)


# Tombol untuk menyimpan partitur

save_button = tk.Button(frame, text="Simpan Partitur", bg="grey", fg="white", command=save_partitur)

save_button.grid(row=5, column=2, padx=5, pady=10)


# Membuat Frame untuk output_text dan scrollbar

output_frame = tk.Frame(root)

output_frame.pack(padx=10, pady=10)


# Menambahkan scrollbar vertikal dan horizontal

scrollbar_vertikal = tk.Scrollbar(output_frame, orient="vertical")

scrollbar_horiz = tk.Scrollbar(output_frame, orient="horizontal")


# Output text box yang bisa di-edit oleh user, dihubungkan dengan scrollbar

output_text = tk.Text(output_frame, height=30, width=66, wrap="none", 

                      yscrollcommand=scrollbar_vertikal.set, xscrollcommand=scrollbar_horiz.set)


output_text.grid(row=0, column=0)


# Menghubungkan scrollbar dengan output_text

scrollbar_vertikal.config(command=output_text.yview)

scrollbar_horiz.config(command=output_text.xview)


scrollbar_vertikal.grid(row=0, column=1, sticky="ns")

scrollbar_horiz.grid(row=1, column=0, sticky="ew")


# Fungsi untuk mempastekan data dari temp_gn_value.txt ke output_text

def paste_gn():

    try:

        # Buka file sementara dan baca nilai

        with open("temp_gn_value.txt", "r") as temp_file:

            gn_value = temp_file.read()

        

        # Paste gn_value ke output_text

        output_text.insert(tk.END, gn_value)

    

    except FileNotFoundError:

        output_text.insert(tk.END, "Tidak ada data yang dicopy.")

        

# Tombol untuk mem-paste gugus nada ke output_text

paste_gn_button = tk.Button(frame, text="Paste Gn", bg="grey", fg="white", command=paste_gn)

paste_gn_button.grid(row=5, column=1, padx=5, pady=5)        


# Menambahkan teks instruksi di atas output_text

instruksi_label = tk.Label(frame, text="Partitur Notasi Angka (Edit di bawah sini):")

instruksi_label.grid(row=6, column=0, padx=5, pady=5)


root.mainloop()

```


### Perubahan Utama:

1. **Indentasi (Menjorok ke Dalam)**: Teks yang di-insert ke `output_text` memiliki spasi di awal untuk membuatnya menjorok ke dalam.

2. **Scrollbar Vertikal dan Horizontal**: Scrollbar vertikal dan horizontal telah ditambahkan ke widget `Text`, yang memungkinkan Anda untuk menggulir ke segala arah di dalam `output_text`.


Dengan kode ini, pengguna bisa menggulir ke atas, bawah, kiri, atau kanan saat mengedit teks di area `output_text`, dan teks yang ditampilkan akan memiliki indentasi.



Bersambung ke:

PEMBUATAN PARTITURE NOTASI ANGKA LAGU (Part-3)




Komentar

Postingan populer dari blog ini

Pemograman R Studio

  Metode Numerik Menggunakan R Pengantar Gambaran Isi Buku Cara Berkontribusi dalam Buku Ini Ucapan Terima Kasih Lisensi 1  Bahasa Pemrograman R 1.1  Sejarah R 1.2  Fitur dan Karakteristik R 1.3  Kelebihan dan Kekurangan R 1.4  RStudio 1.5  Menginstall R dan RStudio 1.6  Working Directory 1.6.1  Mengubah Lokasi Working Directory 1.6.2  Mengubah Lokasi Working Directory Default 1.7  Memasang dan Mengaktifkan Paket R 1.8  Fasilitas Help 1.8.1  Mencari Help dari Suatu Perintah Tertentu 1.8.2  General Help 1.8.3  Fasilitas Help Lainnya 1.9  Referensi 2  Kalkulasi Menggunakan R 2.1  Operator Aritmatik 2.2  Fungsi Aritmetik 2.3  Operator Relasi 2.4  Operator Logika 2.5  Memasukkan Nilai Kedalam Variabel 2.6  Tipe dan Struktur Data 2.7  Vektor 2.7.1  Membuat vektor 2.7.2  Missing Values 2.7.3  Subset Pada Vektor 2.7.4  Operasi Matematis Menggunakan Vektor ...

MIGRASI DATABASE DARI SQLite KE MySQL (Part-1)

  MIGRASI DATABASE DARI SQLite KE MySQL (Part-1) Pemakaian yang mana lebih baik dalam membuat database_musik di mysql atau Exel yang cell Cell pada tabel dilakukan operasi fungsi logika matematika. Untuk keperluan membuat database atau tabel yang memerlukan operasi logika atau matematika, seperti yang Anda sebutkan, MySQL jauh lebih baik dibandingkan Excel. Berikut adalah beberapa alasan mengapa MySQL lebih disarankan: 1. **Kapasitas dan Skalabilitas**: MySQL dapat menangani jumlah data yang jauh lebih besar daripada Excel. Ini penting jika Anda berencana untuk menyimpan banyak data atau melakukan operasi yang kompleks di atas data tersebut. 2. **Kekuatan dan Kinerja**: MySQL dirancang khusus untuk memproses query dan operasi basis data dengan cepat. Ini termasuk operasi matematika, logika, dan agregasi data yang umum dilakukan dalam aplikasi. 3. **Fleksibilitas Struktur**: Dalam MySQL, Anda dapat dengan mudah menentukan struktur tabel yang kompleks dan melakukan kueri yang lebih r...

Cara Menjadi Pengembang Front End – Keterampilan Front End Web Dev

  Menyumbangkan Belajar coding —  kurikulum 3.000 jam gratis 10 JUNI 2022 / #PENGEMBANGAN UJUNG DEPAN Bagaimana Menjadi Pengembang Front End – Keterampilan Front End Web Dev Joel Olawanle Beberapa profesional dengan bayaran tertinggi di dunia adalah pengembang front-end.  Mereka menggunakan pengetahuan dan bakat mereka untuk merancang situs web yang menarik dan ramah pengguna. Pengembang front-end tidak memerlukan gelar atau sertifikat sekolah untuk bekerja.  Sebaliknya, mereka harus memahami dasar-dasar pengembangan front-end, bahasa pemrograman, dan kerangka kerja pengembangan front-end. Dalam panduan ini, Anda akan belajar bagaimana menjadi pengembang front end dengan terlebih dahulu memahami apa yang dimaksud dengan pengembangan front end, keterampilan teknis dan soft skill yang diperlukan, bahasa dan kerangka kerja yang tersedia, dan beberapa langkah untuk memulai. Seorang pengembang front-end di Amerika Serikat dapat memperoleh rata-rata $86,178 per tahun, menu...