Tk_GetPixmap: Error from CreateDIBSection
Bonjour,
Je souhaite créer un logiciel qui permet de créer des interfaces, Il y a "Ajouter un bouton", "Changer le titre" et je rajouterai d'autre fonctionnalités. Quand je créé un bouton avec nbtn (newbutton), une messagebox apparait:
- Titre: Tk_GetPixmap: Error from CreateDIBSection
- Contenu: L'opération a réussi
Une fois que je la ferme, ma fenêtre principale se ferme aussi. Je cherche sur internet mais sans rien trouver, c'est pourquoi je viens vous demander.
Code:
import uuid
from pc import infos
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
import customtkinter as ctk
from tkinter import simpledialog
import os
import webcolors
from customtkinter import CTkImage
class MultiEntryDialog(ctk.CTkToplevel):
def __init__(self, parent, title, entries: list):
super().__init__(parent)
self.title(title)
self.entries = []
for i, entry_name in enumerate(entries):
ctk.CTkLabel(self, text=f"{entry_name}:").grid(row=i, sticky="w")
entry = ctk.CTkEntry(self)
entry.grid(row=i, column=1)
self.entries.append(entry)
button_frame = ctk.CTkFrame(self)
button_frame.grid(row=len(entries), columnspan=2, pady=10)
ok_button = ctk.CTkButton(button_frame, text="OK", command=self.ok)
ok_button.pack(side="left")
cancel_button = ctk.CTkButton(button_frame, text="Annuler", command=self.cancel)
cancel_button.pack(side="left")
self.result = None
self.transient(parent)
self.grab_set()
while self.winfo_exists():
parent.update()
if self.result is None:
self.result = ['', '', '']
def ok(self):
result = [entry.get() for entry in self.entries]
self.destroy()
self.result = result
def cancel(self):
self.destroy()
self.result = ['', '', '']
class Constructor:
objects = []
objects_id = []
def __init__(self):
pass
class App:
memory = []
frames = []
buttons = []
def cthex(self, all_form):
try:
color = webcolors.rgb_to_hex(all_form)
except:
try:
color = webcolors.name_to_hex(all_form)
except Exception as e:
color = all_form
return color
def add_frame(self, win, name, rw, rh, rx, ry, bg, bdw=0):
frame = ctk.CTkFrame(win, width=(infos.screen_size_x * rw), height=(infos.screen_size_y * rh), fg_color=bg,
border_width=bdw)
frame.place(x=(infos.screen_size_x * rx), y=(infos.screen_size_y * ry))
if self.search_frame(name)[0]:
raise RuntimeWarning(f'Frame "{name}" already exists.')
self.frames.append([str(name), frame])
def search_frame(self, name):
for i, frm_infos in enumerate(self.frames):
if name == frm_infos[0]:
return True, i
return False, 0
def rem_frame(self, name):
ex, i = self.search_frame(name)
if not ex:
raise RuntimeWarning(f'Frame {name} doesn\'t exist.')
self.frames[i][1].destroy()
del self.frames[i]
def add_button(self, win, name, rw, rh, rx, ry, bg, bdw=0, command='', text='', image=''):
if not command:
command = 'None'
if not bg:
bg = '#6292bd'
hex = self.cthex(bg)
rvb = []
rvb2 = []
for p in webcolors.hex_to_rgb(hex):
rvb.append(int(p))
rvb2.append(int(p))
for primary in range(len(rvb2)):
rvb2[primary] += 10
hex2 = webcolors.rgb_to_hex(rvb2)
w, h = int(infos.screen_size_x * rw), int(infos.screen_size_y * rh)
if image:
img = Image.open(image)
img.thumbnail((w ** 1, h ** 1))
imgtk = CTkImage(img)
else:
img = Image.new('RGB', (1, 1), tuple(rvb))
imgtk = CTkImage(img)
imgtk.configure(size=(1, 1))
if img.width + len(text) * 8 > w and image:
w += (img.width + len(text) * 8) - w
self.memory.append(imgtk)
button = ctk.CTkButton(win, image=imgtk, text=text, width=w, height=h, command=eval(command),
compound='left',
border_width=bdw, fg_color=bg, bg_color='#2b2b2b', hover_color=hex2)
button.place(x=(infos.screen_size_x * rx - w / 2), y=(infos.screen_size_y * ry + h / 2) + 1)
if self.search_frame(name)[0]:
raise RuntimeWarning(f'Frame "{name}" already exists.')
self.buttons.append([str(name), button, imgtk])
def search_button(self, name):
for i, btn_infos in enumerate(self.buttons):
if name == btn_infos[0]:
return True, i
return False, 0
def rem_button(self, name):
ex, i = self.search_button(name)
if not ex:
raise RuntimeWarning(f'Button {name} doesn\'t exist.')
self.buttons[i][1].destroy()
del self.buttons[i]
def update_theme(self, theme):
ctk.set_appearance_mode(theme)
self.theme = theme
def title(self):
dialog = MultiEntryDialog(self.win, '', ['New title'])
self.win.title(dialog.result[0])
def nbtn(self):
x, y = 0, 0
w, h = 0, 0
sx, sy = infos.screen_size_x, infos.screen_size_y
new_button = ctk.CTkButton(master=self.win, text='', compound='left')
while not infos.is_clicking:
pass
while infos.is_clicking:
pass
while not infos.is_clicking:
x, y = infos.get_pos()
w, h = new_button.winfo_width(), new_button.winfo_height()
new_button.place(x=x * 0.8 - w // 2.5, y=y * 0.8 - h)
self.win.update()
rx, ry = (x * 0.8 - w // 2.5) / infos.screen_size_x, (y * 0.8 - h) / infos.screen_size_y
dialog = MultiEntryDialog(self.win, 'New Button', ['Text', 'Color', 'Command'])
if not dialog.result[0]:
print(dialog.result)
new_button.destroy()
return None
if not dialog.result[2]:
dialog.result[2] = ''
name = uuid.uuid4()
self.add_button(self.win, name, w, h, rx, ry, bg=dialog.result[1], bdw=0, command=dialog.result[2], text=dialog.result[0],
image='')
self.win.update()
new_button.destroy()
self.file_write(
f'objects.append(["button", ["{name}", 0.03, 0.02, {rx}, {ry}, "#282d36", 0, "pass", "{dialog.result[0]}", ""]])\n')
def file_write(self, to_write):
self.file_result.write(to_write)
def __init__(self, title='Windows Tool Kit Interface Creator', theme=None, background='white', style='default',
logo_path=None, objects=None):
self.theme = None
basic = open('basic', 'r')
self.file_result = open('result.py', 'w')
self.file_result.write(basic.read() + '\nobjects = []\n')
if objects is None:
objects = []
self.win = ctk.CTk()
if theme:
try:
self.update_theme(theme)
except:
raise RuntimeWarning(f'Theme {theme} doesn\'t exist')
self.win.geometry(f'{infos.screen_size_x}x{infos.screen_size_y}')
self.win.title(title)
self.win.state('zoomed')
self.win.iconbitmap(logo_path)
self.win.configure(background=background)
self.style = ttk.Style()
self.style.theme_use(style)
for _type, args in objects:
if _type == 'frame':
self.add_frame(self.win, args[0], args[1], args[2], args[3], args[4], args[5], args[6])
elif _type == 'button':
self.add_button(self.win, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
args[8], args[9])
if logo_path:
p1 = tk.PhotoImage(file=logo_path)
self.win.iconphoto(False, p1)
while True:
try:
self.win.winfo_exists()
except:
break
self.win.update()
App(background='dark gray', theme='Dark', style='vista', logo_path='logo.png',
objects=[['frame', ['lbframe', 0.1, 1, 0, 0, '#2b2b2b', 0]],
['frame', ['rbframe', 0.1, 1, 0.9, 0, '#282d36', 0]],
['frame', ['cbar', 1, 0.03, 0, 0, '#2b2b2b', 0]],
['button', ['b1', 0.03, 0.02, 0.03, 0.05, '#282d36', 0, 'self.title', 'Change Title', '']],
['button', ['b1', 0.03, 0.02, 0.03, 0.08, '#282d36', 0, 'self.nbtn', 'Add Button', '']], ])
Windows / Opera 100.0.0.0
6 réponses
Salut,
Difficile de t'aider avec un tel code :
Des imports que l'on ne connait pas.
Fichier en lecture et écriture dont on ne connait pas le contenu (qui ne sont pas refermés d'ailleurs).
Il faut poster un code minimaliste qui génère cette erreur.
Bonjour,
C'est ça que tu appelles un code minimaliste ?
C'est quoi import uuid ?
De plus il faut poster le code de cette façon:
https://codes-sources.commentcamarche.net/faq/11288-poster-un-extrait-de-code
Visuellement, ça doit ressembler à ça:
for k in range(10):
print(k)
@Noa, juste pour préciser la demande de Phil, il faut que ton code puisse, suite à un simple copier coller, être exécuté tel quel et déclencher l'erreur.
- Il ne doit pas dépendre de fichier tiers (ou alors il faut reporter leur contenu, idéalement minimal)
- Il ne doit pas dépendre de modules (à moins que ces modules ne soient standard ou que tu indiques comment les récupérer).
Si on ne peut pas reproduire ton problème, on peut difficilement en comprendre la cause.
@Phil_1857 StatutMembre
C'est quoi import uuid ?
Chez moi ce module semble exister de base (je ne l'ai ni installé via PIP ni APT) et je l'ai déjà vu par le passé dans du code. Au besoin, le module en question est disponible sur pypi (voir ce lien) et est présenté ici.
import uuid
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
import customtkinter as ctk
import os
import webcolors
from customtkinter import CTkImage
class infos:
import ctypes
import pyautogui
from pynput import mouse
def on_mouse_press(x, y, button, pressed):
if pressed:
infos.is_clicking = True
else:
infos.is_clicking = False
@staticmethod
def get_titlebar_size():
SM_CYSIZE = 31
user32 = infos.ctypes.windll.user32
titlebar_height = user32.GetSystemMetrics(SM_CYSIZE)
return titlebar_height
@staticmethod
def get_pos():
infos.current_mouse_x = infos.pyautogui.position()[0]
infos.current_mouse_y = infos.pyautogui.position()[1]
return infos.current_mouse_x, infos.current_mouse_y
@staticmethod
def on_click(x, y, button, pressed):
if button == mouse.Button.left:
infos.is_clicking = True
else:
infos.is_clicking = False
user32 = ctypes.windll.user32
screen_size_x = user32.GetSystemMetrics(0)
screen_size_y = user32.GetSystemMetrics(1)
center_screen_x = screen_size_x // 2
center_screen_y = screen_size_y // 2
ratio = screen_size_x / screen_size_y
pxl_size_x = screen_size_x // 480
pxl_size_y = screen_size_y // 360
current_mouse_x, current_mouse_y = 0, 0
is_clicking = False
mouseListener = mouse.Listener(on_click=on_mouse_press)
mouseListener.start()
@staticmethod
def ctr(xy: list):
rx = xy[0] / infos.screen_size_x
ry = xy[1] / infos.screen_size_y
return [rx, ry]
class MultiEntryDialog(ctk.CTkToplevel):
def __init__(self, parent, title, entries: list):
super().__init__(parent)
self.title(title)
self.entries = []
for i, entry_name in enumerate(entries):
ctk.CTkLabel(self, text=f"{entry_name}:")\
.grid(row=i, sticky="w")
entry = ctk.CTkEntry(self)
entry.grid(row=i, column=1)
self.entries.append(entry)
button_frame = ctk.CTkFrame(self)
button_frame.grid(row=len(entries), columnspan=2,
pady=10)
ok_button = ctk.CTkButton(button_frame, text="OK"
, command=self.ok)
ok_button.pack(side="left")
cancel_button = ctk.CTkButton(button_frame,
text="Annuler",
command=self.cancel)
cancel_button.pack(side="left")
self.result = None
self.transient(parent)
self.grab_set()
while self.winfo_exists():
parent.update()
if self.result is None:
self.result = [''] * len(entries)
def ok(self):
result = [entry.get() for entry in self.entries]
self.destroy()
self.result = result
def cancel(self):
self.destroy()
class Constructor:
objects = []
objects_id = []
def __init__(self):
pass
class App:
memory = []
frames = []
buttons = []
def cthex(self, all_form):
try:
color = webcolors.rgb_to_hex(all_form)
except:
try:
color = webcolors.name_to_hex(all_form)
except Exception as e:
color = all_form
return color
def add_frame(self, win, name, rw, rh, rx, ry, bg, bdw=0):
frame = ctk.CTkFrame(win,
width=(infos.screen_size_x * rw),
height=(infos.screen_size_y * rh),
fg_color=bg,
border_width=bdw)
frame.place(x=(infos.screen_size_x * rx),
y=(infos.screen_size_y * ry))
if self.search_frame(name)[0]:
raise RuntimeWarning(f'Frame "{name}" already exists.')
self.frames.append([str(name), frame])
def search_frame(self, name):
for i, frm_infos in enumerate(self.frames):
if name == frm_infos[0]:
return True, i
return False, 0
def rem_frame(self, name):
ex, i = self.search_frame(name)
if not ex:
raise RuntimeWarning(f'Frame {name} doesn\'t exist.')
self.frames[i][1].destroy()
del self.frames[i]
def add_button(self, win, name,
rw, rh, rx, ry, bg,
bdw=0, command='', text='', image=''):
if not bg:
bg = '#FF0000'
rvb1 = webcolors.hex_to_rgb(bg)
rvb2 = rvb1
new_rvb = []
for p in rvb2:
new_rvb.append(p + 50)
hex1 = webcolors.rgb_to_hex(new_rvb)
if not command:
command = 'lambda: None'
w, h = int(infos.screen_size_x * rw),\
int(infos.screen_size_y * rh)
if image:
img = Image.open(image)
img.thumbnail((w ** 1, h ** 1))
imgtk = CTkImage(img)
else:
img = Image.new('RGB', (1, 1), rvb1)
imgtk = CTkImage(img)
imgtk.configure(size=(1, 1))
if img.width + len(text) * 8 > w and image:
w += (img.width + len(text) * 8) - w
self.memory.append(imgtk)
button = ctk.CTkButton(win, text=text,
width=w, height=h,
command=eval(command),
compound='left',
border_width=bdw,
fg_color=bg,
bg_color='#2b2b2b',
hover_color=hex1)
button.place(x=(infos.screen_size_x * rx - w / 2),
y=(infos.screen_size_y * ry + h / 2) + 1)
if self.search_frame(name)[0]:
raise RuntimeWarning(f'Frame "{name}" already exists.')
self.buttons.append([str(name), button, imgtk])
def search_button(self, name):
for i, btn_infos in enumerate(self.buttons):
if name == btn_infos[0]:
return True, i
return False, 0
def rem_button(self, name):
ex, i = self.search_button(name)
if not ex:
raise RuntimeWarning(f'Button {name} doesn\'t exist.')
self.buttons[i][1].destroy()
del self.buttons[i]
def update_theme(self, theme):
ctk.set_appearance_mode(theme)
self.theme = theme
def title(self):
dialog = MultiEntryDialog(self.win, '', ['New title'])
self.win.title(dialog.result[0])
def nbtn(self):
x, y = 0, 0
w, h = 0, 0
sx, sy = infos.screen_size_x, \
infos.screen_size_y
new_button = ctk.CTkButton(master=self.win,
text='', compound='left')
while not infos.is_clicking:
pass
while infos.is_clicking:
pass
while not infos.is_clicking:
x, y = infos.get_pos()
w, h = new_button.winfo_width(), \
new_button.winfo_height()
new_button.place(x=x * 0.8 - w // 2.5, y=y * 0.8 - h)
self.win.update()
rx, ry = (x * 0.8 - w // 2.5) / infos.screen_size_x, \
(y * 0.8 - h) / infos.screen_size_y
dialog = MultiEntryDialog(self.win,
'New Button',
['Text', 'Color', 'Command'])
if not dialog.result[0]:
print(dialog.result)
new_button.destroy()
return None
if not dialog.result[2]:
dialog.result[2] = ''
name = uuid.uuid4()
self.add_button(self.win, name, w, h, rx,
ry, bg=dialog.result[1],
bdw=0,
command=dialog.result[2],
text=dialog.result[0],
image='')
self.win.update()
new_button.destroy()
self.file_write(
f'objects.append(["button", ["{name}", 0.03, 0.02,'
f' {rx}, {ry}, "#282d36", 0, "pass", "{dialog.result[0]}'
f'", ""]])\n')
def file_write(self, to_write):
self.file_result.write(to_write)
def __init__(self, title='Windows Tool Kit Interface Creator',
theme=None, background='white', style='default',
logo_path=None, objects=None):
self.theme = None
basic = open('basic', 'r')
self.file_result = open('result.py', 'w')
self.file_result.write(basic.read() + '\nobjects = []\n')
if objects is None:
objects = []
self.win = ctk.CTk()
if theme:
try:
self.update_theme(theme)
except:
raise RuntimeWarning(f'Theme {theme} doesn\'t exist')
self.win.\
geometry(f'{infos.screen_size_x}x{infos.screen_size_y}')
self.win.title(title)
self.win.state('zoomed')
self.win.iconbitmap(logo_path)
self.win.configure(background=background)
self.style = ttk.Style()
self.style.theme_use(style)
for _type, args in objects:
if _type == 'frame':
self.add_frame(self.win, args[0], args[1],
args[2], args[3], args[4],
args[5], args[6])
elif _type == 'button':
self.add_button(self.win, args[0], args[1],
args[2], args[3], args[4],
args[5], args[6], args[7],
args[8], args[9])
if logo_path:
p1 = tk.PhotoImage(file=logo_path)
self.win.iconphoto(False, p1)
while True:
try:
self.win.winfo_exists()
except:
break
self.win.update()
App(background='dark gray', theme='Dark', style='vista',
logo_path='logo.png',
objects=[['frame', ['lbframe', 0.1, 1, 0, 0, '#2b2b2b', 0]],
['frame', ['rbframe', 0.1, 1, 0.9, 0, '#282d36', 0]],
['frame', ['cbar', 1, 0.03, 0, 0, '#2b2b2b', 0]],
['button', ['b1', 0.03, 0.02, 0.03, 0.05, '#282d36',
0, 'self.title', 'Change Title', '']],
['button', ['b1', 0.03, 0.02, 0.03, 0.08, '#282d36', 0,
'self.nbtn', 'Add Button', '']], ])
Je ne sais pas si cette version du code répond à votre définition de minimaliste,
normalement on peut le copier-coller et c'est senser marcher.
Merci
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre questionBonjour,
C'est censé marcher ?
Un code minimaliste, c'est un code d'une dizaine ou quinzaine de lignes avec
juste ce qu'il faut pour mettre l'erreur en évidence
De plus, il faut poster le code en utilisant les balises, comme on te l'indique
plus haut:
https://codes-sources.commentcamarche.net/faq/11288-poster-un-extrait-de-code
Visuellement, ça doit ressembler à ça:
for k in range(10):
print(k)
Bonjour Noa
Je ne sais pas si cette version du code répond à votre définition de minimaliste,
C'est mieux, mais ça n'est pas encore ça. En gros il faut enlever tous les blocs / fonctions de code qui ne sont pas utiles pour déclencher ton bug, tout en gardant un programme exécutable en se contentant d'un copier coller.
Je t'invite aussi à reporter l'erreur complète (avec la pile d'appel), cela te permettra de savoir quelle fonction a planté et à quel endroit. Il suffit de garder toutes les sections de code qui ont été traversées jusqu'ici pour faire un premier coup de ménage. Ensuite il faut idéalement supprimer les sections de code qui ont été traversées et qui n'ont pas de rôle dans le déclenchement du problème.
Le code supprimé te permettra ensuite de virer pas mal d'imports (et pour nous, de ne pas avoir à installer pleins de modules qui n'ont rien à voir avec le problème).
On peut le copier-coller et c'est sensé marcher.
Étant sous Linux, je ne vais pas pouvoir pour ma part reproduire ton erreur car CreateDIBSection est une fonction windows, ce qui laisse penser que tu utilises un paquet python spécifique à windows.
Selon cette page, en C, il est possible de récupérer la dernière erreur.
Selon cette page, ton bug pourrait être dû à des modules obsolètes (essaye de les mettre à jour).
Je suis par ailleurs un peu sceptique sur le fait d'utiliser customtkinter, là où tkinter me paraît suffisant (pourquoi une tk.Image ne suffit pas là où tu crées un ctk.CtkImage) ? Essaye de nous expliquer, une fois ton code encore plus minimisé, ce que tu cherches à faire.
Bonne chance
Ok ????.
Voici les 2 méthodes qui peuvent générer des erreurs:
def add_button(self, win, name, rw, rh, rx, ry, bg, bdw=0, command='', text='', image=''): if not command: command = 'None' if not bg: bg = '#6292bd' hex = self.cthex(bg) rvb = [] rvb2 = [] for p in webcolors.hex_to_rgb(hex): rvb.append(int(p)) rvb2.append(int(p)) for primary in range(len(rvb2)): rvb2[primary] += 10 hex2 = webcolors.rgb_to_hex(rvb2) w, h = int(infos.screen_size_x * rw), int(infos.screen_size_y * rh) if image: img = Image.open(image) img.thumbnail((w ** 1, h ** 1)) imgtk = CTkImage(img) else: img = Image.new('RGB', (1, 1), tuple(rvb)) imgtk = CTkImage(img) imgtk.configure(size=(1, 1)) if img.width + len(text) * 8 > w and image: w += (img.width + len(text) * 8) - w self.memory.append(imgtk) button = ctk.CTkButton(win, text=text, width=w, height=h, command=eval(command), compound='left', border_width=bdw, fg_color=bg, bg_color='#2b2b2b', hover_color=hex2) button.place(x=(infos.screen_size_x * rx - w / 2), y=(infos.screen_size_y * ry + h / 2) + 1) if self.search_frame(name)[0]: raise RuntimeWarning(f'Frame "{name}" already exists.') self.buttons.append([str(name), button, imgtk])def nbtn(self): x, y = 0, 0 w, h = 0, 0 sx, sy = infos.screen_size_x, infos.screen_size_y new_button = ctk.CTkButton(master=self.win, text='', compound='left') while not infos.is_clicking: pass while infos.is_clicking: pass while not infos.is_clicking: x, y = infos.get_pos() w, h = new_button.winfo_width(), new_button.winfo_height() new_button.place(x=x * 0.8 - w // 2.5, y=y * 0.8 - h) self.win.update() rx, ry = (x * 0.8 - w // 2.5) / infos.screen_size_x, (y * 0.8 - h) / infos.screen_size_y dialog = MultiEntryDialog(self.win, 'New Button', ['Text', 'Color', 'Command']) if not dialog.result[0]: print(dialog.result) new_button.destroy() return None if not dialog.result[2]: dialog.result[2] = '' name = uuid.uuid4() self.add_button(self.win, name, w, h, rx, ry, bg=dialog.result[1], bdw=0, command=dialog.result[2], text=dialog.result[0], image='') self.win.update() new_button.destroy() self.file_write( f'objects.append(["button", ["{name}", 0.03, 0.02, {rx}, {ry}, "#282d36", 0, "pass", "{dialog.result[0]}", ""]])\n')Imports inconnus:
J'importe la classe infos du pc.py qui contient des informations sur l'ordinateur, tel que les dimensions de l'écran (infos.screen_sizex...), les positions de la souris (infos.get_pos())
nbtn consiste à créer un bouton temporaire qui va se déplacer sur la souris
jusqu'à ce que clique sur l'écran (pour le placer), une fois placé, il ouvre une boite de dialogue pour demander ce qui doit être écrit dedans, la couleur et la commande.
Une fois que l'utilisateur ferme la boite de dialogue, le bouton temporaire est
détruit pour en créer un nouveau avec self.add_button()
Et à partir du moment où je rentre les informations du bouton, l'erreur se déclenche, comme dit précédemment.