টিনকটারে দুটি ফ্রেমের মধ্যে স্যুইচ করুন


94

টিউটোরিয়ালগুলি আমাকে দেখায়, আমি তাদের উপর একটি দুর্দান্ত ছোট জিইউআই দিয়ে আমার প্রথম কয়েকটি স্ক্রিপ্ট তৈরি করেছি, তবে এর মধ্যে কোনওটিই জটিল প্রোগ্রামের জন্য কী করা উচিত তা সম্বোধন করে না।

আপনার খোলার স্ক্রিনের জন্য, 'স্টার্ট মেনু' দিয়ে আপনার কিছু রয়েছে এবং ব্যবহারকারী নির্বাচনের পরে আপনি প্রোগ্রামের একটি আলাদা বিভাগে চলে যান এবং যথাযথভাবে স্ক্রিনটি আবার আঁকেন, এটি করার মার্জিত উপায়টি কী?

একটি মাত্র .destroy()'স্টার্ট মেনু' ফ্রেম এবং তারপরে অন্য অংশের জন্য উইজেটগুলিতে পূর্ণ একটি নতুন তৈরি করতে পারে? এবং যখন তারা পিছনে বোতাম টিপবে তখন এই প্রক্রিয়াটি বিপরীত করবেন?

উত্তর:


177

একটি উপায় হ'ল একে অপরের উপরে ফ্রেমগুলি স্ট্যাক করা, তারপরে আপনি কেবল স্ট্যাকিং ক্রমে একে অপরের উপরে তুলতে পারেন। শীর্ষে থাকা একটি দৃশ্যমান। এটি সবথেকে ভাল কাজ করে যদি সমস্ত ফ্রেম একই আকারের হয় তবে সামান্য কাজ দিয়ে আপনি এটি কোনও আকারের ফ্রেমগুলির সাথে কাজ করতে পারেন।

বিঃদ্রঃ : এটি কাজ করার জন্য, কোনও পৃষ্ঠার সমস্ত উইজেটের অবশ্যই পাতাগুলি (অর্থাত্ self) : বা পিতা বা মাতা হিসাবে কোনও বংশধর থাকতে হবে (বা মাস্টার, আপনি যে পরিভাষা পছন্দ করেন তার উপর নির্ভর করে)।

আপনাকে সাধারণ ধারণাটি দেখানোর জন্য এখানে কিছুটা নিস্পষ্ট উদাহরণ রয়েছে:

try:
    import tkinter as tk                # python 3
    from tkinter import font as tkfont  # python 3
except ImportError:
    import Tkinter as tk     # python 2
    import tkFont as tkfont  # python 2

class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")

        # the container is where we'll stack a bunch of frames
        # on top of each other, then the one we want visible
        # will be raised above the others
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, PageOne, PageTwo):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is the start page", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

        button1 = tk.Button(self, text="Go to Page One",
                            command=lambda: controller.show_frame("PageOne"))
        button2 = tk.Button(self, text="Go to Page Two",
                            command=lambda: controller.show_frame("PageTwo"))
        button1.pack()
        button2.pack()


class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 1", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()


class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 2", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

প্রথম পাতা পৃষ্ঠা 1 পৃষ্ঠা ২

আপনি যদি কোনও ক্লাসে বিভ্রান্তিকর উদাহরণ তৈরির ধারণাটি পান বা নির্মাণের সময় বিভিন্ন পৃষ্ঠাগুলির বিভিন্ন যুক্তি প্রয়োজন হয় তবে আপনি প্রতিটি ক্লাসকে আলাদাভাবে কল করতে পারেন। লুপটি প্রতিটি বর্গ একরকমের পয়েন্টটি চিত্রিত করতে প্রধানত পরিবেশন করে।

উদাহরণস্বরূপ, পৃথকভাবে ক্লাস তৈরি করতে আপনি লুপটি মুছে ফেলতে পারেন (এটির for F in (StartPage, ...)সাথে:

self.frames["StartPage"] = StartPage(parent=container, controller=self)
self.frames["PageOne"] = PageOne(parent=container, controller=self)
self.frames["PageTwo"] = PageTwo(parent=container, controller=self)

self.frames["StartPage"].grid(row=0, column=0, sticky="nsew")
self.frames["PageOne"].grid(row=0, column=0, sticky="nsew")
self.frames["PageTwo"].grid(row=0, column=0, sticky="nsew")

সময়ের সাথে সাথে লোকেরা এই কোডটি (বা একটি অনলাইন টিউটোরিয়াল যা এই কোডটি অনুলিপি করেছে) একটি প্রাথমিক পয়েন্ট হিসাবে ব্যবহার করে অন্যান্য প্রশ্ন জিজ্ঞাসা করেছে। আপনি এই প্রশ্নের উত্তরগুলি পড়তে চাইতে পারেন:


4
বাহ, আপনাকে অনেক ধন্যবাদ. বাস্তবের পরিবর্তে যেমন একাডেমিক প্রশ্ন, লগি এবং প্রতিক্রিয়াহীন হতে শুরু করার আগে একে অপরের উপরে লুকিয়ে থাকা এই পৃষ্ঠাগুলির মধ্যে কতগুলি দরকার?
ম্যাক্স টিলি

4
আমি জানি না। সম্ভবত হাজার হাজার। এটি পরীক্ষা করা যথেষ্ট সহজ হবে।
ব্রায়ান ওকলে

4
একে অপরের উপরে ফ্রেমগুলি স্ট্যাক না করে কোডের খুব কম সংখ্যক লাইনের সাথে এর মতো কোনও প্রভাব অর্জনের সত্যিকারের সহজ উপায় নেই?
প্যারালাক্স সুগার

4
@ স্টিভেনভ্যাসেল্লারো: হ্যাঁ, pack_forgetআপনি যদি ব্যবহার করেন তবে ব্যবহার করা যেতে পারে pack
ব্রায়ান ওকলি

4
সতর্কতা : ব্যবহারকারীরা ট্যাব টিপে পটভূমির ফ্রেমে "লুকানো" উইজেট নির্বাচন করতে পারেন, তারপরে এন্টার দিয়ে সক্রিয় করুন।
স্টিভোসিয়াক

31

এখানে আরও একটি সহজ উত্তর দেওয়া হয়েছে, তবে ক্লাস ব্যবহার না করেই।

from tkinter import *


def raise_frame(frame):
    frame.tkraise()

root = Tk()

f1 = Frame(root)
f2 = Frame(root)
f3 = Frame(root)
f4 = Frame(root)

for frame in (f1, f2, f3, f4):
    frame.grid(row=0, column=0, sticky='news')

Button(f1, text='Go to frame 2', command=lambda:raise_frame(f2)).pack()
Label(f1, text='FRAME 1').pack()

Label(f2, text='FRAME 2').pack()
Button(f2, text='Go to frame 3', command=lambda:raise_frame(f3)).pack()

Label(f3, text='FRAME 3').pack(side='left')
Button(f3, text='Go to frame 4', command=lambda:raise_frame(f4)).pack(side='left')

Label(f4, text='FRAME 4').pack()
Button(f4, text='Goto to frame 1', command=lambda:raise_frame(f1)).pack()

raise_frame(f1)
root.mainloop()

28

সতর্কতা : নীচের উত্তরগুলি বারবার ফ্রেমগুলি ধ্বংস করে এবং পুনরায় তৈরি করার মাধ্যমে মেমরি ফাঁস হতে পারে ।

ফ্রেমগুলিতে স্যুইচ করার এক উপায় tkinter হ'ল পুরানো ফ্রেমটি নষ্ট করে তারপরে এটি আপনার নতুন ফ্রেমের সাথে প্রতিস্থাপন করুন।

ব্রায়ান ওকলির উত্তরটি পরিবর্তন করার পূর্বে পুরানো ফ্রেমটি নষ্ট করার জন্য আমি পরিবর্তন করেছি। একটি অতিরিক্ত বোনাস হিসাবে, এটি containerকোনও সামগ্রীর প্রয়োজনীয়তা অপসারণ করে এবং আপনাকে যে কোনও জেনেরিক Frameশ্রেণি ব্যবহার করতে দেয় ।

# Multi-frame tkinter application v2.3
import tkinter as tk

class SampleApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self._frame = None
        self.switch_frame(StartPage)

    def switch_frame(self, frame_class):
        """Destroys current frame and replaces it with a new one."""
        new_frame = frame_class(self)
        if self._frame is not None:
            self._frame.destroy()
        self._frame = new_frame
        self._frame.pack()

class StartPage(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        tk.Label(self, text="This is the start page").pack(side="top", fill="x", pady=10)
        tk.Button(self, text="Open page one",
                  command=lambda: master.switch_frame(PageOne)).pack()
        tk.Button(self, text="Open page two",
                  command=lambda: master.switch_frame(PageTwo)).pack()

class PageOne(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        tk.Label(self, text="This is page one").pack(side="top", fill="x", pady=10)
        tk.Button(self, text="Return to start page",
                  command=lambda: master.switch_frame(StartPage)).pack()

class PageTwo(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        tk.Label(self, text="This is page two").pack(side="top", fill="x", pady=10)
        tk.Button(self, text="Return to start page",
                  command=lambda: master.switch_frame(StartPage)).pack()

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

প্রথম পাতা প্রথম পৃষ্ঠা পৃষ্ঠা দুই

ব্যাখ্যা

switch_frame()প্রয়োগ করে এমন কোনও ক্লাস অবজেক্ট গ্রহণ করে কাজ করে Frame। ফাংশনটি তখন পুরানোটিকে প্রতিস্থাপনের জন্য একটি নতুন ফ্রেম তৈরি করে।

  • পুরানো _frameএটি উপস্থিত থাকলে মুছে ফেলা হয় , তারপরে নতুন ফ্রেমের সাথে এটি প্রতিস্থাপন করুন।
  • .pack()মেনুবার হিসাবে যুক্ত অন্যান্য ফ্রেমগুলি প্রভাবিত হবে না।
  • প্রয়োগকারী যে কোনও শ্রেণীর সাথে ব্যবহার করা যেতে পারে tkinter.Frame
  • উইন্ডো স্বয়ংক্রিয়ভাবে নতুন সামগ্রীতে ফিট করে

সংস্করণ ইতিহাস

v2.3

- Pack buttons and labels as they are initialized

v2.2

- Initialize `_frame` as `None`.
- Check if `_frame` is `None` before calling `.destroy()`.

v2.1.1

- Remove type-hinting for backwards compatibility with Python 3.4.

v2.1

- Add type-hinting for `frame_class`.

v2.0

- Remove extraneous `container` frame.
    - Application now works with any generic `tkinter.frame` instance.
- Remove `controller` argument from frame classes.
    - Frame switching is now done with `master.switch_frame()`.

v1.6

- Check if frame attribute exists before destroying it.
- Use `switch_frame()` to set first frame.

v1.5

  - Revert 'Initialize new `_frame` after old `_frame` is destroyed'.
      - Initializing the frame before calling `.destroy()` results
        in a smoother visual transition.

v1.4

- Pack frames in `switch_frame()`.
- Initialize new `_frame` after old `_frame` is destroyed.
    - Remove `new_frame` variable.

v1.3

- Rename `parent` to `master` for consistency with base `Frame` class.

v1.2

- Remove `main()` function.

v1.1

- Rename `frame` to `_frame`.
    - Naming implies variable should be private.
- Create new frame before destroying old frame.

v1.0

- Initial version.

4
আমি এই পদ্ধতির চেষ্টা করে ফ্রেমের এই অদ্ভুত রক্তপাত পেয়েছি যখন এটি অনুলিপি করা যায় কিনা তা নিশ্চিত না: imgur.com/a/njCsa
কোয়ান্টিক

4
@ কোয়ান্টিক ব্লিড-ওভার এফেক্টটি ঘটে কারণ পুরানো বোতামগুলি সঠিকভাবে ধ্বংস হচ্ছে না। নিশ্চিত হয়ে নিন যে আপনি সরাসরি ফ্রেম শ্রেণিতে বোতামগুলি সংযুক্ত করছেন (সাধারণত self)।
স্টিভয়েসিয়াক

4
অন্ধকারে নামটি switch_frame()কিছুটা বিভ্রান্তিকর হতে পারে। আমি কি এর নাম পরিবর্তন করব replace_frame()?
স্টিভোসিয়াক

11
আমি এই উত্তরের সংস্করণ ইতিহাসের অংশটি সরানোর পরামর্শ দিচ্ছি। এটি সম্পূর্ণ অকেজো। আপনি যদি ইতিহাসটি দেখতে চান তবে স্ট্যাকওভারফ্লো এটি করার জন্য একটি ব্যবস্থা সরবরাহ করে। এই উত্তরটি পড়া বেশিরভাগ লোকেরা ইতিহাসের বিষয়ে চিন্তা করবেন না।
ব্রায়ান ওকলি

4
সংস্করণ ইতিহাসের জন্য আপনাকে ধন্যবাদ। জেনে রাখা ভাল যে আপনি সময়ের সাথে সাথে উত্তরটি আপডেট করেছেন এবং সংশোধন করেছেন।
ভ্যাসিল ভাস্কিভস্কিই
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.