반응형
개인적으로 학습을 위해 만듦...
완성된 프로그램을 실행한 화면입니다.
작성한 코드 내용입니다..
from tkinter import *
from tkinter import messagebox
from tkinter import ttk
from tkinter import filedialog
import tkinter as tk
import sqlite3
import pandas as pd
# =============================
# 폰트 설정
font = '맑은 고딕', 11
# =============================
# db 연결
conn = sqlite3.connect('data.db')
c = conn.cursor()
# ==================================================================
# 테이블 생성
# column1 = 완료유무
# column2 = 부서
# column3 = 성명
# column4 = 신청내용
# column5 = 비고
c.execute('''CREATE TABLE IF NOT EXISTS App_DB
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
column1 TEXT,
column2 TEXT,
column3 TEXT,
column4 TEXT,
column5 TEXT,
column6 TEXT
)''')
conn.commit()
# tkinter GUI 생성
root = tk.Tk()
root.title("접수 프로그램 ")
root.geometry("1500x850+400+100")
# 오늘 날짜 | 현재시간
import time
weekdays_kr = ['월', '화', '수', '목', '금', '토', '일']
date_frame = tk.Frame(root)
date_frame.pack(side='top', padx=50, pady=10, anchor='nw')
date_label = tk.Label(date_frame, font=('맑은 고딕', 20, 'bold'))
time_label = tk.Label(date_frame, font=('맑은 고딕', 20, 'bold'))
def update_time():
current_time = time.strftime('현재시각 : %H시 %M분 |')
time_label.config(text=current_time)
time_label.after(1000, update_time)
def update_date():
current_date = time.strftime('| %Y년 %m월 %d일 ') + weekdays_kr[time.localtime().tm_wday] + '요일 | '
date_label.config(text=current_date)
date_label.after(1000, update_date)
def show():
date_label.grid(row=0, column=0, padx=0)
time_label.grid(row=0, column=1, padx=0)
show()
update_date()
update_time()
# 입력 폼 =============================================================
input_frame = tk.Frame(root)
input_frame.pack(side='top', padx=30, pady=10, anchor='nw')
# 라벨 이름 설정
lab1 = '부서'
lab2 = '성명'
lab3 = '신청내용'
lab4 = '기타입력'
lab1 = tk.Label(input_frame, text=lab1, font=font)
lab1.grid(row=0, column=0, padx=20, sticky=tk.W)
ent1 = tk.Entry(input_frame, font=font)
ent1.grid(row=1, column=0, padx=20)
ent1.focus() # ent1에 프롬프트 설정
lab2 = tk.Label(input_frame, text=lab2, font=font)
lab2.grid(row=0, column=1, padx=20 ,sticky=tk.W)
ent2 = tk.Entry(input_frame, font=font)
ent2.grid(row=1, column=1, padx=20)
lab3 = tk.Label(input_frame, text=lab3, font=font)
lab3.grid(row=0, column=2, padx=20 ,sticky=tk.W)
ent3 = tk.Entry(input_frame, font=font)
ent3.grid(row=1, column=2, padx=20)
lab4 = tk.Label(input_frame, text=lab4, font=font)
lab4.grid(row=0, column=3, padx=20 ,sticky=tk.W)
ent4 = tk.Entry(input_frame, font=font)
ent4.grid(row=1, column=3, padx=20)
# 엔트리 데이터
team = ent1.get()
name = ent2.get()
helpdesk = ent3.get()
etc = ent4.get()
# 트리뷰 스타일 지정 =============================================================
style = ttk.Style()
style.theme_use('clam')
style.configure('Treeview', background = '#D3D3D3', foreground = 'black', rowheight=25, fieldbackground = '#D3D3D3', font=font)
style.map('Treeview', background = [('selected', 'darkgreen')])
# Treeview.Heading 스타일 생성
style.configure('Treeview.Heading', font=font)
# Treeview 생성 =============================================================
tree = ttk.Treeview(root)
tree.pack(padx=20, pady=20)
tree.configure(height=20)
tree.tag_configure('Treeview.Heading', **{'font': font}) # 스타일 적용
# Treeview 열 설정
tree['columns'] = ('column1', 'column2', 'column3', 'column4', 'column5', 'column6')
tree['show'] = 'headings'
tree.column('column1', width=100, anchor="center")
tree.column('column2', width=150, anchor="center")
tree.column('column3', width=200, anchor="center")
tree.column('column4', width=150, anchor="center")
tree.column('column5', width=600)
tree.column('column6', width=200)
tree.heading('column1', text='번호')
tree.heading('column2', text='접수상태')
tree.heading('column3', text='부서')
tree.heading('column4', text='성명')
tree.heading('column5', text='신청내용')
tree.heading('column6', text='기타입력')
# Treeview 더블 클릭 함수 =============================================================
def on_double_click(event):
# 선택한 행의 값들 가져오기
selection = tree.selection()
if len(selection) == 0:
return
values = tree.item(selection[0], 'values')
# Toplevel 창 열기
top = tk.Toplevel(root)
top.title('')
# Frame
new_ent_frame = tk.Frame(top)
new_ent_frame.pack(padx=15)
# 라벨 이름 설정
new_lab1 = '부서'
new_lab2 = '성명'
new_lab3 = '신청내용'
new_lab4 = '기타입력'
new_lab1 = tk.Label(new_ent_frame, text=new_lab1, font=font)
new_lab1.grid(row=0, column=0, sticky=tk.W)
new_ent1 = tk.Entry(new_ent_frame, font=font)
new_ent1.grid(row=1, column=0)
new_ent1.focus() # new_ent1에 프롬프트 설정
new_lab2 = tk.Label(new_ent_frame, text=new_lab2, font=font)
new_lab2.grid(row=2, column=0, sticky=tk.W)
new_ent2 = tk.Entry(new_ent_frame, font=font)
new_ent2.grid(row=3, column=0)
new_lab3 = tk.Label(new_ent_frame, text=new_lab3, font=font)
new_lab3.grid(row=4, column=0, sticky=tk.W)
new_ent3 = tk.Entry(new_ent_frame, font=font)
new_ent3.grid(row=5, column=0)
new_lab4 = tk.Label(new_ent_frame, text=new_lab4, font=font)
new_lab4.grid(row=6, column=0, sticky=tk.W)
new_ent4 = tk.Entry(new_ent_frame, font=font)
new_ent4.grid(row=7, column=0)
# Save
def edit_item(event=None): # 이벤트 동작될 수 있음
if messagebox.askyesno("EDIT", "변경된 내용은 복구할 수 없습니다.\n저장하려면 YES를 누르세요."):
# 변경된 값 가져오기
new_value1 = new_ent1.get()
new_value2 = new_ent2.get()
new_value3 = new_ent3.get()
new_value4 = new_ent4.get()
# DB 업데이트
row_id = values[0]
c.execute("UPDATE App_DB SET column2 = ? WHERE id = ?", (new_value1, row_id))
c.execute("UPDATE App_DB SET column3 = ? WHERE id = ?", (new_value2, row_id))
c.execute("UPDATE App_DB SET column4 = ? WHERE id = ?", (new_value3, row_id))
c.execute("UPDATE App_DB SET column5 = ? WHERE id = ?", (new_value4, row_id))
conn.commit()
# Toplevel 창 닫기
top.destroy()
# Treeview 업데이트
update_table()
# 저장버튼
save_button = tk.Button(top, text='변경하기', command=edit_item)
save_button.pack(padx=15, pady=15)
# Enter 입력으로 다음 Entry로 이동
new_ent1.bind('<Return>', next_entry)
new_ent2.bind('<Return>', next_entry)
new_ent3.bind('<Return>', next_entry)
new_ent4.bind('<Return>', edit_item)
# 열과 높이 설정
top.columnconfigure(0, weight=1)
top.rowconfigure(0, weight=1)
# =============================================================================================================================
# 다음 entry로 이동
def next_entry(event):
widget = event.widget
widget.tk_focusNext().focus()
return "break"
# ent1로 이동하기
def move_ent1():
ent1.focus_set()
# 이벤트 처리 함수 (단축키 설정 등) ======================================================
def key_enter(event): # 저장
messagebox.showinfo('ADD','추가 되었습니다.')
save_data()
def key_f5(event): # 새로고침
tree.delete(*tree.get_children())
update_table()
messagebox.showinfo('UPDATE','새로 고침.')
def key_delete(event): # 삭제
if messagebox.askyesno("DELETE", "삭제하시겠습니까?"):
delete_data()
# Treeview 새로고침 ======================================================
def update_table():
tree.delete(*tree.get_children()) # Treeview 모든 데이터 삭제
for row in c.execute("SELECT * FROM App_DB"): # DB에서 모든 데이터 가져오기
tree.insert("", "end", values=row) # Treeview에 삽입
# 저장 버튼 함수 ======================================================================
def save_data():
save_button.config(state=tk.DISABLED) # 버튼 동작 후 비활성화
root.after(1000, lambda: save_button.config(state=tk.NORMAL)) # 1000의 시간이 지난 후 다시 활성화
# 엔트리 데이터
team = ent1.get()
name = ent2.get()
helpdesk = ent3.get()
etc = ent4.get()
# DB에 데이터 추가
c.execute("INSERT INTO App_DB (column1, column2, column3, column4, column5) VALUES (?, ?, ?, ?, ?)",
('신청접수', team, name, helpdesk, etc))
conn.commit()
# 트리뷰에 데이터 추가
last_row = c.lastrowid
tree.insert('', 'end', text=last_row, values=(team, name, helpdesk, etc))
# 입력란 초기화 하기
ent1.delete(0, tk.END)
ent2.delete(0, tk.END)
ent3.delete(0, tk.END)
ent4.delete(0, tk.END)
# 테이블 업데이트
update_table()
# ent1로 프롬프트 이동
move_ent1()
# 삭제 함수 (Treeview와 DB 모두 삭제)
def delete_data():
selection = tree.selection()
# 선택된 항목이 없는 경우, 오류 표시 후 함수 종료
if not selection:
messagebox.showerror("Error", "삭제할 항목을 선택해주세요.")
return
# 선택된 모든 항목에 대해 반복하여 삭제
for item in selection: # for 문이 없으면 여러 개를 클릭해도 하나만 삭제됨
data = tree.item(item)['values']
row_id = data[0] # 첫 번째 값인 id를 가져옴
c.execute("DELETE FROM App_DB WHERE id=?", (row_id,)) # row_id에 해당하는 row 데이터 전체 삭제
conn.commit()
tree.delete(item)
# 테이블 갱신
update_table()
# 삭제 후 최상위 항목을 자동으로 선택
if len(tree.get_children()) > 0:
tree.selection_set(tree.get_children()[0])
tree.focus(tree.get_children()[0])
tree.see(tree.get_children()[0])
# 상태변경 : 신청접수
def running():
selection = tree.selection()
selection = selection[0]
data = tree.item(selection)['values']
row_id = data[0] # 첫 번째 값인 id를 가져옴
c.execute("UPDATE App_DB SET column1 = ? WHERE id = ?", ("신청접수", row_id))
conn.commit()
update_table()
messagebox.showinfo('상태','신청접수')
# 상태변경 : 작업완료
def finished(event=None):
selection = tree.selection()
selection = selection[0]
data = tree.item(selection)['values']
row_id = data[0] # 첫 번째 값인 id를 가져옴
c.execute("UPDATE App_DB SET column1 = ? WHERE id = ?", ("완료", row_id))
conn.commit()
update_table()
messagebox.showinfo('상태','작업완료')
# csv파일 내보내기
def csv_export():
# 파일 탐색기 창 열기
file_path = filedialog.asksaveasfilename(defaultextension='.csv')
# 선택한 파일 경로가 있을 경우
if file_path:
# DB에서 데이터 추출
df = pd.read_sql_query("SELECT * from App_DB", conn)
# CSV 파일로 저장
df.to_csv(file_path, index=False, encoding='utf-8-sig') # csv 파일을 utf-8로 저장
# 저장 완료 메시지 박스 출력
messagebox.showinfo("완료", "파일 저장이 완료되었습니다.")
# csv파일 불러오기
def csv_import():
# 파일 탐색기 창 열기
file_path = filedialog.askopenfilename(defaultextension='.csv')
# 선택한 파일 경로가 있을 경우
if file_path:
# CSV 파일에서 데이터 읽어오기
df = pd.read_csv(file_path)
# DB에 데이터 추가
for row in df.itertuples():
c.execute("INSERT INTO App_DB (column1, column2, column3, column4, column5) VALUES (?, ?, ?, ?, ?)",
('신청접수', row.column2, row.column3, row.column4, row.column5))
conn.commit()
# 트리뷰 업데이트
update_table()
# 불러오기 완료 메시지 박스 출력
messagebox.showinfo("완료", "파일 불러오기가 완료되었습니다.")
# 시프트 상/하 키로 범위 지정 :: 동작하는지 확인이 필요함
def on_tree_select(event):
# 범위 지정 확인
if event.state == 1:
# 이전 선택된 아이템과 현재 선택된 아이템의 인덱스 얻기
cur_item = tree.selection()[0]
prev_item = tree.focus()
# 이전 아이템과 현재 아이템의 인덱스를 비교하여 범위 지정
prev_index = tree.index(prev_item)
cur_index = tree.index(cur_item)
if prev_index < cur_index:
items = tree.get_children('', start=prev_index, end=cur_index)
else:
items = tree.get_children('', start=cur_index, end=prev_index)
# 범위 지정된 아이템들 하이라이트 표시
for item in items:
tree.selection_add(item)
else:
# 범위 지정이 아니면 현재 선택된 아이템만 하이라이트 표시
cur_item = tree.focus()
tree.selection_set(cur_item)
# 버튼 프레임 =====================================================================================================
btn_frame = tk.Frame(root)
btn_frame.pack(side='top', padx=30, pady=10, anchor='nw')
# 완료처리
finished_btn = tk.Button(btn_frame, width=10, text = '작업완료', command=finished, font=font)
finished_btn.grid(row=0, column=1, padx=20, pady=5)
# 신청접수
running_btn = tk.Button(btn_frame, width=10, text = '신청접수', command=running, font=font)
running_btn.grid(row=0, column=2, padx=20, pady=5)
# CSV 가져오기
save_button = tk.Button(btn_frame, width=10, text='가져오기', command=csv_import, font=font)
save_button.grid(row=0, column=3, padx=20, pady=5, sticky='e')
# CSV 내보내기
save_button = tk.Button(btn_frame, width=10, text='내보내기', command=csv_export, font=font)
save_button.grid(row=0, column=4, padx=20, pady=5, sticky='e')
# 텍스트 프레임 =====================================================================================================
text_frame = tk.Frame(root, padx=10, pady=10)
text_frame.pack(side=RIGHT)
# 단축키 설명
manual = tk.Label(text_frame,
text='| 새로고침 : F5 | 완료처리 : F8 |', font=font)
manual.pack(padx=20)
# 바인드 설정 =====================================================================================================
ent1.bind('<Return>', next_entry)
ent2.bind('<Return>', next_entry)
ent3.bind('<Return>', next_entry)
ent4.bind('<Return>', key_enter)
tree.bind('<Delete>', key_delete)
tree.bind('<Double-1>', on_double_click)
root.bind('<F5>', key_f5)
root.bind('<F8>', finished)
# 데이터 테이블 초기화
update_table()
# 프로그램 실행
root.mainloop()
# db 연결 종료
conn.close()
반응형
'python' 카테고리의 다른 글
PYTHON과 C++의 비교 (0) | 2023.03.02 |
---|---|
[파이썬] 전화번호 관리 프로그램 (0) | 2023.03.01 |
[파이썬] IP 변경 프로그램 (0) | 2023.02.24 |
[파이썬] 데스크탑 제품번호 정보 확인 (0) | 2023.02.09 |
[파이썬] 도메인과 사용자 계정 확인 (0) | 2023.02.08 |