참가자 중에서 랜덤으로 뽑는 프로그램 (python)
- 목차
반응형
https://github.com/woojangchang/tkinter_apps/tree/master/random_game
용도
한 달에 한 번 강제로 진행하는 모임이 있었고, 진행자는 참여자 중 누군가를 뽑아서 발표를 시켜야 했다. 그런데 진행할 때마다 "왠지" 같은 사람만 계속 발표하는 느낌이고 누군가는 단 한 번도 발표를 하지 않는 느낌이었다. 그래서 이런 프로그램이 있으면 좋겠다고 생각했다.
- 참가자 리스트를 미리 적어두면 그걸 자동으로 가져올 수 있도록
- 한 명씩 랜덤으로 뽑고, 뽑힌 사람은 리스트에서 제외
- 모두가 한 번씩 뽑혔다면 리셋
- 불참자는 리스트에서 아예 제외하여 리셋하여도 계속 제외되도록
- 이번 회의에만 별도로 참석한 경우 리스트에 추가
프로그램
랜덤 게임이라고 이름을 붙여보았다.
사용 방법
목록
- 프로그램과 같은 경로에 "명단.txt" 텍스트 파일 필요
- 텍스트 파일 내용은 줄로 구분
- 다른 명단을 가져오고 싶을 경우 메뉴의 [파일]-[열기]로 선택
- 가나다순으로 정렬
뽑기
- 목록에서 랜덤으로 뽑는다.
초기화
- 뽑힘에서 다시 목록으로 되돌린다.
- 제외된 목록은 그대로 둔다.
추가/제거
- 직접 선택하여 뽑힘으로 넣거나 목록으로 되돌린다.
임시추가
- 원래 명단에 없는 이름을 추가
- 초기화할 경우 사라짐
제외추가/목록추가
- 뽑기 명단에서 제외
전체 코드
import random
from tkinter import *
from tkinter import filedialog
import os
class RandomGame:
def __init__(self, filename='명단.txt'):
# GUI
self.root = Tk()
self.root.title("Random Game")
self.root.geometry("536x600")
self.root.minsize(width=300, height=463)
# root.resizable(False, False)
self.filename = filename
self.picked = []
self.absence = []
self.names = self.get_names()
self.set_icon()
self.set_menu()
self.set_frames()
self.update_listbox()
self.set_buttons()
self.root.config(menu=self.menu)
self.root.bind('<Configure>', self.resize)
self.root.mainloop()
def set_icon(self, filename='icon.ico'):
icon = os.path.join(os.path.dirname(__file__), filename)
if os.path.isfile(icon):
self.root.iconbitmap(icon)
self.root.iconbitmap(default = icon)
def get_names(self):
if os.path.exists(self.filename):
with open(self.filename, 'r', encoding='utf-8') as f:
names_org = f.readlines()
names_org = sorted(names_org)
return names_org
else:
return []
def set_menu(self):
self.menu = Menu(self.root)
self.menu_open = Menu(self.menu, tearoff=0)
self.menu_open.add_command(label='파일 열기', command=self.open_file)
self.menu_open.add_separator()
self.menu_open.add_command(label='끝내기', command=self.root.quit)
self.menu.add_cascade(label='파일', menu=self.menu_open)
def open_file(self):
file = filedialog.askopenfilename(
title='텍스트 파일을 선택하세요',
filetypes=(("텍스트 파일", "*.txt"),),
initialdir='.')
if (file is None) or (file == ''):
return
with open(file, 'r', encoding='utf8') as f:
names_org = f.readlines()
self.names_org = sorted(names_org)
self.names = names_org.copy()
self.absence = []
self.picked = []
self.update_listbox()
self.clear()
def set_frames(self):
self.frame_main = Frame(self.root)
self.frame_main.pack(side='top', fill='both', expand=True)
self.left = LabelFrame(self.frame_main, text='목록', height=25)
self.left.pack(side='left', fill='both', expand=True)
self.listbox = Listbox(self.left, selectmode='extended', height=25, font=('Malgun Gothic', 12))
self.listbox.pack(side='left', fill='both', expand=True)
self.scrollbar = Scrollbar(self.left, orient="vertical")
self.scrollbar.config(command=self.listbox.yview)
self.scrollbar.pack(side="right", fill="y")
self.listbox.config(yscrollcommand=self.scrollbar.set)
self.right = LabelFrame(self.frame_main, text='뽑힘', height=25)
self.right.pack(side='right', fill='both', expand=True)
self.lb_p = Listbox(self.right, selectmode='extended', height=25, font=('Malgun Gothic', 12))
self.lb_p.pack(side='left', fill='both', expand=True)
self.scrollbar2 = Scrollbar(self.right, orient="vertical")
self.scrollbar2.config(command=self.lb_p.yview)
self.scrollbar2.pack(side="right", fill="y")
self.lb_p.config(yscrollcommand=self.scrollbar2.set)
self.frame_option = Frame(self.root)
self.frame_option.pack(side='left', fill='both', expand=True)
self.lf_absence = LabelFrame(self.frame_option, text='제외', height=5)
self.lf_absence.grid(row=1, column=0, columnspan=2, sticky=NS)
self.lb_absence = Listbox(self.lf_absence, selectmode='extended', height=5, font=('Malgun Gothic', 12))
self.lb_absence.pack(side='left', fill='both', expand=True)
self.scrollbar3 = Scrollbar(self.lf_absence, orient="vertical")
self.scrollbar3.config(command=self.lb_absence.yview)
self.scrollbar3.pack(side="right", fill="y")
self.lb_absence.config(yscrollcommand=self.scrollbar3.set)
def update_listbox(self):
self.listbox.delete(0, END)
self.lb_p.delete(0, END)
self.lb_absence.delete(0, END)
for i, name in enumerate(self.names):
self.listbox.insert(i, name)
for i, name in enumerate(self.picked):
self.lb_p.insert(i, name)
for i, name in enumerate(self.absence):
self.lb_absence.insert(i, name)
def pick_name(self):
if len(self.names) == 0:
return
self.pick = random.choice(self.names)
self.names.remove(self.pick)
self.picked.append(self.pick)
self.update_listbox()
def pick_name_directly(self):
self.picked_names = self.listbox.curselection()
self.picked_names = [self.listbox.get(i) for i in self.picked_names]
for name in self.picked_names:
self.names.remove(name)
self.picked.append(name)
self.update_listbox()
def add_name_directly(self):
self.picked_names = self.lb_p.curselection()
self.picked_names = [self.lb_p.get(i) for i in self.picked_names]
for name in self.picked_names:
self.picked.remove(name)
self.names.append(name)
self.update_listbox()
def clear(self):
self.names = self.names_org.copy()
for name in self.absence:
if name in self.names:
self.names.remove(name)
else:
self.absence.remove(name)
self.picked = []
self.update_listbox()
def add_absence(self):
self.absence_names = self.listbox.curselection()
self.absence_names = [self.names[i] for i in self.absence_names]
for name in self.absence_names:
self.names.remove(name)
self.absence.append(name)
self.update_listbox()
def add_present(self):
self.present_names = self.lb_absence.curselection()
self.present_names = [self.lb_absence.get(i) for i in self.present_names]
for name in self.present_names:
self.names.append(name)
self.absence.remove(name)
self.update_listbox()
def set_buttons(self):
self.btn_pick = Button(self.frame_main, text='뽑기', command=self.pick_name, width=12, padx=5, pady=5, relief='groove', font=('Malgun Gothic', 14))
self.btn_pick.pack(side='top', padx=5, pady=5)
self.btn_clear = Button(self.frame_main, text='초기화', command=self.clear, width=12, padx=5, pady=5, relief='groove', font=('Malgun Gothic', 14))
self.btn_clear.pack(side='top', padx=5, pady=5)
self.btn_direct_add = Button(self.frame_main, text='▶ 추가', command=self.pick_name_directly, width=12, padx=5, pady=5, relief='groove', font=('Malgun Gothic', 14))
self.btn_direct_add.pack(side='top', padx=5, pady=5)
self.btn_direct_remove = Button(self.frame_main, text='◀ 제거', command=self.add_name_directly, width=12, padx=5, pady=5, relief='groove', font=('Malgun Gothic', 14))
self.btn_direct_remove.pack(side='top', padx=5, pady=5)
self.btn_absence = Button(self.frame_option, text='▼ 제외추가', command=self.add_absence, width=10, padx=5, pady=5, relief='ridge')
self.btn_absence.grid(row=0, column=0, pady=5)
self.btn_present = Button(self.frame_option, text='▲ 목록추가', command=self.add_present, width=10, padx=5, pady=5, relief='ridge')
self.btn_present.grid(row=0, column=1, pady=5)
self.entry_temporary = Entry(self.frame_main, font=('Malgun Gothic', 14), width=10, relief='solid')
self.entry_temporary.pack(side='bottom', padx=5, pady=5, fill='x')
self.btn_temporary = Button(self.frame_main, text='임시추가', command=self.temporary, width=12, padx=5, pady=5, relief='groove', font=('Malgun Gothic', 14))
self.btn_temporary.pack(side='bottom', padx=5, pady=5)
def temporary(self):
name = str(self.entry_temporary.get())
self.names.append(name)
self.entry_temporary.delete(0, END)
self.update_listbox()
def resize(self, event):
w = self.root.winfo_width()
h = self.root.winfo_height()
# print(left.winfo_width())
# 536-126:20 = w-116:x
x = int(round(20*(w-126)/(536-126), 0))
self.listbox.configure(width=x)
self.lb_p.configure(width=x)
# 730-157:25 = h-157:y
y = int(round(25*(h-200)/(730-157), 0))
# 730:5 = h:y2
y2 = int(h*6/730)-1
self.listbox.configure(height=y)
self.lb_p.configure(height=y)
self.lb_absence.configure(height=y2)
if 20 <= self.listbox.config()['width'][-1]:
self.lb_absence.configure(width=x)
else:
self.lb_absence.configure(width=20)
if __name__ == '__main__':
RandomGame()
728x90
반응형
'파이썬 Python > tkinter' 카테고리의 다른 글
이미지를 확인하면서 각 폴더로 분류하는 프로그램 (0) | 2024.02.11 |
---|---|
(DeepL용) python으로 개행 문자 처리해주기 (0) | 2024.01.30 |