Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Scrollbar tkinter con mousewheel
#1
Buenas:

Tengo este código para que una scrollbar funcione con la rueda del ratón.

  1. self.topCCL = tk.Toplevel()
  2. self.topCCL.title("CENTRO DE CONTROL LOGÍSTICO")
  3. self.topCCL.geometry('800x600')
  4. self.topCCL.resizable(True, True)
  5.    
  6.     # Función scrollbar abajo principal de ccl.
  7.    
  8. def mouse_scroll(event):
  9. self.canvasccl.yview_scroll(-3, "units")
  10.  
  11.     # Función scrollbar arriba principal de ccl.
  12.    
  13. def mouse_scroll01(event):
  14. self.canvasccl.yview_scroll(3, "units")
  15.  
  16. self.frameccl = ttk.Frame(self.topCCL, width=1920, height=1080)
  17. self.frameccl.grid(row=0, column=0)
  18.  
  19. self.scrollccl = ttk.Scrollbar(self.frameccl, orient='vertical', style="S.Vertical.TScrollbar")
  20. self.scrollccl.grid(row=0, column=1, sticky=tk.N+tk.S)
  21.  
  22. self.canvasccl = tk.Canvas(self.frameccl,  scrollregion=(0,0,1250,1250), width=1900, height=1010, yscrollcommand=self.scrollccl.set)#background='#363232'
  23. self.canvasccl.grid(row=0, column=0, sticky=tk.N+tk.S+tk.E+tk.W)
  24. self.canvasccl.bind_all("<Button-4>", mouse_scroll)
  25. self.canvasccl.bind_all("<Button-5>", mouse_scroll01)
  26.  
  27. self.scrollccl.configure(command=self.canvasccl.yview)
  28.  
  29. self.canvasccl.configure(scrollregion=self.canvasccl.bbox("all"))
  30.  
  31. self.frame_canccl = ttk.Frame(self.canvasccl, style="Frames02.TFrame")
  32.  
  33. self.canvasccl.create_window(0,0, window=self.frame_canccl, anchor='nw')



Todo funciona correctamente pero me surge un problema incómodo. Mi app tiene varias ventanas que se abren al mismo tiempo. Me he dado cuenta que independientemente de en la ventana en la que me encuentre interactuando, si muevo la rueda del ratón el scrollbar funciona y sube y baja. Es incómodo porque lo que yo quiero es que baje y suba pero solo cuando esté interactuando en la ventana dónde está esta scrollbar no desde todas. Imagino que tiene que ver con el .bind_all pero no doy con la solución.

Muchas Gracias.
Responder
#2
Hola.

¿Podés reproducir el problema en un código más simple, que podamos copiar y pegar y probar?

Saludos
Responder
#3
Ahí va:

Os pongo un ejemplo con un combobox porque es dónde mejor se ve el problema y fue cuando me dí cuenta.

  1. import tkinter as tk
  2. from tkinter import ttk
  3. from datetime import *
  4. from tkinter import messagebox
  5. import time
  6. import calendar
  7. import psycopg2
  8. import threading
  9. from threading import Timer
  10. import os
  11. import sys
  12. import tkinter.font as tkfont
  13. from functools import partial
  14. import subprocess
  15. import smtplib
  16. from email.mime.multipart import MIMEMultipart
  17. from email.mime.text import MIMEText
  18. from email.mime.base import MIMEBase
  19. from email import encoders
  20.  
  21. class Prueba:
  22.    
  23.     def __init__(self):           
  24.            
  25.             # Ventana principal.
  26.            
  27.             self.win = tk.Tk()
  28.             self.win.title('PRUEBAS')
  29.             self.win.geometry('400x400+600+0')
  30.             self.win.configure(background='black')
  31.             self.win.resizable(False,False)
  32.            
  33.             # Ventana Secundaria.
  34.            
  35.             self.win1 = tk.Toplevel()
  36.             self.win1.title('PRUEBAS 1')
  37.             self.win1.geometry('400x400+100+0')
  38.             self.win1.resizable(False,False)
  39.            
  40.             # Lista de valores del combobox.
  41.            
  42.             lista= ["PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA"
  43.             , "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA"]
  44.            
  45.             # Función para scrollbar hacia abajo con rueda del ratón.
  46.            
  47.             def mouse_scroll(event):
  48.                   self.canvas.yview_scroll(-3, "units")
  49.          
  50.           # Función para scrollbar hacia arriba con rueda del ratón.     
  51.            
  52.             def mouse_scroll01(event):
  53.                   self.canvas.yview_scroll(3, "units")           
  54.            
  55.             # Frame para contener el canvas dónde se alojarán los widgets.
  56.            
  57.             self.frame = ttk.Frame(self.win)
  58.             self.frame.grid(row=0, column=0)
  59.            
  60.             # Estilo personalizado para el scrollbar.
  61.            
  62.             self.stylescroll = ttk.Style()
  63.             self.stylescroll.configure("S.Vertical.TScrollbar", background='light green', troughcolor='beige')
  64.             self.stylescroll.map("S.Vertical.TScrollbar", background=[('active','yellow')], troughcolor=[('active', 'red')])       
  65.  
  66. # Scrollbar de la ventana principal.
  67.  
  68.             self.scroll = ttk.Scrollbar(self.frame, orient='vertical', style="S.Vertical.TScrollbar")
  69.             self.scroll.grid(row=0, column=1, sticky=tk.N+tk.S)
  70.            
  71.             # Canvas dónde irá alojado el scrollbar.
  72.            
  73.             self.canvas = tk.Canvas(self.frame, scrollregion=(0,0,2000,2000), width=385, height=385, yscrollcommand=self.scroll.set)
  74.             self.canvas.grid(row=0, column=0, sticky=tk.N+tk.S+tk.E+tk.W)
  75.             self.canvas.bind_all("<Button-4>", mouse_scroll)
  76.             self.canvas.bind_all("<Button-5>", mouse_scroll01)
  77.            
  78.             self.scroll.configure(command=self.canvas.yview)
  79.            
  80.             self.canvas.config(scrollregion=self.canvas.bbox("all"))
  81.            
  82.             self.frame_can = ttk.Frame(self.canvas)
  83.            
  84.             self.canvas.create_window(0,0, window=self.frame_can, anchor='nw')
  85.            
  86.             # Etiqueta para hacer la prueba y comprobar que funciona el scrollbar con la rueda del ratón.
  87.            
  88.             self.et01 = ttk.Label(self.frame_can, text='HOLA MUNDO')
  89.             self.et01.grid(row=0, column=0)
  90.            
  91.             # Combobox en la ventana secundaria para pruebas con scrollbar.
  92.            
  93.             self.comb01 = ttk.Combobox(self.win1)
  94.             self.comb01.grid(row=0, column=0, padx=10, pady=10)
  95.             self.comb01["values"]= lista
  96.            
  97.             self.win.mainloop()
  98.  
  99. def main():
  100.     myapp = Prueba()
  101.  
  102. if __name__ == '__main__':
  103.     main()


Bien la app crea dos ventanas una con scrollbar y la otra no. Una vez iniciada la app comprobamos que el scrollbar funciona correctamente con la rueda del ratón y si bajamos hacia abajo la etiqueta de prueba desaparece. Pero si hacemos focus en la otra ventana y volvemos a mover la rueda del ratón comprobamos que el scrollbar de la pantalla principal sigue moviéndose. Lo veréis mejor haciendo focus en el combobox y utilizando la rueda del ratón para desplazarte por la lista de elementos del combobox.

Si os dáis cuenta si utilizas la rueda del ratón para bajar en los elementos del combobox efectivamente funciona la barra del combobox pero curiosamente también baja la barra del scrollbar de la ventana principal haciendo que desaparezca la etiqueta.
Responder
#4
Ah, ya veo. Podrías poner un condicional en las funciones asociadas a los eventos, para que solo respondan si provienen del canvas:

  1. # Función para scrollbar hacia abajo con rueda del ratón.
  2.  
  3. def mouse_scroll(event):
  4. if event.widget == self.canvas:
  5. self.canvas.yview_scroll(-3, "units")
  6.  
  7. # Función para scrollbar hacia arriba con rueda del ratón.
  8.  
  9. def mouse_scroll01(event):
  10. if event.widget == self.canvas:
  11. self.canvas.yview_scroll(3, "units")


Saludos!
Responder
#5
Muchísimas gracias Francisco. Por internet era imposible encontrar la solución, aunque para mi app no sirve desconozco el motivo.(Haré más pruebas a ver si veo que es lo que pasa porque en la aplicación esa si funciona). Hay muy poca información al respecto sobre tkinter y las scrollbar.

Pasa como con la poca información que encuentro para los style layout. ¿No sabrás de algún sitio con buena documentación sobre el diseño de widgets en Tkinter?. Me da igual que esté en inglés.
Responder
#6
¡De nada! Efectivamente la documentación de Tk, al menos en Python, es bastante escasa. Yo estoy tratando de suplir cada tanto esa escasez con algún que otro artículo. Te dejo uno de los últimos sobre los estilos en Tk: https://recursospython.com/guias-y-manua...n-tkinter/. También una buena referencia sobre el tema (en inglés) es esta: https://tkdocs.com/tutorial/styles.html. La documentación oficial de Tcl/Tk es un poco árida, además de que está hecha para Tcl, no para Python; pero eventualmente puede servir: https://www.tcl.tk/man/tcl8.6/contents.htm.

Saludos
Responder
#7
Muchas gracias de nuevo!!!!!!. Ya encontré el problema en mi app y es que la ventana dónde tengo la scrollbar tiene otros canvas con su scrollbar correspondiente y claro en la condición hay que especificar todos y cada uno de los canvas para que funcione pero ya esta solucionado. un "if" y varios "or" y solucionado el problema.
Responder
#8
¡Excelente! Smile
Responder
#9
Os remito otro pequeño problemilla que me ha surgido con las scrollbar:

  1. import tkinter as tk
  2. from tkinter import ttk
  3. from datetime import *
  4. from tkinter import messagebox
  5. import time
  6. import calendar
  7. import psycopg2
  8. import threading
  9. from threading import Timer
  10. import os
  11. import sys
  12. import tkinter.font as tkfont
  13. from functools import partial
  14. import subprocess
  15. import smtplib
  16. from email.mime.multipart import MIMEMultipart
  17. from email.mime.text import MIMEText
  18. from email.mime.base import MIMEBase
  19. from email import encoders
  20.  
  21. class Prueba:
  22.    
  23.     def __init__(self):
  24.            
  25. ############################### MAIN WINDOW ##########################
  26.            
  27.             self.win = tk.Tk()
  28.             self.win.title('PRUEBAS')
  29.             self.win.geometry('400x400+200+0')
  30.             self.win.resizable(False,False)
  31.            
  32.             def clowin():
  33.                   self.win.destroy()
  34.            
  35.             def opwin():
  36.                  
  37.                   def clotop():
  38.                         self.win1.destroy()
  39.                  
  40.                   def mouse_scroll2(event):
  41.                         if event.widget == self.scroll1:
  42.                               self.canvas1.yview_scroll(-10, tk.UNITS)
  43.                  
  44.                   def mouse_scroll02(event):
  45.                         if event.widget == self.scroll1:
  46.                               self.canvas1.yview_scroll(10, tk.UNITS)
  47.                  
  48.                   self.win1 = tk.Toplevel()
  49.                   self.win1.title('PRUEBAS 1')
  50.                   self.win1.geometry('400x400')
  51.                   self.win1.resizable(False,False)
  52.                  
  53.                   self.frame1 = ttk.Frame(self.win1)           
  54.                   self.frame1.grid(row=0, column=0)
  55.                  
  56.                   self.scroll1 = ttk.Scrollbar(self.frame1, orient='vertical')
  57.                   self.scroll1.grid(row=0, column=1, sticky=tk.N+tk.S)
  58.                  
  59.                   self.canvas1 = tk.Canvas(self.frame1, scrollregion=(0,0,2000,2000), width=385, height=385, yscrollcommand=self.scroll1.set)
  60.                   self.canvas1.grid(row=0, column=0, sticky=tk.N+tk.S)
  61.                   self.canvas1.bind_all("<Button-4>", mouse_scroll2)
  62.                   self.canvas1.bind_all("<Button-5>", mouse_scroll02)
  63.                  
  64.                   self.et1 = ttk.Label(self.canvas1, text='Probando las scrollbar', font=('DejaVu Serif Condensed', 20, 'bold'))
  65.                   self.et1.grid(row=0, column=0)
  66.                  
  67.                   self.et2 = ttk.Label(self.canvas1, text='Probando las scrollbar', font=('DejaVu Serif Condensed', 20, 'bold'))
  68.                   self.et2.grid(row=1, column=0)
  69.                  
  70.                   self.but3 = ttk.Button(self.canvas1, text='Cerrar', command=clotop)
  71.                   self.but3.grid(row=2, column=0)
  72.                  
  73.                   self.scroll1.configure(command=self.canvas1.yview)
  74.            
  75.                   self.canvas1.config(scrollregion=self.canvas1.bbox("all"))
  76.            
  77.                   self.frame_can1 = ttk.Frame(self.canvas1)
  78.            
  79.                   self.canvas1.create_window(0,0, window=self.frame_can1, anchor='nw')
  80.                  
  81.             def mouse_scroll(event):
  82.                   if event.widget == self.scroll:
  83.                         self.canvas.yview_scroll(-10, tk.UNITS)
  84.                  
  85.             def mouse_scroll01(event):
  86.                   if event.widget == self.scroll:
  87.                         self.canvas.yview_scroll(10, tk.UNITS)
  88.            
  89.             self.frame = ttk.Frame(self.win)           
  90.             self.frame.grid(row=0, column=0)
  91.            
  92.             self.scroll = ttk.Scrollbar(self.frame, orient='vertical')
  93.             self.scroll.grid(row=0, column=1, sticky=tk.N+tk.S)
  94.            
  95.             self.canvas = tk.Canvas(self.frame, scrollregion=(0,0,2000,2000), width=385, height=385, yscrollcommand=self.scroll.set)
  96.             self.canvas.grid(row=0, column=0, sticky=tk.N+tk.S)
  97.             self.canvas.bind_all("<Button-4>", mouse_scroll)
  98.             self.canvas.bind_all("<Button-5>", mouse_scroll01)
  99.            
  100.             self.scroll.configure(command=self.canvas.yview)
  101.            
  102.             self.canvas.config(scrollregion=self.canvas.bbox("all"))
  103.            
  104.             self.frame_can = ttk.Frame(self.canvas)
  105.            
  106.             self.canvas.create_window(0,0, window=self.frame_can, anchor='nw')           
  107.            
  108.             self.but1 = ttk.Button(self.canvas, text='Abrir', command=opwin)
  109.             self.but1.grid(row=0, column=0)
  110.            
  111.             self.but2 = ttk.Button(self.canvas, text='Cerrar', command=clowin)
  112.             self.but2.grid(row=1, column=0)
  113.            
  114.             self.win.mainloop()
  115.  
  116. def main():
  117.     myapp = Prueba()
  118.  
  119. if __name__ == '__main__':
  120.     main()


Bien en la app se abre una ventana con una scrollbar. En principio la scrollbar funciona perfectamente con la rueda del ratón. Hay también un botón que abre otra ventana con su correspondiente scrollbar. Nada más abrir esa ventana la scrollbar de la misma funciona correctamente con la rueda del ratón. Pero curiosamente la scrollbar de la ventana principal deja de funcionar con la rueda del ratón.

Creo que tiene que ver con el .bind_all(). He probado con unbind_all(), unbind() y nada ha funcionado. Creo que la solución sería "reactivar" por decirlo de alguna manera los bind, pero al estar en otro archivo y a pesar de tenerlo todo importado no doy con la solución. ¿Alguna sugerencia?

Muchas gracias.
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)