Python을 사용하여 쉘 명령 실행 및 GUI 애플리케이션 구축

Python 스크립트 내에서 외부 쉘 명령을 실행하고 Tkinter를 사용하여 사용자 친화적인 인터페이스를 생성하는 방법을 살펴보겠습니다.

Python에서 쉘 명령 호출

Python의 os.system() 함수를 사용하면 쉘 명령을 직접 실행할 수 있습니다. 이는 컴파일, 실행 및 데이터 처리를 자동화하는 데 유용합니다.


import os

# C++ 프로그램 컴파일
os.system('make')

# Python 변수를 쉘 명령에 전달
flag_values = [0, 0, 0, 0, 0] # 예시 플래그 값
# flag_values[0] = flag[0] # 실제 구현에서는 이 부분을 변수 할당으로 대체
# ... (나머지 플래그 값 할당)

# C++ 프로그램 실행을 위한 입력 파일 생성
with open('output/cin.massfit', 'w') as f:
    f.write(' '.join(map(str, flag_values)))

# 컴파일된 C++ 프로그램 실행
os.system('./massfit.x < output/cin.massfit')

이 기능은 Python GUI에서 사용자의 입력을 받아 백엔드 C++ 프로그램을 실행하는 데 활용될 수 있습니다.

Tkinter를 이용한 GUI 개발

Tkinter는 Python 표준 라이브러리에 포함된 GUI 툴킷으로, 간단하고 직관적인 인터페이스를 쉽게 만들 수 있습니다.

1. 텍스트 파일 편집기


import tkinter as tk
from tkinter.scrolledtext import ScrolledText

def load_file():
    file_path = filename_entry.get()
    try:
        with open(file_path, 'r') as f:
            content_text.delete('1.0', tk.END)
            content_text.insert(tk.INSERT, f.read())
    except FileNotFoundError:
        content_text.insert(tk.INSERT, f"Error: File '{file_path}' not found.")

def save_file():
    file_path = filename_entry.get()
    try:
        with open(file_path, 'w') as f:
            f.write(content_text.get('1.0', tk.END))
    except Exception as e:
        content_text.insert(tk.INSERT, f"\nError saving file: {e}")

root = tk.Tk()
root.title("Simple Text Editor")
root.resizable(False, False)

content_text = ScrolledText(root)
content_text.pack(side=tk.BOTTOM, expand=True, fill=tk.BOTH)

filename_frame = tk.Frame(root)
filename_frame.pack(side=tk.TOP, fill=tk.X)

filename_entry = tk.Entry(filename_frame)
filename_entry.pack(side=tk.LEFT, expand=True, fill=tk.X)

open_button = tk.Button(filename_frame, text="Open", command=load_file)
open_button.pack(side=tk.LEFT)
save_button = tk.Button(filename_frame, text="Save", command=save_file)
save_button.pack(side=tk.LEFT)

root.mainloop()

2. 버튼 클릭으로 텍스트 변경


import tkinter as tk
from tkinter import ttk

def update_text_and_color():
    action_button.config(text="Clicked!")
    status_label.config(foreground='red', text='Status: Red Label')

app_window = tk.Tk()
app_window.title("Interactive GUI")

status_label = ttk.Label(app_window, text="Initial Status")
status_label.grid(column=0, row=0, padx=5, pady=5)

action_button = ttk.Button(app_window, text="Click Me", command=update_text_and_color)
action_button.grid(column=1, row=0, padx=5, pady=5)

app_window.mainloop()

3. 이름 입력 시 인사말 생성


import tkinter as tk
from tkinter import ttk

def greet_user():
    greeting_message = f"Hello, {name_var.get()}!"
    action_button.config(text=greeting_message)

app_window = tk.Tk()
app_window.title("Greeting App")

ttk.Label(app_window, text="Enter your name:").grid(column=0, row=0, padx=5, pady=5)

name_var = tk.StringVar()
name_entry = ttk.Entry(app_window, width=15, textvariable=name_var)
name_entry.grid(column=0, row=1, padx=5, pady=5)
name_entry.focus()

action_button = ttk.Button(app_window, text="Greet", command=greet_user)
action_button.grid(column=1, row=1, padx=5, pady=5)
action_button.config(state=tk.DISABLED) # 초기 비활성화

# 사용자가 입력할 때 버튼 활성화/비활성화 로직 추가 가능

app_window.mainloop()

4. Matplotlib 그래프 임베딩

Matplotlib 그래프를 Tkinter 애플리케이션에 통합하여 동적 시각화를 제공할 수 있습니다.


import tkinter as tk
import numpy as np
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.backend_bases import key_press_handler

def handle_key_press(event):
    print(f"Key pressed: {event.key}")
    key_press_handler(event) # 기본 Matplotlib 동작 유지

root_window = tk.Tk()
root_window.wm_title("Matplotlib in Tkinter")

plot_figure = Figure(figsize=(6, 4), dpi=100)
time = np.arange(0, 3, 0.01)
plot_figure.add_subplot(111).plot(time, 2 * np.sin(2 * np.pi * time))

canvas = FigureCanvasTkAgg(plot_figure, master=root_window)
canvas.draw()
canvas_widget = canvas.get_tk_widget()

toolbar = NavigationToolbar2Tk(canvas, root_window)
toolbar.update()

canvas_widget.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
canvas.mpl_connect("key_press_event", handle_key_press)

quit_button = tk.Button(master=root_window, text="Quit", command=root_window.quit)
quit_button.pack(side=tk.BOTTOM)
toolbar.pack(side=tk.BOTTOM, fill=tk.X)

root_window.mainloop()

5. 핵 질량 액체 방울 모델 적합 GUI

이 예제는 이전 섹션의 쉘 명령 실행 기능과 Matplotlib 그래프 임베딩을 결합하여 핵 물리학 계산을 위한 복잡한 GUI를 보여줍니다.


#coding=utf-8
import os
import tkinter as tk
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

# Initialize main window
root = tk.Tk()
root.title("Nuclear Mass Liquid Drop Model Fit")

# Setup Matplotlib figure
plot_fig = Figure(figsize=(8, 5), dpi=100)
plot_ax = plot_fig.add_subplot(111)

# Global variables for model parameters and flags
param_flags = [0, 0, 0, 0, 0] # volume, surface, symmetry, coulomb, pairing
button_colors = ['#d9d9d9', 'green'] # default, active

def toggle_param(index):
    param_flags[index] = (param_flags[index] + 1) % 2
    button = [button_vol, button_surf, button_sym, button_coul, button_pair][index]
    button.config(bg=button_colors[param_flags[index]], activebackground=button_colors[param_flags[index]])

def execute_fit_and_plot(plot_type):
    # Execute C++ program
    os.system('make') # Assume compilation happens here
    
    # Prepare input for C++ program
    input_str = ' '.join(map(str, param_flags))
    with open('output/cin.massfit', 'w') as f:
        f.write(input_str)
    os.system('./massfit.x < output/cin.massfit')

    # Load results and plot
    try:
        data = np.loadtxt("output/res.txt")
        Z, N, A, Bres = data[:,0], data[:, 1], data[:, 2], data[:, 3]

        plot_ax.clear()
        plot_ax.set_ylabel("Bres = Bexp. - Bth. (MeV)")
        
        if plot_type == 'Z':
            plot_ax.set_xlabel("Z")
            plot_ax.scatter(Z, Bres, s=5)
        elif plot_type == 'N':
            plot_ax.set_xlabel("N")
            plot_ax.scatter(N, Bres, s=5)
        
        canvas.draw()
    except FileNotFoundError:
        plot_ax.text(0.5, 0.5, "Results file not found.", ha='center', va='center')
        canvas.draw()
    except Exception as e:
        plot_ax.text(0.5, 0.5, f"Error loading data: {e}", ha='center', va='center')
        canvas.draw()

# Create GUI elements
button_vol = tk.Button(root, text='Volume', command=lambda: toggle_param(0))
button_surf = tk.Button(root, text="Surface", command=lambda: toggle_param(1))
button_sym = tk.Button(root, text="Symmetry", command=lambda: toggle_param(2))
button_coul = tk.Button(root, text="Coulomb", command=lambda: toggle_param(3))
button_pair = tk.Button(root, text="Pairing", command=lambda: toggle_param(4))
button_plot_Z = tk.Button(root, text="Plot Bres vs Z", command=lambda: execute_fit_and_plot('Z'))
button_plot_N = tk.Button(root, text="Plot Bres vs N", command=lambda: execute_fit_and_plot('N'))

# Pack buttons
button_vol.pack(side=tk.LEFT, padx=2, pady=5)
button_surf.pack(side=tk.LEFT, padx=2, pady=5)
button_sym.pack(side=tk.LEFT, padx=2, pady=5)
button_coul.pack(side=tk.LEFT, padx=2, pady=5)
button_pair.pack(side=tk.LEFT, padx=2, pady=5)
button_plot_Z.pack(side=tk.LEFT, padx=5, pady=5)
button_plot_N.pack(side=tk.LEFT, padx=5, pady=5)

# Embed plot canvas
canvas = FigureCanvasTkAgg(plot_fig, root)
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

# Main loop
root.mainloop()

태그: python os Shell Tkinter GUI

7월 17일 22:43에 게시됨