Topic: larghezza frame e scrollbar  (Letto 64 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline Alberto_aliberti

  • python unicellularis
  • *
  • Post: 10
  • Punti reputazione: 0
    • Mostra profilo
larghezza frame e scrollbar
« il: Gennaio 12, 2022, 16:23 »
Buongiorno a tutti,
Ho scritto un codice che crea una finestra con la scrollbar.
Funziona bene, l'unica cosa è che se riduco la dimensione orizzondare della finestra principale sotto i 400, la scrollbar scompare, qualcuno potrebbe spiegarmi il motivo ?

ecco il codice:


import tkinter as tk
from tkinter import ttk


class ScrollableFrame(ttk.Frame):
    def __init__(self, container, *args, **kwargs):
        super().__init__(container, *args, **kwargs)
        canvas = tk.Canvas(self)
        scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
        self.scrollable_frame = ttk.Frame(canvas)

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")

        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")


root = tk.Tk()
root.geometry("400x300")
 
frame1 = ScrollableFrame(root)
frame1.pack()

for i in range(100):
    tk.Button(frame1.scrollable_frame, text=f"Button {i}").grid(row=i, column=0, padx=10, pady=10)

root.mainloop()

Offline nuzzopippo

  • python sapiens
  • *****
  • Post: 541
  • Punti reputazione: 0
    • Mostra profilo
Re:larghezza frame e scrollbar
« Risposta #1 il: Gennaio 13, 2022, 09:44 »
La scrollbar scompare perché frame1 NON viene ridimensionato assieme alla finestra, rimane delle dimensioni iniziali in sostanza, e quindi la posizione della scrollbar cade all'estero della finestra e "sparisce", prova a variarne il pack in questo modo
frame1.pack(fill='both', expand=True)

il problema si risolverà

Offline Alberto_aliberti

  • python unicellularis
  • *
  • Post: 10
  • Punti reputazione: 0
    • Mostra profilo
Re:larghezza frame e scrollbar
« Risposta #2 il: Gennaio 13, 2022, 12:30 »
Grazie Nuzzopippo, potresti consigliarmi un libro per tkinter?
Come faccio a collegare la scollbar con la rotellina del mouse?
Comunque ho provato e ha lostesso qualche probelma

ecco il codice:

import tkinter as tk
from tkinter import ttk


class ScrollableFrame(ttk.Frame):
    def __init__(self, container, *args, **kwargs):
        super().__init__(container, *args, **kwargs)
        canvas = tk.Canvas(self)
        scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
        self.scrollable_frame = ttk.Frame(canvas)

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")

        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")


root = tk.Tk()
root.geometry("300x300")
 
frame1 = ScrollableFrame(root)
frame1.pack(fill='both', expand=True)

for i in range(100):
    tk.Button(frame1.scrollable_frame, text=f"Button {i}").grid(row=i, column=0, padx=10, pady=10)

root.mainloop()
« Ultima modifica: Gennaio 13, 2022, 14:52 da Alberto_aliberti »

Offline nuzzopippo

  • python sapiens
  • *****
  • Post: 541
  • Punti reputazione: 0
    • Mostra profilo
Re:larghezza frame e scrollbar
« Risposta #3 il: Gennaio 13, 2022, 15:34 »
Riguardo alla "rotellina", dipende dal sistema operativo che utilizzi, bisogna fare il binding del mouse, sotto windows si intercetta l'evento "<MouseWheel>" che nel caso di Linux (il mio s.o.) non esiste e si intercettano gli eventi "<Button-4>" (scroll su) e "<Button-5>" (scroll giù) ... riguardo al Tuo problema presente "comunque" è dato dalle dimensione degli elementi non fissate e di default, ovviamente il canvas NON diminuisce la sua dimensione minima all'eccessivo ridursi della finestra, superata una certa soglia la riduzione porta la non visibilità di ciò che eccede la finestra attiva.
Nelle mie applicazioni uso non definire una dimensione per la finestra ma, dopo aver istanziato tutti i controlli necessari alle loro dimensioni di default aggiornare la finestra e fissare le dimensioni che assume quale minime.

Ti esemplifico il Tuo codice intercettando e gestendo la rotella del mouse con la scrollbar e fissando le dimensioni minime della finestra dopo la sua definizione (quando inserisci il codice utilizza in pulsante "pythoncode" dell'editor dei post
import tkinter as tk
from tkinter import ttk


class ScrollableFrame(ttk.Frame):
    def __init__(self, container, *args, **kwargs):
        super().__init__(container, *args, **kwargs)
        self.canvas = tk.Canvas(self)
        scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        self.scrollable_frame = ttk.Frame(self.canvas)

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(
                scrollregion=self.canvas.bbox("all")
            )
        )

        self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")

        self.canvas.configure(yscrollcommand=scrollbar.set)

        self.canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        # per Windows
        #scrollbar.bind('<MouseWheel>', self._on_mousewheel)
        # per linux
        scrollbar.bind('<Button-4>', self._on_mousewheel)
        scrollbar.bind('<Button-5>', self._on_mousewheel)

    def _on_mousewheel(self, evt):
        #self.canvas.yview_scroll(-(evt.delta/120), 'units')
        move = 0
        if evt.num == 5 or evt.delta == -120:
            move = -1
        elif evt.num == 4 or evt.delta == 120:
            move = 1
        else:
            return
        self.canvas.yview_scroll(move, 'units')


root = tk.Tk()
#root.geometry("400x300")
 
frame1 = ScrollableFrame(root)
frame1.pack(fill='both', expand=True)

for i in range(100):
    tk.Button(frame1.scrollable_frame, text=f"Button {i}").grid(row=i, column=0, padx=10, pady=10)

root.update()
l = root.winfo_reqwidth()
h = root.winfo_reqheight()
root.minsize(l, h)

root.mainloop()


Riguardo al libro su tkinter, mi dispiace, non ne conosco, io ho imparato ciò che a me è servito da questa documentazione ed una enormità di prove e ricerche in internet (San Google fa miracoli) ... certo, avevo una esperienza pregressa sulle interfacce grafiche ed avevo idea di cosa cercare.

Offline Alberto_aliberti

  • python unicellularis
  • *
  • Post: 10
  • Punti reputazione: 0
    • Mostra profilo
Re:larghezza frame e scrollbar
« Risposta #4 il: Gennaio 13, 2022, 18:48 »
Grazie, Quindi non si può costruire un Frame con scollbar che sia più corto di 400? neanche trovando un alternativa alla canvas?
Si possono usare 2 laout manager diversi(come ad esempio.grid e .place) in 2 frame diversi?
« Ultima modifica: Gennaio 13, 2022, 20:09 da Alberto_aliberti »

Offline nuzzopippo

  • python sapiens
  • *****
  • Post: 541
  • Punti reputazione: 0
    • Mostra profilo
Re:larghezza frame e scrollbar
« Risposta #5 il: Gennaio 13, 2022, 21:37 »
Grazie, Quindi non si può costruire un Frame con scollbar che sia più corto di 400? neanche trovando un alternativa alla canvas?
Certo che si può, ed utilizzando i canvas, pure! Se guardi la documentazione che Ti ho lincato vedrai che il canvas ha le proprietà "width" ed "height" che puoi utilizzare per impostarlo direttamente, inoltre i controlli si adatteranno alle dimensioni definite per la finestra, però stabiliranno anche delle "dimensioni minime" coerenti con il contesto impostato, al di sotto delle quali (sommate ovviamente) cominceranno a non essere visualizzati perché lo spazio della finestra è insufficiente.

Il fatto che io normalmente non forzi il dimensionamento dei vari widget non significa che non lo faccia se mi è opportuno ma, in genere, il dimensionamento di default è ragionevolmente accettabile per le varie tipologie di controlli ed equilibrato per il sistema in uso, pertanto se non ho necessità particolari trovo logico accettare i dimensionamenti standard ed adeguare le dimensioni minime della finestra in modo che la stessa non possa essere ridotta in maniera tale da coprire i controlli. È semplice e mi evita una caterva di elementi da considerare facendo altrimenti.
Leggi la docs e fai qualche prova per conto Tuo, poi fai conoscere il Tuo pensiero.

Si possono usare 2 laout manager diversi(come ad esempio.grid e .place) in 2 frame diversi?
Certo che si, si possono usare anche tutti e tre i layout-manager disponibili (place-pack-grid) contemporaneamente ... a patto di sapere cosa si fa.
Funzionano in maniera differente tra loro e può essere complicato equilibrarli se non si è ben capito come funzionano, ed anche avendoli studiati approfonditamente a volte possono capitare visualizzazioni inaspettate, semplicemente perché non si è ben considerato un qualche fattore ... ancora una volta è una questione di quante "energie" si vogliano dedicare ad una particolare impostazione, personalmente trovo opportune le soluzioni quanto più lineari e dirette possibili, applicare una singola logica, invece di due (o tre), confonde meno le idee e rende più semplice leggere (e mantenere) il codice dopo un po' di tempo ... poi, è una questione di gusti personali, c'è chi ama l'avventura ;)
« Ultima modifica: Gennaio 13, 2022, 21:41 da nuzzopippo »