I have created a notebook and added a frame to it:
nb = ttk.Notebook(root, style="TNotebook")
page1 = ttk.Frame(nb, style='Frame1.TFrame')
layout1(page1)
nb.add(page1, text='Welcome')
So i have a function layout1, the first page of the notebook,
i added to it a Text:
def layout1(page):
entry = Text(page, width=20)
entry.place(relx=0.03, rely=0.1, height=400)
Button(page, text='EXECUTE', command=import_entry).place(relx=0.5, rely=0.6)
And next i have my import_entry function:
def import_entry():
result = entry.get()
print(result)
I can't get the entry because of accessibilty of variables in function. So, how can i get it?
Here is an example of how you should structure your app with a class:
import tkinter
import tkinter.ttk as ttk
class App(tkinter.Tk):
def __init__(self):
super().__init__()
# assign on_closing method to window close event
self.protocol("WM_DELETE_WINDOW", self.on_closing)
self.title("Example App")
self.geometry("600x500")
self.button_1 = tkinter.Button(master=self, text="Test", command=self.button_event)
self.button_1.pack(pady=10)
# create more widgets ...
def button_event(self, event):
print("button pressed")
def on_closing(self):
# code that needs to happen when gets closed
self.destroy() # controlled closing of window with .destroy()
if __name__ == "__main__":
app = App()
app.mainloop()
Related
I'm tinkering with Tkinter and trying to check if my program is open on pressing a button, but the Tkinter is not updating my label. Why?
from win32gui import GetWindowRect, FindWindow
from tkinter import Tk, ttk, BooleanVar
class Bot:
root = Tk()
is_gta_open = BooleanVar(None, False)
def mta_open_string(self):
return "włączone" if self.is_gta_open.get() else "wyłączone"
def draw_gui(self):
frame = ttk.Frame(self.root, padding=10)
frame.grid()
ttk.Label(frame, text=f"Status gry: {self.mta_open_string()}").grid(column=0, row=0)
ttk.Button(frame, text="Odśwież", command=lambda: [self.try_finding_rect(), self.root.update()]).grid(column=1, row=0)
self.root.mainloop()
def try_finding_rect(self):
window_handle = FindWindow("Grand theft auto San Andreas", None)
if window_handle == 0:
self.is_gta_open.set(False)
return
self.is_gta_open.set(True)
def run(self):
self.try_finding_rect()
self.draw_gui()
if __name__ == "__main__":
Bot().run()
I'm updating the state using self.root.update method and using BooleanVar, so I don't know why this is not working.
I've put together a very minimal example app that should work as intended. I don't have a copy of GTA to test with so I used a different app, but it should function the same way with any app in principle:
import tkinter as tk
import ctypes
from tkinter import ttk
class Bot(tk.Tk): # init Tk
def __init__(self):
super.__init___()
APP_NAME = 'Grand theft auto San Andreas'
self.status_label = tk.Label(self, text='Press the button')
self.status_label.pack()
self.run_btn = ttk.Button(
self,
text='Click Me!',
command=lambda: self.check_for_app(APP_NAME)
)
self.run_btn.pack()
def check_for_app(app_name: str):
user32 = ctypes.WinDLL('user32')
if user32.FindWindowW(None, app_name):
self.status_label.config(text='Running')
else:
self.status_label.config(text='Not Running')
if __name__ == '__main__':
app = Bot()
app.mainloop()
Updating a variable won't change an f-string that uses the variable. You must explicitly configure the widget to show the new value.
To do that you'll need to keep a reference to the label widget, and then update the widget with the configure method.
def draw_gui(self):
...
self.status_label = ttk.Label(frame, text=f"Status gry: {self.mta_open_string()}")
self.status_label.grid(column=0, row=0)
...
def try_finding_rect(self):
...
self.is_gta_open.set(True)
self.status_label.configure(text=f"Status gry: {self.mta_open_string()}")
Personally I recommend using a proper method for the button rather than a complicated lambda. That will make the code easier to read and easier to debug.
For example:
def draw_gui(self):
...
ttk.Button(frame, text="Odśwież", command=self.update_status)
...
def update_status(self):
self.try_finding_rect(),
self.status_label.configure(text=f"Status gry: {self.mta_open_string()}")
from tkinter import *
root = Tk()
def main():
Window1 = Window(root, "hello", "500x500",)
class Window:
def __init__(self, root, title, geometry,):
self.root = root
root.title(title)
root.geometry(geometry)
root.mainloop()
class Button(Window):
def __init__(self, message):
self.message = message
super().__init__(root,)
Button(root, text=message,).pack()
root.mainloop()
Button("HI")
main()
One of the two major issues I see is that your Button class is hiding the one that tkinter defines with the same name that would have been available via the from tkinter import *. The second one is that your Button shouldn't be derived from your Window class because subclassing implies there's is an "is a" relationship between the two classes — which is clearly not the case with them.
Below is an object-oriented way to do things that does work:
import tkinter as tk # PEP 8 recommends avoiding `import *`
def main():
root = tk.Tk()
window1 = Window(root, "hello", "500x500")
Button(root, "HI")
root.mainloop()
class Window:
def __init__(self, root, title, geometry):
self.root = root
root.title(title)
root.geometry(geometry)
class Button:
def __init__(self, parent, message):
self.message = message
tk.Button(parent, text=message).pack()
if __name__ == '__main__':
main()
There are a couple of issues.
Firstly, you're creating a subclass of Window called "Button". When you subclass something, it means that it will be of a similar type as it's parent (Window != Button). But more than that, when you define Button, you're actually hiding tkinter's button!
Second, you need to think about the event loop. When working with GUIs, you want to set everything up (where is the button, where are form elements, etc.) before running the mainloop (where possible). You're calling the root.mainloop function in each element, when you should only really call it once (and probably in your main() method).
So how to actually do it? You're code may look something like this
from tkinter import *
class Window:
def __init__(self, root, title, geometry, ):
self.root = root
root.title(title)
root.geometry(geometry)
def add_button(self, label):
btn = Button(self.root, text=label)
btn.pack(side='top')
def main():
root = Tk()
Window1 = Window(root, "hello", "500x500", )
Window1.add_button("Hi!")
root.mainloop()
if __name__ == "__main__":
main()
Here, the window has a method called "add_button", where you can add whatever button you want. Note that it is just creating a new Button object (the parent is "root") and then is "packing" it (feel free to read more about tk's layouts), which puts it in its place
I've also cleaned up the main function and called it under the classic 'if name == "main":' line.
import tkinter as tk
def main():
root = tk.Tk()
window1 = Window(root, "hello", "500x500")
Button(root, "Click me", 2, 2, 10, 5)
root.mainloop()
class Window:
def __init__(self, root, title, geometry):
self.root = root
root.title(title)
root.geometry(geometry)
class Button:
def __init__(self, parent, message, row, column, width, height,):
self.message = message
self.row = row
self.column = column
self.width = width
self.height = height
tk.Button(parent, text=message, height=height, width=width).grid(column=column, row=row)
if __name__ == '__main__':
main()
the grid function isnt working now lol
When a resize event is triggered, how could I retrieve the toplevel, from which this event was triggered?
I have written a small programm, where the main window has a button that opens another window and each new window gets a binding for the resize method that currently prints the height and width of the window. In the main project, the toplevel is used as an index for lists to retrieve information for that specific window, so it would be ideal to be able to retrieve the toplevel as well. Is that possible, either directly or indirectly?
import tkinter as tk
class MyApp(tk.Frame):
def __init__(self, master = None):
self.main()
tk.Frame.__init__(self, master)
def main(self):
btn = tk.Button(root, text="New Window", command=self.neues_fenster)
btn.grid(row=0, column = 0)
def neues_fenster(self):
top = tk.Toplevel()
top.title("Some Window")
top.minsize(width = 150, height = 150)
top.bind("<Configure>", self.resize)
def resize(self, event):
print("width", event.width, "height", event.height)
if __name__=="__main__":
root = tk.Tk()
myapp = MyApp(master = root)
myapp.mainloop()
In effbot document,You could use event.widget to get the widget.(It is also okay even if it is toplevel).
All the possible attributes of event:
I want my GUI to have a 'new window' option that will be just the same as the first one.
The problem is that it also has an exit(quit) button that won't work as it should - whenever I open the new window and then press the button, in the first click nothing happens and in the second one it closes both windows (if 3 windows are open so it'll close everything in the third click and so on).
This the relevant code:
from Tkinter import *
from ttk import *
class Application(Tk):
def __init__(self):
self.root = Tk()
self.root.geometry("250x150")
self.app = Frame(self.root)
self.app.grid()
self.create_menu()
self.create_widgets()
self.root.mainloop()
def create_menu(self):
menu = Menu(self.root)
self.root.config(menu=menu)
sub_menu = Menu(menu)
menu.add_cascade(label="File", menu=sub_menu)
sub_menu.add_command(label="New", command=self.__init__)
sub_menu.add_command(label="Run", command=self.enter)
sub_menu.add_separator()
sub_menu.add_command(label="Exit", command=self.app.quit)
I also tried to change:
sub_menu.add_command(label="New", command=self.__init__)
to:
sub_menu.add_command(label="New", command=self.new window)
Where:
def new_window(self):
class App(Application):
Application.__init__(self)
Both do the same thing.
How can I fix it?
In a Tkinter-Application there may only be one Tk-object. If the object is destroyed or destroyed by the garbage collector, Tkinter will be disabled. Use Toplevel for other other windows instead.
Try this instead:
from Tkinter import *
from ttk import *
class Application(object):
def __init__(self, master):
self.root = master
self.root.geometry("250x150")
self.app = Frame(self.root)
self.app.grid()
self.create_menu()
self.create_widgets()
def create_menu(self):
menu = Menu(self.root)
self.root.config(menu=menu)
sub_menu = Menu(menu)
menu.add_cascade(label="File", menu=sub_menu)
sub_menu.add_command(label="New", command=self.new)
sub_menu.add_command(label="Run", command=self.enter)
sub_menu.add_separator()
sub_menu.add_command(label="Exit", command=self.quit)
def new(self):
window = Toplevel(tk)
return Application(window)
def quit(self):
tk.destroy()
tk = Tk()
Application(tk)
tk.mainloop()
I want to create a popup message box which prompts user to enter an input. I have this method inside a class. I am basing my code on this guide by java2s.
class MyDialog:
def __init__(self, parent):
top = self.top = Toplevel(parent)
Label(top, text="Value").pack()
self.e = Entry(top)
self.e.pack(padx=5)
b = Button(top, text="OK", command=self.ok)
b.pack(pady=5)
def ok(self):
print "value is", self.e.get()
self.top.destroy()
root = Tk()
d = MyDialog(root)
root.wait_window(d.top)
But in this, top = self.top = Toplevel(parent) doesn't work for me.
I have a mockup of what I am trying to accomplish.
My program structure looks something like this:
class MainUI:
def__int__(self):
...
self.initUI()
def initUI(self):
.......
Popup = Button(self, text="Enter Value", command=self.showPopup)
def showPopup(self):
#create the popup with an Entry here
How can I create a message box in Python which accepts user input?
I'm a little confused about your two different blocks of code. Just addressing the first block of code, nothing happens because you never enter the mainloop. To do that, you need to call root.mainloop(). The typical way of doing this is to add a button to root widget and bind a callback function to the Button (which includes d=MyDialog() and root.wait_window(d.top))
Here's some basic code which I hope does what you want ...
from Tkinter import *
import sys
class popupWindow(object):
def __init__(self,master):
top=self.top=Toplevel(master)
self.l=Label(top,text="Hello World")
self.l.pack()
self.e=Entry(top)
self.e.pack()
self.b=Button(top,text='Ok',command=self.cleanup)
self.b.pack()
def cleanup(self):
self.value=self.e.get()
self.top.destroy()
class mainWindow(object):
def __init__(self,master):
self.master=master
self.b=Button(master,text="click me!",command=self.popup)
self.b.pack()
self.b2=Button(master,text="print value",command=lambda: sys.stdout.write(self.entryValue()+'\n'))
self.b2.pack()
def popup(self):
self.w=popupWindow(self.master)
self.b["state"] = "disabled"
self.master.wait_window(self.w.top)
self.b["state"] = "normal"
def entryValue(self):
return self.w.value
if __name__ == "__main__":
root=Tk()
m=mainWindow(root)
root.mainloop()
I get the value from the popupWindow and use it in the main program (take a look at the lambda function associated with b2).
Main window:
"Click me" window:
Main window while "click me" is open:
import tkinter as tk
from tkinter import simpledialog
ROOT = tk.Tk()
ROOT.withdraw()
# the input dialog
USER_INP = simpledialog.askstring(title="Test",
prompt="What's your Name?:")
# check it out
print("Hello", USER_INP)
Enjoy ...
I did it in Tkinter without any classes. I created a function that starts a new window.
popup.Tk()
popup.mainloop()
In that window there is an Entry field from where I get the text with a variable which value is: entry.get()
Then you can use that variable for whatever you need and it will take the text from that Entry field.
I just tried this:
def get_me():
s = simpledialog.askstring("input string", "please input your added text")
Source: https://www.youtube.com/watch?v=43vzP1FyAF8