I am making an app with Tkinter (2.7) that imports a frame from another file. Unfortunately though the background colour isn't showing even though I have defined it in the imported file. The text widget on the frame shows up though. I have tried taking the mainframe = … out of the class and putting it into the body of the code between the two bottom lines but to no avail.
Main file:
import Tkinter as tk
import frames
class Window(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("Example Code")
mainframe = frames.Main(start)
start = Window()
start.mainloop()
Frame file:
import Tkinter as tk
class Main(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.config(background="#5fe689")
tk.Label(text="hi").pack()
Any help is appreciated!
You never put the frame in the root window. You need to call pack, place or grid on mainframe.
Related
I have a class where I create a Label on the init method:
import tkinter as tk
from tkinter.filedialog import askopenfilename
class app(tk.Tk):
def __init__(self, master):
label1 = tk.Label(master, text="Select file...")
label1.pack()
Then with a button I call a method to choose a file and change the label text to filename path.
def files(self):
filename = askopenfilename()
self.label1.config(text=filename)
The problem is that when I choose the file, the app gets closed without errors, so I don't know what's going on.
Outside the class I have:
root = tk.Tk()
app_gui = app(root)
root.mainloop()
In your specific case, there are two problems. The first is that you're creating two instances of tk.Tk. You should never do that.
The second is that you aren't creating self.label1 so any attempt to modify it will fail.
The solution is to first remove tk.Tk as a superclass for app. The second is to properly define self.label1
class app():
def __init__(self, master):
self.label1 = tk.Label(...)
...
On a side note, you should seriously consider following the naming conventions of PEP8 and name your main class App. PEP8 is nearly universal in the python world, and deviating from it makes your code harder to read.
I'm fairly new to python and try to build a simple GUI following an object oriented approach. Therefor I let my widget classes inherit from tk.Frame and create an application controller to build the GUI.
My application contains the following two files:
mainModule.py
# coding: utf8
from testPackage import myGUI
import Tkinter as tk
root = tk.Tk() # Main window
my_gui = myGUI.MainApplication(root)
root.mainloop() # Hold window open until we close it
myGUI.py
# coding: utf8
import Tkinter as tk
# Application initializer
class MainApplication(tk.Frame):
def __init__(self, master):
self.master = master
tk.Frame.__init__(self, master)
self.configure_gui()
self.pack() # <--- CODE IN QUESTION
self.create_widgets()
def configure_gui(self):
self.master.title("Any title")
self.master.geometry('800x600')
self.master.minsize(600, 100)
def create_widgets(self):
self.main_window = MainWindow(self)
self.main_window.pack()
# Main Data Window
class MainWindow(tk.Frame):
def __init__(self, master):
self.master = master
tk.Frame.__init__(self, master)
self.main_window = tk.Label(self, text="This is a test")
self.main_window.pack(side="top", fill="x")
Initially running my code without self.pack() (marked as #Code in question) in the MainApplication class definition gave me only the root basic window without the Label created from MainWindow class.
As simple as the answer may be but why?
I used a few sources to get into the topic inbefore and some of them didn't use any geometry manager on the root window (or i'm to inexpierienced to see it. Source below for examples).
Source:
https://www.begueradj.com/tkinter-best-practices.html
http://python-textbok.readthedocs.io/en/latest/Introduction_to_GUI_Programming.html#putting-it-all-together
Tkinter example code for multiple windows, why won't buttons load correctly?
Only after reading following answers regarding widget creation I came aware of the missing part:
Best way to structure a tkinter application
creating a custom widget in tkinter
Figuring that pack() on initialization would be the same as
MainApplication(root).pack(side="top", fill="both", expand=True)
or
Example(root).place(x=0, y=0, relwidth=1, relheight=1)
for a grid based layout.
I guess it's a very simple or obvious element i don't see relating to inheritance but i'm not entirely sure why have to pack() the MainApplication Frame and furthermore why it seems to work for example without this step.
Because MainWindow inherits from Frame, it is itself a frame. If you never call pack, place, or grid on it, it will be invisible. This is no different than if you created a button or scrollbar or any other widget and then don't call one of those methods on it.
Since all of the other widgets are a children of this frame, they will be invisible since their parent is invisible.
Somewhat unrelated to the question being asked, self.pack() is a code smell. Generally speaking, a class should never call pack, place or grid on itself. This tightly couples itself to the caller (meaning, this widget has to know that the caller is using one of those methods).
In other words, if you decide that MainApplication wants to switch from pack to grid for all of its children, you can't just update MainApplication, you also have to update MainWindow. In this case, the root window has only one child so the problem is fairly small, but by doing it this way you are starting a bad practice that will eventually cause you problems.
The rule of thumb is that the function that creates a widget should be responsible for adding it to the screen. That means that it would be better to do it like this:
root = tk.Tk()
my_gui = myGUI.MainApplication(root)
my_gui.pack(fill="both", expand=True)
You would then need to remove self.pack() from MainApplication.__init__.
You also have some very misleading code that might be contributing to the confusion. Take a look at this code:
# Main Data Window
class MainWindow(tk.Frame):
def __init__(self, master):
...
self.main_window = tk.Label(self, text="This is a test")
self.main_window.pack(side="top", fill="x")
Notice how you have a class named MainWindow. Within that you have a label that is named self.main_window, but self.main_window is not a MainWindow. This is especially confusing since the function that creates MainWindow also creates an instance variable named self.main_window.
You might want to consider renaming this label to be something else (eg: self.label, self.greeting, etc).
I'm creating a json editor in python using tkinter.
I've added a scrollbar by creating a Canvas, and putting a Frame inside it.
Then I set the Scrollbar command to canvas.yview.
Theres two things that are messing up, and I have no idea why.
When I press the scroll buttons (up and down arrows) the canvas is not scrolling
I am packing the scrollbar onto the window (root) right now instead of the frame, because whenever i pack it onto the frame, the tkinter application does not open, and my computer fan starts turning on... Anyone know what is going on here? (Therefore the scrollbar is tiny if you try to run the code)
Here is my code:
EDIT> Code shortened
import Tkinter as tk
import webbrowser
import os
import bjson as bj
class App:
def __init__(self, master):
self.window = master
self.window.geometry("800x450")
self.canvas = tk.Canvas(self.window, width=800, height=400)
self.master = tk.Frame(self.canvas, width=800, height=400)
self.canvas.pack()
self.master.place(x=0, y=0)
scrollbar = tk.Scrollbar(self.window)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
scrollbar.config(command=self.canvas.yview)
def init(self):
master = self.master
self.frames = {
"Home": HomeFrame(master)
}
self.openFrame = None
self.loadFrame("Home")
def loadFrame(self, frame):
self.openFrame = self.frames[frame]
self.openFrame.display()
def setTitle(self, t):
self.window.title(t)
class Frame:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(master)
self.frame.grid(row=0, column=0, sticky='news')
self.init()
self.frame_create()
def display(self):
self.frame.tkraise() #raises frame to top
self.frame_load() #initializes the frame
def clear(self):
for widget in self.frame.winfo_children():
widget.destroy()
def init(self): pass
def frame_load(self): pass
def frame_create(self): pass
class HomeFrame(Frame):
def frame_create(self):
p = self.frame
for i in range(20):
tk.Label(p, text="This is content... " + str(i)).pack()
for j in range(2):
LineBreak(p)
def LineBreak(p):
tk.Label(p, text="").pack()
root = tk.Tk()
glob = {}
app = App(root)
app.init()
root.mainloop()
It is a bit long, and a bit messy, but you should see how I'm adding the scrollbar in the __init__ of App
Anyone have any idea what's going on, and how to fix it?
Thanks in advance!
There are many things wrong with your code. However, the problem with the scrollbar not working properly has to do with two things you are neglecting to do:
First, scrollbars and widgets require two way communication. The canvas needs to be told about the scrollbar, and the scrollbar needs to be told about the canvas. You are doing one but not the other:
self.canvas.configure(yscrollcommand=scrollbar.set)
scrollbar.configure(command=self.canvas.yview)
Second, you need to configure the scrollregion attribute of the canvas. This tells tkinter what part of the larger virtual canvas you want to be viewable. Typically this is done in a binding on the <Configure> method of the canvas, and usually you will want to set it to the bounding box of everything in the canvas. For the latter you can pass the string "all" to the bbox method:
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
If you know the exact size of the area you want to be scrollable, you can simply set it to that value (eg: scrollregion=(0,0,1000,1000) to scroll around in a region that is 1000x1000 pixels).
The reason for point #2 is that you can't use both pack and grid for widgets that share the same parent. When you do, you'll get the behavior you describe. That is because grid will try to layout all of the widgets. This may result in some widgets changing size. pack will notice the change in the size of one or more widgets and try to re-layout all of the widgets. This may result in some widgets changing size. grid will notice the change in the size of one or more widgets and try to re-layout all of the widgets. And so on.
I am using tkinter to create a popup from within a plug-in for another program. The issue is that with two monitors, if the program I call the plug-in from is on the left monitor then the popup shows up on the right one.
OS is windows, but I would like to be able to use this for both windows and linux
Any way I can fix this so that the popup displays in front of the program?
code sample
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
called by
root = tk.Tk()
app = Application(master=root)
app.mainloop()
image of issue:
I am quite new to tkinter and I wonder how I should create frames.
If one is prefered over the other one, why is it so?
Is it better like this:
import tkinter as tk
class MainApplication(tk.Frame):
def __init__(self, parent):
main_frame = tk.Frame(parent)
root = tk.Tk()
main_app = MainApplication(root)
root.mainloop()
or like this:
import tkinter as tk
class MainApplication(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
root = tk.Tk()
main_app = MainApplication(root)
root.mainloop()
The first one creates two frames -- the instance itself (main_app) is a frame, and it contains a child frame (main_frame). Though, because you don't call the __init__ of Frame, the first frame is not properly constructed.
If you are immediately going to create an internal frame and put everything inside it, it's pointless to inherit from Frame.
By the way, your code doesn't quite work. If you want to actually see the application widget (and its children) then you're going to need to call pack, place or grid on the widget.
For example:
root = tk.Tk()
main_app = MainApplication(root)
main_app.pack(fill="both", expand=True)
root.mainloop()