I have this super simple implementation of a textBox:
root = Tk()
root.geometry('1650x900')
center_windows(root)
root.resizable(0, 0)
scrollbar = Scrollbar(root)
old_xml_text = Text(root, wrap=WORD, yscrollcommand=scrollbar.set, height=40, width=60)
old_xml_text.grid(row=0, column=0,pady=(100,0),padx=(50,50),sticky='we')
scrollbar.config(command=old_xml_text.yview)
The problem is that if I paste there a long text (2k lines) it became extremely laggy during scrolling.
How can I solve this?
If there is no solution using Tkinter, is there any other way to achieve this using other package (in Python)? I don't want any kind of lag when I past or scroll the text. Am I forced to use C/C++ ?
Any suggestion appreciated.
The problem lies in the computation time it takes the Text widget to insert all line breaks and thereby to compute the total number of lines and the current position. While scrolling, this computation is too slow and you get lags and the scrollbar is rendered useless.
If you want to speed it up and remove the lags, you have to insert line breaks manually, so that no line extends the 60 character width of your text window. If you insert line breaks and don't pass it to the wrapper, it won't lag. See the following example for reference:
from tkinter import *
root = Tk()
root.geometry('800x600')
#center_windows(root)
root.resizable(0, 0)
scrollbar = Scrollbar(root)
old_xml_text = Text(root, wrap=WORD, yscrollcommand=scrollbar.set, width=60,height=10)
old_xml_text.grid(row=0, column=0,pady=(100,0),padx=(0,0),sticky=N+S+E)
scrollbar.config(command=old_xml_text.yview)
scrollbar.grid(row=0,column=1,pady=(100,0),sticky=N+S+W)
scrollbar2 = Scrollbar(root)
old_xml_text2 = Text(root, wrap=WORD, yscrollcommand=scrollbar2.set, width=60,height=10)
old_xml_text2.grid(row=2, column=0,pady=(100,0),padx=(0,0),sticky=N+S+E)
scrollbar2.config(command=old_xml_text2.yview)
scrollbar2.grid(row=2,column=1,pady=(100,0),sticky=N+S+W)
old_xml_text.insert(END,"Hello World, this is a test of reaction times\n"*1000)
old_xml_text2.insert(END,"Hello World, this is a test of reaction times"*1000)
You can see that the Text widget with line breaks is perfectly well scrollable while the one that uses the Text widget wrapper is not.
Related
Here is my code
from tkinter import *
root = Tk()
root.geometry('500x500')
btn = Button(root, text = 'Play', height=5,width=30, command = root.destroy)
btn.place(x=140, y=200)
w = Label(root, text ='Lost', font=("Courier", 50), height=4)
w.pack()
root.mainloop()#
The button is meant to say play on it
This is a side effect of several things. What's happening here is that the text in your label is being centered vertically in a box with room for 4 lines. That text has opaque background, so the bottom of text box is sitting over the top of your button and hiding the text. If you remove height=4, you'll see that it works just fine.
The other problem here is mixing the placement tools. You are mixing place and pack, and that is going to cause trouble. You may need to think about the layout issues some more.
I've made a GUI using Tkinter. For the time being, I set the geometry to '962x652' and made it so the user can't resize it by using .resizable(0, 0). I'm now looking for a way to make it so when the GUI is resized, all the elements change size as well along side it, preferably with the aspect ratio locked.
Is there a way to achieve this whilst making it so only the element change size visibly without changing actually changing size? For example, if my GUI contains a scrolledtext box, if the user was to resize the GUI, the scrolledtext will also increase in size, but so will the text and each line of text in it will stay in the same line. I hope that makes sense.
I've add some code down below to show what I'm working with. This should have a similar effect to what I currently have:
import tkinter as tk
from tkinter import *
from tkinter import scrolledtext
TrialGUI = Tk()
TrialGUI.title('Resize GUI')
TrialGUI.geometry('962x652+0+0')
#Remove the following so you can resize the GUI
TrialGUI.resizable(0, 0)
#These are the two frames. I've changed their colour so they are visible when they are resized.
ABC1b = Frame(TrialGUI, bg='lightpink', bd=20, width=900, height=600)
ABC1b.grid(row=0, column=0)
ABC2 = Frame(TrialGUI, bg='lightblue', bd=20, width=452, height=600)
ABC2.grid(row=0, column=1)
#This is the text box
txtQuestion = scrolledtext.ScrolledText(ABC1b, wrap=tk.WORD, width=42, height=10, font=(14))
txtQuestion.grid(row=0, column=0, columnspan=4, pady=3)
#This inserts text into it. I made it insert which line the text should be in so it is easier to check if it is still in the same line when it is resized.
txtQuestion.insert(tk.INSERT, 'This should be in the first line.----------------------------------- This should be in the second line.------------------------------ This should be in the third line.----------------------------------')
TrialGUI.mainloop()
If anyone decides to play around with this code, remember to remove TrialGUI.resizable(0, 0) so it can be resized.
Im coding my personal text editor. But i have a problem with the 2 widget text and the scrollbar (connect one scrollbar to two text).
What is my idea and logic (at the beginning)?
I want to display 2 text, one for writing text entered by user, and one to display the number of the line. I pack both of them, in the root. Then i create a scrollbar, that will scroll on Y axes the 2 text, so what i want to do (mainly) is to connect 2 widget (text) to one scrollbar.
But it didn't work.
This system absolutely doesn't work, are there any suggest or fix to fix this first idea?
Other ideas that i found.
After the first attempt, i thought that i can pack the 2 texts into 1 container. I tried to create a frame (packed into root) that contains the 2 texts, i did this because i have to connect the scrollbar only to the frame. But it didn't work, moreover it didnt allow me to write the following snippet: command=frame.yview in the scrollbar option, it seems that i cant connect frame to scrollbar.
So:
I will ask u if my reasoning are good, and how to solve. If not what can i do?
Similar question found on Google: (but that i dont undestand)
How to scroll two parallel text widgets with one scrollbar?
Tkinter adding line number to text widget
from tkinter import *
root = Tk()
root.geometry("480x540+100+100")
root.config(cursor='')
line = Text(root, bg="light grey", font="Roman 24", width=4)
line.pack(side=LEFT, fill=BOTH)
text = Text(root, bg="grey", font="Roman 24")
text.pack(side=LEFT, fill=BOTH, expand=True)
scrollbar = Scrollbar(text, orient=VERTICAL, command=(line.yview, text.yview))
text.configure(yscrollcommand=scrollbar.set)
line.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side=RIGHT, fill=Y)
for n in range(50):
line.insert("{}.0".format(n+1), "{}\n".format(n+1))
text.insert("{}.0".format(n+1), "Line no. {}\n".format(n+1))
if __name__ == '__main__':
root.mainloop()
There's nothing special about a scrollbar - it just calls a function when you move it. The API for this function is well defined. While it normally should call the yview (or xview) method of a scrollable window, there's no requirement that it must.
If you want to control two widgets with a single scrollbar, create a function for your scrollbar that scrolls both windows.
def multiple_yview(*args):
line.yview(*args)
text.yview(*args)
scrollbar = Scrollbar(text, orient=VERTICAL, command=multiple_yview)
You will have a similar problem when you scroll the text widget while entering new lines or moving around with cursor keys. You'll need to configure the yscrollcommand attribute of the text widget to call a function so that it both updates the scrollbar and also scrolls the other window (and maybe also add additional line numbers)
I'm relatively new to Python and coding in general, so I'm a bit rubbish with most of the terminology.
I've researched this myself but I'm still relatively unsure (kept messing up), so hope someone can help me.
I'm looking to attach the scrollbar within my code to the right side of the text widget, rather than having it floating around the bottom corner.
My project is a text adventure (learning Python along to a book), and I have been building a very basic GUI to house the game. Essentially the text box here is placeholder, and it'll be replaced with the game code down the line, with graphics making up the rest of the window surrounding the center text/command prompt. I'm assuming doing this would be doable relatively easily?
I'm happy to work out just how to sort the scrollbar currently, as it's helping me learn!
Thanks guys!
from tkinter import *
root = Tk()
root.title("GAME TITLE")
mainframe = Frame(root, width=720, height=540)
mainframe.pack()
gametext = Text(root, width=75, height=15)
gametext.place(relx=0.5, rely=0.7, anchor=CENTER)
scrollbar = Scrollbar(root, command=gametext.yview)
gametext.config(yscrollcommand=scrollbar.set)
scrollbar.pack(side=RIGHT, fill=Y)
gametext.tag_configure('fonttype1', font = ('Arial', '12', 'bold'))
quote = """GAMEPLAY TEXT HERE"""
gametext.insert(END, quote, 'fonttype1')
root.mainloop()
Sample Screenshot of code running
If all you're using is a text widget and scrollbar, use pack for both. place is best used very, very rarely.
scrollbar.pack(side=RIGHT, fill=Y)
gametext.pack(side=LEFT, fill=BOTH, expand=True)
Here's my program:
import tkinter as tk
#Create main window object
root = tk.Tk()
#build GUI
for i in range(5):
tk.Label(root, text="hello", height=0).grid(row=i)
#mainloop
root.mainloop()
It produces the following (running in Xubuntu 16.04 LTS)
Notice all that extra vertical space between the lines of text. I don't want that! How do I decrease it?
If I run this code instead:
import tkinter as tk
#Create main window object
root = tk.Tk()
#build GUI
for i in range(5):
tk.Label(root, text="hello", height=0).grid(row=i)
tk.Grid.rowconfigure(root, i, weight=1) #allow vertical compression/expansion to fit window size after manual resizing
#mainloop
root.mainloop()
...it opens up and initially looks exactly the same as before, but now I can manually drag the box vertically to shrink it, like so:
Notice how much more vertically-compressed it is! But, how do I do this programatically, so I don't have to manually drag it to make it this way? I want to set this tight vertical spacing from the start, but no matter which parameters I change in Label, grid, or rowconfigure I can't seem to make it work without me manually dragging the box with the mouse to resize and vertically compress the text.
There are many ways to affect vertical spacing.
When you use grid or pack there are options for padding (eg: pady, ipady, minsize). Also, the widget itself has many options which control its appearance. For example, in the case of a label you can set the borderwidth, highlightthickness and pady values to zero in order to make the widget less tall.
Different systems have different default values for these various options, and for some of the options the default is something bigger than zero. When trying to configure the visual aspects of your GUI, the first step is to read the documentation, and look for options that affect the visual appearance. Then, you can start experimenting with them to see which ones give you the look that you desire.
In your specific case, this is about the most compact you can get:
label = tk.Label(root, highlightthickness=0, borderwidth=0, pady=0, text="hello")
label.grid(row=i, pady=0, ipady=0)
You can programatically modify the geometry just before starting the main loop instead of manually dragging it (change 0.6 to whatever % reduction you want):
import tkinter as tk
#Create main window object
root = tk.Tk()
#build GUI
for i in range(5):
label = tk.Label(root, text = 'hello')
label.grid(row=i)
tk.Grid.rowconfigure(root, i, weight=1) #allow vertical compression/expansion to fit window size after manual resizing
#mainloop
root.update()
root.geometry("{}x{}".format(root.winfo_width(), int(0.6*root.winfo_height())))
root.mainloop()
Here is a screenshot of the result running on Xubuntu 16.04 LTS with Python 3.5.2: