Problem mit X_Scrollbar

Fragen zu Tkinter.
Antworten
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,

ich habe eine GUI mit tkinter erstellt und eine X_Scrollbar ist eingerichtet.
Bei überlangen Texten, lässt sich die Scrollbar zwar bewegen, aber der Fensterinhalt bewegt sich nicht.

Nachfolgender Code ist lauffähig und sollte zum Testen funktionieren.
Vielleicht fällt Euch der Fehler auf, dass zwar die Scrollbar sich bewegt aber das Fenster nicht!

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x

import tkinter as tk

"""Programmname"""
PROGRAMMNAME = 'gui_Dataset_Vertical.py'


class DatasetVertical(object):
    """
    Tabellarische Ausgabe der Daten im vertikalen Datenformat.
    """

    def __init__(self, tk_status, data, labels, color):

        tk_check = {'tk' : tk.Tk, 'top' : tk.Toplevel}
        self.my_win = tk_check[tk_status]()
        self.my_win.title('DATASET VERTICAL')

        # Ermittle die Größe des Bildschirmes
        self.screenx = self.my_win.winfo_screenwidth()
        self.screeny = self.my_win.winfo_screenheight()

        self.label_names = labels
        self.name_width = round(int(max([len(name) for name in labels])) * 1.3)
        # Erstellung Dictionary für GUI-Ausgabe.
        self._dict_ = dict()
        max_item = set()
        for i, row in enumerate(data):
            for c, x in enumerate(row):
                try:
                    self._dict_[i].update({c : x})
                except KeyError:
                    self._dict_[i] = {c : x}
                max_item.add(len(x))
        self.max_width  = round(max(max_item) + 3)

        self.color = color
        if self.color == '':
            self.color = 'grey'
        self.ipadx = 5 # Abstand zu Text in x
        self.ipady = 2 # Abstand zu Text in y
        self.window = tk.Frame(self.my_win, bg=self.color)
        self.window.grid(row=0, column=0, sticky=tk.NSEW)
        self.window.grid_rowconfigure(0, weight=1)
        self.window.grid_columnconfigure(0, weight=1)


    def start(self):

        # Buttons erstellen
        self.button_frame = tk.Label(self.window)
        self.button_frame.grid(row=1, column=0)
        button_text = 'Schließen'
        self.len_max = len(button_text)
        tk.Button(self.button_frame, width=self.len_max, text=button_text,
            command=self.close).grid(row=0, column=0)

        self.canvas = tk.Canvas(self.window, bd=0)
        self.canvas.grid(row=0, column=0, sticky=tk.NSEW)

        self.canvas1 = tk.Canvas(self.canvas, bg='darkgrey', bd=0)
        self.canvas1.grid(row=0, column=0, sticky=tk.NSEW)

        ## scrollbar erstellen
        yscrollbar = tk.Scrollbar(self.canvas, orient=tk.VERTICAL,
            bg = 'darkgrey', activebackground = 'lightsteelblue')
        yscrollbar.grid(row=0, column=2, sticky=tk.NS)
        xscrollbar = tk.Scrollbar(self.canvas, orient=tk.HORIZONTAL,
            bg = 'darkgrey', activebackground = 'lightsteelblue')
        xscrollbar.grid(row=1, column=1, sticky=tk.EW)
        self.canvas2 = tk.Canvas(self.canvas, bg='darkgrey', bd=0,
            scrollregion=(0, 0, 0, 0),
            xscrollcommand=xscrollbar.set,
            yscrollcommand=yscrollbar.set)
        self.canvas2.grid(row=0, column=1, sticky=tk.NSEW)

        self.build_table()

        yscrollbar.config(command=self.canvas2.yview)
        xscrollbar.config(command=self.canvas2.xview)

        self.canvas.update_idletasks()
        x, y, w, h = self.canvas.bbox(tk.ALL)
        self.xpos += 20 # Y-Scrollbar
        self.ypos += 40 # Button-Spalte

        new_w = w
        if self.xpos > self.screenx:
            new_w = self.screenx
            w = self.xpos + x
        self.canvas2.config(scrollregion=(x, y, w, h),
            width=new_w, height=self.ypos)


    def build_table(self):
        """Tabellenspalte erstellen"""

        width = self.max_width
        if ('BENENNUNG' in self.label_names
                or 'BESCHREIBUNG' in self.label_names):
            width=50
        self.ypos = 0
        for i, name in enumerate(self.label_names):
            self.xpos = 0
            height = 1
            if name == 'BENENNUNG':
                height = 2
            elif name == 'BESCHREIBUNG':
                height = 5
            label = tk.Label(self.canvas1, width=self.name_width, height=height,
                text=name, bd=1, highlightthickness=1, anchor=tk.W)
            label.grid(row=i, column=0, padx=self.ipadx, pady=self.ipady)
            self.xpos += label.winfo_reqwidth()
            self.canvas.create_window(self.xpos, self.ypos)
            for i2column in range(len(self._dict_)):
                text = self._dict_[i2column][i]
                label2 = tk.Label(self.canvas2, width=width, height=height,
                    wraplength=395, justify=tk.LEFT, text=text, bd=1,
                    highlightthickness=1, anchor=tk.W)
                label2.grid(row=i, column=i2column, padx=self.ipadx,
                    pady=self.ipady)
                self.xpos += label2.winfo_reqwidth()
            self.ypos += label2.winfo_reqheight()


    def close(self):
        self.my_win.quit()
        self.my_win.destroy()


    def run(self):
        self.start()
        # Setze Fenster mittig.
        hdw = (self.screenx - self.xpos) / 2
        if self.xpos > self.screenx:
            hdw = self.screenx
        hdh = (self.screeny - self.ypos) / 2
        if self.ypos > self.screeny:
            hdh = self.screeny
        self.my_win.geometry('{}x{}+{}+{}'.format(self.xpos, self.ypos,
            round(hdw), round(hdh)))
        self.my_win.mainloop()


def main():
    tk_status = 'tk'
    products = [('048', '80108095', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
        'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'),
        ('048', '80108095', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
        'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'),
        ('048', '80108095', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
        'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'),
        ('048', '80108095', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
        'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'),
        ('048', '80108095', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
        'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')]
    labels = ['ID', 'NUMBER', 'BENENNUNG', 'BESCHREIBUNG']
    color = 'red'
    DatasetVertical(tk_status, products, labels, color).run()


if __name__ == '__main__':
    main()
Hoffe, Ihr könnt mir helfen.

Grüße Nobuddy
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Die X_Scrollbar ist sichtbar und lässt sich auch hin und her schieben, leider folgt aber der obere Fensterteil nicht mit dazu.
Dieser bewegt sich überhaupt nicht.

Was kann hier das Problem sein, dass die X_Scrollbar nicht richtig funktioniert?

Grüße Nobuddy
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Nobuddy
Hier eine mögliche Variante (Prototyp). Jetzt noch ohne Mausradunterstützung. Ausprobiert auf Ubuntu 16.04 Python2 & 3:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk


APP_TITLE = "DATASET VERTICAL"
APP_BACK_GND = "#d1d19d"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 500
APP_HEIGHT = 400

B119 = 'b'*119 # Platzhalter für Beschreibung
A044 = 'a'*44  # Platzhalter für Bennenung

PRODUCT_FRAME = ('048', '80108095', A044, B119)
NUM_PRODUCT_FRAMES = 5
PRODUCTS = [('048', '80108095', A044, B119)] * NUM_PRODUCT_FRAMES

PROD_ITEM_ID = 'ID'
PROD_ITEM_NR = 'NUMBER'
PROD_ITEM_NAME = 'BENENNUNG'
PROD_ITEM_DOC = 'BESCHREIBUNG'
PROD_ITEMS = [PROD_ITEM_ID, PROD_ITEM_NR, PROD_ITEM_NAME, PROD_ITEM_DOC]

ROW_HEADER_LABELS = [
    (PROD_ITEM_ID, 1),
    (PROD_ITEM_NR, 1),
    (PROD_ITEM_NAME, 2),
    (PROD_ITEM_DOC, 5)]
    
COLOR = 'red'


class Application(tk.Frame):

    def __init__(self, master, data, row_header_labels, color):
        self.master = master
        self.row_header_labels = row_header_labels
        self.color = color
        self.data_dict = dict()
        for row_index, item_data in enumerate(data):
            row_dict = dict()
            for item_index, prod_item_key in enumerate(PROD_ITEMS):
                row_dict[prod_item_key] = item_data[item_index]
            self.data_dict[row_index] = row_dict    
            
        self.master.protocol("WM_DELETE_WINDOW", self.close)
        tk.Frame.__init__(self, master)

        xscrollbar = tk.Scrollbar(self, orient='horizontal', bd=0,
            relief='flat', bg='darkgrey', troughcolor='gray',
            activebackground='lightsteelblue')
        xscrollbar.grid(row=1, column=0, sticky='we')

        yscrollbar = tk.Scrollbar(self, orient='vertical', bd=0,
            relief='flat', bg='darkgrey', troughcolor='gray',
            activebackground='lightsteelblue')
        yscrollbar.grid(row=0, column=1, sticky='ns')

        self.plane = tk.Canvas(self, bg=color, bd=0,
            xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set)
        self.plane.grid(row=0, column=0, sticky='nswe')
        self.plane.bind('<Configure>', self.update_scrollbars)

        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        xscrollbar.config(command=self.plane.xview)
        yscrollbar.config(command=self.plane.yview)
        
        self.table_frame = tk.Frame(self.plane)
        self.table_frame.pack()
        
        self.plane.create_window(0, 0, anchor='nw', window=self.table_frame)
        self.table_row_header()
        
    def table_row_header(self):
        self.row_header_frame = tk.Frame(self.table_frame)
        self.row_header_frame.pack(side='left', expand=True)
        
        for label_data in self.row_header_labels:
            name, height = label_data
            label = tk.Label(self.row_header_frame, text=name, height=height,
                anchor='w', bg='gray90', fg='steelblue')
            label.pack(fill='x', padx=2, pady=1)
            
        for column_index in range(len(self.data_dict)):
            print(column_index)
            self.item_frame = tk.Frame(self.table_frame)
            self.item_frame.pack(side='left', expand=True)
            for row_index, label_data in enumerate(ROW_HEADER_LABELS):
                item_name, label_height = label_data
                item_data = self.data_dict[column_index][item_name]
                tk.Label(self.item_frame, text=item_data, height=label_height,
                    wraplength=395, justify='left', anchor='w', bg='gray90'
                    ).pack(fill='x', padx=1, pady=1)
                    
    def update_scrollbars(self, event):

        if self.plane.bbox('all') != None:
            x0, y0, x1, y1 = self.plane.bbox('all')
        else:
            self.plane.config(scrollregion=(0, 0, 0, 0))
            return
            
        #~~ Skaliere die Ziehleisten auf den neuen Canvas-Inhalt    
        region = (x0, y0, x1, y1)
        self.plane.config(scrollregion=region)
        
        #~~ Setze die Zieleisten in Ausgangslage
        self.plane.xview('moveto', 0.0, None)
        self.plane.yview('moveto', 0.0, None)

    def close(self):
        print("Application-Shutdown")
        self.master.destroy()

    
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    screenx = app_win.winfo_screenwidth()
    screeny = app_win.winfo_screenheight()
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    #app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    app_win.geometry("{}x{}".format(screenx, screeny))
    app_win.config(bg=APP_BACK_GND)
    app = Application(app_win,
        data=PRODUCTS, row_header_labels=ROW_HEADER_LABELS, color=COLOR).pack(
            fill='both', expand=True, padx=6, pady=6)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()      
Gruss wuf :wink:
Take it easy Mates!
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo wuf,

Danke für Dein Beispiel, werde mir das genauer anschauen!

Grüße Nobuddy
Antworten