Struggling to get a simple form to work in a tkinter instance. Is
there a known issue with not being able to click on tk.Entry boxes?
I'll take the key parts of the code out to see if anyone can spot
something i'm doing wrong?
class CreateWindow():
def __init__(self):
self.root = tk.Tk()
self.root.overrideredirect(True)
***Then I do a whole load of importing images, setting background and other stuff ***
self.messageText = tk.StringVar()
self.MessageBox = tk.Entry(self.root, textvariable = self.messageText)
self.MessageBox.place(x=100, y=100)
self.root.mainloop()
This code is then called from if main = name
Does anyone see anything I'm doing wrong??
The reason why I cannot click on the entry box is that root.overrideredirect(True) prevents the entry box from getting focus. I have listed a new question RPI Tkinter Window, I want to use a command like overrideredirect and maintain entry box functionality to focus on how to work around this.
Related
This question already has answers here:
tkinter - How to drag and drop widgets?
(3 answers)
Closed 5 years ago.
Currently, I am working with Python 3.5 GUI development using tkinter module. I want to be able to drag an image from one place to another within the application. Does tkinter support drag and drop within an application, and if so, how do you do it?
from tkinter import *
root = Tk()
root.geometry("640x480")
canvas = Canvas(root, height=480, width=640, bg="white")
frame = Frame(root, height=480, width=640, bg="white")
frame.propagate(0)
image = PhotoImage(file="C:/Users/Shivam/Pictures/Paint/Body.png")
label = Label(canvas, image=image)
label.pack()
label_2 = Label(frame, text="Drop Here !")
label_2.pack()
label_2.place(x=200, y=225, anchor=CENTER)
canvas.pack(side=LEFT)
frame.pack()
root.mainloop()
Tkinter doesn't have any direct support for drag and drop within an application. However, drag and drop requires not much more than making suitable bindings for a button click (<ButtonPress-1>), the mouse moving while the button is clicked (<B1-Motion>), and when the button is released (<ButtonRelease-1>).
Here is a very simplestic example which is designed to work with your code.
First, we'll create a class that can manage the dragging and dropping. It's easier to do this as a class rather than a collection of global functions.
class DragManager():
def add_dragable(self, widget):
widget.bind("<ButtonPress-1>", self.on_start)
widget.bind("<B1-Motion>", self.on_drag)
widget.bind("<ButtonRelease-1>", self.on_drop)
widget.configure(cursor="hand1")
def on_start(self, event):
# you could use this method to create a floating window
# that represents what is being dragged.
pass
def on_drag(self, event):
# you could use this method to move a floating window that
# represents what you're dragging
pass
def on_drop(self, event):
# find the widget under the cursor
x,y = event.widget.winfo_pointerxy()
target = event.widget.winfo_containing(x,y)
try:
target.configure(image=event.widget.cget("image"))
except:
pass
To use it, all you need to do is call the add_draggable method, giving it the widget(s) you wish to drag.
For example:
label = Label(canvas, image=image)
...
dnd = DragManager()
dnd.add_dragable(label)
...
root.mainloop()
That's all it takes for the basic framework. It's up to you to create a floating draggable window, and to perhaps highlight the item(s) that can be dropped on.
Other implementations
For another implementation of the same concept, see https://github.com/python/cpython/blob/master/Lib/tkinter/dnd.py
https://github.com/akheron/cpython/blob/master/Lib/tkinter/dnd.py
I tested it and it still seems to work in python 3.6.1, I suggest experimenting with it and making it your own, because it doesn't seem to be officially supported in Tkinter.
I have some pretty simple code right now that I am having issues with.
root = Tk()
label1 = Label(root, text ="Enter String:")
userInputString = Entry(root)
label1.pack()
userInputString.pack()
submit = Button(root,text = "Submit", command = root.destroy)
submit.pack(side =BOTTOM)
root.mainloop()
print(userInputString)
When I run the code everything operates as I would expect except
print(userInputString)
for an input asdf in the Entry print will return something like 0.9355325
But it will never be the same value back to back always random.
I am using python 3.5 and Eclipse Neon on a Windows 7 Machine.
Ultimately the goal is to accept a string from the user in the box that pops up and then be able to use that value as string later on. For example, it might be a file path that needs to be modified or opened.
Is Entry not the correct widget I should be using for this? Is there something inherently wrong with the code here? I am new to python and don't have a lot of strong programming experience so I am not even certain that this is set up right to receive a string.
Thanks in advance if anyone has any ideas.
There are two things wrong with your print statement. First, you print the widget, not the text in the widget. print(widget) prints str(widget), which is the tk pathname of the widget. The '.' represents the root window. The integer that follows is a number that tkinter assigned as the name of the widget. In current 3.6, it would instead be 'entry', so you would see ".entry".
Second, you try to print the widget text after you destroy the widget. After root.destroy, the python tkinter wrapper still exists, but the tk widget that it wrapped is gone. The following works on 3.6, Win10.
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="Enter String:")
entry = tk.Entry(root)
def print_entry(event=None):
print(entry.get())
entry.bind('<Key-Return>', print_entry)
entry.focus_set()
submit = tk.Button(root, text="Submit", command=print_entry)
label.pack()
entry.pack()
submit.pack()
root.mainloop()
Bonus 1: I set the focus to the entry box so one can start typing without tabbing to the box or clicking on it.
Bonus 2: I bound the key to the submit function so one can submit without using the mouse. Note that the command then requires an 'event' parameter, but it must default to None to use it with the button.
The NMT Reference, which I use constantly, is fairly complete and mostly correct.
Hi I am new to programming and I apologize if this is an obvious mistake. I am writing a gui on tkinter using python 3.5 on Mac OsX El Capitan. Here is the code so far:
from tkinter import *
from tkinter import ttk
class GUI(object):
def __init__(self, master):
master.title("Title")
master.resizable(False, False)
self.frame1 = ttk.Frame(master)
self.frame1.pack()
ttk.Label(text="Organism").grid(row=1, column=0)
self.organism_picker = ttk.Combobox(self.frame1, values=("Drosophila melanogaster",
"Danio rerio",
"Caenorhabditis elegans",
"Rattus norvegicus",
"Mus musculus",
"Homo sapiens"))
self.organism_picker.grid(row=2, column=0)
ttk.Label(text="Core gene symbol:").grid(row=3, column=0)
self.core = ttk.Entry(self.frame1)
self.core.grid(row=4, column=0)
root = Tk()
gui = GUI(root)
root.mainloop()
When I run this the program enters the main loop, but the gui window never appears and the launcher is not reponding.
I tried to reinstall python 3, installed ActiveTcl, tried using ActivePython instead. Nut none of it worked.
Thank you all in advance for your answers.
You should not use pack() and grid() as this will generate a geometry manager conflict as pointed out in this error:
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack
try changing:
self.frame1.pack()
to:
self.frame1.grid()
In this case I would suggest using pack overall, since this is a fairly simple layout. please refer to this guide:
When to use the Pack Manager
Compared to the grid manager, the pack manager is somewhat limited,
but it’s much easier to use in a few, but quite common situations:
Put a widget inside a frame (or any other container widget), and have
it fill the entire frame Place a number of widgets on top of each
other Place a number of widgets side by side
AND FINALLY:
Note: Don’t mix grid and pack in the same master window. Tkinter will
happily spend the rest of your lifetime trying to negotiate a solution
that both managers are happy with. Instead of waiting, kill the
application, and take another look at your code. A common mistake is
to use the wrong parent for some of the widgets.
The only problem with your code is that you forgot to attach the two labels to the the main widget self.frame1.
To fix that, modify them as follow:
#Attach the 2 labels to self.frame1
ttk.Label(self.frame1,text="Organism").grid(row=1, column=0)
ttk.Label(self.frame1,text="Core gene symbol:").grid(row=3, column=0)
Demo
After doing that, you will get this:
I'm currently trying to make a small application with a GUI that pulls weather from a website and displays the results in a window. I've got it to work without the GUI and also with the GUI but when I wrote the latter it was all in one script and not very organized. Because it was so unorganized, I decided to make make a separate script that would draw the GUI when the class was called.
Part of the GUI is an 'Entry' box that can be added via Tkinter. The entry box stores it's content into a StringVar() and that content can displayed using .get(). This works fine and well when I wrote everything unorganized into one script but I can't for the life of me figure out how to pass this StringVar() from one method to another in my program. This is what it looks like:
from Tkinter import *
import Forecast
class Frames(object):
def __init__(self):
pass
def main_frame(self):
main = Tk()
main.title('WeatherMe')
main.geometry('300x100')
query = StringVar()
Label(main, text='Enter a city below').pack()
Entry(main, textvariable=query).pack()
Button(main, text="Submit", command=self.result_frame).pack()
main.mainloop()
def result_frame(self):
result = Tk()
result.title('City')
result.geometry('600x125')
Button(result, text="OK", command=result.destroy).pack()
result.mainloop()
Basically my goal is to have one window open when the program is launched with a label, an entry box, and a submit button. When a city is entered in the entry box and submit it clicked a new window will open displaying the results.
Because the entry is on the first window I need to pass the value of entry's StringVar() to the second window so it can then pull the data and display the labels. No matter what I try it doesn't seem to work, I either get a 404 error meaning something is wrong with that string making the link it tries to get a response from invalid or a concatenate error 'cannot concatenate str and instance objects'.
I've also tried saving StringVar() as a variable outside of either method but the issue with that is I need to then call another instance of Tk() before StringVar().
You are creating two separate instances of Tk. You shouldn't do that. One reason why is because of this exact problem: you can't share instances of widgets or tkinter variables between them.
If you need more than one window, create a single root window and then one or more instances of Toplevel. Also, call mainloop only for the root window.
I'm trying to prepopulate a text field based on the most recent entry. As this is not a Listbox, I don't see how to do it, and I'm not seeing any examples on the web. Thanks.
Update. I've managed to find a partial way of doing this. Still wondering, is it possible to supply suggested text in Tkinter which fades when the text box is clicked?
from Tkinter import *
app = Tk()
app.title("GUI Example")
app.geometry('560x460+200+200')
x = Text(app)
x.insert(END, "Before")
x.pack()
def replace():
x.delete(1.0, END)
x.insert(END, "After")
abutton = Button(app, text="Click me", command=replace)
abutton.pack()
app.mainloop()
Well, I personally don't know of any options to do this (any answers giving one will easily trump this one).
However, you can closely mimic this behavior with a little coding. Namely, you can bind the textbox to a function that will insert/remove the default text for you.
Below is a simple script to demonstrate:
import Tkinter as tk
tk.Tk()
textbox = tk.Text(height=10, width=10)
textbox.insert(tk.END, "Default")
textbox.pack()
# This is for demonstration purposes
tk.Text(height=10, width=10).pack()
def default(event):
current = textbox.get("1.0", tk.END)
if current == "Default\n":
textbox.delete("1.0", tk.END)
elif current == "\n":
textbox.insert("1.0", "Default")
textbox.bind("<FocusIn>", default)
textbox.bind("<FocusOut>", default)
tk.mainloop()
Notice how:
When you click in the top textbox, the default text disappears.
When you click in the bottom textbox, the top one loses focus and the default text reappears.
This behavior will only occur if there is nothing in the top textbox.