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.

Código:
self.topCCL = tk.Toplevel()
self.topCCL.title("CENTRO DE CONTROL LOGÍSTICO")
self.topCCL.geometry('800x600')
self.topCCL.resizable(True, True)
   
    # Función scrollbar abajo principal de ccl.
   
def mouse_scroll(event):
self.canvasccl.yview_scroll(-3, "units")

    # Función scrollbar arriba principal de ccl.
   
def mouse_scroll01(event):
self.canvasccl.yview_scroll(3, "units")

self.frameccl = ttk.Frame(self.topCCL, width=1920, height=1080)
self.frameccl.grid(row=0, column=0)

self.scrollccl = ttk.Scrollbar(self.frameccl, orient='vertical', style="S.Vertical.TScrollbar")
self.scrollccl.grid(row=0, column=1, sticky=tk.N+tk.S)

self.canvasccl = tk.Canvas(self.frameccl,  scrollregion=(0,0,1250,1250), width=1900, height=1010, yscrollcommand=self.scrollccl.set)#background='#363232'
self.canvasccl.grid(row=0, column=0, sticky=tk.N+tk.S+tk.E+tk.W)
self.canvasccl.bind_all("<Button-4>", mouse_scroll)
self.canvasccl.bind_all("<Button-5>", mouse_scroll01)

self.scrollccl.configure(command=self.canvasccl.yview)

self.canvasccl.configure(scrollregion=self.canvasccl.bbox("all"))

self.frame_canccl = ttk.Frame(self.canvasccl, style="Frames02.TFrame")

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
¡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
Ahí va:

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

Código:
import tkinter as tk
from tkinter import ttk
from datetime import *
from tkinter import messagebox
import time
import calendar
import psycopg2
import threading
from threading import Timer
import os
import sys
import tkinter.font as tkfont
from functools import partial
import subprocess
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders

class Prueba:
   
    def __init__(self):           
           
            # Ventana principal.
           
            self.win = tk.Tk()
            self.win.title('PRUEBAS')
            self.win.geometry('400x400+600+0')
            self.win.configure(background='black')
            self.win.resizable(False,False)
           
            # Ventana Secundaria.
           
            self.win1 = tk.Toplevel()
            self.win1.title('PRUEBAS 1')
            self.win1.geometry('400x400+100+0')
            self.win1.resizable(False,False)
           
            # Lista de valores del combobox.
           
            lista= ["PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA"
            , "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA","PRUEBA", "PRUEBA"]
           
            # Función para scrollbar hacia abajo con rueda del ratón.
           
            def mouse_scroll(event):
                  self.canvas.yview_scroll(-3, "units")
         
          # Función para scrollbar hacia arriba con rueda del ratón.     
           
            def mouse_scroll01(event):
                  self.canvas.yview_scroll(3, "units")           
           
            # Frame para contener el canvas dónde se alojarán los widgets.
           
            self.frame = ttk.Frame(self.win)
            self.frame.grid(row=0, column=0)
           
            # Estilo personalizado para el scrollbar.
           
            self.stylescroll = ttk.Style()
            self.stylescroll.configure("S.Vertical.TScrollbar", background='light green', troughcolor='beige')
            self.stylescroll.map("S.Vertical.TScrollbar", background=[('active','yellow')], troughcolor=[('active', 'red')])       

# Scrollbar de la ventana principal.

            self.scroll = ttk.Scrollbar(self.frame, orient='vertical', style="S.Vertical.TScrollbar")
            self.scroll.grid(row=0, column=1, sticky=tk.N+tk.S)
           
            # Canvas dónde irá alojado el scrollbar.
           
            self.canvas = tk.Canvas(self.frame, scrollregion=(0,0,2000,2000), width=385, height=385, yscrollcommand=self.scroll.set)
            self.canvas.grid(row=0, column=0, sticky=tk.N+tk.S+tk.E+tk.W)
            self.canvas.bind_all("<Button-4>", mouse_scroll)
            self.canvas.bind_all("<Button-5>", mouse_scroll01)
           
            self.scroll.configure(command=self.canvas.yview)
           
            self.canvas.config(scrollregion=self.canvas.bbox("all"))
           
            self.frame_can = ttk.Frame(self.canvas)
           
            self.canvas.create_window(0,0, window=self.frame_can, anchor='nw')
           
            # Etiqueta para hacer la prueba y comprobar que funciona el scrollbar con la rueda del ratón.
           
            self.et01 = ttk.Label(self.frame_can, text='HOLA MUNDO')
            self.et01.grid(row=0, column=0)
           
            # Combobox en la ventana secundaria para pruebas con scrollbar.
           
            self.comb01 = ttk.Combobox(self.win1)
            self.comb01.grid(row=0, column=0, padx=10, pady=10)
            self.comb01["values"]= lista
           
            self.win.mainloop()

def main():
    myapp = Prueba()

if __name__ == '__main__':
    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:

Código:
# Función para scrollbar hacia abajo con rueda del ratón.

def mouse_scroll(event):
    if event.widget == self.canvas:
        self.canvas.yview_scroll(-3, "units")

# Función para scrollbar hacia arriba con rueda del ratón.      

def mouse_scroll01(event):
    if event.widget == self.canvas:
        self.canvas.yview_scroll(3, "units")

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
#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
¡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
#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
¡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
#9
Os remito otro pequeño problemilla que me ha surgido con las scrollbar:

Código:
import tkinter as tk
from tkinter import ttk
from datetime import *
from tkinter import messagebox
import time
import calendar
import psycopg2
import threading
from threading import Timer
import os
import sys
import tkinter.font as tkfont
from functools import partial
import subprocess
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders

class Prueba:
   
    def __init__(self):
           
############################### MAIN WINDOW ##########################
           
            self.win = tk.Tk()
            self.win.title('PRUEBAS')
            self.win.geometry('400x400+200+0')
            self.win.resizable(False,False)
           
            def clowin():
                  self.win.destroy()
           
            def opwin():
                 
                  def clotop():
                        self.win1.destroy()
                 
                  def mouse_scroll2(event):
                        if event.widget == self.scroll1:
                              self.canvas1.yview_scroll(-10, tk.UNITS)
                 
                  def mouse_scroll02(event):
                        if event.widget == self.scroll1:
                              self.canvas1.yview_scroll(10, tk.UNITS)
                 
                  self.win1 = tk.Toplevel()
                  self.win1.title('PRUEBAS 1')
                  self.win1.geometry('400x400')
                  self.win1.resizable(False,False)
                 
                  self.frame1 = ttk.Frame(self.win1)           
                  self.frame1.grid(row=0, column=0)
                 
                  self.scroll1 = ttk.Scrollbar(self.frame1, orient='vertical')
                  self.scroll1.grid(row=0, column=1, sticky=tk.N+tk.S)
                 
                  self.canvas1 = tk.Canvas(self.frame1, scrollregion=(0,0,2000,2000), width=385, height=385, yscrollcommand=self.scroll1.set)
                  self.canvas1.grid(row=0, column=0, sticky=tk.N+tk.S)
                  self.canvas1.bind_all("<Button-4>", mouse_scroll2)
                  self.canvas1.bind_all("<Button-5>", mouse_scroll02)
                 
                  self.et1 = ttk.Label(self.canvas1, text='Probando las scrollbar', font=('DejaVu Serif Condensed', 20, 'bold'))
                  self.et1.grid(row=0, column=0)
                 
                  self.et2 = ttk.Label(self.canvas1, text='Probando las scrollbar', font=('DejaVu Serif Condensed', 20, 'bold'))
                  self.et2.grid(row=1, column=0)
                 
                  self.but3 = ttk.Button(self.canvas1, text='Cerrar', command=clotop)
                  self.but3.grid(row=2, column=0)
                 
                  self.scroll1.configure(command=self.canvas1.yview)
           
                  self.canvas1.config(scrollregion=self.canvas1.bbox("all"))
           
                  self.frame_can1 = ttk.Frame(self.canvas1)
           
                  self.canvas1.create_window(0,0, window=self.frame_can1, anchor='nw')
                 
            def mouse_scroll(event):
                  if event.widget == self.scroll:
                        self.canvas.yview_scroll(-10, tk.UNITS)
                 
            def mouse_scroll01(event):
                  if event.widget == self.scroll:
                        self.canvas.yview_scroll(10, tk.UNITS)
           
            self.frame = ttk.Frame(self.win)           
            self.frame.grid(row=0, column=0)
           
            self.scroll = ttk.Scrollbar(self.frame, orient='vertical')
            self.scroll.grid(row=0, column=1, sticky=tk.N+tk.S)
           
            self.canvas = tk.Canvas(self.frame, scrollregion=(0,0,2000,2000), width=385, height=385, yscrollcommand=self.scroll.set)
            self.canvas.grid(row=0, column=0, sticky=tk.N+tk.S)
            self.canvas.bind_all("<Button-4>", mouse_scroll)
            self.canvas.bind_all("<Button-5>", mouse_scroll01)
           
            self.scroll.configure(command=self.canvas.yview)
           
            self.canvas.config(scrollregion=self.canvas.bbox("all"))
           
            self.frame_can = ttk.Frame(self.canvas)
           
            self.canvas.create_window(0,0, window=self.frame_can, anchor='nw')           
           
            self.but1 = ttk.Button(self.canvas, text='Abrir', command=opwin)
            self.but1.grid(row=0, column=0)
           
            self.but2 = ttk.Button(self.canvas, text='Cerrar', command=clowin)
            self.but2.grid(row=1, column=0)
           
            self.win.mainloop()

def main():
    myapp = Prueba()

if __name__ == '__main__':
    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)