pythontkinterpygame

Why are Tkinter Scales broken across multiple files?


My tk scales for rgb values and 'logic' variable are ceasing to function when I import my class into a file with another 'main tk'. The scales are present and interactable but fail to change the values of the tk vars. This is for my NEA.

import tkinter as tk
from tkinter import messagebox,ttk

#Personal imports
from Julia import Julia
from Mandel import Mandelbrot
from Carpet import Carpet

class main:

    def __init__(self):
        pass
    def launch(self):
        self.hometk()

    def hometk(self):
        self.base = tk.Tk()
        self.base.geometry("500x500")
        self.base.wm_attributes('-transparentcolor',self.base['bg'])

        bg= tk.PhotoImage(file="NEA\product\Julia_bg.png")
        bglabel=tk.Label(self.base,image=bg)
        bglabel.place(x=0,y=0)

        topframe=tk.Frame(self.base,width=500,height=250)
        topframe.pack(side=tk.TOP)

        bottomframe=tk.Frame(self.base,width=500,height=250,pady=10)
        bottomframe.pack(side=tk.BOTTOM)

        leftframe=tk.Frame(bottomframe,width=500,pady=10)
        middleframe=tk.Frame(bottomframe,width=500,pady=10)
        rightframe=tk.Frame(bottomframe,width=500,pady=10)

        leftframe.pack(side=tk.LEFT)
        middleframe.pack(side=tk.LEFT)
        rightframe.pack(side=tk.RIGHT)

        title1=tk.Label(topframe,text="FRACTAL GENERATOR",pady=10,font=("Copperplate Gothic Bold",20),fg="white").pack(side=tk.LEFT)


        self.combo_mj=ttk.Combobox(master=leftframe,values=["Mandelbrot","Julia"])
        self.combo_mj.bind("<<ComboboxSelected>>",self.selection_confirm_mj)
        self.combo_mj.pack()

        self.combo_sc=ttk.Combobox(master=middleframe,values=["Triangle","Carpet"])
        self.combo_sc.bind("<<ComboboxSelected>>",self.selection_confirm_sc)
        self.combo_sc.pack()

        self.combo_ls=tk.StringVar()

        self.combo_ls=ttk.Combobox(master=rightframe,values=["Lorenz"])
        self.combo_ls.bind("<<ComboboxSelected>>",self.selection_confirm_ls)
        self.combo_ls.pack()



        self.base.mainloop()

    def selection_confirm_ls(self,thing):

        choice = self.combo_ls.get()
        q=messagebox.askokcancel(title="Launch",message=f"Launch {choice} generator")
        if q:
            pass
            #object=Lorenz() #must add lorenz import
            self.base.withdraw()
            object.launch()
            self.base.deiconify()

    def selection_confirm_sc(self,thing):

        choice = self.combo_sc.get()
        q=messagebox.askokcancel(title="Launch",message=f"Launch {choice} generator")
        if q:
            if choice=="Triangle":
                pass
                #object=Triangle() #must add triangle import
            elif choice=="Carpet":
                object=Carpet()
            self.base.withdraw()
            object.launch()
            self.base.deiconify()


    def selection_confirm_mj(self,thing):
            
        choice = self.combo_mj.get()
        q=messagebox.askokcancel(title="Launch",message=f"Launch {choice} generator")
        if q:
            if choice=="Mandelbrot":
                object=Mandelbrot()
            elif choice=="Julia":
                object=Julia()
            object.launch()


                    





if __name__=="__main__":
    program=main()
    program.launch()

from Fractalbase import Fractal #personal import with Fractal super class
import tkinter as tk, pygame

class Mandelbrot(Fractal):#Mandelbrot class #GROUP A Complex OOP model

    def __init__(self): 
         return super().__init__()

    def launch(self): # public method to run
         self.__setup()



    def __setup(self): # indicated private method to setup tkinter and pygame environments
        Fractal._Fractal__setup_required(self)

        button_win = tk.Frame(self.root, width = 500, height = 25) # button frames
        button_win.pack(side = tk.TOP)

        logic_win = tk.Frame(self.root, width = 500, height = 25) # button frames
        logic_win.pack(side = tk.TOP)

        self.logic=tk.IntVar(value=5)
        logiclabe=tk.Label(logic_win,text="Logic").pack(side=tk.LEFT)
        logicslider=tk.Scale(logic_win, from_=1, to_=10, orient=tk.HORIZONTAL,variable=self.logic).pack(side=tk.LEFT)

        colour_frame=tk.Frame(self.root,width=500,height=25)
        colour_frame.pack(side=tk.TOP)
        self.r=tk.IntVar(value=255)
        self.g=tk.IntVar(value=255)
        self.b=tk.IntVar(value=255)

        rgblabel=tk.Label(colour_frame,text="RGB Values").pack(side=tk.LEFT)
        rslider=tk.Scale(colour_frame, from_=0, to_=255, orient=tk.HORIZONTAL,variable=self.r).pack(side=tk.LEFT)
        gslider=tk.Scale(colour_frame, from_=0, to_=255, orient=tk.HORIZONTAL,variable=self.g).pack(side=tk.LEFT)
        bslider=tk.Scale(colour_frame, from_=0, to_=255, orient=tk.HORIZONTAL,variable=self.b).pack(side=tk.RIGHT)

        run_button = tk.Button(button_win,text ="run",command=self.__pygame_loop)
        run_button.pack(side=tk.RIGHT) 

        self.root.mainloop() # launch tk environment


    def __fractal(self,zoom,alignmentx,alignmenty): # indicated private method for mandelbrot fractal
        r=(self.r.get())/255
        g=(self.g.get())/255
        b=(self.b.get())/255
        
        Fractal._Fractal__fractal(self,zoom,alignmentx,alignmenty)
        pxa = pygame.PixelArray(self.screen)
        print(f"current zoom: {zoom,alignmentx,alignmenty}")
        for i in range(0,500,2):    # for every color:
            for j in range(0,500,2):    # For every row
                z = complex(alignmentx+i/zoom,alignmenty+j/zoom)
                c = z
                for k in range(round(256/self.logic.get())):
                    z = z * z + c       #GROUP A Complex mathematical equation
                    if abs(z)>3:
                        break
                k*=self.logic.get()
                for q in range(0,2):
                    for s in range(0,2):
                        pxa[i+q,j+s]= pygame.Color(round(r*k),round(g*k),round(b*k)) # set the colour accordingly


    def __pygamesetup(self):
        Fractal._Fractal__pygamesetup(self)
        self.zoom=200  #base alignment and zoom
        self.alignmentx=-2
        self.alignmenty=-1.25

    def __pygame_loop(self): # indicated private method for main pygame loop

        self.__pygamesetup()
        
        while self.run:
            pygame.event.set_allowed([pygame.MOUSEBUTTONDOWN]) # set allowed events to remove unecessary ones
            for event in pygame.event.get():
                if event.type == pygame.MOUSEBUTTONDOWN: # check for new centre and zoom from mouse
                    self.newfractal=True
                    print(event)
                    x,y=event.pos
                    if event.button == 1: # set zoom values
                        self.zoom+=50
                    elif event.button == 3:
                        self.zoom-=50
                        if self.zoom == 150:
                            self.zoom=200
                        
                    self.alignmentx=((self.alignmentx)+((x-250)/250))   # new centre calculation, needs work
                    round(self.alignmentx,3)
                    self.alignmenty=((self.alignmenty)+((y-250)/250))
                    round(self.alignmenty,3)

            if self.newfractal: # only regenerate if required
                self.__fractal(self.zoom,self.alignmentx,self.alignmenty) # run to generate new fractal image
            self.newfractal=False

            pygame.display.update()
            self.root.update()

import tkinter as tk
import tkinter.messagebox as messagebox
import pygame,os




class Fractal:

    def __init__(self): 
        pass

    def launch(self): # public method to run
        self.__setup_required

    def __setup_required(self): # indicated private method to setup tkinter and pygame environments

        self.root = tk.Tk()      # set tk frames
        self.clock=pygame.time.Clock()       #set clock

        embed_pygame = tk.Frame(self.root, width = 500, height = 500) # pygame frames
        embed_pygame.pack(side = tk.BOTTOM)

        os.environ['SDL_WINDOWID'] = str(embed_pygame.winfo_id())# embed pygame screen in tk frame by intercepting os windows
        os.environ['SDL_VIDEODRIVER'] = 'windib'

        pygame.display.init()        
        self.screen = pygame.display.set_mode((500,500))     #set display    

        self.root.protocol("WM_DELETE_WINDOW", self.__windowexit) # protocol to intercept tk window close and direct to __windowexit method


    def __windowexit(self): # indicated private method to ensure tk and pygame environments close and terminate
        close = messagebox.askokcancel("","Exit?") # conformation box
        if close:
            self.run = False
            pygame.quit()
            self.root.quit()

                
    def __fractal(self,zoom,alignmentx,alignmenty): # indicated private method for fractal 
        pass

    def __pygamesetup(self): # indicated private method to setup pygame properties and numerical values
        self.screen.fill((255, 255, 255)) 
        pygame.draw.rect(self.screen, "black",(0,0,500,500)) # use black rectangle to correctly initiate screen and pixel array
        pxa = pygame.PixelArray(self.screen)
        pygame.display.flip()
        self.root.update() 
        self.run = True 
        self.clock.tick(30)
        self.newfractal=True
        self.screen.fill((255, 255, 255)) # set screen

the sliders should change the inner colour of the fractal when refreshed with run.


Solution

  • Problem solved, using a Toplevel window instead of a new Tk has worked.

    self.root = tk.Toplevel()