Is the objects of tkinter.Tk independent of each other? - python

I write a python script (named script2.py) which includes tkinter. To be convenient, I write a function at the bottom. It looks like:
import tkinter
import pygubu
class GuiApp2:
def __init__(self,master):
self.builder=pygubu.Builder()
self.builder.add_from_file('test.ui')
self.builder.get_object('Frame_main',master)
self.list_box_a=self.builder.get_object('Listbox_a')
self.lba_value_set=tkinter.StringVar()
self.list_box_a['listvariable']=self.lba_value_set
def set_value_set(self,the_value_set):
self.lba_value_set.set(the_value_set)
def run(the_value_set):
master=tkinter.Tk()
app=GuiApp1(master)
app.set_value_set(the_value_set)
master.mainloop()
def main():
run(['1','2','3'])
if __name__ == '__main__':
main()
And then I write another script (named script1.py) which calls the function at the bottom of the script above. It is:
import tkinter
import pygubu
import script2
class GuiApp1:
def __init__(self,master):
self.builder=pygubu.Builder()
self.builder.add_from_file('mainapp.ui')
self.builder.get_object('Frame_main',master)
self.button_show=self.builder.get_object('Button_show')
self.button_show['command']=self.command_for_button_show
def command_for_button_show(self):
script2.run(['1','2','3'])
def main():
master=tkinter.Tk()
app=GuiApp1(master)
master.mainloop()
if __name__ == '__main__':
main()
When I run script2.py, everything is fine. But when I run script1.py which imports script2.py the Listbox in script2.py is empty.
Of course, these two scripts are not the files I use in my project. The files I really use is too long and difficult to read.
In order to find out the problem, I inserted several print functions in my script to show the values of the variable in my scripts. Finally, every print result is fine except the Listbox.
Thus I simplified the real scripts to these scripts which are easy to read.
I guess maybe the master(tkinter.Tk()) in script1.py affect the master in script2.py. Because the logic of GUI Management in tkinter is different from it in dotNet.
Is there anyone who's met a similar problem or have some idea about that?

Yes, they are independent. Each time you create an instance of Tk, you create a new instance of an embedded Tcl interpreter. As a consequence, the widgets in one know nothing about the widgets in another.
A well written tkinter program should never create more than one instance of Tk. If you need additional windows you should create instances of Toplevel. You also should call mainloop() exactly once.

Related

How to call modules from another .py file

first time posting!
I'm fairly new to python (and programing!), and I have started to make a basic tkinter program. The code is getting pretty long now, and I want to split it between different .py files to make it more navigatable. So far, all my code exists in classes, seperating the main window, from calculation functions, secondary windows and so on.
First question, is it considered good practice to split code like this? I feel like it is, but want to make sure!
Secondly, how is the best way to handle modules between files?
For example, I have tkinter and matplotlib imported in the main_window.py file. I have the main_window class function which calls a different class which I want to move to another file, but this secondary class has a line which calls tkinter. I want to pass self through the secondary function so that it is using the same instance, as it were.
Here is an example code to illustrate. The first file, main_window.py:
# main_window.py
import tkinter as tk
import matplotlib
import matplotlib.pyplot as plt
import app_design # app_design.py contains the code I want to break out
class MainWindow:
def __intit__(self, root):
self.root = root
self.start_gui()
def start_gui(self):
# a bunch of code
...
# in reality this is read from a program file on startup
color_mode = "Dark"
# This is just an example, the matplotlib call in the other app is in the __init__
self.bg_col_mode = tk.StringVar()
self.bg_col_mode.set(app_design.AppColors(color_mode).background())
# a bucnh more code of various tk widgets and matplotlib charts
...
if __name__ == '__main__':
app = MainWindow(tk.Tk())
app.root.mainloop()
and then an example of some code which I'd like to split out. This is not the only instance of the class referencing a module outside the MainWindow class, but it works as an example:
# app_design.py
class AppColors:
def __init__(self, color_mode):
self.color_mode = color_mode
if self.col_mode == "Dark":
self.plt.style.use("Dark") # it is this .plt call that has moved from the main_window.py file to the new file
else:
self.plt.style.use("Light")
def background_mode(self):
if self.color_mode == "Dark":
return "#292929" # colour code
else:
return "#F8F1F1"
Hopefully this makes sense!
First question, is it considered good practice to split code like this? I feel like it is, but want to make sure!
I actually don't know myself, I only have coded stuff for backend.
Secondly, how is the best way to handle modules between files?
You simply import the file (or function directly).
Example:
file1.py
def hello(name):
print("Hello ", name)
file2.py
from file1 import hello
hello("arjix")
this way you can directly use the function hello
or
import .file1
file1.hello("arjix")
PS: Make sure these two files are in the same folder.

plt.savefig stops working when called from another file

I have a code that works well for bulk data analysis and plotting. But now i'm trying to incorporate it into a larger data analysis GUI. I find that when i run my code on its own, all goes well. But when i call it from the main code and run it from a tkinter button, it's not the same. Everything looks the same and it runs smoothly, the only difference is that no files are saved.
i think maybe it's a problem with which window is defined with "____init____"? or something with how i create and destroy Tk() windows within the subcode?
**the stackoverflow text editor uses underscores to make text bold/itallic, so for all cases that double underscores are used to wrap "init" or "main" in python, i had to use four on each side here
my code (saved as SubCode.py):
def AnalysisFunction():
*does things*
main = Tk()
os.chdir(OutputFolder)
plt.savefig('image.png')
main.destroy()
if __name__ == '__main__':
AnalysisFuntion()
the code i want to add mine into:
import SubCode
class TopLevel(Frame):
def __init__(self, master):
Frame.__init__(self,master)
*Creates main GUI window*
MyButton = Button(root, command = self.CallSubCode)
def CallSubCode(self):
SubCode.AnalysisFunction()
root = Tk()
main_window = TopLevel(root)
root.mainloop()
Any ideas why the subcode alone can save figures but it cannot when called by the larger GUI? FYI, it still creates all variables correctly when running through the larger GUI.
I think you should just save the image in SubCode.py without creating a tkinter window. i.e
def AnalysisFunction():
*does things*
os.chdir(OutputFolder)
plt.savefig('image.png')
if __name__ == '__main__':
AnalysisFuntion()
i figured it out, I had to put the whole SubCode within a class structure, then call it as its own Toplevel app. I think otherwise the plt.savefig command doesn't know which Tkinter window it is working with, and tries to find data in the "host" window, not the one which is handling the data.

Simple Python GUI program won't run, says RESTART

I'm trying to create a python program that pulls up a simple window that displays the text "Hello World?" I've imported tkinter and have created a class called MyGUI that should create a simple window. Then I create an instance of the MyGUI class. When I hit "F5" or run the programming after saving it, I get an error:
RESTART: C:....my filepath.....
>>>
Here is the code:
import tkinter
class MyGUI:
def init (self):
# Create the main window widget.
self.main_window = tkinter.tk()
# Create a Label widget containing the
# text 'Hello World!'
self.label = tkinter.Label(self.main_window, text="Hello World!")
# Call the Label widget's pack method.
self.label.pack()
# Enter the tkinter main loop.
tkinter.mainloop()
# Create an instance of the MyGUI class
my_gui = MyGUI()
What causes the "RESTART" error? Does where I save my .py file matter for this program?
Any help would be greatly appreciated. Thanks
The good news:
Your code works (in that it doesn't crash in python3, as is)!
The bad news:
Your code doesn't do anything :( Your only function would raise an exception if called
You have a code-unrelated problem
To resolve problem #1, change init to __init__ and tkinter.tk to tkinter.Tk()
__init__ is the function called by default on instance construction. The underscores are important if you want to override it. The other issue is just a typo.
You're broader problem is... broader. yes it matters where you save your file. If you don't save it in the place you are running python from, you need to supply an absolute path to it, or a relative path from the place you are running from. This is a broad topic, but pretty important and not too challenging. Maybe try here, or any python tutorial.
I don't know what type F5 does on your computer. I would not in general expect it to run python code. Are you in an IDE, then maybe it does run python code? Are you playing call of duty, because then it's more likely to lob a virtual grenade? F5 is app-dependent, probably not a universal binding on your machine

Python and Tkinter: object oriented programming query

I am trying to learn python, Tkinter and oop. Below is the code that I wrote after following tutorial on effbot.org
from Tkinter import Tk, Frame, Label
class Nexus(object):
"""Top level object which represents entire app"""
def __init__(self, main_window):
self.nexus_frame = Frame(main_window)
self.nexus_frame.pack()
self.label = Label(main_window, text="Tkinter")
self.label.pack()
def main():
main_window = Tk()
nexus_app = Nexus(main_window)
main_window.wm_title("Hello World Window")
width = main_window.winfo_screenwidth()
height = main_window.winfo_screenheight()
main_window.wm_minsize(width=width-100, height=height-100)
main_window.mainloop()
if __name__ == "__main__":
main()
Here a top level window is created first and it is passed as argument to Nexus class where I am adding a frame and a label to the frame. Then I am setting the size of top level window relative to current screen size back in the main function.
My question is why was the top level window create in main function?
Could it not be created inside __init__ of Nexus class itself?
What difference would it make if main_window was create inside __init__ of Nexus class and mainloop() was started therein?
Once Tk.mainloop is entered, no further code will be executed. Instead, the Tk event loop will take over (hence the name).
What that means is that if you, eg, did something like this:
def main():
...
main_window.mainloop()
print 'Hello world!'
then that print statement would never be executed (or, at least, not while the GUI is running).
So, with that in mind, why is there a problem with creating the root window and executing main loop within the constructor (the __init__ statement)? Well, two basic reasons:
It would mean that the constructor never returns, which is unexpected. If a programmer sees this:
def main():
Nexus()
print 'Hello world!'
then he or she will expect that print statement to be executed. As a rule, you don't expect creating an instance of a class to be the kind of thing which will cause an infinite loop (as the event loop is).
Related to that is the second reason: it would not be possible to create more than one instance of Nexus, because as soon as you create one, Tk.mainloop will take over. Again, that's unexpected: a class is a description of a type of object, and you would normally expect to be able to instantiate more than one object like that.
At the moment, if you write:
def main():
...
Nexus(main_window)
Nexus(main_window)
then you'll get two copies of your Nexus window on the screen. That's expected, and sensible. The alternative would not be.
So what's the take-away message?
When you're dealing with GUI programs, entering the event loop is the last thing you want to do. Your setup might involve creating one object (as now), or it might involve creating many objects (eg, a complex GUI app might have two or three windows).
Because we want to be able to write similar code in both cases, the usual approach is to create the root window (the Tk object) once, and then pass it in as a reference to any classes that need to know about it.

Accessing GUI elements from outside the GUI class

I'm hoping someone can help me with a Qt designer question. I'm trying to modify GUI elements from outside the class calling the GUI file. I've set up example code showing the structure of my programs. My goal is to get func2, in the main program (or another class) to change the main window's statusbar.
from PyQt4 import QtCore, QtGui
from main_gui import Ui_Main
from about_gui import Ui_About
#main_gui and about_gui are .py files generated by designer and pyuic
class StartQT4(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Main()
self.ui.setupUi(self)
self.ui.actionMyaction.triggered.connect(self.func1)
#Signals go here, and call this class's methods, which call other methods.
#I can't seem to call other methods/functions directly, and these won't take arguments.
def func1(self):
#Referenced by the above code. Can interact with other classes/functions.
self.ui.statusbar.showMessage("This works!")
def func2(self):
StartQT4.ui.statusbar.showMessage("This doesn't work!")
#I've tried many variations of the above line, with no luck.
#More classes and functions not directly-related to the GUI go here; ie the most of the program.
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = StartQT4()
myapp.show()
sys.exit(app.exec_())
I'm trying to get func2 to work, since I don't want my whole program to be under the StartQT4 class. I've tried many variations of that line, but can't seem to access GUI items from outside of this class. I've tried sending signals as well, but still can't get the syntax right.
It's possible that my structure is bogus, which is why I posted most of it. Essentially I have a .py file created by Designer, and my main program file, which imports it. The main program file has a class to initiate the GUI, (and a class for each separate window). It has signals in this class, that call methods in the class. These methods call functions from my main program, or other classes I've created. The end of the program has the if __name__ == "__main__" code, to start the GUI. Is this structure bogus? I've read many tutorials online, all different, or outdated.
Your func1 method is a way to go - since ui is a field in StartQT4 class, you should directly manipulate with its data only within the same class. There is nothing wrong that you have all user interface functionality for one widget in one class - it is not a big issue if you have only two classes in your code, but having several classes to reference the fields directly is potential nightmare for maintentace (what if you change the name of statusbar widget?).
However, if you actually want to edit it from func2, then you need to pass the reference of StartQT4 object to it, because you need to specify for what instance of window you need to change status bar message.
def func2(qtWnd): # Self should go here if func2 is beloning to some class, if not, then it is not necessary
qtWnd.ui.statusbar.showMessage("This should work now!")
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = StartQT4()
myapp.show()
func2(myapp)
sys.exit(app.exec_())

Categories

Resources