No errors but wont run - python

So I have this code:
try:
# for Python2
from Tkinter import *
except ImportError:
# for Python3
from tkinter import *
class Injector():
def __openInjector(self):
root = Tk()
root.geometry('600x400')
root.title('Toontown Rewritten Injector')
root.resizable(False, False)
def __init__(self):
self.code = ''
self.__openInjector()
def runInjectorCode(self):
exec(self.code.get(1.0, 'end'), globals())
def __openInjector(self):
root = Tk()
root.geometry('600x400')
root.title('Toontown Rewritten Injector')
root.resizable(False, False)
frame = Frame(root)
self.code = Text(frame, width=70, height=20)
self.code.pack(side='left')
Button(root, text='Inject!', command=self.runInjectorCode).pack()
scroll = Scrollbar(frame)
scroll.pack(fill='y', side='right')
scroll.config(command=self.code.yview)
self.code.config(yscrollcommand=scroll.set)
frame.pack(fill='y')
Injector()
In the IDLE console it works fine and does everthing I want it to do. But whenever I run the .py file on my Desktop. The black window appears, then just closes and nothing happens. Any help?

First, you have two methods in your class with the same name. The first one gets overwritten by the second one. At the end of that second one, you need the following line:
root.mainloop()
This will actually run the GUI. It's needed when running from a script, but not when running within the interactive interpreter.
Add it at the end of the second __openInjector:
...
self.code.config(yscrollcommand=scroll.set)
frame.pack(fill='y')
root.mainloop()

At the end of your second __openInjector method, add the line: root.mainloop().
This is necessary for Tkinter to run your code. mainloop is really nothing more than an infinite loop that waits for events. An event may be a user interaction, such as clicking a button.
My guess is you don't need mainloop when running interactively for purely convenience reasons.

Related

Why doesn't Tkinter Entry's get function return anything?

I'm trying to use two dialogs to get manual input, and then work with that data.
All source I've found claim I should use the get() function, but I wrote a simple mini program yet, and I can't make the second dialog work.
I hope someone can tell me what I'm doing wrong. Here's a file:
from tkinter import *
from tkinter.filedialog import askdirectory
from tkinter import messagebox
def getpath():
def selectPath():
path_ = askdirectory()
path.set(path_)
root = Tk()
root.title('select path')
path = StringVar()
def close():
if(path.get()==""):
messagebox.showinfo("","nothing")
else:
root.withdraw()
root.quit()
Label(root,text="path:").grid(row=0,column=0)
Entry(root,textvariable = path).grid(row=0,column=1)
Button(root,text="select",command=selectPath).grid(row=0,column=2)
Button(root,text="enter",command=close).grid(row=0,column=3)
root.mainloop()
return path.get()
def getname():
def get_need_name():
name = need_name.get()
print('hereherehere'+name) #does not work
root = Tk()
root.title('select name')
need_name = StringVar()
Label(root,text="name:").grid(row=0,column=0)
entry = Entry(root,bd=10,textvariable=need_name)
entry.grid(row=0,column=1)
Button(root,text="enter", font=16, bg="silver", relief='groove', command=get_need_name).grid(row=0,column=2)
root.mainloop()
return name.get()
def main():
path = getpath()
print("mypath:"+path)
print('******************')
print('done!')
name = getname()
print("myname:"+name)
if __name__ == '__main__':
main()
This give me two dialogs I can type in, but only the first dialog works.
The reason is that you are creating multiple instances of Tk, and you don't destroy the instances when you are done with them. This causes two problems. First is a memory leak. Each time you call one of these functions you create a new window and a new tcl interpreter.
The second problem is that the first root window becomes the default window when a root isn't specified. When you create a StringVar in the second function, because you didn't specify which root window it belongs to it will be assigned to the first root window. When you use it as the target of textvariable in a second instance of Tk, tkinter thinks the variable doesn't exist so it creates a new one for the second window. However, your reference is still to the one created in the first root window and is never updated by user input in the second window.
Confusing? Yes, which is why you typically shouldn't be creating more than one instance of Tk.
To make your code work with as few changes as possible and to remove the memory leak caused by not destroying the windows, you can change the last couple of lines in your method to look like the following. This destroys the root window when you are done with it, removing the memory leak and the side effect of having more than one root window.
root = Tk()
...
root.mainloop()
value = path.get()
root.destroy()
return value
The second dialog should look similar:
root = Tk()
...
root.mainloop()
value = name.get()
root.destroy()
return value
This retrieves the value after mainloop exits but before the underlying tcl interpreter is deleted, and then destroys the window and its tcl interpreter.
The next time you create an instance of Tk, that instance will become the new default root, and any new instance of StringVar will go to that root.
Another solution would be to specify the master for the StringVar instance, but that leaves the memory leak in place so it's only half of a solution.
Arguably a better solution is to create a single root window, and either reuse it or create instances of Toplevel rather than Tk. Effbot has some decent documentation on how to create a modal window with wait_window.
After some testing, and googling the root.quit() is the problem
here is a working example for you to look at and mess with.
from tkinter import *
from tkinter.filedialog import askdirectory
from tkinter import messagebox
root = Tk()
path = StringVar()
def select_path():
#uses the return value to set no need to create an additional variable
path.set(askdirectory())
def close():
if path.get() == "":
messagebox.showinfo("","Please select path")
else:
get_name_frame.tkraise()
def get_name():
print("hereherehere", name.get())
get_path_frame = Frame(root)
get_path_frame.grid(row=0, column=0, sticky="nsew")
Label(get_path_frame,text="path:").grid(row=0,column=0)
Entry(get_path_frame,textvariable = path).grid(row=0,column=1)
Button(get_path_frame,text="select",command=select_path).grid(row=0,column=2)
Button(get_path_frame,text="enter",command=close).grid(row=0,column=3)
get_name_frame = Frame(root)
get_name_frame.grid(row=0, column=0,sticky="nsew")
Label(get_name_frame, text="name: ").grid(row=0, column=0)
name = StringVar()
entry = Entry(get_name_frame, bd=10, textvariable = name)
entry.grid(row=0, column=1)
Button(get_name_frame,text="enter", font=16, bg="silver", relief='groove', command=get_name).grid(row=0,column=2)
get_path_frame.tkraise()
root.mainloop()

how to call a function from another script inside an imported class

I am building my first larger Python application using tkinter, python 3.6.3 and window OS. The GUI for the application consists of a Notebook with several tabs. Each of the tabs in turn contains a Labelframe which in turn contains a number of other widgets.
When searching Stackflow, I found the idea to lets each labelFrame be a class. Thereafter import the class in the main.py and finally creating an instance of the class.
Now when pressing the button 'Start' in tab1 I would like to execute the 'printThis' function. Ideally I would like to use the function defined in the script main.py. It would also be interested in knowing how to call the 'printThis' method withing the Run_Test_Window class. Unfortunately I have not solved either problem.
Interestingly the program actually prints "Now successful" without that I do anything but when I press the 'Start'-button nothing happens.
Grateful for help! Thanks!
main.py
import tkinter as tk
import tkinter.ttk as ttk
import RunTestClass as RT
def printThis():
print('Successful')
root = tk.Tk()
note = ttk.Notebook(root)
note.grid()
tab1 = ttk.Label(note, width = -20)
note.add(tab1, text = " Run Test ")
window1 = RT.Run_Test_Window(tab1)
root.mainloop()
RunTestClass.py
import tkinter as tk
import tkinter.ttk as ttk
# from main import printThis
class Run_Test_Window:
def printThis(self):
print('Now successful!')
def __init__(self,tab1):
runTestLabelFrame = ttk.LabelFrame(text ="Run Test", padding =10)
runTestLabelFrame.grid(in_ = tab1, padx = 20, pady = 20)
self.startButton = ttk.Button(runTestLabelFrame, text="START",command=self.printThis())
self.startButton.grid(row=5, column=1, padx = 10)
If I'm correct you want the button to use the printThis() from main. This can be done by adding the following in your main:
rt = RT.Run_Test_Window(tab1)
rt.startButton.configure(command=printThis)
To call the printThis() defined in RunTestClass, use (also in main)
rt.printThis()
Note: leave the brackets when creating the button in the command argument. So change it to this:
self.startButton = ttk.Button(runTestLabelFrame, text="START",command=self.printThis)

Python: Tkinter: Why is it root.mainloop() and not app.mainloop()

I'm a new member to Stack Overflow.
I found this thread, but was not allowed to comment or ask questions on it, so I thought I'd just reference it here: How can I make a in interactive list in Python's Tkinter complete with buttons that can edit those listings?
from tkinter import *
import os
import easygui as eg
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
# character box
Label(frame, text = "Characters Editor").grid(row = 0, column = 0, rowspan = 1, columnspan = 2)
charbox = Listbox(frame)
for chars in []:
charbox.insert(END, chars)
charbox.grid(row = 1, column = 0, rowspan = 5)
charadd = Button(frame, text = " Add ", command = self.addchar).grid(row = 1, column = 1)
charremove = Button(frame, text = "Remove", command = self.removechar).grid(row = 2, column = 1)
charedit = Button(frame, text = " Edit ", command = self.editchar).grid(row = 3, column = 1)
def addchar(self):
print("not implemented yet")
def removechar(self):
print("not implemented yet")
def editchar(self):
print("not implemented yet")
root = Tk()
root.wm_title("IA Development Kit")
app = App(root)
root.mainloop()
Could somebody explain to me why the very last line is root.mainloop()?
Being a novice with Python, and coming from a background that's procedural-oriented with no object-orient experience, I would have thought it would have been app.mainloop().
In fact app = App(root) , app is never used again in the rest of the code! I'm having trouble understanding why root.mainloop() still works.
I'm not sure if you'll find this answer satisfying, but you call root.mainloop() because root is the object that has the mainloop method. In the code you've given, App has no mainloop function.
In simpler terms, this is just how tkinter works -- you always end your script by calling the mainloop method of the root window. When that method returns, your program will exit.
Let's start at the beginning. The simplest, non-OO Tkinter program is going to look like the following example. Note that this is a python 2.x example, and I do not use a global import since I think global imports are bad.
import Tkinter as tk
root = tk.Tk()
<your widgets go here>
root.mainloop()
Many people find that a pure procedural style is not an effective way to write code, so they might choose to write this in an object-oriented style. It's natural to think of "the app" as a singleton object. There are many ways to do this -- the one in your question is, unfortunately, not one of the clearer ways to do it.
A slightly better way, IMO, would be to structure the code like this:
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
<your widgets go here>
app = App()
app.mainloop()
In this case, mainloop is still being called, though now it's a method of App since App inherits from Tk. It is conceptually the same as root.mainloop() since in this case, app is the root window even though it goes by a different name.
So, in both cases, mainloop is a method that belongs to the root window. And in both cases, it must be called for the GUI to function properly.
There is a third variation which is what the code you picked is using. And with this variation, there are several ways to implement it. The variation is your question uses a class to define the GUI, but does not inherit from Tk. This is perfectly fine, but you still must call mainloop at some point. Since you don't create (or inherit) a mainloop function in your class, you must call the one associated with the root window. The variations I speak of are how and where the instance of App is added to the root window, and how mainloop is ultimately called.
Personally I prefer that App inherits from Frame, and that you pack the app outside the definition of the app. The template I use looks like this:
class App(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
<your widgets go here>
if __name__ == "__main__":
root = tk.Tk()
app = App(root)
app.pack(fill="both", expand=True)
root.mainloop()
In this final example, app and root are two completely different objects. app represents a frame that exists inside the root window. Frames are commonly used this way, as a container for groups of other widgets.
So, in all cases, mainloop must be called. where it is called, and how, depends a bit on your coding style. Some people prefer to inherit from the root window, some don't. In either case, you must call the mainloop function of the root window.
I tested both like you see:
One is written with "app." + ".pack()" and one calls "mainframe." + ".grid()"
#-*- coding: utf-8 -*-
#THIS IS THE "MAINFRAME." - PART
from Tkinter import *
import ttk
def show():
p = password.get() #get password from entry
print(p)
root = Tk()
root.title("Ingos first program")
mainframe = ttk.Frame(root, padding="30 30 60 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
password = StringVar() #Password variable
passEntry = Entry(mainframe, textvariable=password, show='*').grid(column=3, row=3, sticky=S)
submit = Button(mainframe, text='Show Console',command=show).grid(column=3, row=4, sticky=S)
root.mainloop()
def show():
p = password.get() #get password from entry
print(p)
#THIS IS THE "APP."-PART. BOTH WORKS FINE.
app = Tk()
app.title("Ingos first program")
password = StringVar() #Password variable
passEntry = Entry(app, textvariable=password, show='#').pack()
submit = Button(app, text='Show Console',command=show).pack()
app.mainloop()
This instance works fine with python 2.7. In that test even app. can handle "mainloop()"
That script opens 2 windows, one after another (if you close the first one) and the first programm is formatted, didn't tryed to write the colum=3... stuff in the pack() clamps.
I still started the Tkinter so don't fight me, just trying.. Hope I could help to answer your question.
All the best, Ingo
The App object is just your app code, and the reason you call App(root) is to make an instance with your class, which then has access to your root window.
It receives this reference in the __init__ method:
def __init__(self, master):
# master refers to the root window now
...
You can see the entire definition of the App object (given by the block beginning with class App:), and it doesn't even have a mainloop method, so to start the main Tkinter loop, you have to call it on the root window.
In the example in the Python2 documentation, they do call it as you suspected should be done, but note that their example class subclasses the Tk object Frame. In your example code, App is an old-style class that doesn't inherit anything.

"execfile" doesn't work properly

I'm trying to make a launcher for my Python program with Tkinter. I used the execfile function, and fortunately it opened the target GUI. However, none of the buttons would work, and it would say the global variable most functions reference isn't defined.
The code to launch the program:
def launch():
execfile("gui.py")
That works. The base code for the target program:
from Tkinter import *
gui = Tk()
gui.title("This is a GUI")
EDIT:
Example of a button:
def buttonWin():
buttonWindow = Toplevel(gui)
button = Button(buttonWindow, text = "Button", width = 10, command = None)
button.pack()
When it references that 'gui' variable for Toplevel, it comes up with an error. I tried defining the 'gui' variable in the Launcher script, but that only caused the target script to open first, instead of the Launcher:
gui = Tk()
launcher = Tk()
launcher.title("Launcher")
def launch():
return execfile("gui.py")
launchButton = Button(launcher, text = "Launch", width = 10, command = launch)
When I try pressing one of this program's buttons, I get a NameError:
$NameError: Global variable 'gui' is not defined$
Also this is in Python 2.7.5.
Thank you anyone who answers, and sorry for any errors with the code blocks; I'm new.
The problem is that you have structured the Tkinter program incorrectly.
In "gui.py" you should have something like:
from Tkinter import *
gui= Tk()
gui.mainloop()
You can add buttons to perform functions and customize it:
from Tkinter import *
gui = Tk()
gui.title("This is a GUI")
def launch():
execfile("gui.py")
launchbutton = Button(gui, text='Launch Program', command=launch)
launchbutton.pack()
gui.mainloop()
I think with your function buttonWin you were trying to do what is normally handled by a class; see unutbu's answer here.
I'm not sure if I've addressed your problem, but this should be a start.

Showing Mouseposition with python

I want to track my mouse-position and show that in a tiny window.
For that, I created this piece of code:
#! /usr/bin/python
from Tkinter import *
from Xlib import display
def mousepos():
data = display.Display().screen().root.query_pointer()._data
return data["root_x"], data["root_y"]
root = Tk()
strl = "mouse at {0}".format(mousepos())
lab = Label(root,text=strl)
lab.pack()
root.title("Mouseposition")
root.mainloop()
This little script shows the mouse-position on startup but doesn't refresh it on mouse-movement. I don't get behind it (did I say that I'm new to python?).
I think I have to use an event from Xlib that tells my script when the mouse is moving...
How do I refresh my mouse-position?
Use root.after to call update periodically.
Use strl = tk.StringVar() and tk.Label(...,textvariable=strl) to
allow the Label text to change.
Call strl.set() to change the Label text.
A default value for screenroot equal to display.Display().screen().root was added
to mousepos so that most of that long chain of function calls are
not repeated every time mousepos is called. Calling mousepos() without any arguments will continue to work as usual.
import Tkinter as tk
import Xlib.display as display
def mousepos(screenroot=display.Display().screen().root):
pointer = screenroot.query_pointer()
data = pointer._data
return data["root_x"], data["root_y"]
def update():
strl.set("mouse at {0}".format(mousepos()))
root.after(100, update)
root = tk.Tk()
strl = tk.StringVar()
lab = tk.Label(root,textvariable=strl)
lab.pack()
root.after(100, update)
root.title("Mouseposition")
root.mainloop()

Categories