Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scrollbar in Tkinter inside Text widget

I have problem with set in Scrollbar inside Text widget in Tkinter. I know, that it's preferable to use grid to locate widgets but I want to set my widget in absolute location (x,y - red dot on GUI picture) with specified height and width.

My code:

from Tkinter import *
from ttk import *

class NotebookDemo(Frame):

    def __init__(self):      
        Frame.__init__(self)       
        self.pack(expand=1, fill=BOTH)
        self.master.title('Sample')
        self.master.geometry("650x550+100+50")
        self._initUI()

    def _initUI(self):
        self._createPanel()

    def _createPanel(self):

        # create frame inside top level frame
        panel = Frame(self)    
        panel.pack(side=TOP, fill=BOTH, expand=1)

        # create the notebook
        nb = Notebook(panel)
        nb.pack(fill=BOTH, expand=1, padx=2, pady=3)        
        self._FirstTab(nb)


    def _FirstTab(self, nb):

        # frame to hold content
        frame = Frame(nb)

        #textbox
        txtOutput = Text(frame, wrap = NONE, height = 17, width = 70)
        txtOutput.place(x=10, y=75)

        #button
        btnStart = Button(frame, text = 'Start', underline=0)
        btnStart.place(x=220, y=380)

        #scrollbar
        #vscroll = Scrollbar(frame, orient=VERTICAL, command=txtOutput.yview)
        #txtOutput['yscroll'] = vscroll.set
        #vscroll.pack(side=RIGHT, fill=Y)
        #txtOutput.pack(fill=BOTH, expand=Y)

        #add to notebook (underline = index for short-cut character)
        nb.add(frame, text='TAB 1', underline=0, padding=2)

if __name__ == '__main__':
    app = NotebookDemo()
    app.mainloop()

GUI:

If I uncomment this part of code (set Scrollbar):

vscroll = Scrollbar(frame, orient=VERTICAL, command=txtOutput.yview)
txtOutput['yscroll'] = vscroll.set
vscroll.pack(side=RIGHT, fill=Y)

My Scrollbar is located inside all window, not inside Text box:

enter image description here

But of course I want to have the Scrollbar inside the Text box widget (black border). If I use pack function to textbox:

txtOutput.pack(fill=BOTH, expand=Y)

text widget fill in the whole window...:

enter image description here

I really don't know how fix this problem. Any help will be appreciated. Thank you!

EDIT:

Of course I can use place method with Scrollbar too, but I can't change length of them, because it hasn't attribute length.

vscroll.place(x=573, y=75)

enter image description here

like image 470
Lipstick Avatar asked Mar 10 '23 00:03

Lipstick


2 Answers

While I rarely recommend place, it is quite powerful when you take advantage of the configuration options. For example, you can use in_ to specify a widget that this widget is to be placed relative to. You can use relx to specify a relative x coordinate, and you can use relheight to specify a height.

In your case you can try something like this:

vscroll.place(in_=txtOutput, relx=1.0, relheight=1.0, bordermode="outside")

If you want the illusion that the scrollbar is embedded inside the text widget as is (or used to be) common on some platforms, I recommend placing the text widget and scrollbar in a frame.You can use pack to put the widgets in the frame, and continue to use place to place the combination anywhere you want.

For example:

txtFrame = Frame(frame, borderwidth=1, relief="sunken")
txtOutput = Text(txtFrame, wrap = NONE, height = 17, width = 70, borderwidth=0)
vscroll = Scrollbar(txtFrame, orient=VERTICAL, command=txtOutput.yview)
txtOutput['yscroll'] = vscroll.set

vscroll.pack(side="right", fill="y")
txtOutput.pack(side="left", fill="both", expand=True)

txtFrame.place(x=10, y=75)
like image 137
Bryan Oakley Avatar answered Mar 19 '23 06:03

Bryan Oakley


Different geometry managers like place and pack don't mix so well. I see four options for you:

Use a parent frame

Create a new Frame that you place at the exact same position as you did with the text box. In this frame, you can use another geometry manager (I'd prefer pack) to make the layout appear as you want.

Use ScrolledText

Use the ScrolledText Tkinter module to have the solution above in a premade form. Note that this widget doesn't use ttk so the scrollbar style does not really adapt to the OS' look. Just use import ScrolledText and replace the Text creation in your code with ScrolledText.ScrolledText(...).

Use place for the scrollbar

If you are using place for the text widget, use place for the scrollbar too. place has options that allow you to place a widget relative to another widget both in location and size (ie: you can place the scrollbar along the right edge of the text widget, and cause it to be exactly as tall as the text widget). See Bryan's answer.

Don't use place

Simple as that. Use grid or pack instead, unless you really need to use place.

like image 22
TidB Avatar answered Mar 19 '23 06:03

TidB