With a simple tkinter gui like this:
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.grid()
self.createWidgets()
def printHello(self):
print("Hello")
def createWidgets(self):
self.quitButton = tk.Button(self, text='Quit',
command=self.quit)
self.quitButton.grid(row=1,column=0)
self.printButton = tk.Button(self, text='Print',command=lambda: self.printHello())
self.printButton.grid(row=1,column=1)
app = Application()
app.master.title('Sample application')
app.mainloop()
I am trying to follow this documentation to connect the event loop with the ipython notebook's kernel: https://ipython.org/ipython-doc/3/config/eventloops.html
But I can't quite seem to grasp how it works especially: #register_integration('tk')
How can I exactly connect the event loops? And if I do, what can I do with a connected event loop?
Related
I am new to Python, so I don’t have any code that I tried or tested. Do any of know how to open a blank window that can be ran with Python? I’m aware this has probably been asked, however I couldn’t find it. Thank you.
Using tkinter you can do this to open a blank window:
from tkinter import *
root = Tk()
root.title("Hello this is title")
root.geometry("500x300")
root.mainloop()
Try this, should work fine:
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.create_widgets()
def create_widgets(self):
self.hi_there = tk.Button(self)
self.hi_there["text"] = "Hello World\n(click me)"
self.hi_there["command"] = self.say_hi
self.hi_there.pack(side="top")
self.quit = tk.Button(self, text="QUIT", fg="red", command=self.master.destroy)
self.quit.pack(side="bottom")
def say_hi(self):
print("hi there, everyone!")
root = tk.Tk()
app = Application(master=root)
app.mainloop()
I have created a small application in tkinter before using just top down programming but I am starting another project, this time using OOP and classes. But I'm having a hard time getting started, I just need someone to point me in the right direction. I've already dabbled in OOP with PyGame but I'm having difficulty with tkinter. Heres my code, where i'm just trying to display a button to the screen:
import tkinter as tk
from tkinter import ttk as ttk
import sqlite3
class Button(tk.Frame):
def __init__(self):
tk.Frame.__init__(self)
tk.Button(root, text = "Hello", width = 25)
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
self.button = Button()
self.button.pack(side="bottom",fill="x")
if __name__ == "__main__":
root = tk.Tk()
MainApplication(root).pack(side="top", fill="both", expand=True)
root.mainloop()
Try this:
import tkinter as tk
from tkinter import ttk # The `as tkk` isn't needed
# Here you might want to consider inheriting from `tk.Button` but it isn't going to change anything
class Button(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
# It's always a good idea to keep a reference to all of your widgets
self.button = tk.Button(self, text="Hello", width=25)
# You should call `.pack`/`.grid`/`.place` here:
# Note it doesn't really matter which one you choose
self.button.pack(fill="both")
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent # Technically this isn't needed because the line above sets `self.master` to parent
self.button = Button(self) # Pass in self into the Button class
self.button.pack(side="bottom", fill="x")
if __name__ == "__main__":
root = tk.Tk()
main_app = MainApplication(root)
main_app.pack(side="top", fill="both", expand=True)
root.mainloop()
I passed in self when creating the Button object in self.button = Button() and I called self.button.pack(...) inside the Button class.
The whole point of OOP programming it to limit global variables and group similar objects in a single class definition. That is why both your Button and MainApplication classes shouldn't rely on root. Apart from that, your code is very nice :D
I am creating a GUI on Tkinter that needs to open or close windows when buttons are pressed, and I would prefer if each window was in its own file. I tried creating a very simple example of this with the three files below. The first window is supposed to have a button that, when pressed, closes the current window and opens the next one. I'm currently running into a problem where the window is created but the button is not. How do I fix this?
Main.py
from MyTkWindow import *
myWindow = MyTkWindow()
myWindow.start()
MyTkWindow.py
import tkinter as tk
from NextFrame import *
class MyTkWindow(tk.Frame):
def __init__(self, parent=None):
tk.Frame.__init__(self)
nextWin = NextWindow()
NextScreen = tk.Button(self, text="Next", command=lambda:[self.destroy(), nextWin.start()])
NextScreen.pack()
def start(self):
self.mainloop()
NextFrame.py
import tkinter as tk
class NextWindow(tk.Frame):
def __init__(self, parent=None):
tk.Frame.__init__(self)
Leave = tk.Button(self, text="Quit", command=lambda: self.destroy())
Leave.pack()
def start(self):
self.mainloop()
I got this to work with the indicated changes. The primary problem was due to not calling the pack() method of the windows/frames being created.
main.py:
from MyTkWindow import *
myWindow = MyTkWindow()
myWindow.pack() # ADDED
myWindow.start()
MyTkWindow.py:
import tkinter as tk
from NextFrame import *
class MyTkWindow(tk.Frame):
def __init__(self, parent=None):
tk.Frame.__init__(self, parent) # ADDED parent argument.
nextWin = NextWindow()
NextScreen = tk.Button(self, text="Next",
command=lambda: [self.destroy(),
nextWin.pack(), # ADDED
nextWin.start()])
NextScreen.pack()
def start(self):
self.mainloop()
NextFrame.py:
import tkinter as tk
class NextWindow(tk.Frame):
def __init__(self, parent=None):
tk.Frame.__init__(self, parent) # ADDED parent argument.
Leave = tk.Button(self, text="Quit",
command=lambda: self.destroy())
Leave.pack()
def start(self):
self.mainloop()
Suggestion: Read and start following the PEP 8 - Style Guide for Python Code because it will make your code more understanable and maintainable. Specifically, the Naming Conventions section especially with respect to class, variable, and module file names.
A script should open an application with two buttons visible. When Hello button is pressed a new button is gridded into the row number 1 and Hello button to be deactivated. When this new button is pressed it should delete itself off the grid and reactivate hello button but it does not do it.
Please check the video to see it in action.
Code edited to comment suggestion
from tkinter import *
class Application(Frame):
def __init__(self, master=None):
self.master = master
self.master.geometry('300x100+10+10')
Frame.__init__(self, master)
self.pack()
self.createWidgets()
def new_button(self):
print("enable_b")
self.hi_there.config(state=ACTIVE)
self.new_button.grid_remove()
def say_hi(self):
print("hi there, everyone!")
self.new_button = Button(self)
self.new_button.config(text = "New BTN", command=self.new_button)
self.new_button.grid(row=1,column=0)
self.hi_there.config(state=DISABLED)
def createWidgets(self):
self.QUIT = Button(self)
self.QUIT.config(text="QUIT",fg="red",command=self.quit)
self.QUIT.grid(row=0,column=1)
self.hi_there = Button(self)
self.hi_there["text"] = "Hello",
self.hi_there["command"] = self.say_hi
self.hi_there.grid(row=0,column=0)
def quit(self):
self.master.destroy()
def testit():
root = Tk()
app = Application(master=root)
app.mainloop()
if __name__ == '__main__':
testit()
Initially, self.new_button refers to a method. Then, you do this:
self.new_button = Button(self)
That effecting removes the method and replaces it with the button widget itself.
Also, you never assign a command to the new button, so clicking it doesn't cause anything to be called.
Where your program will technically work just fine with the 2 correction mentioned in Bryan's answer I am not sure why you are taking all the extra effort configuring the widgets for each individual field. All your configs can be done when you create the widget.
That said you can also change a few things for a cleaner code and 1 change I think that really needs to be made is how you are removing the new_button from the grid. When you do grid_remove() this only takes the widget off the screen but does not get rid of the widget. Then next time you press the say_hi button you will end up creating a new button and the old button will still exist. Instead I think I would use destroy() on the button and then let say_hi recreate it.
See this revised version of your code. You will see what I mean about configuring everything when creating the widget and also you do not need to write your own function for quit you can simply do self.master.destroy in the quit button command.
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.master = master
self.master.geometry('300x100+10+10')
self.create_widgets()
def new_btn(self):
print("enable_b")
self.hi_there.config(state="active")
self.new_button.destroy()
def say_hi(self):
print("hi there, everyone!")
self.new_button = tk.Button(self, text="New BTN", command=self.new_btn)
self.new_button.grid(row=1, column=0)
self.hi_there.config(state="disabled")
def create_widgets(self):
tk.Button(self, text="QUIT", fg="red", command=self.master.destroy).grid(row=0,column=1)
self.hi_there = tk.Button(self, text="Hello", command=self.say_hi)
self.hi_there.grid(row=0, column=0)
if __name__ == '__main__':
root = tk.Tk()
app = Application(master=root).pack()
root.mainloop()
I have a very simple program with TkInter in Python.
How to I use the "fill" or "expand" options with the following code?
from Tkinter import *
class Application(Frame):
def sayhello(self):
print "Hello!"
def createWidgets(self):
self.var = Button(self, text="Hello", command = self.sayhello)
self.var.pack(side=LEFT)
self.QUIT = Button(self, text="QUIT", fg="red", command = self.quit)
self.QUIT.pack(side=LEFT)
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
root = Tk()
app = Application(master=root)
app.mainloop()
root.destroy()
Note: I have to use the self.var.pack() format so it can do a "command" when it's pressed...unless anyone has a better way?
To make an object fill it's container in the y axis, you would use the parameter fill="y" (or fill=Y if you import Y from Tkinter).
Note that this only controls how the widget fills its container. In your code, this makes the button fill the inner frame, but because your inner frame doesn't fill the main window in the y axis, you might not get the visual effect you expect.
Also, specifically in the case of buttons on the Macintosh, the button won't grow to fill the space. On OSX, buttons are native widgets which can't grow in height.