import tkinter as tk #Sert à la création d'interfaces from tkinter import messagebox import os #Pour les opérations relatives aux chemins et les emplacements des fichiers import matplotlib.pyplot as plt #Pour les créations de grahiques import shutil #Utilisé pour la copie et le déplacement de fichiers import xml.etree.ElementTree as ET #Pour l'intéraction avec Inkscape import base64 import numpy as np #Bibliothèque mathématique import subprocess import sys import json # Format: (Z, 'Symbol', 'Nom en anglais', 'Groupe', col, row) elements = [ (1, 'H', 'Hydrogen', 'Nonmetal', 1, 1), (2, 'He', 'Helium', 'Noble gas', 18, 1), (3, 'Li', 'Lithium', 'Alkali metal', 1, 2), (4, 'Be', 'Beryllium', 'Alkaline earth metal', 2, 2), (5, 'B', 'Boron', 'Metalloid', 13, 2), (6, 'C', 'Carbon', 'Nonmetal', 14, 2), (7, 'N', 'Nitrogen', 'Nonmetal', 15, 2), (8, 'O', 'Oxygen', 'Nonmetal', 16, 2), (9, 'F', 'Fluorine', 'Halogen', 17, 2), (10, 'Ne', 'Neon', 'Noble gas', 18, 2), (11, 'Na', 'Sodium', 'Alkali metal', 1, 3), (12, 'Mg', 'Magnesium', 'Alkaline earth metal', 2, 3), (13, 'Al', 'Aluminium', 'Post-transition metal', 13, 3), (14, 'Si', 'Silicon', 'Metalloid', 14, 3), (15, 'P', 'Phosphorus', 'Nonmetal', 15, 3), (16, 'S', 'Sulfur', 'Nonmetal', 16, 3), (17, 'Cl', 'Chlorine', 'Halogen', 17, 3), (18, 'Ar', 'Argon', 'Noble gas', 18, 3), (19, 'K', 'Potassium', 'Alkali metal', 1, 4), (20, 'Ca', 'Calcium', 'Alkaline earth metal', 2, 4), (21, 'Sc', 'Scandium', 'Transition metal', 3, 4), (22, 'Ti', 'Titanium', 'Transition metal', 4, 4), (23, 'V', 'Vanadium', 'Transition metal', 5, 4), (24, 'Cr', 'Chromium', 'Transition metal', 6, 4), (25, 'Mn', 'Manganese', 'Transition metal', 7, 4), (26, 'Fe', 'Iron', 'Transition metal', 8, 4), (27, 'Co', 'Cobalt', 'Transition metal', 9, 4), (28, 'Ni', 'Nickel', 'Transition metal', 10, 4), (29, 'Cu', 'Copper', 'Transition metal', 11, 4), (30, 'Zn', 'Zinc', 'Post-transition metal', 12, 4), (31, 'Ga', 'Gallium', 'Post-transition metal', 13, 4), (32, 'Ge', 'Germanium', 'Metalloid', 14, 4), (33, 'As', 'Arsenic', 'Metalloid', 15, 4), (34, 'Se', 'Selenium', 'Nonmetal', 16, 4), (35, 'Br', 'Bromine', 'Halogen', 17, 4), (36, 'Kr', 'Krypton', 'Noble gas', 18, 4), (37, 'Rb', 'Rubidium', 'Alkali metal', 1, 5), (38, 'Sr', 'Strontium', 'Alkaline earth metal', 2, 5), (39, 'Y', 'Yttrium', 'Transition metal', 3, 5), (40, 'Zr', 'Zirconium', 'Transition metal', 4, 5), (41, 'Nb', 'Niobium', 'Transition metal', 5, 5), (42, 'Mo', 'Molybdenum', 'Transition metal', 6, 5), (43, 'Tc', 'Technetium', 'Transition metal', 7, 5), (44, 'Ru', 'Ruthenium', 'Transition metal', 8, 5), (45, 'Rh', 'Rhodium', 'Transition metal', 9, 5), (46, 'Pd', 'Palladium', 'Transition metal', 10, 5), (47, 'Ag', 'Silver', 'Transition metal', 11, 5), (48, 'Cd', 'Cadmium', 'Post-transition metal', 12, 5), (49, 'In', 'Indium', 'Post-transition metal', 13, 5), (50, 'Sn', 'Tin', 'Post-transition metal', 14, 5), (51, 'Sb', 'Antimony', 'Metalloid', 15, 5), (52, 'Te', 'Tellurium', 'Metalloid', 16, 5), (53, 'I', 'Iodine', 'Halogen', 17, 5), (54, 'Xe', 'Xenon', 'Noble gas', 18, 5), (55, 'Cs', 'Caesium', 'Alkali metal', 1, 6), (56, 'Ba', 'Barium', 'Alkaline earth metal', 2, 6), (100000000000000000000000000000000000000000000000000, '-', 'Lanthanides', 'Lanthanide', 3, 6), #placeholder pour l'affichage du tableau (57, 'La', 'Lanthanum', 'Lanthanide', 3, 9), (58, 'Ce', 'Cerium', 'Lanthanide', 4, 9), (59, 'Pr', 'Praseodymium', 'Lanthanide', 5, 9), (60, 'Nd', 'Neodymium', 'Lanthanide', 6, 9), (61, 'Pm', 'Promethium', 'Lanthanide', 7, 9), (62, 'Sm', 'Samarium', 'Lanthanide', 8, 9), (63, 'Eu', 'Europium', 'Lanthanide', 9, 9), (64, 'Gd', 'Gadolinium', 'Lanthanide', 10, 9), (65, 'Tb', 'Terbium', 'Lanthanide', 11, 9), (66, 'Dy', 'Dysprosium', 'Lanthanide', 12, 9), (67, 'Ho', 'Holmium', 'Lanthanide', 13, 9), (68, 'Er', 'Erbium', 'Lanthanide', 14, 9), (69, 'Tm', 'Thulium', 'Lanthanide', 15, 9), (70, 'Yb', 'Ytterbium', 'Lanthanide', 16, 9), (71, 'Lu', 'Lutetium', 'Lanthanide', 17, 9), (72, 'Hf', 'Hafnium', 'Transition metal', 4, 6), (73, 'Ta', 'Tantalum', 'Transition metal', 5, 6), (74, 'W', 'Tungsten', 'Transition metal', 6, 6), (75, 'Re', 'Rhenium', 'Transition metal', 7, 6), (76, 'Os', 'Osmium', 'Transition metal', 8, 6), (77, 'Ir', 'Iridium', 'Transition metal', 9, 6), (78, 'Pt', 'Platinum', 'Transition metal', 10, 6), (79, 'Au', 'Gold', 'Transition metal', 11, 6), (80, 'Hg', 'Mercury', 'Post-transition metal', 12, 6), (81, 'Tl', 'Thallium', 'Post-transition metal', 13, 6), (82, 'Pb', 'Lead', 'Post-transition metal', 14, 6), (83, 'Bi', 'Bismuth', 'Post-transition metal', 15, 6), (84, 'Po', 'Polonium', 'Post-transition metal', 16, 6), (85, 'At', 'Astatine', 'Halogen', 17, 6), (86, 'Rn', 'Radon', 'Noble gas', 18, 6), (87, 'Fr', 'Francium', 'Alkali metal', 1, 7), (88, 'Ra', 'Radium', 'Alkaline earth metal', 2, 7), (200000000000000000000000000000000000000000000000000, '_', 'Actinides', 'Actinide', 3, 7), #placeholder pour l'affichage du tableau (89, 'Ac', 'Actinium', 'Actinide', 3, 10), (90, 'Th', 'Thorium', 'Actinide', 4, 10), (91, 'Pa', 'Protactinium', 'Actinide', 5, 10), (92, 'U', 'Uranium', 'Actinide', 6, 10), (93, 'Np', 'Neptunium', 'Actinide', 7, 10), (94, 'Pu', 'Plutonium', 'Actinide', 8, 10), (95, 'Am', 'Americium', 'Actinide', 9, 10), (96, 'Cm', 'Curium', 'Actinide', 10, 10), (97, 'Bk', 'Berkelium', 'Actinide', 11, 10), (98, 'Cf', 'Californium', 'Actinide', 12, 10), (99, 'Es', 'Einsteinium', 'Actinide', 13, 10), (100, 'Fm', 'Fermium', 'Actinide', 14, 10), (101, 'Md', 'Mendelevium', 'Actinide', 15, 10), (102, 'No', 'Nobelium', 'Actinide', 16, 10), (103, 'Lr', 'Lawrencium', 'Actinide', 17, 10), (104, 'Rf', 'Rutherfordium', 'Transition metal', 4, 7), (105, 'Db', 'Dubnium', 'Transition metal', 5, 7), (106, 'Sg', 'Seaborgium', 'Transition metal', 6, 7), (107, 'Bh', 'Bohrium', 'Transition metal', 7, 7), (108, 'Hs', 'Hassium', 'Transition metal', 8, 7), (109, 'Mt', 'Meitnerium', 'none', 9, 7), (110, 'Ds', 'Darmstadtium', 'none', 10, 7), (111, 'Rg', 'Roentgenium', 'none', 11, 7), (112, 'Cn', 'Copernicium', 'Transition metal', 12, 7), (113, 'Nh', 'Nihonium', 'none', 13, 7), (114, 'Fl', 'Flerovium', 'none', 14, 7), (115, 'Mc', 'Moscovium', 'none', 15, 7), (116, 'Lv', 'Livermorium', 'none', 16, 7), (117, 'Ts', 'Tennessine', 'none', 17, 7), (118, 'Og', 'Oganesson', 'none', 18, 7), ] buttons = {} class PeriodicTableApp: #Création d'un objet def __init__(self, master): #Fonction qui se lance automatiquement lors de la création de l'objet self.master = master #Permet de combiner la fenêtre tkinter à l'objet self.last_clicked = None #Création d'une variable pour stocker le dernier click effectué for (num, sym, name, fam, col, row) in elements: #Parcourt la liste des éléments btn = tk.Button(master, text=sym, width=5, height=2, font=("Georgia", 11, "bold"), command=lambda s=sym: self.on_click(s)) #Paramètres d'affichage du bouton btn.grid(row=row, column=col) #Grille des boutons avec les coordonnées buttons[sym] = btn for (num, sym, name, fam, *_) in elements : #Donne au couleur au bouton selon le groupe de l'élément if fam == "Halogen" : buttons[sym].config(bg="yellow") buttons[sym].config(fg="black") elif fam == "Nonmetal" : buttons[sym].config(bg="light green") buttons[sym].config(fg="black") elif fam == "Transition metal" : buttons[sym].config(bg="pink") buttons[sym].config(fg="black") elif fam == "Noble gas" : buttons[sym].config(bg="steelblue") buttons[sym].config(fg="white") elif fam == "Post-transition metal" : buttons[sym].config(bg="gray") buttons[sym].config(fg="black") elif fam == "Metalloid" : buttons[sym].config(bg="brown") buttons[sym].config(fg="black") elif fam == "Alkali metal" : buttons[sym].config(bg="red") buttons[sym].config(fg="black") elif fam == "Alkaline earth metal" : buttons[sym].config(bg="orange") buttons[sym].config(fg="black") elif fam == "Lanthanide" : buttons[sym].config(bg="blue") buttons[sym].config(fg="white") elif fam == "Actinide" : buttons[sym].config(bg="purple") buttons[sym].config(fg="white") elif fam == "none": buttons[sym].config(fg="white") buttons[sym].config(bg="black") def on_click(self, symbol): #Fonction qui s'active lors d'un click sur un bouton famille="" for i in range(len(elements)) : #Parcourt la liste d'éléments if symbol in elements[i] and len(symbol)==len(elements[i][1]) : famille=elements[i][3] name=elements[i][2] num=elements[i][0] buttons[symbol].config(bg="white") #Le bouton sélectionné devient blanc if famille == "Halogen" : buttons[symbol].config(fg="gold") elif famille == "Nonmetal" : buttons[symbol].config(fg="green") elif famille == "Transition metal" : buttons[symbol].config(fg="deeppink") elif famille == "Noble gas" : buttons[symbol].config(fg="steelblue") elif famille == "Post-transition metal" : buttons[symbol].config(fg="dimgray") elif famille == "Metalloid" : buttons[symbol].config(fg="brown") elif famille == "Alkali metal" : buttons[symbol].config(fg="red") elif famille == "Alkaline earth metal" : buttons[symbol].config(fg="darkorange") elif famille == "Lanthanide" : buttons[symbol].config(fg="blue") elif famille == "Actinide" : buttons[symbol].config(fg="purple") elif famille == "none": buttons[symbol].config(fg="black") # buttons[symbol].config(fg="black") #Le texte du bouton sélectionné devient noir self.last_clicked = symbol #Stocke le symbole dans la variable print("Clic sur :", name, "-", symbol, "-", num, f"({famille})") #Affiche dans le terminal l'élément clické (symbol) reponse = messagebox.askokcancel("Group of the element ?", f"Click on {name} ({symbol}), Do you want to select the rest of the group ({famille})?") if reponse is True : for (num, sym, name, fam, *_) in elements : if fam == famille : #Sélection du groupe entier buttons[sym].config(bg="white") if famille == "Halogen" : buttons[sym].config(fg="gold") elif famille == "Nonmetal" : buttons[sym].config(fg="green") elif famille == "Transition metal" : buttons[sym].config(fg="deeppink") elif famille == "Noble gas" : buttons[sym].config(fg="steelblue") elif famille == "Post-transition metal" : buttons[sym].config(fg="dimgray") elif famille == "Metalloid" : buttons[sym].config(fg="brown") elif famille == "Alkali metal" : buttons[sym].config(fg="red") elif famille == "Alkaline earth metal" : buttons[sym].config(fg="darkorange") elif famille == "Lanthanide" : buttons[sym].config(fg="blue") elif famille == "Actinide" : buttons[sym].config(fg="purple") elif famille == "none": buttons[sym].config(fg="black") # buttons[sym].config(fg="black") print(f"Selecting the {famille} group") reponse2 = messagebox.askokcancel("Group engraving", f"Click on {famille}, create a file ?") if reponse2 is True : list_col=[[] for i in range(18)] for (num, sym, name, fam, col, row) in elements : if fam == famille : #Boucle pour la création d'une liste regroupant les infos du groupe sélectionné if sym == "-" or sym == "_": continue #Exclue les placholders s'il y en a list_data=[] list_data.append(sym) list_data.append(num) list_data.append(name) list_data.append(fam) list_data.append(col) list_data.append(row) list_col[col-1].append(list_data) print(list_col) #Création du .svg width_mm = 600 height_mm = 300 square_size=80 square_sizeh=60 stroke_width=1 svg_content = f''' ''' for i in range(len(list_col)): for j in range(len(list_col[i])): x = 50 + i * square_size # Each square starts exactly where previous ends y = 50 + list_col[i][j][5] * square_sizeh svg_content += f' ' svg_content += f' ' text_x=x+square_size/2 text_y=y+square_sizeh/2 text_content_sym = str(list_col[i][j][0]) if len(str(list_col[i][j][0]))==1: font_size = square_size * 0.55 if len(str(list_col[i][j][0]))==2: font_size = square_size * 0.50 svg_content += f''' {text_content_sym} ''' text_content_num = str(list_col[i][j][1]) if len(str(list_col[i][j][1]))==1: font_size = square_size * 0.68 if len(str(list_col[i][j][1]))==2: font_size = square_size * 0.63 if len(str(list_col[i][j][1]))==3: font_size = square_size * 0.48 svg_content += f''' {text_content_num} ''' text_content_name = str(list_col[i][j][2]) if len(str(list_col[i][j][2]))>4 and len(str(list_col[i][j][2]))<9: font_size = (square_size * 0.2)/(len(str(list_col[i][j][2]))*0.18) elif len(str(list_col[i][j][2]))<5 : font_size = (square_size * 0.2)/(len(str(list_col[i][j][2]))*0.3) elif len(str(list_col[i][j][2]))>5 : font_size = (square_size * 0.2)/(len(str(list_col[i][j][2]))*0.14) svg_content += f''' {text_content_name} ''' svg_content += '' with open(f'{famille}grp.svg', 'w') as f: f.write(svg_content) print(f"SVG created: {famille}grp") os.startfile(f"D:/fbalba/prog/{famille}grp.svg") #Ouvre le .svg if reponse2 is False : #Pour que les boutons récupèrent leur couleur originale s'ils ne sont plus sélectionnés for (num, sym, name, fam, *_) in elements : if fam == famille : if famille == "Halogen" : buttons[sym].config(bg="yellow") buttons[sym].config(fg="black") elif famille == "Nonmetal" : buttons[sym].config(bg="light green") buttons[sym].config(fg="black") elif famille == "Transition metal" : buttons[sym].config(bg="pink") buttons[sym].config(fg="black") elif famille == "Noble gas" : buttons[sym].config(bg="steelblue") buttons[sym].config(fg="white") elif famille == "Post-transition metal" : buttons[sym].config(bg="gray") buttons[sym].config(fg="black") elif famille == "Metalloid" : buttons[sym].config(bg="brown") buttons[sym].config(fg="black") elif famille == "Alkali metal" : buttons[sym].config(bg="red") buttons[sym].config(fg="black") elif famille == "Alkaline earth metal" : buttons[sym].config(bg="orange") buttons[sym].config(fg="black") elif famille == "Lanthanide" : buttons[sym].config(bg="blue") buttons[sym].config(fg="white") elif famille == "Actinide" : buttons[sym].config(bg="purple") buttons[sym].config(fg="white") elif famille == "none": buttons[sym].config(fg="white") buttons[sym].config(bg="black") if reponse is False : reponse3 = messagebox.askokcancel("Element engraving", f"Click on {name} ({symbol}), create a file ?") if reponse3 is True : JSON_PATH = f"{symbol}.json" #Crée un fichier .json with open(JSON_PATH, "w", encoding="utf-8") as f: #Rédige le .json avec la case à cliquer json.dump({"symbol": symbol}, f, ensure_ascii=False, indent=2) subprocess.Popen(["start", "powershell", "-NoExit", "-Command", "python updaterunna.py"], shell=True) # la ligne précédente ouvre un autre powershell et lance updaterunna.py dans celui-ci. Ce porgramme lit ensuite le .json le plus récent du dossier pour cliquer la case voulue. if reponse3 is False : #Pour que les boutons récupèrent leur couleur originale s'ils ne sont plus sélectionnés if famille == "Halogen" : buttons[symbol].config(bg="yellow") buttons[symbol].config(fg="black") elif famille == "Nonmetal" : buttons[symbol].config(bg="light green") buttons[symbol].config(fg="black") elif famille == "Transition metal" : buttons[symbol].config(bg="pink") buttons[symbol].config(fg="black") elif famille == "Noble gas" : buttons[symbol].config(bg="steelblue") buttons[symbol].config(fg="white") elif famille == "Post-transition metal" : buttons[symbol].config(bg="gray") buttons[symbol].config(fg="black") elif famille == "Metalloid" : buttons[symbol].config(bg="brown") buttons[symbol].config(fg="black") elif famille == "Alkali metal" : buttons[symbol].config(bg="red") buttons[symbol].config(fg="black") elif famille == "Alkaline earth metal" : buttons[symbol].config(bg="orange") buttons[symbol].config(fg="black") elif famille == "Lanthanide" : buttons[symbol].config(bg="blue") buttons[symbol].config(fg="white") elif famille == "Actinide" : buttons[symbol].config(bg="purple") buttons[symbol].config(fg="white") elif famille == "none": buttons[symbol].config(fg="white") buttons[symbol].config(bg="black") root = tk.Tk() #Permet de créer la fenêtre root.configure(bg="white") root.title("Periodic Table") #Nom de la fenêtre app = PeriodicTableApp(root) #Permet à l'objet PeriodicTableApp de s'afficher dans la fenêtre root.mainloop() #Fait fonctionner la fenêtre jusqu'à sa fermeture