Mysterious extra space after buttons in tkinter - python

I'm running tkinter on Python3.4 on Windows and I want two buttons in my GUI box.
I'm following [this link]
The code is this:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.initialize()
def initialize(self):
button_crop = tk.Button(self, text=u"Crop", command=self.OnCrop)
button_crop.pack(side="left")
button_reset = tk.Button(self, text=u"Reset", command=self.OnReset)
button_reset.pack(side="left")
def OnCrop(self):
pass
def OnReset(self):
pass
app = App()
app.mainloop()
Now I get a button which has some extra space to the right
I've tried initialising a grid() and then button_crop.grid(column=0, row=1) but I get the same result.
Please help me remove this extra blank space to the right.

Do you want this behaviour?
import tkinter as tk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.initialize()
def initialize(self):
button_crop = tk.Button(self, text=u"Crop", command=self.OnCrop)
button_crop.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.E, tk.W))
button_crop = tk.Button(self, text=u"Reset", command=self.OnReset)
button_crop.grid(row=0, column=1, sticky=(tk.N, tk.S, tk.E, tk.W))
for i in range(2):
self.columnconfigure(i, weight=1)
self.rowconfigure(0, weight=1)
def OnCrop(self):
pass
def OnReset(self):
pass
app = App()
app.mainloop()

Related

Tkinter reference methods and variables between classes

I am stuck at referencing methods and variables between classes in Tkinter.
Here is an simple example, I have three different types of windows, which I would like to put into different classes.
In the root window, I can click the button to open the second window, where I can input something in to the Text widget.
Also in the 2nd window I want the OK button to read the content in the Text widget and insert the content into another Text widget into the 3rd window. And the Cancel button can close the 2nd window and show the root window again.
There is many bugs in the code, because I couldn't figure out how to make cross references between classes to access the methods and variables.
Could anyone help me to accomplish that? Thanks.
from tkinter import *
from tkinter import scrolledtext
def main():
"""The main app function"""
root = Tk()
root_window = Root(root)
return None
class Root:
def __init__(self, root):
# Main root window configration
self.root = root
self.root.geometry("200x100")
self.btn_ok = Button(self.root, text="Open new window",
command=NewWindow)
self.btn_ok.pack(padx=10, pady=10)
def hide(self):
"""Hide the root window."""
self.root.withdraw()
def show(self):
"""Show the root window from the hide status"""
self.root.update()
self.root.deiconify()
def onClosing(self, window):
window.destroy()
self.show()
class NewWindow:
def __init__(self):
Root.hide()
self.new_window = Toplevel()
lbl = Label(self.new_window, text="Input here:")
lbl.pack(padx=10, pady=(10, 0), anchor=W)
# Create a scrolledtext widget.
self.new_content = scrolledtext.ScrolledText(
self.new_window, wrap=WORD,
)
self.new_content.pack(padx=10, expand=True, fill=BOTH, anchor=W)
# Respond to the 'Cancel' button.
btn_cancel = Button(self.new_window, text="Cancel", width=10,
command=lambda: Root.onClosing(self.new_window))
btn_cancel.pack(padx=10, pady=10, side=RIGHT)
# Add 'OK' button to read sequence
self.btn_ok = Button(self.new_window, text="OK", width=10,
command=WorkingWindow)
self.btn_ok.pack(padx=10, pady=10, side=RIGHT)
def readContent(self):
self.content = self.new_content.get(1.0, END)
self.new_window.destroy()
workwindow = WorkingWindow()
class WorkingWindow:
def __init__(self):
self.work_window = Toplevel()
self.work_content = scrolledtext.ScrolledText(self.work_window, wrap=WORD, font=("Courier New", 11))
self.work_content.pack(padx=10, expand=True, fill=BOTH, anchor=W)
self.work_content.insert(1.0, Root.content)
if __name__ == '__main__':
main()
You were almost there all you have to do is pass the instance of Root class to other class you are calling
Here is the corrected code:
from tkinter import *
from tkinter import scrolledtext
def main():
"""The main app function"""
root = Tk()
root_window = Root(root)
root.mainloop()
class Root:
def __init__(self, root):
# Main root window configration
self.root = root
self.root.geometry("200x100")
self.btn_ok = Button(self.root, text="Open new window",
command=lambda :NewWindow(self))
self.btn_ok.pack(padx=10, pady=10)
def hide(self):
"""Hide the root window."""
self.root.withdraw()
def show(self):
"""Show the root window from the hide status"""
self.root.update()
self.root.deiconify()
def onClosing(self, window):
window.destroy()
self.show()
class NewWindow:
def __init__(self, parent):
parent.hide()
self.new_window = Toplevel()
lbl = Label(self.new_window, text="Input here:")
lbl.pack(padx=10, pady=(10, 0), anchor=W)
# Create a scrolledtext widget.
self.new_content = scrolledtext.ScrolledText(
self.new_window, wrap=WORD,
)
self.new_content.pack(padx=10, expand=True, fill=BOTH, anchor=W)
# Respond to the 'Cancel' button.
btn_cancel = Button(self.new_window, text="Cancel", width=10,
command=lambda: parent.onClosing(self.new_window))
btn_cancel.pack(padx=10, pady=10, side=RIGHT)
# Add 'OK' button to read sequence
self.btn_ok = Button(self.new_window, text="OK", width=10,
command=self.readContent)
self.btn_ok.pack(padx=10, pady=10, side=RIGHT)
def readContent(self):
self.content = self.new_content.get(1.0, END)
self.new_window.destroy()
workwindow = WorkingWindow(self)
class WorkingWindow:
def __init__(self, parent):
self.work_window = Toplevel()
self.work_content = scrolledtext.ScrolledText(self.work_window, wrap=WORD, font=("Courier New", 11))
self.work_content.pack(padx=10, expand=True, fill=BOTH, anchor=W)
self.work_content.insert(1.0, parent.content)
if __name__ == '__main__':
main()

tkinter - how to add scrollbar to all tabs (canvas)

How can i add scrollbar to my Frame in tkinter? I would like to add scrollbar in Comments_tab.
I was trying to play with Canvas, however, i am doing something wrong. Could i ask for your advice please?
class Main(tk.Tk):
def __init__(self):
#
tk.Tk.__init__(self)
#make notebook fill display
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
#Notebook
nb = ttk.Notebook(self)
nb.grid(row=0, column=0, sticky='nswe')
#keep a reference to the pages
self.p0 = Config_tab(self)
self.p1 = Comments_tab(self)
#Canvas
canvas_comments=tk.Canvas(self.p1,bg='#FFFFFF',width=300,height=300,scrollregion=(0,0,500,500))
vbar=tk.Scrollbar(self.p1,orient=tk.VERTICAL)
vbar.grid(row=0, column=0, sticky="NSE")
vbar.config(command=canvas_comments.yview)
tk.Label(self.p1, text="asdddddd").grid(row=0,column=0)
canvas_comments.config(width=300,height=300)
canvas_comments.config(yscrollcommand=vbar.set)
canvas_comments.grid(row=0, column=0, sticky="NSEW")
#tabs
nb.add(self.p0, text="Config")
nb.add(self.p1, text="Comments")
class Comments_tab(tk.Frame):
def __init__(self, master, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
tk.Label(self, text="HU3: ").grid(row=3, column=0)
if __name__ == "__main__":
root = Main()
root.geometry('800x600')
root.title("HAT")
root.mainloop()

Edit/add Tkinter widget in one Tkinter class from another Tkinter class

Suppose I have two tkinter classes which act as separate windows. How could I edit any given widget from one class in the other tkinter class. ALso, how could I add a widget in one tkinter class from the other tkinter class?
from tkinter import Tk, Label, Button
class MyFirstGUI:
def __init__(self, master):
self.master = master
master.title("A simple GUI")
self.label = Label(master, text="This is
our first GUI!")
self.label.pack()
self.greet_button = Button(master,
text="Greet", command=self.greet)
self.greet_button.pack()
self.close_button = Button(master,
text="Close", command=master.quit)
self.close_button.pack()
def greet(self):
print("Greetings!")
root = Tk()
my_gui = MyFirstGUI(root)
root.mainloop()
from tkinter import Tk, Label, Button
class MyFirstGUI2:
def __init__(self, master):
self.master = master
master.title("A simple GUI")
self.label = Label(master, text="This is
our first GUI!")
self.label.pack()
self.greet_button = Button(master,
text="Greet", command=self.greet)
self.greet_button.pack()
self.close_button = Button(master,
text="Close", command=master.quit)
self.close_button.pack()
def greet(self):
print("Greetings!")
root = Tk()
my_gui = MyFirstGUI2(root)
root.mainloop()
I think it would be better to use a Toplevel widget for your two windows (or at least one of them). Right now your first window will be created and the code will stop when it gets to the root.mainloop() line. The second window will not be created until you close the first one.
And you can pass in a reference from each class.
import tkinter
from tkinter import Tk, Label, Toplevel, Button
class MainWidget:
def __init__(self, master):
self.master = master
self.widgetTwo = None
self.label = Label(self.master, text='Widget One')
self.label.pack()
class WidgetTwo(Toplevel):
def __init__(self, master, mainWidget):
Toplevel.__init__(self, master)
self.master = master
self.mainWidget = mainWidget
self.labelTwo = Label(self, text='Widget Two')
self.labelTwo.pack()
Button(self, text='Change Main Widget Text', command=self.ChangeMainWidgetLabel).pack()
def ChangeMainWidgetLabel(self):
self.mainWidget.label.config(text='Widget One text changed')
mw = Tk()
mainWidget = MainWidget(mw)
widgetTwo = WidgetTwo(mw, mainWidget)
mainWidget.widgetTwo = widgetTwo
mw.mainloop()

Calling function from different class gives TypeError: missing 1 required positional argument

I was trying to build something where I wanted to give separate class to each frames. Now when I called onSet function of AddWidgets class it shows an
ERROR: TypeError: onSet() missing 1 required positional argument: 'text'
What am I doing wrong? And how to solve this? My Code is given below:
import tkinter as tk
from tkinter import ttk
class MainWindow:
def __init__(self, master):
self.master = master
self.master.title("Class Function")
self.master.wm_iconbitmap('icon.ico')
self.master.geometry("360x240+100+100")
self.frame1 = ttk.Frame(self.master)
self.frame1.grid(row=0, column=0, padx=16, pady=16)
self.frame2 = ttk.Frame(self.master)
self.frame2.grid(row=0, column=1, padx=16, pady=16)
self.add = AddWidgets(self.frame1)
self.edit = EditWidgets(self.frame2)
class AddWidgets:
def __init__(self, master):
self.master = master
self.create_widgets()
def create_widgets(self):
self.label1 = ttk.Label(self.master, text="0")
self.label1.grid(row=0, column=0, padx=4, pady=4)
def onSet(self, text):
self.label1.configure(text=text)
class EditWidgets:
def __init__(self, master):
self.master = master
self.create_widgets()
def create_widgets(self):
def onEdit():
self.send_text = self.entry_text.get()
AddWidgets.onSet(self.send_text)
self.entry_text = tk.StringVar()
self.entry1 = ttk.Entry(self.master, textvariable=self.entry_text)
self.entry1.grid(row=0, column=0, padx=4, pady=4)
self.button1 = ttk.Button(self.master, text="edit", command=onEdit)
self.button1.grid(row=0, column=1, padx=4, pady=4)
def main():
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
I am new to Python and tkinter. I want to build a desktop app/software. I want to develop the software by following MVC pattern. So any resource for MVC in tkinter and suggestions on how can I improve my coding, software development process would be appreciated.
The method onSet requires the instance of the class as a first argument, while you're only passing the text argument. So when you call your onSet method you should pass the instance of the AddWidgets class as first argument.
You're instantiating this class in the MainWindow class:
self.add = AddWidgets(self.frame1)
So you should pass the self.add variable to the onSet function. In order to do that you should have your EditWidget class accept an additional parameter widget:
class MainWindow:
def __init__(self, master):
self.master = master
self.master.title("Class Function")
self.master.wm_iconbitmap('icon.ico')
self.master.geometry("360x240+100+100")
self.frame1 = ttk.Frame(self.master)
self.frame1.grid(row=0, column=0, padx=16, pady=16)
self.frame2 = ttk.Frame(self.master)
self.frame2.grid(row=0, column=1, padx=16, pady=16)
self.add = AddWidgets(self.frame1)
self.edit = EditWidgets(self.frame2, self.add) <--Add parameter self.add
class AddWidgets:
def __init__(self, master):
self.master = master
self.create_widgets()
def create_widgets(self):
self.label1 = ttk.Label(self.master, text="0")
self.label1.grid(row=0, column=0, padx=4, pady=4)
def onSet(self, text):
self.label1.configure(text=text)
class EditWidgets:
def __init__(self, master, widget): <-- add parameter widget
self.master = master
self.create_widgets()
self.widget = widget
def create_widgets(self):
def onEdit():
self.send_text = self.entry_text.get()
self.widget.onSet(self.send_text) <--call onSet from widget instance
[...]
EDIT:
If you want to create different tabs, all with the same widgets, one approach could be the following: you create a MainWindow class, where you add all the tabs to your window using the Notebook class.
Then you create a Add Widgets class that adds the required widgets to a frame. You instantiate this class on each of the created tabs, in order to populate them with the widgets.
In order to get the values of the variables you set in each tab you can write a method getEntryValue (or whatever name) that returns the value set on the entry. Something like this:
class MainWindow:
def __init__(self, master):
self.master = master
self.master.title("Class Function")
self.master.geometry("360x240+100+100")
n = ttk.Notebook(master)
self.f1 = ttk.Frame(n) # Create first tab
self.f2 = ttk.Frame(n) # Create second tab
n.add(self.f1, text='One')
n.add(self.f2, text='Two')
n.pack()
self.widget1 = AddWidgets(self.f1)
self.widget2 = AddWidgets(self.f2)
class AddWidgets:
def __init__(self, master):
self.master = master
self.create_widgets()
def create_widgets(self):
def onEdit():
send_text = self.entry_text.get()
self.label1.configure(text = send_text)
self.label1 = ttk.Label(self.master, text="0")
self.label1.grid(row=0, column=0, padx=4, pady=4)
self.entry_text = tk.StringVar()
self.entry1 = ttk.Entry(self.master, textvariable=self.entry_text)
self.entry1.grid(row=0, column=1, padx=4, pady=4)
self.button1 = ttk.Button(self.master, text="edit", command=onEdit)
self.button1.grid(row=0, column=2, padx=4, pady=4)
def getEntryText(self):
return self.entry_text.get()
Hope it helps.

tkinter "Class" has no attribute "button" even though is set in an instance

I'm trying run example from this tutorial and getting an error:
self.startBtn.config(state=tk.DISABLED) AttributeError: 'Example' object has no attribute 'startBtn'
I rewrite my code for simplicity (and get still the error):
#!/usr/bin/env python3
import tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.grid()
startBtn = tk.Button(self, text="Start", command=self.disableButton)
startBtn.grid(row=0, column=0, padx=10, sticky=tk.E)
def disableButton(self):
self.startBtn.config(state=tk.DISABLED)
def main():
root = tk.Tk()
root.geometry("400x300")
app = Example(root)
app.mainloop()
if __name__ == '__main__':
main()
What I missed?
Actualization
I forgot mention that program is able to compile and error occurs when button is pressed.
In the function, you use:
def disableButton(self):
self.startBtn.config(state=tk.DISABLED)
but the button is created without self:
startBtn = tk.Button(self, text="Start", command=self.disableButton)
startBtn.grid(row=0, column=0, padx=10, sticky=tk.E)
Simply make it:
self.startBtn = tk.Button(self, text="Start", command=self.disableButton)
self.startBtn.grid(row=0, column=0, padx=10, sticky=tk.E)
def disableButton(self):
self.startBtn.config(state=tk.DISABLED)
...to be able to configure the button's state in the function.

Categories

Resources