def _find_item(menu: tkinter.Menu, label: str) -> Optional[int]: last_index = menu.index('end') if last_index is not None: # menu not empty for index in range(last_index + 1): if menu.type( index) in _MENU_ITEM_TYPES_WITH_LABEL and menu.entrycget( index, 'label') == label: return index return None
def _find_item(menu: tkinter.Menu, label: str) -> Optional[int]: last_index = menu.index("end") # type: ignore[no-untyped-call] if last_index is not None: # menu not empty for index in range(last_index + 1): if (menu.type(index) in _MENU_ITEM_TYPES_WITH_LABEL # type: ignore[no-untyped-call] and menu.entrycget(index, "label") == label # type: ignore[no-untyped-call] ): return index return None
class App(Tk): """ Main app. Put an icon in the system tray with a right click menu to create notes. """ def __init__(self): Tk.__init__(self) self.withdraw() self.notes = {} self.img = PhotoImage(file=cst.IM_ICON) self.icon = PhotoImage(master=self, file=cst.IM_ICON_48) self.iconphoto(True, self.icon) self.ewmh = ewmh.EWMH() style = Style(self) style.theme_use("clam") self.close1 = PhotoImage("img_close", file=cst.IM_CLOSE) self.close2 = PhotoImage("img_closeactive", file=cst.IM_CLOSE_ACTIVE) self.roll1 = PhotoImage("img_roll", file=cst.IM_ROLL) self.roll2 = PhotoImage("img_rollactive", file=cst.IM_ROLL_ACTIVE) self.protocol("WM_DELETE_WINDOW", self.quit) self.icon = tktray.Icon(self, docked=True) # --- Menu self.menu_notes = Menu(self.icon.menu, tearoff=False) self.hidden_notes = {cat: {} for cat in CONFIG.options("Categories")} self.menu_show_cat = Menu(self.icon.menu, tearoff=False) self.menu_hide_cat = Menu(self.icon.menu, tearoff=False) self.icon.configure(image=self.img) self.icon.menu.add_command(label=_("New Note"), command=self.new) self.icon.menu.add_separator() self.icon.menu.add_command(label=_('Show All'), command=self.show_all) self.icon.menu.add_cascade(label=_('Show Category'), menu=self.menu_show_cat) self.icon.menu.add_cascade(label=_('Show Note'), menu=self.menu_notes, state="disabled") self.icon.menu.add_separator() self.icon.menu.add_command(label=_('Hide All'), command=self.hide_all) self.icon.menu.add_cascade(label=_('Hide Category'), menu=self.menu_hide_cat) self.icon.menu.add_separator() self.icon.menu.add_command(label=_("Preferences"), command=self.config) self.icon.menu.add_command(label=_("Note Manager"), command=self.manage) self.icon.menu.add_separator() self.icon.menu.add_command(label=_("Backup Notes"), command=self.backup) self.icon.menu.add_command(label=_("Restore Backup"), command=self.restore) self.icon.menu.add_separator() self.icon.menu.add_command(label=_("Export"), command=self.export_notes) self.icon.menu.add_command(label=_("Import"), command=self.import_notes) self.icon.menu.add_separator() self.icon.menu.add_command(label=_('Check for Updates'), command=lambda: UpdateChecker(self)) self.icon.menu.add_command(label=_('About'), command=lambda: About(self)) self.icon.menu.add_command(label=_('Quit'), command=self.quit) # --- Restore notes self.note_data = {} if os.path.exists(PATH_DATA): with open(PATH_DATA, "rb") as fich: dp = pickle.Unpickler(fich) note_data = dp.load() for i, key in enumerate(note_data): self.note_data["%i" % i] = note_data[key] backup() for key in self.note_data: data = self.note_data[key] cat = data["category"] if not CONFIG.has_option("Categories", cat): CONFIG.set("Categories", cat, data["color"]) if data["visible"]: self.notes[key] = Sticky(self, key, **data) else: self.add_note_to_menu(key, data["title"], cat) self.nb = len(self.note_data) self.update_menu() self.update_notes() self.make_notes_sticky() # --- class bindings # newline depending on mode self.bind_class("Text", "<Return>", self.insert_newline) # char deletion taking into account list type self.bind_class("Text", "<BackSpace>", self.delete_char) # change Ctrl+A to select all instead of go to the beginning of the line self.bind_class('Text', '<Control-a>', self.select_all_text) self.bind_class('TEntry', '<Control-a>', self.select_all_entry) # bind Ctrl+Y to redo self.bind_class('Text', '<Control-y>', self.redo_event) # unbind Ctrl+I and Ctrl+B self.bind_class('Text', '<Control-i>', lambda e: None) self.bind_class('Text', '<Control-b>', lambda e: None) # highlight checkboxes when inside text selection self.bind_class("Text", "<ButtonPress-1>", self.highlight_checkboxes, True) self.bind_class("Text", "<ButtonRelease-1>", self.highlight_checkboxes, True) self.bind_class("Text", "<B1-Motion>", self.highlight_checkboxes, True) evs = [ '<<SelectAll>>', '<<SelectLineEnd>>', '<<SelectLineStart>>', '<<SelectNextChar>>', '<<SelectNextLine>>', '<<SelectNextPara>>', '<<SelectNextWord>>', '<<SelectNone>>', '<<SelectPrevChar>>', '<<SelectPrevLine>>', '<<SelectPrevPara>>', '<<SelectPrevWord>>' ] for ev in evs: self.bind_class("Text", ev, self.highlight_checkboxes, True) # check for updates if CONFIG.getboolean("General", "check_update"): UpdateChecker(self) # --- class bindings methods def highlight_checkboxes(self, event): txt = event.widget try: deb = cst.sorting(txt.index("sel.first")) fin = cst.sorting(txt.index("sel.last")) for ch in txt.children.values(): try: i = cst.sorting(txt.index(ch)) if i >= deb and i <= fin: ch.configure(style="sel.TCheckbutton") else: ch.configure(style=txt.master.id + ".TCheckbutton") except TclError: pass except TclError: for ch in txt.children.values(): try: i = cst.sorting(txt.index(ch)) ch.configure(style=txt.master.id + ".TCheckbutton") except TclError: pass def redo_event(self, event): try: event.widget.edit_redo() except TclError: # nothing to redo pass def select_all_entry(self, event): event.widget.selection_range(0, "end") def select_all_text(self, event): event.widget.tag_add("sel", "1.0", "end-1c") self.highlight_checkboxes(event) def delete_char(self, event): txt = event.widget deb_line = txt.get("insert linestart", "insert") tags = txt.tag_names("insert") if txt.tag_ranges("sel"): if txt.tag_nextrange("enum", "sel.first", "sel.last"): update = True else: update = False txt.delete("sel.first", "sel.last") if update: txt.master.update_enum() elif txt.index("insert") != "1.0": if re.match('^\t[0-9]+\.\t$', deb_line) and 'enum' in tags: txt.delete("insert linestart", "insert") txt.insert("insert", "\t\t") txt.master.update_enum() elif deb_line == "\t•\t" and 'list' in tags: txt.delete("insert linestart", "insert") txt.insert("insert", "\t\t") elif deb_line == "\t\t": txt.delete("insert linestart", "insert") elif "todolist" in tags and txt.index("insert") == txt.index( "insert linestart+1c"): try: ch = txt.window_cget("insert-1c", "window") txt.delete("insert-1c") txt.children[ch.split('.')[-1]].destroy() txt.insert("insert", "\t\t") except TclError: txt.delete("insert-1c") else: txt.delete("insert-1c") def insert_newline(self, event): mode = event.widget.master.mode.get() if mode == "list": event.widget.insert("insert", "\n\t•\t") event.widget.tag_add("list", "1.0", "end") elif mode == "todolist": event.widget.insert("insert", "\n") ch = Checkbutton(event.widget, takefocus=False, style=event.widget.master.id + ".TCheckbutton") event.widget.window_create("insert", window=ch) event.widget.tag_add("todolist", "1.0", "end") elif mode == "enum": event.widget.configure(autoseparators=False) event.widget.edit_separator() event.widget.insert("insert", "\n\t0.\t") event.widget.master.update_enum() event.widget.edit_separator() event.widget.configure(autoseparators=True) else: event.widget.insert("insert", "\n") def make_notes_sticky(self): for w in self.ewmh.getClientList(): if w.get_wm_name()[:7] == 'mynotes': self.ewmh.setWmState(w, 1, '_NET_WM_STATE_STICKY') self.ewmh.display.flush() def add_note_to_menu(self, nb, note_title, category): """add note to 'show notes' menu. """ try: name = self.menu_notes.entrycget(category.capitalize(), 'menu') if not isinstance(name, str): name = str(name) menu = self.menu_notes.children[name.split('.')[-1]] end = menu.index("end") if end is not None: # le menu n'est pas vide titles = self.hidden_notes[category].values() titles = [t for t in titles if t.split(" ~#")[0] == note_title] if titles: title = "%s ~#%i" % (note_title, len(titles) + 1) else: title = note_title else: title = note_title except TclError: # cat is not in the menu menu = Menu(self.menu_notes, tearoff=False) self.menu_notes.add_cascade(label=category.capitalize(), menu=menu) title = note_title menu.add_command(label=title, command=lambda: self.show_note(nb)) self.icon.menu.entryconfigure(4, state="normal") self.hidden_notes[category][nb] = title def backup(self): """Create a backup at the location indicated by user.""" initialdir, initialfile = os.path.split(PATH_DATA_BACKUP % 0) fichier = asksaveasfilename(defaultextension=".backup", filetypes=[], initialdir=initialdir, initialfile="notes.backup0", title=_('Backup Notes')) if fichier: try: with open(fichier, "wb") as fich: dp = pickle.Pickler(fich) dp.dump(self.note_data) except Exception as e: report_msg = e.strerror != 'Permission denied' showerror(_("Error"), _("Backup failed."), traceback.format_exc(), report_msg) def restore(self, fichier=None, confirmation=True): """Restore notes from backup.""" if confirmation: rep = askokcancel( _("Warning"), _("Restoring a backup will erase the current notes."), icon="warning") else: rep = True if rep: if fichier is None: fichier = askopenfilename(defaultextension=".backup", filetypes=[], initialdir=LOCAL_PATH, initialfile="", title=_('Restore Backup')) if fichier: try: keys = list(self.note_data.keys()) for key in keys: self.delete_note(key) if not os.path.samefile(fichier, PATH_DATA): copy(fichier, PATH_DATA) with open(PATH_DATA, "rb") as myfich: dp = pickle.Unpickler(myfich) note_data = dp.load() for i, key in enumerate(note_data): data = note_data[key] note_id = "%i" % i self.note_data[note_id] = data cat = data["category"] if not CONFIG.has_option("Categories", cat): CONFIG.set("Categories", cat, data["color"]) if data["visible"]: self.notes[note_id] = Sticky(self, note_id, **data) self.nb = len(self.note_data) self.update_menu() self.update_notes() except FileNotFoundError: showerror( _("Error"), _("The file {filename} does not exists.").format( filename=fichier)) except Exception as e: showerror(_("Error"), str(e), traceback.format_exc(), True) def show_all(self): """Show all notes.""" for cat in self.hidden_notes.keys(): keys = list(self.hidden_notes[cat].keys()) for key in keys: self.show_note(key) def show_cat(self, category): """Show all notes belonging to category.""" keys = list(self.hidden_notes[category].keys()) for key in keys: self.show_note(key) def hide_all(self): """Hide all notes.""" keys = list(self.notes.keys()) for key in keys: self.notes[key].hide() def hide_cat(self, category): """Hide all notes belonging to category.""" keys = list(self.notes.keys()) for key in keys: if self.note_data[key]["category"] == category: self.notes[key].hide() def manage(self): """Launch note manager.""" Manager(self) def config(self): """Launch the setting manager.""" conf = Config(self) self.wait_window(conf) col_changes, name_changes = conf.get_changes() if col_changes or name_changes: self.update_notes(col_changes, name_changes) self.update_menu() alpha = CONFIG.getint("General", "opacity") / 100 for note in self.notes.values(): note.attributes("-alpha", alpha) note.update_title_font() note.update_text_font() note.update_titlebar() def delete_cat(self, category): """Delete all notes belonging to category.""" keys = list(self.notes.keys()) for key in keys: if self.note_data[key]["category"] == category: self.notes[key].delete(confirmation=False) def delete_note(self, nb): if self.note_data[nb]["visible"]: self.notes[nb].delete(confirmation=False) else: cat = self.note_data[nb]["category"] name = self.menu_notes.entrycget(cat.capitalize(), 'menu') if not isinstance(name, str): name = str(name) menu = self.menu_notes.children[name.split('.')[-1]] index = menu.index(self.hidden_notes[cat][nb]) menu.delete(index) if menu.index("end") is None: # the menu is empty self.menu_notes.delete(cat.capitalize()) if self.menu_notes.index('end') is None: self.icon.menu.entryconfigure(4, state="disabled") del (self.hidden_notes[cat][nb]) del (self.note_data[nb]) self.save() def show_note(self, nb): """Display the note corresponding to the 'nb' key in self.note_data.""" self.note_data[nb]["visible"] = True cat = self.note_data[nb]["category"] name = self.menu_notes.entrycget(cat.capitalize(), 'menu') if not isinstance(name, str): name = str(name) menu = self.menu_notes.children[name.split('.')[-1]] index = menu.index(self.hidden_notes[cat][nb]) del (self.hidden_notes[cat][nb]) self.notes[nb] = Sticky(self, nb, **self.note_data[nb]) menu.delete(index) if menu.index("end") is None: # the menu is empty self.menu_notes.delete(cat.capitalize()) if self.menu_notes.index('end') is None: self.icon.menu.entryconfigure(4, state="disabled") self.make_notes_sticky() def update_notes(self, col_changes={}, name_changes={}): """Update the notes after changes in the categories.""" categories = CONFIG.options("Categories") categories.sort() self.menu_notes.delete(0, "end") self.hidden_notes = {cat: {} for cat in categories} for key in self.note_data: cat = self.note_data[key]["category"] if cat in name_changes: cat = name_changes[cat] self.note_data[key]["category"] = cat if self.note_data[key]["visible"]: self.notes[key].change_category(cat) elif cat not in categories: default = CONFIG.get("General", "default_category") default_color = CONFIG.get("Categories", default) if self.note_data[key]["visible"]: self.notes[key].change_category(default) self.note_data[key]["category"] = default self.note_data[key]["color"] = default_color cat = default if cat in col_changes: old_color, new_color = col_changes[cat] if self.note_data[key]["color"] == old_color: self.note_data[key]["color"] = new_color if self.note_data[key]["visible"]: self.notes[key].change_color(cst.INV_COLORS[new_color]) if not self.note_data[key]['visible']: self.add_note_to_menu(key, self.note_data[key]["title"], self.note_data[key]['category']) else: self.notes[key].update_menu_cat(categories) self.save() if self.menu_notes.index("end") is not None: self.icon.menu.entryconfigure(4, state="normal") else: self.icon.menu.entryconfigure(4, state="disabled") def update_menu(self): """Populate self.menu_show_cat and self.menu_hide_cat with the categories.""" self.menu_hide_cat.delete(0, "end") self.menu_show_cat.delete(0, "end") categories = CONFIG.options("Categories") categories.sort() for cat in categories: self.menu_show_cat.add_command( label=cat.capitalize(), command=lambda c=cat: self.show_cat(c)) self.menu_hide_cat.add_command( label=cat.capitalize(), command=lambda c=cat: self.hide_cat(c)) def save(self): """Save the data.""" with open(PATH_DATA, "wb") as fich: dp = pickle.Pickler(fich) dp.dump(self.note_data) def new(self): """Create a new note.""" key = "%i" % self.nb self.notes[key] = Sticky(self, key) data = self.notes[key].save_info() data["visible"] = True self.note_data[key] = data self.nb += 1 self.make_notes_sticky() def export_notes(self): export = Export(self) self.wait_window(export) categories_to_export, only_visible = export.get_export() if categories_to_export: initialdir, initialfile = os.path.split(PATH_DATA_BACKUP % 0) fichier = asksaveasfilename(defaultextension=".html", filetypes=[ (_("HTML file (.html)"), "*.html"), (_("Text file (.txt)"), "*.txt"), (_("All files"), "*") ], initialdir=initialdir, initialfile="", title=_('Export Notes As')) if fichier: try: if os.path.splitext(fichier)[-1] == ".html": # --- html export cats = {cat: [] for cat in categories_to_export} for key in self.note_data: cat = self.note_data[key]["category"] if cat in cats and ( (not only_visible) or self.note_data[key]["visible"]): cats[cat].append( (self.note_data[key]["title"], cst.note_to_html(self.note_data[key], self))) text = "" for cat in cats: cat_txt = "<h1 style='text-align:center'>" + _( "Category: {category}").format( category=cat) + "<h1/>\n" text += cat_txt text += "<br>" for title, txt in cats[cat]: text += "<h2 style='text-align:center'>%s</h2>\n" % title text += txt text += "<br>\n" text += "<hr />" text += "<br>\n" text += '<hr style="height: 8px;background-color:grey" />' text += "<br>\n" with open(fichier, "w") as fich: fich.write('<body style="max-width:30em">\n') fich.write( text.encode( 'ascii', 'xmlcharrefreplace').decode("utf-8")) fich.write("\n</body>") # if os.path.splitext(fichier)[-1] == ".txt": else: # --- txt export # export notes to .txt: all formatting is lost cats = {cat: [] for cat in categories_to_export} for key in self.note_data: cat = self.note_data[key]["category"] if cat in cats and ( (not only_visible) or self.note_data[key]["visible"]): cats[cat].append( (self.note_data[key]["title"], cst.note_to_txt(self.note_data[key]))) text = "" for cat in cats: cat_txt = _("Category: {category}").format( category=cat) + "\n" text += cat_txt text += "=" * len(cat_txt) text += "\n\n" for title, txt in cats[cat]: text += title text += "\n" text += "-" * len(title) text += "\n\n" text += txt text += "\n\n" text += "-" * 30 text += "\n\n" text += "#" * 30 text += "\n\n" with open(fichier, "w") as fich: fich.write(text) # else: # # --- pickle export # note_data = {} # for key in self.note_data: # if self.note_data[key]["category"] in categories_to_export: # if (not only_visible) or self.note_data[key]["visible"]: # note_data[key] = self.note_data[key] # # with open(fichier, "wb") as fich: # dp = pickle.Pickler(fich) # dp.dump(note_data) except Exception as e: report_msg = e.strerror != 'Permission denied' showerror(_("Error"), str(e), traceback.format_exc(), report_msg) def import_notes(self): fichier = askopenfilename(defaultextension=".backup", filetypes=[(_("Notes (.notes)"), "*.notes"), (_("All files"), "*")], initialdir=LOCAL_PATH, initialfile="", title=_('Import')) if fichier: try: with open(fichier, "rb") as fich: dp = pickle.Unpickler(fich) note_data = dp.load() for i, key in enumerate(note_data): data = note_data[key] note_id = "%i" % (i + self.nb) self.note_data[note_id] = data cat = data["category"] if not CONFIG.has_option("Categories", cat): CONFIG.set("Categories", cat, data["color"]) self.hidden_notes[cat] = {} if data["visible"]: self.notes[note_id] = Sticky(self, note_id, **data) self.nb = int(max(self.note_data.keys(), key=lambda x: int(x))) + 1 self.update_menu() self.update_notes() except Exception: message = _("The file {file} is not a valid .notes file." ).format(file=fichier) showerror(_("Error"), message, traceback.format_exc()) def cleanup(self): """Remove unused latex images.""" img_stored = os.listdir(cst.PATH_LATEX) img_used = [] for data in self.note_data.values(): img_used.extend(list(data.get("latex", {}).keys())) for img in img_stored: if img not in img_used: os.remove(os.path.join(cst.PATH_LATEX, img)) def quit(self): self.destroy()
class Fenetre: def __init__(self, root, job): # Récupération de l'objet Jeu self.jeu = job self.saved = True # Création de la fenêtre principale self.root = root self.root.title('Rêve de Dragon') self.root.resizable(True, True) # Création des menus # On a 4 menu principaux : filemenu, cmdmenu, viewmenu et helpmenu self.menubar = Menu(root) self.root.config(menu=self.menubar) # filemenu: menu de manipulation des fichiers contenant les personnages self.filemenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Fichier", menu=self.filemenu) self.filemenu.add_command(label="Nouveau", command=self.nouveau) self.filemenu.add_command(label="Ouvrir", command=self.ouvrir) self.filemenu.add_separator() self.filemenu.add_command(label="Enregistrer", command=self.jeu.enregistrer) self.filemenu.add_command(label="Enregistrer sous...", command=self.jeu.enregistrer_sous) self.filemenu.add_separator() self.filemenu.add_command(label="Fermer", command=self.fermer) self.filemenu.add_separator() self.filemenu.add_command(label="Imprimer", command=self.void, state='disabled') self.filemenu.add_separator() self.filemenu.add_command(label="Quitter", command=self.quitter) # cmdmenu: menu des commandes sur les personnages self.cmdmenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Commande", menu=self.cmdmenu) self.cmdmenu.add_command(label="Nouvelle Partie", command=self.partie) self.cmdmenu.add_separator() self.cmdmenu.add_command(label="Nouveau Personnage", command=self.creer) self.cmdmenu.add_separator() self.cmdmenu.add_command(label="Valider le Personnage", command=self.valider) # viewmenu: menu de sélection du personnage à l'affichage # Ce menu est vide en l'absence de personnage # Il est rempli au chargement ou à la création d'un personnage self.viewmenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Personnage", menu=self.viewmenu) # helpmenu: menu d'aide self.helpmenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Aide", menu=self.helpmenu) self.helpmenu.add_command(label="Règles du Jeu", command=self.regles) self.helpmenu.add_command(label="Utilisation du Programme", command=self.utilise) self.helpmenu.add_command(label="A Propos...", command=self.a_propos) # frame1 : Fiche du personnage frame1 = Frame(root, borderwidth=0, relief='flat', height=200, width=600) frame1.grid(row=0, column=0, sticky='NW', padx="10", pady="5") # Nom self.Entry_Nom = StringVar() self.Old_Nom = "" Label(frame1, text='Nom:').grid(row=0, column=0, columnspan=2, sticky='E') Entry(frame1, textvariable=self.Entry_Nom, justify='left', width=34)\ .grid(row=0, column=2, columnspan=4, sticky='W', padx="5") # Age self.Entry_Age = IntVar() Label(frame1, text='Age:').grid(row=1, column=0, columnspan=2, sticky='E') Entry(frame1, textvariable=self.Entry_Age, justify='right', width=3)\ .grid(row=1, column=2, sticky='W', padx="5") # Heure de naissance (pour hauts-rêvants) self.Entry_Heure = IntVar() Label(frame1, text='Heure de Naissance:').grid(row=1, column=3, sticky='E') Entry(frame1, textvariable=self.Entry_Heure, justify='right', width=3) \ .grid(row=1, column=4, sticky='W', padx="5") # Taille self.Entry_Taille = IntVar() Label(frame1, text='Taille:').grid(row=1, column=5, sticky='E') Entry(frame1, textvariable=self.Entry_Taille, justify='right', width=3)\ .grid(row=1, column=6, sticky='W', padx="5") # Poids self.Entry_Poids = IntVar() Label(frame1, text='Poids:').grid(row=1, column=7, sticky='E') Entry(frame1, textvariable=self.Entry_Poids, justify='right', width=3)\ .grid(row=1, column=8, sticky='W', padx="5") # Beauté self.Entry_Beaute = IntVar() Label(frame1, text='Beauté:').grid(row=2, column=0, columnspan=2, sticky='E') Entry(frame1, textvariable=self.Entry_Beaute, justify='right', width=3) \ .grid(row=2, column=2, sticky='W', padx="5") # Cheveux self.Entry_Cheveux = StringVar() Label(frame1, text='Cheveux:').grid(row=2, column=3, sticky='E') Entry(frame1, textvariable=self.Entry_Cheveux, justify='left', width=8)\ .grid(row=2, column=4, sticky='W', padx="5") # Yeux self.Entry_Yeux = StringVar() Label(frame1, text='Yeux:').grid(row=2, column=5, sticky='E') Entry(frame1, textvariable=self.Entry_Yeux, justify='left', width=8)\ .grid(row=2, column=6, sticky='W', padx="5") # Haut rêvant self.Entry_HRevant = IntVar() Checkbutton(frame1, text="Haut-Rêvant", variable=self.Entry_HRevant, command=self.sel_revant) \ .grid(row=2, column=7, columnspan=2, sticky='W', padx="5") # Sexe self.Entry_Sexe = StringVar() Label(frame1, text='Sexe:').grid(row=3, column=0, columnspan=2, sticky='E') Entry(frame1, textvariable=self.Entry_Sexe, justify='left', width=2)\ .grid(row=3, column=2, sticky='W', padx="5") # Ambidextre self.Entry_Ambidextre = IntVar() Label(frame1, text='Ambidextre:').grid(row=3, column=3, sticky='E') Entry(frame1, textvariable=self.Entry_Ambidextre, justify='right', width=3)\ .grid(row=3, column=4, sticky='W', padx="5") # Signes Particuliers self.Entry_SignesP = StringVar() Label(frame1, text='Signes Particuliers:').grid(row=3, column=5, sticky='E') Entry(frame1, textvariable=self.Entry_SignesP, justify='left', width=37)\ .grid(row=3, column=6, columnspan=3, sticky='W', padx="5") # Frame 2 : Caractéristiques frame2 = LabelFrame(root, text=" Caractéristiques ", borderwidth=2, relief='ridge', height=200, width=600) frame2.grid(row=1, column=0, sticky='NW', padx="10", pady="5") frame20 = LabelFrame(frame2, text=' Physiques ', borderwidth=2, relief='ridge', height=200, width=200) frame20.grid(row=0, column=0, sticky='NW', padx="5", pady="5") frame21 = LabelFrame(frame2, text=' Mentales ', borderwidth=2, relief='ridge', height=200, width=200) frame21.grid(row=0, column=1, sticky='NW', padx="5", pady="5") frame22 = LabelFrame(frame2, text=' Pouvoirs ', borderwidth=2, relief='ridge', height=200, width=200) frame22.grid(row=0, column=2, sticky='NW', padx="5", pady="5") frame23 = LabelFrame(frame2, text=' Dérivées ', borderwidth=2, relief='ridge', height=200, width=200) frame23.grid(row=0, column=3, sticky='NW', padx="5", pady="5") self.Entry_C = [] # Colonne 0 de taille à Dextérité for i in range(0, 6): self.Entry_C.append(IntVar()) Label(frame20, text=" "+personnage.caracteristique(i, 1)+':')\ .grid(row=i, column=0, sticky='E') Entry(frame20, textvariable=self.Entry_C[i], justify='right', width=3)\ .grid(row=i, column=1, sticky='W', padx="5") Label(frame20, text=' ').grid(row=6, column=0, sticky='E') # Colonne 1 de Vue à Empathie for i in range(6, 12): self.Entry_C.append(IntVar()) Label(frame21, text=" "+personnage.caracteristique(i, 1) + ':')\ .grid(row=i-6, column=0, sticky='E') Entry(frame21, textvariable=self.Entry_C[i], justify='right', width=3)\ .grid(row=i-6, column=1, sticky='W', padx="5") Label(frame21, text=' ').grid(row=6, column=0, sticky='E') # Colonne 2 de Rêve à Chance for i in range(12, 14): self.Entry_C.append(IntVar()) Label(frame22, text=" "+personnage.caracteristique(i, 1) + ':')\ .grid(row=i-12, column=0, sticky='E') Entry(frame22, textvariable=self.Entry_C[i], justify='right', width=3)\ .grid(row=i-12, column=1, sticky='W', padx="5") for i in range(2, 7): Label(frame22, text=' ').grid(row=i, column=0, sticky='E') # Colonne 3 de Tir à Dérobée (ne peuvent être saisies) for i in range(14, 18): self.Entry_C.append(IntVar()) Label(frame23, text=" "+personnage.caracteristique(i, 1) + ':')\ .grid(row=i-14, column=0, sticky='E') Entry(frame23, textvariable=self.Entry_C[i], justify='right', width=3, state='disabled')\ .grid(row=i-14, column=1, sticky='W', padx="5") for i in range(4, 7): Label(frame23, text=' ').grid(row=i, column=0, sticky='E') # frame 3 : Points et Seuils (ne peuvent être saisis) frame3 = Frame(root, borderwidth=0, relief='flat', height=200, width=600, padx="5", pady="5") frame3.grid(row=2, column=0, sticky='NW', padx="10") self.Entry_P = [] # Vie - Endurance - Encombrement for i in range(0, 3): self.Entry_P.append(IntVar()) Label(frame3, text=personnage.point(i, 1) + ':').grid(row=0, column=2 * i, sticky='E') Entry(frame3, textvariable=self.Entry_P[i], justify='right', width=3, state='disabled')\ .grid(row=0, column=2*i+1, sticky='W', padx="5") # Bonus aux Dommages - Malus Armure - Seuil de Constitution - Seuil de Sustentation for i in range(3, 7): self.Entry_P.append(IntVar()) Label(frame3, text=personnage.point(i, 1) + ':').grid(row=1, column=2 * i - 6, sticky='E') Entry(frame3, textvariable=self.Entry_P[i], justify='right', width=3, state='disabled')\ .grid(row=1, column=2*i-5, sticky='W', padx="5") # frame 4 : Compétences frame4 = LabelFrame(root, text=" Compétences ", borderwidth=2, relief='ridge', height=200, width=800) frame4.grid(row=3, column=0, columnspan=2, sticky='NW', padx="10", pady="5") frame40 = LabelFrame(frame4, text=' Générales ', borderwidth=2, relief='ridge', height=200, width=300) frame40.grid(row=0, column=0, rowspan=2, sticky='NW', padx="5", pady="5") frame41 = LabelFrame(frame4, text=' Particulières ', borderwidth=2, relief='ridge', height=200, width=300) frame41.grid(row=0, column=1, rowspan=2, sticky='NW', padx="5", pady="5") frame42 = LabelFrame(frame4, text=' Spécialisées ', borderwidth=2, relief='ridge', height=200, width=300) frame42.grid(row=0, column=2, rowspan=2, sticky='NW', padx="5", pady="5") frame43 = LabelFrame(frame4, text=' Connaissances ', borderwidth=2, relief='ridge', height=200, width=300) frame43.grid(row=0, column=3, sticky='NW', padx="5", pady="5") frame44 = LabelFrame(frame4, text=' Draconic ', borderwidth=2, relief='ridge', height=200, width=300) frame44.grid(row=1, column=3, sticky='SW', padx="5", pady="5") frame45 = LabelFrame(frame4, text=' Combat Mélée ', borderwidth=2, relief='ridge', height=200, width=300) frame45.grid(row=0, column=4, rowspan=2, sticky='NW', padx="5", pady="5") frame46 = LabelFrame(frame4, text=' Combat Tir-Lancer ', borderwidth=2, relief='ridge', height=200, width=300) frame46.grid(row=0, column=5, rowspan=2, sticky='NW', padx="5", pady="5") self.Entry_A = [] # Colonne 0 : Générales for i in range(0, 11): self.Entry_A.append(IntVar()) Label(frame40, text=" " + personnage.competence(i, 2) + ':').grid( row=i, column=0, sticky='E') Entry(frame40, textvariable=self.Entry_A[i], justify='right', width=3)\ .grid(row=i, column=1, sticky='W', padx="5") for i in range(11, 15): Label(frame40, text=' ').grid(row=i, column=0, sticky='E') # Colonne 1 : Particulières for i in range(11, 26): self.Entry_A.append(IntVar()) Label(frame41, text=" " + personnage.competence(i, 2) + ':').grid(row=i - 11, column=0, sticky='E') Entry(frame41, textvariable=self.Entry_A[i], justify='right', width=3)\ .grid(row=i-11, column=1, sticky='W', padx="5") # Colonne 2 : Spécialisées for i in range(26, 36): self.Entry_A.append(IntVar()) Label(frame42, text=" "+personnage.competence(i, 2)+':')\ .grid(row=i-25, column=0, sticky='E') Entry(frame42, textvariable=self.Entry_A[i], justify='right', width=3)\ .grid(row=i-25, column=1, sticky='W', padx="5") for i in range(10, 15): Label(frame42, text=' ').grid(row=i + 1, column=0, sticky='E') # Colonne 3: Connaissances for i in range(36, 43): self.Entry_A.append(IntVar()) Label(frame43, text=" "+personnage.competence(i, 2)+':')\ .grid(row=i-35, column=0, sticky='E') Entry(frame43, textvariable=self.Entry_A[i], justify='right', width=3)\ .grid(row=i-35, column=1, sticky='W', padx="5") Label(frame43, text=' ').grid(row=8, column=0, sticky='E') # Colonne 3 : Draconic self.Draconic = [] for i in range(0, 4): self.Entry_A.append(IntVar()) Label(frame44, text=" "+personnage.competence(i+43, 2)+':')\ .grid(row=i, column=0, sticky='E') self.Draconic.append( Entry(frame44, textvariable=self.Entry_A[i + 43], justify='right', width=3)) self.Draconic[i].grid(row=i, column=1, sticky='W', padx="5") Label(frame44, text=' ').grid(row=4, column=0, sticky='E') # Colonne 4 : Combat Mélée for i in range(47, 60): self.Entry_A.append(IntVar()) Label(frame45, text=personnage.competence(i, 2) + ':') \ .grid(row=i - 46, column=0, sticky='E') Entry(frame45, textvariable=self.Entry_A[i], justify='right', width=3) \ .grid(row=i - 46, column=1, sticky='W', padx="5") for i in range(13, 15): Label(frame45, text=' ').grid(row=i + 1, column=0, sticky='E') # Colonne 5 : Combat Tir for i in range(60, 66): self.Entry_A.append(IntVar()) Label(frame46, text=" " + personnage.competence(i, 2) + ':') \ .grid(row=i - 59, column=0, sticky='E') Entry(frame46, textvariable=self.Entry_A[i], justify='right', width=3) \ .grid(row=i - 59, column=1, sticky='W', padx="5") for i in range(6, 15): Label(frame46, text=' ').grid(row=i + 1, column=0, sticky='E') # frame5 : table de résolution et lancer de dé frame5 = LabelFrame(root, text=" Résolution et Lancer de Dés ", borderwidth=2, relief='ridge', height=200, width=600) frame5.grid(row=0, column=1, rowspan=3, columnspan=2, sticky='NW', padx="10", pady="5") # Listbox caractéristiques Label(frame5, text=' Caractéristique:').grid(row=0, column=0, columnspan=2, padx="10", sticky='NW') self.liste1 = Listbox(frame5, height=13, width=18, relief='sunken') self.liste1.grid(row=1, column=1, sticky='NW', pady="5") for i in range(0, 18): self.liste1.insert(i, personnage.caracteristique(i, 1)) self.liste1.bind('<<ListboxSelect>>', self.sel_liste1) # Listbox compétences Label(frame5, text='Compétence:').grid(row=0, column=2, columnspan=2, padx="10", sticky='NW') self.liste2 = Listbox(frame5, height=13, width=18, relief='sunken') self.liste2.grid(row=1, column=3, sticky='NW', pady="5") for i in range(0, 66): self.liste2.insert(i, personnage.competence(i, 2)) self.liste2.bind('<<ListboxSelect>>', self.sel_liste2) # Zone de résulats self.Entry_R_C_Val = IntVar() Entry(frame5, textvariable=self.Entry_R_C_Val, justify='right', width=3,) \ .grid(row=16, column=0, sticky='E', padx="10") self.Entry_R_C_Name = StringVar() Entry(frame5, textvariable=self.Entry_R_C_Name, justify='left', width=18, state='disabled') \ .grid(row=16, column=1, sticky='W') self.Entry_R_A_Val = IntVar() Entry(frame5, textvariable=self.Entry_R_A_Val, justify='right', width=3,) \ .grid(row=16, column=2, sticky='E', padx="10") self.Entry_R_A_Name = StringVar() Entry(frame5, textvariable=self.Entry_R_A_Name, justify='left', width=18, state='disabled') \ .grid(row=16, column=3, sticky='W') Label(frame5, text=' Seuil de Réussite:').grid(row=17, column=0, sticky='NE') self.Entry_R_Seuil = IntVar() Entry(frame5, textvariable=self.Entry_R_Seuil, justify='right', width=3, state='disabled')\ .grid(row=17, column=1, sticky='W', padx="10") Label(frame5, text='Tirage:').grid(row=17, column=2, sticky='NE') self.Entry_R_Tirage = IntVar() Entry(frame5, textvariable=self.Entry_R_Tirage, justify='right', width=3, state='disabled') \ .grid(row=17, column=3, sticky='W', padx="10") Label(frame5, text='Résultat Spécial:').grid(row=18, column=0, sticky='NE') self.Entry_R_Special = StringVar() Entry(frame5, textvariable=self.Entry_R_Special, justify='left', width=30, state='disabled') \ .grid(row=18, column=1, columnspan=2, sticky='W', padx="10") Label(frame5, text=' ').grid(row=19, column=4, sticky='NE') # Bouton pour le lancer de Dés Button(frame5, text="Lancer les Dés", command=self.lancer) \ .grid(row=18, column=3, columnspan=3, sticky='W', padx="10") # La mascote # On la fait déborder sur le frame4 pour gagner en largeur totale self.dragon = PhotoImage(file='./dragon3.gif') logo = Canvas(root, width=200, height=181, bd=1, relief='ridge') logo.grid(row=3, column=1, columnspan=2, sticky='SE', padx="10", pady="3") logo.create_image(0, 0, image=self.dragon, anchor='nw') # L'ecran étant initialisé, on peut créér un premier personnage par défaut self.creer() return # Fonction de recopie de la sélection depuis la Listbox des caractéristiques # Met à jour les 2 champs points et nom de caractéristique pour le calcul de résolution def sel_liste1(self, event): if self.liste1.curselection() != (): index = self.liste1.curselection()[0] self.Entry_R_C_Name.set(self.liste1.get(index)) self.Entry_R_C_Val.set(self.Entry_C[index].get()) return # Fonction de recopie de la sélection depuis la Listbox des compétences # Met à jour les 2 champs points et nom de compétence pour le calcul de résolution def sel_liste2(self, event): if self.liste2.curselection() != (): index = self.liste2.curselection()[0] self.Entry_R_A_Name.set(self.liste2.get(index)) self.Entry_R_A_Val.set(self.Entry_A[index].get()) return # Fonction de changement d'etat haut-rêvant def sel_revant(self): if self.Entry_HRevant.get() != 1: for i in range(0, 4): self.Entry_A[i + 42].set(-11) self.Draconic[i].configure(state='disabled') else: for i in range(0, 4): self.Draconic[i].configure(state='normal') return # Nouveau jeu # Il faut préalablement fermer le jeu en cours def nouveau(self): if self.fermer(): self.jeu.nouveau() return # Ouvrir jeu # Il faut préalablement fermer le jeu en cours # On reçoit le nom du jeu suivi d'une liste de personnages ou None si rien d'ouvert par le jeu def ouvrir(self): if self.fermer(): names = self.jeu.ouvrir() if names != None: numero = -1 for person in names: # index 0 : nom du fichier jeu if numero < 0: self.root.title('Rêve de Dragon - ' + person) # autres index : personnages # index vaudra le nombre de personnages reçus else: self.viewmenu.add_command(label=person, command=lambda index=numero: self.selectionner(index)) numero += 1 # On affiche le premier personnage if numero > 0: self.selectionner(0) return # Fermer le jeu en cours # On efface tous les personnages # on cree un nouveau personnage vide pour obtenir un affichage vierge def fermer(self): if not self.saved: self.saved = askyesno( 'Fermer', 'Voulez-vous vraiment fermer ce Jeu ?\nLes données non enregistrées seront perdues' ) if self.saved: last = self.viewmenu.index("end") if last is not None: for i in range(last + 1): self.viewmenu.delete(0) self.root.title('Rêve de Dragon') self.jeu.fermer() self.creer() return self.saved # Quitter le programme # onh détruit la fenêtre et on quitte def quitter(self): if askyesno('Quitter', 'Voulez-vous vraiment quitter le programme ?'): self.root.destroy() self.root.quit() return # Fonction interne d'affichage des données d'un personnage # Copie toutes les données du dictionnaire local dans les variables associées aux champs de saisie def affiche(self): self.Entry_Nom.set(self.pod["Fiche"]["Nom"]) self.Entry_Age.set(self.pod["Fiche"]["Age"]) self.Entry_Heure.set(self.pod["Fiche"]["Heure_Naissance"]) self.Entry_Taille.set(self.pod["Fiche"]["Taille"]) self.Entry_Poids.set(self.pod["Fiche"]["Poids"]) self.Entry_Sexe.set(self.pod["Fiche"]["Sexe"]) self.Entry_Cheveux.set(self.pod["Fiche"]["Cheveux"]) self.Entry_Yeux.set(self.pod["Fiche"]["Yeux"]) self.Entry_Beaute.set(self.pod["Fiche"]["Beaute"]) self.Entry_Ambidextre.set(self.pod["Fiche"]["Ambidextre"]) self.Entry_HRevant.set(self.pod["Fiche"]["Haut_Revant"]) self.Entry_SignesP.set(self.pod["Fiche"]["Signes_Particulier"]) for i in range(0, 18): self.Entry_C[i].set( self.pod["Caracteristique"][personnage.caracteristique(i, 0)]) for i in range(0, 7): self.Entry_P[i].set(self.pod["Point"][personnage.point(i, 0)]) for i in range(0, 66): self.Entry_A[i].set(self.pod["Competence"][personnage.competence( i, 0)][personnage.competence(i, 1)]) if self.Entry_HRevant.get() != 1: for i in range(0, 4): self.Draconic[i].configure(state='disabled') return # Création d'un nouveau personnage # On demande au jeu de créer un nouveau personnage dans la liste # On initialise toutes les variables de saisie aux valeur reçues def creer(self): self.pod = self.jeu.creer() self.affiche() return # Validation des données du personnage # On reconstitue le dictionnaire qui est envoyé au jeu pour vérification # Le jeu répond avec un dictionnaire contenant # - l'index du personnage # - Le nom de personnage # - Un message d'erreur ou d'acceptation def valider(self): if len(self.Entry_Nom.get()) < 1: return self.pod["Fiche"]["Nom"] = self.Entry_Nom.get() self.pod["Fiche"]["Age"] = self.Entry_Age.get() self.pod["Fiche"]["Heure_Naissance"] = self.Entry_Heure.get() self.pod["Fiche"]["Taille"] = self.Entry_Taille.get() self.pod["Fiche"]["Poids"] = self.Entry_Poids.get() self.pod["Fiche"]["Sexe"] = self.Entry_Sexe.get() self.pod["Fiche"]["Cheveux"] = self.Entry_Cheveux.get() self.pod["Fiche"]["Yeux"] = self.Entry_Yeux.get() self.pod["Fiche"]["Beaute"] = self.Entry_Beaute.get() self.pod["Fiche"]["Ambidextre"] = self.Entry_Ambidextre.get() self.pod["Fiche"]["Haut_Revant"] = self.Entry_HRevant.get() self.pod["Fiche"]["Signes_Particulier"] = self.Entry_SignesP.get() for i in range(0, 18): self.pod["Caracteristique"][personnage.caracteristique( i, 0)] = self.Entry_C[i].get() for i in range(0, 7): self.pod["Point"][personnage.point(i, 0)] = self.Entry_P[i].get() for i in range(0, 65): self.pod["Competence"][personnage.competence( i, 0)][personnage.competence(i, 1)] = self.Entry_A[i].get() retour = self.jeu.valider(self.pod) index = retour["index"] # On a bien un index valide : alors on met à jour le menu et on va chercher les données du personnage if index is not None: if self.viewmenu.entrycget(index, 'label') != self.Old_Nom: self.viewmenu.entryconfigure(index, label=retour["nom"]) elif self.viewmenu.entrycget(index, 'label') != retour["nom"]: self.viewmenu.add_command( label=retour["nom"], command=lambda index=index: self.selectionner(index)) self.pod = self.jeu.selectionner(index) self.affiche() # En cas d'erreur ou retour ok, il y a un message du jeu if len(retour["message"]): showerror("Validation", retour["message"]) self.saved = False return # Sélection d'un personnage depuis le menu # On envoie au jeu l'index du menu qui correspond à l'index de la liste du jeu # Les données du personnage reçu sont ensuite affichées def selectionner(self, code): self.pod = self.jeu.selectionner(code) self.affiche() return # Nouvelle partie # On demande au Jeu de changer de partie # Le jeu renvoie le contenu du personnage courant def partie(self): if askyesno( 'Nouvelle Partie', 'Voulez-vous vraiment terminer cette partie ?\nLes données non enregistrées seront perdues' ): self.pod = self.jeu.partie() self.affiche() return # Lancer de dé # Calcul de résolution puis lancer des dés # On passe au jeu les valeurs de caractéristiques et compétences sélectionnées # Le résultat sera récupéré en retour et affiché def lancer(self): resultat = self.jeu.lancer(self.Entry_R_C_Val.get(), self.Entry_R_A_Val.get()) self.Entry_R_Seuil.set(resultat["seuil"]) self.Entry_R_Tirage.set(resultat["tirage"]) self.Entry_R_Special.set(resultat["special"]) self.saved = False return # Affichage de la boite de dialogue A propos # Le texte est dans le fichier A_PROPOS.TXT def a_propos(self): fp = open("A_PROPOS.TXT", "r") texte_a_propos = fp.read() fp.close() showinfo("A Propos de...", texte_a_propos) return # Dialogue d'aide pour connaitre les règles du jeu # Le texte est dans le fichier REGLES.TXT def regles(self): file = "REGLE.TXT" titre = "Règles du Jeu Rêve de Dragon." self.aide(file, titre) return # Le texte est dans le fichier AIDE.TXT def utilise(self): file = "AIDE.TXT" titre = "Utilisation de Rêve de Dragon." self.aide(file, titre) return # Aide du jeu # Affiche une boite de dialogue avec un widget texte contenant l'aide def aide(self, file, titre): # On ouvre une fenêtre fille de celle du jeu self.wdw = Toplevel() self.wdw.geometry('+400+100') self.wdw.title(titre) # Le texte de l'aide est stocké dans un fichier Atexte fp = open(file, "r") texte_aide = fp.read() fp.close() # On l'affiche dans un widget Text avec une barre de défilement # Ne fonctionne que si on utilise grid pour placer les Widgets # Il faut mettre le widget en état disabled pour éviter que l'on y entre du texte self.S = Scrollbar(self.wdw, orient='vertical') self.T = Text(self.wdw, height=50, width=100, font=('TkDefaultFont', 10)) self.T.grid(row=0, column=0, sticky='NW') self.S.configure(command=self.T.yview) self.T.configure(yscrollcommand=self.S.set) self.S.grid(row=0, column=1, sticky='SN') self.T.configure(state='normal') self.T.insert('end', texte_aide) self.T.configure(state='disabled') # La nouvelle fenêtre est ouverte en modal # Il faudra la fermer pour reprendre le contrôle de la fenêtre principale self.wdw.transient(self.root) self.wdw.grab_set() self.root.wait_window(self.wdw) return # fonction qui ne fait rien (pour les tests) def void(self): return
class Example(Frame): def __init__(self): super().__init__() self.initUI() def initUI(self): self.conn = sqlite3.connect('tatardict.db') # Подключаемся к базе self.curdict = self.conn.cursor() self.master.title('Татарский язык') self.menubar = Menu(self.master) self.master.config(menu=self.menubar) self.fileMenu = Menu(self.menubar) self.nfm = Menu(self.menubar) self.tfm = Menu(self.menubar) self.fileMenu.add_cascade(label="Выбор темы", menu=self.tfm) self.curdict.execute('SELECT sub_them, in_them FROM themes') th = self.curdict.fetchall() self.choice_them = StringVar() for text, mode in th: self.tfm.add_radiobutton(label=text, value=mode, variable=self.choice_them, command=self.choise_theme) self.choice_them.set(2) self.fileMenu.add_command(label="Выход", command=self.onExit) self.menubar.add_cascade(label="≡", menu=self.fileMenu) self.them = Label(self.master, text='Тема: ' + self.tfm.entrycget(self.choice_them.get(), 'label'), bd=1, relief='flat', anchor='w') self.them.grid(row=1, column=0, columnspan=2) self.question = Label(self.master, text=' ', font=('BOLD', 12), fg='red') self.question.grid(row=2, column=0, columnspan=4) ttk.Separator(self.master, orient='horizontal').grid(row=3, column=0, columnspan=2, sticky='ew') answer_width = 15 # Ширина кнопок ответа self.v = StringVar() # Выбранный ответ радиокнопкой self.var = StringVar() # Строка состояния 'предыдущий ответ self.var1 = StringVar() # Подсчет количества выполненных ответов self.var1.set('0/0') self.rightanswer = 0 self.allanswer = 0 self.b1 = Radiobutton(self.master, text='', variable=self.v, value='', indicatoron=0, width=answer_width) self.b2 = Radiobutton(self.master, text='', variable=self.v, value='', indicatoron=0, width=answer_width) self.b3 = Radiobutton(self.master, text='', variable=self.v, value='', indicatoron=0, width=answer_width) self.b4 = Radiobutton(self.master, text='', variable=self.v, value='', indicatoron=0, width=answer_width) self.b5 = Radiobutton(self.master, text='', variable=self.v, value='', indicatoron=0, width=answer_width) self.b1.grid(row=4, column=0, columnspan=4) self.b2.grid(row=5, column=0, columnspan=4) self.b3.grid(row=6, column=0, columnspan=4) self.b4.grid(row=7, column=0, columnspan=4) self.b5.grid(row=8, column=0, columnspan=4) self.NextButton = Button(self.master, text='Дальше', command=self.next_question).grid(row=9, column=1, columnspan=3, sticky='e') self.status = Label(self.master, text='Предыдущий ответ: ', bd=1, relief='sunken', width=18, anchor='w').grid(row=10, column=0) self.status1 = Label(self.master, text='Не было!', textvariable=self.var, bd=1, relief='sunken', width=10, anchor='w').grid(row=10, column=1) self.status2 = Label(self.master, text=' Количество вопросов: ', bd=1, relief='sunken', width=18, anchor='e').grid(row=11, column=0, sticky='w') self.status3 = Label(self.master, textvariable=self.var1, bd=1, relief='sunken', width=10, anchor='w').grid(row=11, column=1) self.choise_theme() # Определение правильности ответа, переход на следующий вопрос def next_question(self): if self.question['text'] == self.v.get(): self.var.set('правильный') self.rightanswer += 1 else: self.var.set('не верный') self.allanswer += 1 self.var1.set(str(self.allanswer) + '/' + str(self.rightanswer)) self.create_question() # Выбор темы def choise_theme(self): choices_them = self.tfm.entrycget(self.choice_them.get(), 'label') self.them["text"] = 'Тема: ' + choices_them dbselect = 'SELECT tatar, orys FROM dictionary where in_themes = ' self.curdict.execute(dbselect + self.choice_them.get()) self.f = self.curdict.fetchall() self.create_question() # Создаем вопрос def create_question(self): self.ff = random.choice(self.f) # Предотвращаем повторяемость вопросов if 'oldword' in locals(): while self.ff == oldword: self.ff = random.choice(self.f) self.f.remove(self.ff) self.fff = random.sample(self.f, 4) self.fff.append(self.ff) random.shuffle(self.fff) self.question['text'] = self.ff[1] self.result = self.ff[0] self.b1["text"] = self.fff[0][0] self.b1["value"] = self.fff[0][1] self.b2["text"] = self.fff[1][0] self.b2["value"] = self.fff[1][1] self.b3["text"] = self.fff[2][0] self.b3["value"] = self.fff[2][1] self.b4["text"] = self.fff[3][0] self.b4["value"] = self.fff[3][1] self.b5["text"] = self.fff[4][0] self.b5["value"] = self.fff[4][1] self.f.append(self.ff) oldword = self.ff # Сохраняем предыдущий ответ def onExit(self): self.master.destroy()