0

I've had a little dilemma and I think that it might be the same for a few people(hopefully). The following code gets names from a text file in the same folder, then prints them out in a frame. Unfortunately I don't know how to add a scrolling functionality into just this frame (nameframe). I need this code so that when you have a long list of names, all the names can be seen. Currently you can only see half of the names. I also would like the buttons to be the same size.

from tkinter import *
import time
import datetime
import re

root = Tk()
root.title("Attendence Register")
root.geometry('1350x650+0+0')

root.resizable(False, False)

nameframe = Frame(root, height=650, width=300)
nameframe.pack(side='left')

saveframe = Frame(root, height=650, width=300)
saveframe.pack(side='right')

outlist = []

def saveDataPresent(line):
    presentcount[line] += 1

    if presentcount[line] %2 == 1:
        present[line].configure(bg='#ff4dd2')
        line = (line + ' is present')
        outlist.append(line)
        #print(outlist)

    else:
        present[line].configure(bg='#66ff66')
        line = (line + ' is present')
        outlist.remove(line)
        #print(outlist)

def saveDataAbsent(line):
    absentcount[line] += 1

    if absentcount[line] % 2 == 1:
        absent[line].configure(bg='#ff4dd2')
        line = (line + ' is absent')
        outlist.append(line)
        #print(outlist)

    else:
        absent[line].configure(bg='#ff6666')
        line = (line + ' is absent')
        outlist.remove(line)
        #print(outlist)

def saveDataIll(line):
    illcount[line] += 1

    if illcount[line] % 2 == 1:
        ill[line].configure(bg='#ff4dd2')
        line = (line + ' is ill')
        outlist.append(line)
        #print(outlist)

    else:
        ill[line].configure(bg='#ffa31a')
        line = (line + ' is ill')
        outlist.remove(line)
        #print(outlist)

def saveDataHoliday(line):
    holidaycount[line] += 1

    if holidaycount[line] % 2 == 1:
        holiday[line].configure(bg='#ff4dd2')
        line = (line + ' is holiday')
        outlist.append(line)
        #print(outlist)

    else:
        holiday[line].configure(bg='light blue')
        line = (line + ' is holiday')
        outlist.remove(line)
        #print(outlist)

def saveData():
    now = datetime.datetime.now()
    now = str(now)
    dire = 'logs/'
    now = dire + now

    now = re.sub(':', '', now)
    now += '.txt'

    log = open(now, "w+")
    log.close()
    log = open(now, "a")
    for i in outlist:
        i = (i + '\n')
        log.write(i)
    log.close()

text = open('names.txt','r')
line = text.readline()
count = 0
present = {}
absent = {}
ill = {}
holiday = {}

presentcount = {}
absentcount = {}
illcount = {}
holidaycount = {}

for line in text:
    count+= 1
    name = Label(nameframe, text=line)
    name.grid(row=count, column = 0)

    presentcount[line] = 0
    absentcount[line] = 0
    illcount[line] = 0
    holidaycount[line] = 0


    present[line] =  Button(nameframe, text='/', pady = 20, padx=20, bg ='#66ff66', command=lambda line=line: saveDataPresent(line))
    present[line].grid(row=count, column = 2)

    holiday[line] = Button(nameframe, text='H', pady=20, padx=20, bg='light blue', command=lambda line=line: saveDataHoliday(line))
    holiday[line].grid(row=count, column=3)

    ill[line] = Button(nameframe, text='ill', pady=20, padx=20, bg ='#ffa31a', command=lambda line=line: saveDataIll(line))
    ill[line].grid(row=count, column=4)

    absent[line] = Button(nameframe, text='NA', pady=20, padx=20, bg ='#ff6666', command=lambda line=line: saveDataAbsent(line))
    absent[line].grid(row=count, column=5)

savebut = Button(saveframe, text='Save', pady = 20, padx=20, command=saveData)
savebut.pack()

root.mainloop()

Thanks for any help I hope my question is clear. In summary, I would like to know how to add a functioning scroll bar, or atleast something to help to be able to see all the names. This scroll bar should only affect nameframe. To show my situation more clearly: Image of the frame cutting

This is the sort of thing that I'm looking for:

nameframe = Frame(root, height=650, width=300)
nameframe.pack(side='left')

vsb = Scrollbar(orient="vertical", command=nameframe.yview)
nameframe.configure(yscrollcommand=vsb.set)

saveframe = Frame(root, height=650, width=300)

This commes up with the error: 'Frame' object has no attribute 'yview' saveframe.pack(side='right')

  • You cannot just add a scrollbar to a frame. You will need to use a canvas to manage scrolling down a frame. There is a known workaround for wanting to scroll down a list of widgets. – Mike - SMT Nov 12 '18 at 17:15
  • Possible duplicate of [Python Tkinter scrollbar for frame](https://stackoverflow.com/questions/16188420/python-tkinter-scrollbar-for-frame) – Mike - SMT Nov 12 '18 at 17:15
  • Though it is similar, it isn't exactly what I'm looking for, and because I'm new to python, I'm struggling to adjust the code for my needs – PythonNewbie Nov 12 '18 at 17:19
  • The link I provided is actually what you are looking for. You need to build a frame on a canvas in order to properly scroll down the widgets. This is just how it works. I will build a modified version of your example. – Mike - SMT Nov 12 '18 at 17:21
  • thanks for your commitment Mike, I'll try it too if you are certain. – PythonNewbie Nov 12 '18 at 17:26
  • Do you need to be able to scroll a frame (something that's not directly supported, but still possible), or are you wanting a solution for being able to scroll through multiple lines of text (which is directly supported and quite easy). – Bryan Oakley Nov 12 '18 at 18:03

1 Answers1

1

As pointed out in the link I provided you need to be using a canvas to scroll over widgets by adding a frame window to the canvas. There is also this post that may better explain what to do here: Adding a scrollbar to a group of widgets in Tkinter.

My example is only to solve the problem of scrolling through your widgets. Please note you may have other issues to review.

I prefer to use grid() manager so I updated your code accordingly. Please let me know if you have any questions.

Here is your code updated (with some general cleanup):

import tkinter as tk
import datetime
import re

root = tk.Tk()
root.title("Attendence Register")
root.geometry('1350x650+0+0')
root.resizable(False, False)
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
saveframe = tk.Frame(root, height=650, width=300)
saveframe.grid(row=0, column=2)

outlist = []

def saveDataPresent(line):
    presentcount[line] += 1
    if presentcount[line] %2 == 1:
        present[line].configure(bg='#ff4dd2')
        line = (line + ' is present')
        outlist.append(line)
    else:
        present[line].configure(bg='#66ff66')
        line = (line + ' is present')
        outlist.remove(line)

def saveDataAbsent(line):
    absentcount[line] += 1
    if absentcount[line] % 2 == 1:
        absent[line].configure(bg='#ff4dd2')
        line = (line + ' is absent')
        outlist.append(line)
    else:
        absent[line].configure(bg='#ff6666')
        line = (line + ' is absent')
        outlist.remove(line)

def saveDataIll(line):
    illcount[line] += 1
    if illcount[line] % 2 == 1:
        ill[line].configure(bg='#ff4dd2')
        line = (line + ' is ill')
        outlist.append(line)
    else:
        ill[line].configure(bg='#ffa31a')
        line = (line + ' is ill')
        outlist.remove(line)

def saveDataHoliday(line):
    holidaycount[line] += 1
    if holidaycount[line] % 2 == 1:
        holiday[line].configure(bg='#ff4dd2')
        line = (line + ' is holiday')
        outlist.append(line)

    else:
        holiday[line].configure(bg='light blue')
        line = (line + ' is holiday')
        outlist.remove(line)

def saveData():
    now = datetime.datetime.now()
    now = str(now)
    dire = 'logs/'
    now = dire + now
    now = re.sub(':', '', now)
    now += '.txt'
    log = open(now, "w+")
    log.close()
    log = open(now, "a")
    for i in outlist:
        i = (i + '\n')
        log.write(i)
    log.close()

text = ['names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names', 'names']
#line = text.readline()
count = 0
present = {}
absent = {}
ill = {}
holiday = {}
presentcount = {}
absentcount = {}
illcount = {}
holidaycount = {}

canvas = tk.Canvas(root, borderwidth=0)
frm = tk.Frame(canvas)
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
canvas.grid(row=0, column=0, sticky="ns")
vsb.grid(row=0, column=1, sticky="ns")
canvas.create_window((4,4), window=frm, anchor="nw")

def onFrameConfigure(canvas):
    canvas.configure(scrollregion=canvas.bbox("all"))

frm.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))

for line in text:
    count += 1

    name = tk.Label(frm, text=line)
    name.grid(row=count, column=0)

    presentcount[line] = 0
    absentcount[line] = 0
    illcount[line] = 0
    holidaycount[line] = 0

    present[line] =  tk.Button(frm, text='/', pady=20, padx=20, bg='#66ff66', command=lambda line=line: saveDataPresent(line))
    present[line].grid(row=count, column=2)
    holiday[line] = tk.Button(frm, text='H', pady=20, padx=20, bg='light blue', command=lambda line=line: saveDataHoliday(line))
    holiday[line].grid(row=count, column=3)
    ill[line] = tk.Button(frm, text='ill', pady=20, padx=20, bg='#ffa31a', command=lambda line=line: saveDataIll(line))
    ill[line].grid(row=count, column=4)
    absent[line] = tk.Button(frm, text='NA', pady=20, padx=20, bg='#ff6666', command=lambda line=line: saveDataAbsent(line))
    absent[line].grid(row=count, column=5)

tk.Button(saveframe, text='Save', pady=20, padx=20, command=saveData).grid(row=0, column=0)

root.mainloop()
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
  • Mike, I can't thank you enough for all your help in getting me to overcome this barrier. I'd eventually figured out that you had to put a frame iniside of thee canvas, but for a reason I still havent figured out, but that I'm working on, the scroll bar always appeared grey, and didn't function. Though I will still look into why this grey scroll bar occured, for my own understanding, you have taken down this barrier for me so that I can continue learning this great language. I really can't thank you enough and I hope one day that I might be able to help people just as you have helped me. Thanks – PythonNewbie Nov 12 '18 at 19:35
  • I couldn't finish my paragraph in that comment, everything seemss to be going smoothly and I'm just trying to implament multiple classes so it can actually be useful. I also notice that you also commented on my last problem, which I managed to figure out. Thanks for the commitment to the stack overflow community. – PythonNewbie Nov 12 '18 at 19:38
  • @PythonNewbie this one is a bit tricky for new programmers. I had a hard time with it when I first started out as well. Once you have a sold grasp on most of tkinter it will make much more sense down the road. – Mike - SMT Nov 12 '18 at 19:38
  • @PythonNewbie glad to help :D. Answering question is actually how I learn my skill set. People have problems I would never think of on my own so it becomes a fun challenge to work it out and see what I can do. – Mike - SMT Nov 12 '18 at 19:41
  • I guess I might try to give back to the community too, I'll start at the bottom though ;) – PythonNewbie Nov 12 '18 at 19:52
  • @PythonNewbie just make sure you select the check mark next to the answers that help you solve your problem. This will let everyone know you found a solution. – Mike - SMT Nov 12 '18 at 20:01