简体   繁体   中英

How to convert this example from python2 to python3

I'm trying to convert a working example in github from python2 to python3 and running into a problem I don't understand.

The original is https://gist.github.com/EugeneBakin/76c8f9bcec5b390e45df I apply the following patch and get an error message about too many arguments to the SampleApp init method. Since I don't understand why the original had its *args and **kwargs when the only call had no arguments at all, something is not adding up for me. But it worked in python2, so I was hoping it would work in python3 as well, because I recognize that usage as useful.

However, it may not matter because the stack trace on the error message does not include that call, or any call for that matter. Another puzzle.

I want to solve this without just blindly removing arguments because I may need some when I go to apply this in my real use case.

I also want to remove importing as *, as I regard it as dangerous and as hiding information useful to a reader.

The patch:

--- VSFrame.py  2017-12-16 14:30:33.458923856 -0800
+++ VSFrame3.py 2017-12-16 15:01:21.914423486 -0800
@@ -1,21 +1,21 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
-from Tkinter import *   # from x import * is bad practice
-from ttk import *
+import tkinter as tk
+import tkinter.ttk as ttk

 # http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame

-class VerticalScrolledFrame(Frame):
+class VerticalScrolledFrame(ttk.Frame):
     """A pure Tkinter scrollable frame that actually works!
     * Use the 'interior' attribute to place widgets inside the scrollable frame
     * Construct and pack/place/grid normally
     * This frame only allows vertical scrolling
     """
     def __init__(self, parent, *args, **kw):
-        Frame.__init__(self, parent, *args, **kw)            
+        super().__init__(self, parent, *args, **kw)            

         # create a canvas object and a vertical scrollbar for scrolling it
-        vscrollbar = Scrollbar(self, orient=VERTICAL)
+        vscrollbar = ttk.Scrollbar(self, orient=VERTICAL)
         vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
         canvas = Canvas(self, bd=0, highlightthickness=0,
                         yscrollcommand=vscrollbar.set)
@@ -51,9 +51,9 @@

 if __name__ == "__main__":

-    class SampleApp(Tk):
+    class SampleApp(tk):
         def __init__(self, *args, **kwargs):
-            root = Tk.__init__(self, *args, **kwargs)
+            root = tk.__init__(self, *args, **kwargs)


             self.frame = VerticalScrolledFrame(root)

And after the comment by Willem (thanks for that), it is now

--- VSFrame.py  2017-12-16 14:30:33.458923856 -0800
+++ VSFrame3.py 2017-12-16 16:04:00.938380716 -0800
@@ -1,21 +1,21 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
-from Tkinter import *   # from x import * is bad practice
-from ttk import *
+import tkinter as tk
+import tkinter.ttk as ttk

 # http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame

-class VerticalScrolledFrame(Frame):
+class VerticalScrolledFrame(ttk.Frame):
     """A pure Tkinter scrollable frame that actually works!
     * Use the 'interior' attribute to place widgets inside the scrollable frame
     * Construct and pack/place/grid normally
     * This frame only allows vertical scrolling
     """
     def __init__(self, parent, *args, **kw):
-        Frame.__init__(self, parent, *args, **kw)            
+        super().__init__(self, parent, *args, **kw)            

         # create a canvas object and a vertical scrollbar for scrolling it
-        vscrollbar = Scrollbar(self, orient=VERTICAL)
+        vscrollbar = ttk.Scrollbar(self, orient=VERTICAL)
         vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
         canvas = Canvas(self, bd=0, highlightthickness=0,
                         yscrollcommand=vscrollbar.set)
@@ -51,10 +51,9 @@

 if __name__ == "__main__":

-    class SampleApp(Tk):
+    class SampleApp(tk.Tk):
         def __init__(self, *args, **kwargs):
-            root = Tk.__init__(self, *args, **kwargs)
-
+            root = tk.TK.__init__(self, *args, **kwargs)

             self.frame = VerticalScrolledFrame(root)
             self.frame.pack()

I got it working by making it conform more nearly to the style in https://docs.python.org/3.5/library/tkinter.html#a-simple-hello-world-program

Full source follows.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import tkinter as tk
import tkinter.ttk as ttk

# Python3 version of http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame

class VerticalScrolledFrame(ttk.Frame):
    """A pure Tkinter scrollable frame that actually works!
    * Use the 'interior' attribute to place widgets inside the scrollable frame
    * Construct and pack/place/grid normally
    * This frame only allows vertical scrolling
    """
    def __init__(self, parent):
        super().__init__(parent)

        # create a canvas object and a vertical scrollbar for scrolling it
        vscrollbar = ttk.Scrollbar(self, orient=tk.VERTICAL)
        vscrollbar.pack(fill=tk.Y, side=tk.RIGHT, expand=tk.FALSE)
        canvas = tk.Canvas(self, bd=0, highlightthickness=0,
                        yscrollcommand=vscrollbar.set)
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.TRUE)
        vscrollbar.config(command=canvas.yview)

        # reset the view
        canvas.xview_moveto(0)
        canvas.yview_moveto(0)

        # create a frame inside the canvas which will be scrolled with it
        self.interior = interior = ttk.Frame(canvas)
        interior_id = canvas.create_window(0, 0, window=interior,
                                           anchor=tk.NW)

        # track changes to the canvas and frame width and sync them,
        # also updating the scrollbar
        def _configure_interior(event):
            # update the scrollbars to match the size of the inner frame
            size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
            canvas.config(scrollregion="0 0 %s %s" % size)
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the canvas's width to fit the inner frame
                canvas.config(width=interior.winfo_reqwidth())
        interior.bind('<Configure>', _configure_interior)

        def _configure_canvas(event):
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the inner frame's width to fill the canvas
                canvas.itemconfigure(interior_id, width=canvas.winfo_width())
        canvas.bind('<Configure>', _configure_canvas)


if __name__ == "__main__":

    class SampleApp(ttk.Frame):
        def __init__(self, master=None):
            super().__init__(master)
            self.create_widgets()

        def create_widgets(self):
            self.frame = VerticalScrolledFrame(root)
            self.frame.pack()
            self.label = ttk.Label(text="Shrink the window to activate the scrollbar.")
            self.label.pack()
            buttons = []
            for i in range(10):
                buttons.append(ttk.Button(self.frame.interior, text="Button " + str(i)))
                buttons[-1].pack()

    root = tk.Tk()
    app = SampleApp(master=root)
    app.mainloop()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM