We're a community of 1077K IT Pros here for help, advice, solutions, professional growth and fun. Join us!
1,076,506 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Start New Discussion Reply to this Discussion

Controlling ONE text widget with two scrollars

Hi,

this is, let's say, the second part of this thread: http://www.daniweb.com/forums/thread291657.html

I have managed to control two widgets with one scrollbar, but now I have realized that, althought the widgets can be controlled individually via the mouse wheel or the keyboard, I sometimes need individual controls for each widget.


This is tony's code from prevois thread:

try:
    from Tkinter import *
except ImportError: ## Python 3
    from tkinter import *

root = Tk()

class App:
    def __init__(self,master):
        scrollbar = Scrollbar(master, orient=VERTICAL)
        self.b1 = Text(master, yscrollcommand=scrollbar.set)
        self.b2 = Text(master, yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.yview)
        scrollbar.pack(side=RIGHT, fill=Y)
        self.b1.pack(side=LEFT, fill=BOTH, expand=1)
        self.b2.pack(side=LEFT, fill=BOTH, expand=1)
    
    def yview(self, *args):
        self.b1.yview(*args)
        self.b2.yview(*args)


app = App(root)

for item in range(0,40):
    for i in range(item):
        it=str(i)+' '
        app.b1.insert(1.0,it)
        app.b2.insert(1.0,it)
    app.b1.insert(1.0,'\n')
    app.b2.insert(1.0,'\n')
    
    
root.mainloop()

This is my try:

import tkinter.scrolledtext

try:
    from Tkinter import *
except ImportError: ## Python 3
    from tkinter import *

root = Tk()

class App:
    def __init__(self,master):
        scrollbar = Scrollbar(master, orient=VERTICAL)
        self.b1 = tkinter.scrolledtext.ScrolledText(master, yscrollcommand=scrollbar.set)
        self.b2 = tkinter.scrolledtext.ScrolledText(master, yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.yview)
        scrollbar.pack(side=RIGHT, fill=Y)
        self.b1.pack(side=LEFT, fill=BOTH, expand=1)
        self.b2.pack(side=LEFT, fill=BOTH, expand=1)
    
    def yview(self, *args):
        self.b1.yview(*args)
        self.b2.yview(*args)


app = App(root)

for item in range(0,40):
    for i in range(item):
        it=str(i)+' '
        app.b1.insert(1.0,it)
        app.b2.insert(1.0,it)
    app.b1.insert(1.0,'\n')
    app.b2.insert(1.0,'\n')
    
    
root.mainloop()

I changed the widgets to scrolled text idgets, but it causes a weird behavior in the scrollbar that affects both widgets.


Now, is there a way to scroll these widgets (either text or scrolledtext) without using a toolbar, for example, with buttons for up and down, or with the keyboard (pressing a key for scrolling up and another for scrolling down)?

Remember I'm using tkinter and python 3.x

Thank you.

3
Contributors
3
Replies
1 Year
Discussion Span
11 Months Ago
Last Updated
4
Views
Question
Answered
G_S
Junior Poster
128 posts since Mar 2010
Reputation Points: 48
Solved Threads: 3
Skill Endorsements: 0

Sorry, I know this code is for Python 2.x, but hopefully it can point you in the right direction. There is a piece of code that I did NOT write myself but I implemented it in one of my programs. It basically creates a few text widgets in a loop and puts them in a list, also binding the scroll bar to a custom "scrolling" function. I don't think it would be too difficult to adapt this code and rather than binding the scroll bar itself, just bind arrow keys or buttons to the custom "scrolling" function. Good luck. I've pasted the code below; an example of how to implement it is given at the bottom.

from Tkinter import *

class CustomListbox(Frame):
    def __init__(self, master, lists):
	Frame.__init__(self, master)
	self.lists = []
	for l,w in lists:
	    frame = Frame(self); frame.pack(side=LEFT, expand=YES, fill=BOTH)
	    Button(frame, text=l, bg="#000000", fg="green", activeforeground="#999999", activebackground="#000000", relief=FLAT, highlightthickness=1, highlightbackground="#414141", highlightcolor="#414141", font=("Calibri", 9)).pack(fill=X)
	    lb = Listbox(frame, bg="#000000", fg="green", highlightthickness=1, width=w, borderwidth=0, selectborderwidth=0,
			 relief=FLAT, exportselection=FALSE)
	    lb.pack(expand=YES, fill=BOTH)
	    self.lists.append(lb)
	    lb.bind('<B1-Motion>', lambda e, s=self: s._select(e.y))
	    lb.bind('<Button-1>', lambda e, s=self: s._select(e.y))
	    lb.bind('<Leave>', lambda e: 'break')
	    lb.bind('<B2-Motion>', lambda e, s=self: s._b2motion(e.x, e.y))
	    lb.bind('<Button-2>', lambda e, s=self: s._button2(e.x, e.y))
	frame = Frame(self); frame.pack(side=LEFT, fill=Y)
	Label(frame, borderwidth=1, relief=RAISED).pack(fill=X)
	sb = Scrollbar(frame, orient=VERTICAL, command=self._scroll, bg="black", activebackground="#313131")
	sb.pack(expand=YES, fill=Y)
	self.lists[0]['yscrollcommand']=sb.set

    def _select(self, y):
	row = self.lists[0].nearest(y)
	self.selection_clear(0, END)
	self.selection_set(row)
	return 'break'

    def _button2(self, x, y):
	for l in self.lists: l.scan_mark(x, y)
	return 'break'

    def _b2motion(self, x, y):
	for l in self.lists: l.scan_dragto(x, y)
	return 'break'

    def _scroll(self, *args):
	for l in self.lists:
	    apply(l.yview, args)

    def curselection(self):
	return self.lists[0].curselection()

    def delete(self, first, last=None):
	for l in self.lists:
	    l.delete(first, last)

    def get(self, first, last=None):
	result = []
	for l in self.lists:
	    result.append(l.get(first,last))
	if last: return apply(map, [None] + result)
	return result
	    
    def index(self, index):
	self.lists[0].index(index)

    def insert(self, index, *elements):
	for e in elements:
	    i = 0
	    for l in self.lists:
		l.insert(index, e[i])
		i = i + 1

    def size(self):
	return self.lists[0].size()

    def see(self, index):
	for l in self.lists:
	    l.see(index)

    def selection_anchor(self, index):
	for l in self.lists:
	    l.selection_anchor(index)

    def selection_clear(self, first, last=None):
	for l in self.lists:
	    l.selection_clear(first, last)

    def selection_includes(self, index):
	return self.lists[0].selection_includes(index)

    def selection_set(self, first, last=None):
	for l in self.lists:
	    l.selection_set(first, last)

if __name__ == '__main__':
    root = Tk()
    Label(root, text='MultiListbox').pack()
    mlb = MultiListbox(root, (('Subject', 40), ('Sender', 20), ('Date', 10)))
    for i in range(1000):
	mlb.insert(END, ('Important Message: %d' % i, 'John Doe', '10/10/%04d' % (1900+i)))
    mlb.pack(expand=YES,fill=BOTH)
    root.mainloop()
SoulMazer
Posting Whiz in Training
215 posts since Sep 2008
Reputation Points: 36
Solved Threads: 13
Skill Endorsements: 0

By 2to3 to remove the apply, fixing the inconsistent space/tabs and Changing the main to create CustomListBox:

try:
    from tkinter import *
except ImportError:
    from Tkinter import *

class CustomListbox(Frame):
    def __init__(self, master, lists):
        Frame.__init__(self, master)
        self.lists = []
        for l,w in lists:
            frame = Frame(self); frame.pack(side=LEFT, expand=YES, fill=BOTH)
            Button(frame, text=l, bg="#000000", fg="green", activeforeground="#999999", activebackground="#000000", relief=FLAT, highlightthickness=1, highlightbackground="#414141", highlightcolor="#414141", font=("Calibri", 9)).pack(fill=X)
            lb = Listbox(frame, bg="#000000", fg="green", highlightthickness=1, width=w, borderwidth=0, selectborderwidth=0,
                 relief=FLAT, exportselection=FALSE)
            lb.pack(expand=YES, fill=BOTH)
            self.lists.append(lb)
            lb.bind('<B1-Motion>', lambda e, s=self: s._select(e.y))
            lb.bind('<Button-1>', lambda e, s=self: s._select(e.y))
            lb.bind('<Leave>', lambda e: 'break')
            lb.bind('<B2-Motion>', lambda e, s=self: s._b2motion(e.x, e.y))
            lb.bind('<Button-2>', lambda e, s=self: s._button2(e.x, e.y))
        frame = Frame(self); frame.pack(side=LEFT, fill=Y)
        Label(frame, borderwidth=1, relief=RAISED).pack(fill=X)
        sb = Scrollbar(frame, orient=VERTICAL, command=self._scroll, bg="black", activebackground="#313131")
        sb.pack(expand=YES, fill=Y)
        self.lists[0]['yscrollcommand']=sb.set

    def _select(self, y):
        row = self.lists[0].nearest(y)
        self.selection_clear(0, END)
        self.selection_set(row)
        return 'break'

    def _button2(self, x, y):
        for l in self.lists: l.scan_mark(x, y)
        return 'break'

    def _b2motion(self, x, y):
        for l in self.lists: l.scan_dragto(x, y)
        return 'break'

    def _scroll(self, *args):
        for l in self.lists:
            l.yview(*args)

    def curselection(self):
        return self.lists[0].curselection()

    def delete(self, first, last=None):
        for l in self.lists:
            l.delete(first, last)

    def get(self, first, last=None):
        result = []
        for l in self.lists:
            result.append(l.get(first,last))
        if last: return list(map(*[None] + result))
        return result
        
    def index(self, index):
        self.lists[0].index(index)

    def insert(self, index, *elements):
        for e in elements:
            i = 0
            for l in self.lists:
                l.insert(index, e[i])
                i = i + 1

    def size(self):
        return self.lists[0].size()

    def see(self, index):
        for l in self.lists:
            l.see(index)

    def selection_anchor(self, index):
        for l in self.lists:
            l.selection_anchor(index)

    def selection_clear(self, first, last=None):
        for l in self.lists:
            l.selection_clear(first, last)

    def selection_includes(self, index):
        return self.lists[0].selection_includes(index)

    def selection_set(self, first, last=None):
        for l in self.lists:
            l.selection_set(first, last)

if __name__ == '__main__':
    root = Tk()
    Label(root, text='CustomListbox').pack()
    mlb = CustomListbox(root, (('Subject', 40), ('Sender', 20), ('Date', 10)))
    for i in range(1000):
        mlb.insert(END, ('Important Message: %d' % i, 'John Doe', '10/10/%04d' % (1900+i)))
        mlb.pack(expand=YES,fill=BOTH)
    root.mainloop()
pyTony
pyMod
Moderator
6,312 posts since Apr 2010
Reputation Points: 879
Solved Threads: 987
Skill Endorsements: 26

Thank you very much everybody (forgot to thank and mark as solved, sory)

G_S
Junior Poster
128 posts since Mar 2010
Reputation Points: 48
Solved Threads: 3
Skill Endorsements: 0
Question Answered as of 11 Months Ago by SoulMazer and pyTony

This question has already been solved: Start a new discussion instead

Post: Markdown Syntax: Formatting Help
 
You
 
© 2013 DaniWeb® LLC
Page rendered in 0.0656 seconds using 2.69MB