Second row entry width affect the first row style in tkinter? - python

I'm trying to create the some sample application.
Which first row is One label then input entry box then submit button.
Then second row has the another entry box.
My problem is when I increase width of the entry box in second row it affect the first row style. I don't know what is the problem.
import Tkinter
tk_obj = Tkinter.Tk()
tk_geo = tk_obj.geometry("1200x800")
Tkinter.Label(tk_obj, text='Enter query ').grid(row=1,column=1)
def callback():
print "hi"
E1 = Tkinter.Entry(tk_obj,bd=3,width=120)
E1.grid(row=1, column=2,ipady=3)
b = Tkinter.Button(tk_obj, text="Check", command=callback)
b.grid(row=1,column=3)
E2 = Tkinter.Entry(tk_obj,bd=3,width=100)
E2.grid(row=2,column=1,ipady=100)
tk_obj.mainloop()

The grid method places widgets in the center of the cell they inhabit. When you have two widgets of different sizes sharing a row or column, this means that there will be blank space around the smaller widget. To make the second Entry widget span the first two columns, use columnspan=2 when you grid() it. To left-align it within those two columns, use sticky='W':
E2.grid(row=2,column=1,ipady=100, columnspan=2, sticky='W')
You can then adjust that Entry widget's width attribute until it looks the way you want it to.

Related

How can I make an another block of items under a grid in tkinter? - Python

I want to make a 'maze' game with tkinter, and I wanted to display some things under the grid(game area), and this happend:
Because I wanted to put the text in the last line and the first column of the grid.
frame = tk.Frame(window)
frame.grid(row=line+1, column=0)
label = tk.Label(master=frame, text="Dashing:")
label.pack()
Any ideas, how can I fix this?
Make the frame span all of the columns:
frame.grid(row=line+1, column=0, columnspan=17)

Tkinter: Why is the next 'Label' taking it's 0 column differently?

label = tk.Label(window, text="Guess a number that can be anything from '10' to '50', you have 5 chances !!!", fg="black", bg="white", font=("Arial Bold", 25))
label.grid(row=0)
inp = tk.Entry(window)
inp.grid(row=1)
Output Should Be Something Like this:
Guess a number that can be anything from '10' to '50'...
Input Field
but its:
Input field is away from the centre, why?
Use Sticky
import tkinter as tk
window =tk.Tk()
label = tk.Label(window, text="Guess a number that can be anything from '10' to '50', you have 5 chances !!!", fg="black", bg="white", font=("Arial Bold", 25))
label.grid(row=0)
inp = tk.Entry(window)
inp.grid(row=1,sticky="w")
window.mainloop()
Column zero has a very wide label in it which forces the column to be as wide as the label. The entry widget is in that same very wide column, and by default grid centers items in the column.
If you want the entry widget aligned to the left, you can use the sticky option to force the widget to "stick" to the west (left) side of the column.
inp.grid(row=1,sticky="w")
If these are the only two widgets in the UI, this is probably the right solution. If you plan to have other widgets aligned with either the label or the entry widget, you may need to do something else. Without knowing more about the final product it's hard to say for sure.
Another solution would be to configure the label to span two columns, and have the second column be given all of the extra space. That will cause the first column to be as small as necessary.
label.grid(row=0, columnspan=2)
window.grid_columnconfigure(1, weight=1)
The choice depends a bit on what else you plan to do with the window. If you're only going to have these two widgets and nothing else, the first solution requires one less line of code. The second solution makes it easier to add other widgets on the same row as the entry widget.

Why does this tkinter grid center the checkbox added at the end?

I am not able to figure out that how column span is working. I know this sounds a bit foolish but,
i was just confused on seeing the output, how the checkbox is put automatically below the password input box(entry2 box).
use of grid()
from tkinter import *
root = Tk()
label1 = Label(root,text='Name:')
label2 = Label(root,text='Password:')
entry1 = Entry(root)
entry2 = Entry(root)
label1.grid(row=0,column=0)
entry1.grid(row=0,column=1)
label2.grid(row=1,column=0)
entry2.grid(row=1,column=1)
c = Checkbutton(root,text='Keep me logged in')
c.grid(columnspan=2)
root.mainloop()
Thank you very much for your time.
This is because of the default values of "column" and "row" (see below)
column : Insert the widget at this column. Column numbers start with 0. If omitted, defaults to 0.
row : Insert the widget at this row. Row numbers start with 0. If omitted, defaults to the first empty row in the grid.
Hence, the check button defaults to the first column, and the first empty row, which is row 3.
For more, see: https://effbot.org/tkinterbook/grid.htm
In your case, c.grid(columnspan=2) is exactly the same as c.grid(row=2, column=0, columnspan=2). When you don't explicity set a row and column, row defaults to the next empty row and column defaults to zero.
Thus, you are putting the checkbutton in row 2, and it spans columns 0 and 1. Since you aren't using the sticky attribute, the default behavior is to be centered in the space that was allotted to it.
If your main goal is to have it left-aligned, just add sticky="w" when calling grid:
c.grid(row=2, column=0, columnspan=2, sticky="w")

Is there a way to get the row number at the insertion point of a Tkinter text widget?

I'm trying to change the color of text in a text widget similar to how a VS code changes the code colors:
Like this:
To do this I have a Text widget and I have a function handleCodeEditor bound to <KeyRelease> that will split the text widget's contents by row and then conditionally modify text colors. To make the process less exhaustive I would like to only modify the current row, but I am not aware of any method that would give me the row number.
Any ideas?
def getrow(event):
index = textbox.index(INSERT)
row = index.split(".")[0]
print(row)
root = Tk()
textbox = Text(root)
textbox.bind("<KeyRelease>",getrow)
textbox.pack()
root.mainloop()
This function will print the current line number whenever a key is released.
Hope this is what you're after.

Programatically add and remove tkinter python labels causes IndexError: list index out of range

Sorry for the vague title but I didn't know how to explain myself better. Basically what I try to do in tkinter here is adding and removing labels. The label value gets updated so that I always have an increment of 1 even though I deleted a label in the beginning. If I generate labels and delete them from the bottom up I have no problems but it I delete one from the middle and then try to clean my list I get an error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1536, in __call__
return self.func(*args)
File "/Users/XXXX/Helper/development/dynamicListLabels.py", line 21, in <lambda>
labelList[index].append(ttk.Button(root, text="Remove", command=lambda: removeLabel(labelList[index][0], index)))
IndexError: list index out of range
My python code looks like this:
#!/usr/bin/python
from Tkinter import *
import ttk
def removeLabel(labelToRemove, bla):
labelList[labelToRemove.get()][1].destroy()
labelList[labelToRemove.get()][2].destroy()
del labelList[labelToRemove.get()]
for label in labelList:
index = labelList.index(label)
label[0].set(index)
def addNewLabel():
labelList.append([IntVar()])
index = len(labelList) - 1
labelList[index][0].set(index)
labelList[index].append(ttk.Label(root, textvariable=labelList[index][0]))
labelList[index].append(ttk.Button(root, text="Remove", command=lambda: removeLabel(labelList[index][0], index)))
labelList[index][1].grid(column=0)
labelList[index][2].grid(column=1, row=labelList[index][1].grid_info()['row'])
root = Tk()
labelList = []
ttk.Button(root, text="add label", command=addNewLabel).grid(column=1, row=0)
root.mainloop()
And my GUI looks like this:
Thanks for your help!
Design
The main problem comes when dealing with different indexes. Trying to manipulate them carefully leads to complicated operations resulting in a long and inefficient code. To remedy to this problem, we simply get rid of them and take advantage of the label class variable Tkinter.IntVar() you already are using. This gives us full control of the labels and associated widgets.
An other efficient decision to take that prevents from getting lot of headache is to attach each (label, button) couple widgets to a unique Tkinter.Frame() instance. This offers the advantage of deleting the frame using destroy() method leading automatically to the destruction of the widgets it contains. In the same time, this keeps the look of your GUI and makes your it scalable as it offers you the possibility to add more widgets.
Designing addNewLabel()
There is nothing new here compared to your original code except, as I said in 2. each (label, button) couple will be drawn into a single and unique Tkinter.Frame() instance. Of course, the list frames must be declared global in this method.
Designing removeLabel()
From 1. the only argument we need to pass to removeLabel() is the Tkinter variable (var in the code below) inherent to the label we want to get rid of.
We need then to loop over list of frames (frames in the code below) using winfo_children() to seek for the label which has the text variable we are looking for.
Note that because I draw the label before the button inside individual frames, winfo_children() returns as first widget list element the label
winfo_children():
Returns a list containing the path names of all the children of window. Top-level windows are returned as children of their logical
parents. The list is in stacking order, with the lowest window first,
except for Top-level windows which are not returned in stacking order.
Use the wm stackorder command to query the stacking order of Top-level
windows.
This is why it is correct to write : if frame.winfo_children()[0].var == var and destroy the frame that contains the label which satisfies this condition.
Solution
Here is the program. I commented the lines which I think deserve to be commented:
'''
Created on Jun 25, 2016
#author: billal begueradj
'''
from Tkinter import *
import ttk
def removeLabel(var):
global frames
z = -1
# Loop over the list of rames
for frame in frames:
z = z + 1
# Check the text variable of the label of this frame
if frame.winfo_children()[0].var == var:
# Destroy the related frame
frame.destroy()
# Update the size of the list of frames
frames = frames[:z] + frames[z+1:]
# Do not forget to always rest this flag back to -1
z = -1
# Update the labels' numbers
r = 0
for frame in frames:
frame.winfo_children()[0].var.set(r)
r = r + 1
def addNewLabel():
global frames, i
var = IntVar()
frame = Frame(root)
i = i + 1
frame.grid(row=i, column=0)
var.set(len(frames))
l = ttk.Label(frame, textvariable=var)
l.grid(row=0, column=0)
l.var = var
b = ttk.Button(frame, text="Remove", command=lambda: removeLabel(var))
b.grid(row=0, column=1)
frames.append(frame)
if __name__ == '__main__':
root = Tk()
frames = []
i = 1
ttk.Button(root, text="add label", command=addNewLabel).grid(column=0, row=0)
root.mainloop()
Demo
Let us create 6 labels:
Now let us delete the label number 3. You can see that the numbering of the labels is automatically updated:
Now let us add a new label. You can see the newly added label has a number which is consecutive to the last existing label number in the list:
Note that the length of the list is updated all the time as you wanted.

Categories