Tk_GetPixmap: Error al crear DIBSection
Hola,
Quiero crear un software que permita crear interfaces. Hay "Agregar un botón", "Cambiar el título" y añadiré otras funcionalidades. Cuando creo un botón con nbtn (newbutton), aparece un messagebox:
- Título: Tk_GetPixmap: Error from CreateDIBSection
- Contenido: La operación tuvo éxito
Una vez que lo cierro, mi ventana principal también se cierra. Busco en Internet pero no encuentro nada, por eso vengo a pedirle ayuda.
Código:
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', '']], ])
6 respuestas
Bonjour,
¿Es eso lo que llamas código minimalista?
¿Qué es import uuid?
Además hay que publicar el código de esta forma:
https://codes-sources.commentcamarche.net/faq/11288-poster-un-extrait-de-code
Visualmente, debe parecerse a esto:
for k in range(10): print(k)
@Noa, solo para precisar la solicitud de Phil, hace falta que tu código, tras un simple copiar y pegar, pueda ejecutarse tal cual y desencadene el error.
- No debe depender de archivos externos (o si lo hace, hay que reportar su contenido, idealmente mínimo)
- No debe depender de módulos (a menos que esos módulos sean estándar o indiques cómo recuperarlos).
Si no podemos reproducir tu problema, difícilmente podremos entender la causa.
@Phil_1857 EstadoMiembro
¿Qué es import uuid?
En mi equipo este módulo parece existir por defecto (no lo he instalado vía PIP ni APT) y ya lo he visto en código en el pasado. Si es necesario, el módulo en cuestión está disponible en PyPI (ver este enlace) y se presenta aquí.
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', '']], ])
No sé si esta versión del código cumple con su definición de minimalista,
normalmente se puede copiar y pegar y se supone que funciona.
Gracias
Hola,
¿Se supone que debe funcionar?
Un código minimalista es un código de una decena o quince líneas con
sólo lo necesario para que el error quede destacado
Además, hay que publicar el código usando las etiquetas, como se indica
más arriba:
https://codes-sources.commentcamarche.net/faq/11288-poster-un-extrait-de-code
Visualmente, debe verse así:
for k in range(10): print(k)
Hola Noa
No sé si esta versión del código cumple con tu definición de minimalista,
Es mejor, pero no es todavía eso. En resumen, hay que quitar todos los bloques / funciones de código que no sean útiles para activar tu fallo, manteniendo un programa ejecutable con solo copiar y pegar.
También te invito a reportar el error completo (con la pila de llamadas), eso te permitirá saber qué función falló y en qué punto. Basta con conservar todas las secciones de código que se han recorrido hasta ahora para hacer una primera limpieza. Luego hay que, idealmente, eliminar las secciones de código que se han recorrido y que no tienen un papel en el desencadenante del problema.
El código eliminado te permitirá luego quitar bastantes importaciones (y para nosotros, no tener que instalar muchos módulos que no tienen nada que ver con el problema).
Se puede copiar y pegar y se supone que funciona.
Al estar en Linux, no voy a poder por mi parte reproducir tu error porque CreateDIBSection es una función de Windows, lo que hace pensar que estés usando un paquete de Python específico para Windows.
Según esta página, en C, es posible recuperar el último error.
Según esta página, tu fallo podría deberse a módulos obsoletos (intenta actualizarlos).
Por otra parte, soy un poco escéptico respecto a usar customtkinter, donde tkinter me parece suficiente (¿por qué una tk.Image no basta donde creas un ctk.CtkImage)? Intenta explicarnos, una vez que tu código esté aún más minimizado, lo que buscas hacer.
Buena suerte
Ok ????.
Aquí están los 2 métodos que pueden generar errores:
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.