Tix ScrolledListbox not scrollable - python

Hello and happy new year,
i'm trying to build a user interface and have a
problem with the Tix.ScrolledListbox.
(Python 2.6.5, Tix 8.4.3, Windows XP)
I wanted to use it to show items of varying number,
depending on a previous choice made by the user.
It's a GIS thing: the user picks a layer from a
ComboBox, presses a button and the Listbox
shows all fieldnames retrieved from the attribute
table. So for some layers there are 5, for others
30 fields. In principle it works.
But the scrollbar next to the listbox remains
grey with no function.
In a small test snippet, where, after pressing
a button, a random (0..100) number of items is shown
in the listbox the scrollbar works.
I have no idea.
Anybody had this before?
Edit: The following samplecode shows a not scrollable
scrolledListbox when arcpy is imported
import Tix
import random
import arcpy
class SampleApp(object):
def __init__(self):
self.window = Tix.Tk()
#listbox
self.lbx = Tix.ScrolledListBox(self.window, width = 30)
self.lbx.listbox.insert(Tix.END, " ")
self.lbx.listbox.bind("<<ListboxSelect>>", self.Choose)
#button to generate new list
self.btn = Tix.Button(self.window, text = "new list",
command = self.NewList)
#label shows chosen list item
self.lbl = Tix.Label(self.window, text = " ", bg = "white")
#pack
self.btn.pack(pady = 10)
self.lbx.pack(side="top", fill="both", expand=True, pady = 10)
self.lbl.pack(pady = 10)
self.window.mainloop()
#function to generate new listbox items on button command
def NewList(self):
self.lbx.listbox.delete(0, Tix.END)
r = random.randint(1, 30)
for i in range(r):
self.lbx.listbox.insert(Tix.END, i)
#event to show selected item in label
def Choose(self, event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection[0])
self.lbl.config(text = value)
sa = SampleApp()

Did you attach the scrollbar to the listbox?
from Tkinter import *
root = Tk()
scrollbar = Scrollbar(root)
scrollbar.pack(side=RIGHT, fill=Y)
listbox = Listbox(root)
listbox.pack()
for i in range(100):
listbox.insert(END, i)
# attach listbox to scrollbar
listbox.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=listbox.yview)
mainloop()
stolen from: http://effbot.org/zone/tkinter-scrollbar-patterns.htm
edit: Tix.ScrolledListBox works differently so don't mix it up with the above solution.

Related

Random Names picker with new draws on Each new Button Click

I'm trying to select random names from a list to display on a textbox in a tkinter GUI, with a button and need new draws to display in tkinter script each time I click the button.
Here's my code so far:
from tkinter import *
from random import sample
root = Tk()
root.title('Name Picker')
root.iconbitmap('c:/myguipython/table.ico')
root.geometry("400x400")
def pick():
# 5 entries
entries = ["1st name","2nd name","3rd name","4th name","5th name"]
# convert to a set
entries_set = set(entries)
# convert back to a list
unique_entries = list(entries_set)
number_of_items = 2
rando = sample(unique_entries, number_of_items)
rando1 = sample(unique_entries, number_of_items)
my_text = Text(root, width=40, height=10, font=("Helvetica", 18))
my_text.pack(pady=10)
if len(my_text.get(1.0, END)) != 0:
my_text.delete(1.0, END)
my_text.insert(INSERT, rando + rando1)
my_text.pack(expand= 1, fill= BOTH)
topLabel = Label(root, text="Picked Names", font=("Helvetica", 24))
topLabel.pack(pady=20)
winButton = Button(root,
text="pick names",
font=("Helvetica", 24), command=pick)
winButton.pack(pady=20)
root.mainloop()
I need several subsets of random draws (I'm using rando and rando1 values as example above).
When I click the button the 1st time it does display the names strings as expected, but when I click again nothing changes (the names remain the same).
What I need is for new draws to display each time I click the button.
I thought of clearing the textbox if not empty and populating back when clicking again on empty textbox (with the delete and insert statements above). But that's not working.
After some research I found this snippet:
# Import package and it's modules
from tkinter import *
# text_update function
def text_updation(language):
text.delete(0, END)
text.insert(0, language)
# create root window
root = Tk()
# root window title and dimension
root.title("GeekForGeeks")
# Set geometry (widthxheight)
root.geometry('400x400')
# Entry Box
text = Entry(root, width=30, bg='White')
text.pack(pady=10)
# create buttons
button_dict = {}
words = ["Python", "Java", "R", "JavaScript"]
for lang in words:
# pass each button's text to a function
def action(x = lang):
return text_updation(x)
# create the buttons
button_dict[lang] = Button(root, text = lang,
command = action)
button_dict[lang].pack(pady=10)
# Execute Tkinter
root.mainloop()
It seems it's close to what I need but the dictionary use seems incompatible with my conversion to a set and then back to a list and then the sampling before the displaying in the textbox of my code.
How could I use the given snippet to solve this issue? Or lese if it's not possible with this snippet, what other other solution of insight to look for would you suggest? Your help is appreciated.
In your code you are calling the widget constructor for the Text widget every time you press the button. What you should do is create the widget outside of the function and use the function just to update the widget's contents. There is also quite a bit of erroneous code as well.
For example:
from tkinter import *
from random import sample
root = Tk()
root.title('Name Picker')
root.iconbitmap('c:/myguipython/table.ico')
root.geometry("400x400")
def pick():
entries = ["1st name","2nd name","3rd name","4th name","5th name"]
number_of_items = 2
rando = sample(entries, number_of_items)
rando1 = sample(entries, number_of_items)
my_text.delete(1.0, END)
my_text.insert(INSERT, rando + rando1)
topLabel = Label(root, text="Picked Names", font=("Helvetica", 24))
topLabel.pack(pady=20)
winButton = Button(root, text="pick names", font=("Helvetica", 24), command=pick)
winButton.pack(pady=20)
my_text = Text(root, width=40, height=10, font=("Helvetica", 18))
my_text.pack(pady=10)
root.mainloop()

How to refresh the window in Tkinter?

I've been writing this program using the Tkinter module in Python3.6.2. There are buttons to to open a list of teams and a list of competitors and I'd prefer to keep the outputs in one window, however if I click the "Teams" button followed by the "Individuals" button, the two elements open one after the other.
I'm hoping to add a button that resets the window (removing the outputs, leaving just the buttons), but I haven't found any solutions online that work with my program.
from tkinter import *
import tkinter as tk
bgcol = "#0B8CFF"
class MainMenu:
def __init__(self, master):
self.master = master
master.title("Scoring System GUI")
master.geometry("500x750+75+60")
self.label = Label(master, text="GUI")
self.label.pack()
self.team_button = Button(master, text="Teams", command=self.openTeams)
self.team_button.pack()
def openTeams(self):
self.label = Label(text="Team #1:")
self.label.pack()
team1 = open("team1.csv", "r")
message = team1.read()
text = Text(root, width = "50", height = "6", fg = "#000000")
text.pack()
text.insert(END, message)
redteam.close()
Here's a photo of the current output:
You have to clear the Text widget before inserting new strings. Just insert the following line before your text.insert(...) statement:
text.delete('1.0', END)
By the way, if you only want to display a list and not edit it (as I guess is the case here) a Listbox widget if often a better choice than a Text widget.
To do that you need to create another method inside your class and parse it to another button as callback command.
def reset_func(self):
self.text.delete('1.0', END)
with this method inside when you parse it as command to your button it will clear the content in text widget .

python GUI tkinter scrollbar not working for canvas

I am learning python GUI with Tkinter. i just created two listbox and populated those in a canvas so that i can configure canvas with scrollbar and those two listbox scroll togather when i scroll canvas. but something is not working.
Here is the structure:
canvas = Canvas(master)
scrollBar = Scrollbar(master)
movieListBox = Listbox(canvas)
statusListBox = Listbox(canvas)
canvas.config(yscrollcommand = scrollBar.set)
movieListBox.config(width = 55)
statusListBox.config(width = 8)
movieListBox.pack(fill = "y", side = "left")
statusListBox.pack(fill = "y", side = "right")
canvas.pack(side = "left", fill = "y", expand = "true")
scrollBar.config(command = canvas.yview)
scrollBar.pack(fill = "y", side = "left")
for i in range(500):
movieListBox.insert(i, "movie name")
statusListBox.insert(i, "downloading")
master.mainloop()
I'm pretty new to tkinter and python myself, but I did find something that works. This is from another question, (I didn't write the code) which was about having two listboxes of different lengths linked to the same scrollbar. If you copy their code (below) you'll see that it works fine for listboxes of equal length. Your question is pretty old, but I hope it helps someone. Cheers.
Where I found this:
Scrolling two listboxes of different lengths with one scrollbar
try:
# Python2
import Tkinter as tk
except ImportError:
# Python3
import tkinter as tk
class App(object):
def __init__(self,master):
scrollbar = tk.Scrollbar(master, orient='vertical')
self.lb1 = tk.Listbox(master, yscrollcommand=scrollbar.set)
self.lb2 = tk.Listbox(master, yscrollcommand=scrollbar.set)
scrollbar.config(command=self.yview)
scrollbar.pack(side='right', fill='y')
self.lb1.pack(side='left', fill='both', expand=True)
self.lb2.pack(side='left', fill='both', expand=True)
def yview(self, *args):
"""connect the yview action together"""
self.lb1.yview(*args)
self.lb2.yview(*args)
root = tk.Tk()
# use width x height + x_offset + y_offset (no spaces!)
root.geometry("320x180+130+180")
root.title("connect 2 listboxes to one scrollbar")
app = App(root)
# load the list boxes for the test
for n in range(64+26, 64, -1): #listbox 1
app.lb1.insert(0, chr(n)+'ell')
for n in range(70+30, 64, -1):
app.lb2.insert(0, chr(n)+'ell') #listbox 2
root.mainloop()

How do you keep a widget in view while scrolling?

I am using Tix to automatically create a scroll bar as the content changes. I want to keep a button or two in the user's view while they scroll through the contents of the application.
I haven't seen this question for Tkinter/Tix yet so I thought I'd ask.
The following code will create a sample of the problem where the button is at a fixed point in the window, and is subject to being scrolled.
from Tkinter import *
import Tix
class some_GUI:
def __init__(self, root):
sw= Tix.ScrolledWindow(root, scrollbar=Tix.AUTO)
sw.pack(fill=Tix.BOTH, expand=1)
frame1 = Frame(sw.window)
frame1.grid(row = 0, column = 1)
frame2 = Frame(sw.window)
frame2.grid(row = 0, column = 2)
def quit():
root.quit()
for i in range(0,300):
label1 = Label(frame1, text = "foo")
label1.grid(row = i, column = 0)
button = Button(frame2, text = "Quit", command = quit)
button.pack()
root = Tix.Tk()
display = some_GUI(root)
root.mainloop()
I want the button(s) to be in "frame2" and centered vertically relative to the application's window. I tried using winfo_height/winfo_width to find the frame's height/ width to work with update, but these values didn't change with the addition of the labels and button.
Attempted/possible solutions:
I put frame2 in sw.subwidgets_all[1] by doing the following:
frame1.pack(side = LEFT)
frame2 = Frame(sw.subwidgets_all()[1])
frame2.pack(side = RIGHT)
button = Button(frame2, text = "Quit", command = quit)
button.pack(side = RIGHT)
This allows the fixed position relative to the application, but the window resizes relative to the button's parent instead of frame1. Another drawback is that the horizontal scrollbar is only relative to frame1.
Find the midpoint of the scrollbar and update the position of the buttons relative to those coordinates using place(maybe?) not sure how to accomplish this, and seeing SO solutions in general I think this might be an inefficient way of doing this.
EDIT: Although this isn't exactly what I had in mind, the following code works as per falsetru's suggestion in the comments:
from Tkinter import *
import Tix
class some_GUI:
def __init__(self, root):
def quit():
root.quit()
frame2 = Frame(root)
frame2.pack(side = RIGHT)
button = Button(frame2, text = "Quit", command = quit)
button.pack()
frame1 = Frame(root)
frame1.pack(side = LEFT)
sw= Tix.ScrolledWindow(frame1, scrollbar=Tix.AUTO)
sw.pack(fill=Tix.BOTH, expand=1)
for widget in sw.subwidgets_all():
print widget
for i in range(0,300):
label1 = Label(sw.window, text = "foo")
label1.grid(row = i, column = i)
print root.winfo_toplevel()
for widget in sw.subwidgets_all():
print widget
root = Tix.Tk()
display = some_GUI(root)
root.mainloop()
You can put the button out of ScrollWindows:
import Tix
from Tkinter import *
def build_ui(root):
sw = Tix.ScrolledWindow(root, scrollbar=Tix.AUTO)
sw.pack(side=LEFT, fill=Tix.BOTH, expand=1)
for i in range(300):
label1 = Label(sw.window, text="foo")
label1.grid(row=i, column=0)
button = Button(root, text="Quit", command=root.quit)
button.pack(side=RIGHT)
root = Tix.Tk()
build_ui(root)
root.mainloop()
The second option you mentioned could be the one that satisfies your situation, however that is computationally expensive as you will need to delete the button(s) and redraw them over and over relatively to the scrollbar up/down motion. Not only this is ugly by design but it can be an obstacle for any further scalability of your application or even lead to unexpected bugs if your application runs some serious operations.
The only realistic solution I see for your problem is to fix the button(s) on (for example the bottom of) the upper canvas (or whatever region you want to set) and outside the scrollable region as #falsetru commented you.

Tkinter Scrollbar in frame with multiple textframes

Question
How can I have a scrollbar which moves an entire Tkinter frame? Note: I am using Python 2.7.3.
Code and Explanation
I have this code for defining the scrollbar
scrollbar = Scrollbar(soeg)
scrollbar.pack(side=RIGHT, fill="y")
And this code for defining the textframes
h = 0
s = 0
for i in dom_nodup:
abc = dom_nodup[h]
text = Text(soeg, bg="brown", fg="white", height="10", width="60")
text.insert(INSERT, "%s \n" % abc[0])
text.insert(END, "%s \n\n\n" % abc[1])
text.pack()
h += 1
s += 1
A new textframe is created for each text entity for later easier overview (planning on having a button to show/hide the input).
The scrollbar is present but is not functional
I would recommend that you use the ScrolledText widget. It automatically adds a scrollbar to each text widget, and has the same arguments as Text. Here is a brief example of how to do it.
from Tkinter import * #Import the Tkinter module
from ScrolledText import ScrolledText #import the scrolled text module
message = "I \n am \n scroll \n able. \n\n\n\n\n\n Yes I am!"
class Application(Frame): #Create a frame for the widgets
def __init__(self, master): #initialize the grid and widgets
Frame.__init__(self,master)
self.grid()
self.widgets()
def widgets(self):
self.mytext = ScrolledText(self, width = 10) #Creates the widget
self.mytext.grid() #Places it
root = Tk()
root.title("My Text Example")
#make my screen dimensions work
root.geometry("500x1000")
app = Application(root)
root.mainloop()
For more information, please see the Tkinterbook and this question.
To make a scrollbar functional you must do two things: you must tell it which scrollable widget to scroll, and you must tell the scrollable widget which scrollbar to update with the current position.
scrollbar.configure(command=text.yview)
text.configure(yscrollcommand=scrollbar.set)

Categories

Resources