Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Asociar función con argumentos a <<ComboboxSelected>>
#1
Buenas, estoy haciendo un desarrollo en donde vista y modelo van separados, y no logro que la función asociada al  <<ComboboxSelected>> se ejecute.
Copio aquí debajo el código.

Vista:
titulo_label = Label(pesta0, text="Título:", background="pink", font=("Courier", 10, "bold"))
titulo_label.place(x=10, y=93)
titulo_entry = ttk.Combobox(pesta0, textvariable=titulo, background="plum2")
titulo_entry['values']=modelo.combo_input()                                                
titulo_entry.bind("<<ComboboxSelected>>", modelo.consxtit(titulo.get(), isbn))             
titulo_entry.place(x=69, y=96, width=618)


Modelo:
def combo_input():
    cursor=base.cursor()
    query = ('SELECT título FROM ejemplares')
    cursor.execute(query)
    data=[]
    for rows in cursor:
        data.append(rows[0])
    print(sorted(data))             
    return(sorted(data))


def consxtit(titulo, isbn):
    cursor=base.cursor()
    data = (titulo, )
    sql = ('SELECT isbn FROM ejemplares WHERE título=?')
    cursor.execute(sql, data)
    result = cursor.fetchone()
    print(result)
    if result is not None:
        isbn.set(result)


Básicamente se trata de que al elegir un título, me muestre el isbn. La función  combo_input() funciona correctamente, pero la  consxtit(titulo, isbn) no hace nada. Nada de nada. Ni siquiera ejecuta el  print(result) que contiene, por lo que interpreto que tengo un error en la llamada a la función desde la Vista. He probado quitando los argumentos y sólo llamando a la función, pero claro, el modelo al recibirla no recibe el argumento sobre el que debe trabajar (título). He probado utilizando una lambda, pero tampoco.

Espero me haya podido explicar y me den una mano, porque no le estoy encontrando la vuelta que de seguro es un detalle mínimo.

Saludos.
Responder
#2
Hola, Diego.

Hay una diferencia entre esto:

Código:
combo.bind("<<ComboboxSelected>>", funcion())

Y esto:

Código:
combo.bind("<<ComboboxSelected>>", funcion)

En el primer caso se llama a la función y se pasa su valor de retorno como segundo argumento de bind(). En el segundo caso se pasa la función misma como argumento. Esto segundo es lo que vos querés. Sin embargo, el método bind() no te permite especificar qué argumentos debe usar para llamar a la función posteriormente, cuando ocurra el evento <<ComboboxSelected>>. Entonces hay que usar functools.partial():

Código:
from functools import partial

titulo_entry.bind("<<ComboboxSelected>>", partial(modelo.consxtit, titulo.get(), isbn))

Tené en cuenta que el titulo.get() se ejecuta al momento en que se asocia el evento (o sea, en la inicialización del programa), no cuando ocurre. Por ende probablemente ese segundo argumento siempre sea una cadena vacía. Te conviene pasarlo así:

Código:
titulo_entry.bind("<<ComboboxSelected>>", partial(modelo.consxtit, titulo, isbn))

Y luego llamar al .get() dentro de la función consxtit().

Saludos
¡No te pierdas nuestro curso oficial en Udemy para aprender Python, bases de datos SQL, orientación a objetos, tkinter y mucho más!

También ofrecemos consultoría profesional de desarrollo en Python para personas y empresas.
Responder
#3
Hola Francisco. Te cuento que he probado ambos métodos (titulo_entry.bind("<<ComboboxSelected>>", partial(modelo.consxtit, titulo.get(), isbn)) y titulo_entry.bind("<<ComboboxSelected>>", partial(modelo.consxtit, titulo, isbn))) y me devuelve el mismo mensaje:


TypeError: consxtit() takes 2 positional arguments but 3 were given

No sé por qué cuenta tres argumentos.
Responder
#4
Un momento, un momento. Un comentario en tu respuesta me dejó pensando, así que hice una prueba y... ¡socorro!!!

Me he dado cuenta que la línea "titulo_entry['values']=modelo.combo_input()" sólo muestra los valores del Combobox al momento de iniciar el programa. Si posteriormente, durante la ejecución del mismo, llamo a una función que agrega un título a la base (pongámosle "agregar"), ese nuevo valor no se muestra hasta que no se cierre y se abra de nuevo el programa.
Intentando solucionarlo, realicé una llamada a la función "combo_input()" dentro de la función "agregar", pero tampoco resulta.

Este inconveniente se me transformó en prioritario ya que, en todo caso, la función vinculada al <ComboboxSelected>> la puedo quitar y enviarla a un botón, quitándome el problema de encima. Pero esto de que no me actualice los valores del Combobox me pone mal.
Responder
#5
(03-07-2023, 11:30 PM)Diego escribió: Hola Francisco. Te cuento que he probado ambos métodos (titulo_entry.bind("<<ComboboxSelected>>", partial(modelo.consxtit, titulo.get(), isbn)) y titulo_entry.bind("<<ComboboxSelected>>", partial(modelo.consxtit, titulo, isbn))) y me devuelve el mismo mensaje:


TypeError: consxtit() takes 2 positional arguments but 3 were given

No sé por qué cuenta tres argumentos.

Tk pasa un argumento extra con información del evento, así que deberías agregarlo a tu función, aunque no vayas a usarlo:

Código:
def consxtit(titulo, isbn, event):

Saludos
¡No te pierdas nuestro curso oficial en Udemy para aprender Python, bases de datos SQL, orientación a objetos, tkinter y mucho más!

También ofrecemos consultoría profesional de desarrollo en Python para personas y empresas.
Responder
#6
(04-07-2023, 06:53 PM)Diego escribió: Un momento, un momento. Un comentario en tu respuesta me dejó pensando, así que hice una prueba y... ¡socorro!!!

Me he dado cuenta que la línea "titulo_entry['values']=modelo.combo_input()" sólo muestra los valores del Combobox al momento de iniciar el programa. Si posteriormente, durante la ejecución del mismo, llamo a una función que agrega un título a la base (pongámosle "agregar"), ese nuevo valor no se muestra hasta que no se cierre y se abra de nuevo el programa.
Intentando solucionarlo, realicé una llamada a la función "combo_input()" dentro de la función "agregar", pero tampoco resulta.

Este inconveniente se me transformó en prioritario ya que, en todo caso, la función vinculada al <ComboboxSelected>> la puedo quitar y enviarla a un botón, quitándome el problema de encima. Pero esto de que no me actualice los valores del Combobox me pone mal.

Eso es correcto: Tk no es "reactivo". Si tu fuente de datos cambia, tenés que ocuparte de ejecutar nuevamente esta línea para actualizar los datos:

Código:
titulo_entry['values']=modelo.combo_input() 

Saludos
¡No te pierdas nuestro curso oficial en Udemy para aprender Python, bases de datos SQL, orientación a objetos, tkinter y mucho más!

También ofrecemos consultoría profesional de desarrollo en Python para personas y empresas.
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)