0

I want to convert my Yahoo Earnings Calendar page scraper that creates a csv file to a GUI but I noticed if there were too many companies being reported that day, the tkinter window was only so big to display a set amount. I was wondering if there was a way to implement a scrollbar to my window. Any help is appreciated thanks!

from tkinter import *
from tkinter.tix import *
import csv
from datetime import date
import yahooFinanceToCSV

root = Tk()

# open file
with open(r'earnings_{}.csv'.format(date.today()), newline = "") as file:
   reader = csv.reader(file)

   # r and c tell us where to grid the labels
   r = 0
   for col in reader:
      c = 0
      for row in col:
         # i've added some styling
         label = tkinter.Label(root, width = 35, height = 2, \
                               text = row, relief = tkinter.RIDGE)
         label.grid(row = r, column = c)
         c += 1
      r += 1

root.mainloop()

My yahoo earnings scraper code

import pandas as pd
from datetime import date

# Forcing Pandas to display max rows and columns.
pd.option_context('display.max_rows', None, 'display.max_columns', None)
# Reading the earnings calendar table on yahoo finance website.
# earnings = pd.read_html('https://finance.yahoo.com/calendar/earnings')[0]
earnings = pd.read_html("https://finance.yahoo.com/calendar/earnings?from=2020-01-19&to=2020-01-25&day=2020-01-21")[0]
# Writing to a CSV file.
earnings.to_csv(r'earnings_{}.csv'.format(date.today()), index=None)

NOTE: The HTML is being forced to January 21 2020 because there 40ish companies reporting. Usually I run the code daily for said day's earnings but 21st Jan 2020 helps recreating the issue that needs to be solved.

CSM
  • 23
  • 5

2 Answers2

2

As Tk and Frame do not support Scrollbar, you need to simulate a ScrolledFrame by using Canvas, Scrollbar and Frame widgets:

def ScrolledFrame(parent):
  def on_resize(event):
    bbox = canvas.bbox('all')
    canvas.config(width=bbox[2], scrollregion=bbox)

  def on_mouse_wheel(event):
    # better checking whether event happens inside frame
    canvas.yview_scroll(event.delta//-30, 'units')

  # note: Canvas is the outer container
  canvas = tkinter.Canvas(parent)
  # *** modify the below line to suit your layout manager
  canvas.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=1)

  sb = tkinter.Scrollbar(parent, orient=tkinter.VERTICAL, command=canvas.yview)
  # *** modify the below line to use same layout manager as canavas
  sb.pack(side=tkinter.RIGHT, fill=tkinter.Y)

  canvas.config(yscrollcommand=sb.set)

  frame = tkinter.Frame(canvas)
  canvas.create_window(0, 0, window=frame, anchor='nw')
  frame.bind('<Configure>', on_resize)
  # use bind_all() to make sure mouse wheel events can be triggered
  # even the canvas is filled with labels on top 
  canvas.bind_all('<MouseWheel>', on_mouse_wheel)

  return frame

Then create a ScrolledFrame:

frame = ScrolledFrame(root)
# *** don't call any layout manager function, e.g. frame.pack() or frame.grid()

And create all the labels inside the ScrolledFrame:

label = tkinter.Label(frame, ...)
label.grid(...)

You can modify ScrolledFrame() function based on your requirement.

acw1668
  • 40,144
  • 5
  • 22
  • 34
  • You're great! Thanks for the help! – CSM Jan 20 '20 at 16:24
  • Would you happen to know how I can make the scroll move according to the mouse wheel? Currently I have to use the left click hold + drag to use the scroll bar. – CSM Jan 20 '20 at 17:05
  • Did you try the mouse wheel when the cursor is within the scrollbar? – acw1668 Jan 20 '20 at 17:26
  • I guess that's one way to do it but I would much rather be able to scroll in the frame itself – CSM Jan 20 '20 at 22:06
  • 1
    Updated result to support mouse wheel scrolling. – acw1668 Jan 20 '20 at 23:03
  • Awesome thank you once again! – CSM Jan 20 '20 at 23:18
  • This might be a bit too much to ask but would you know how I can make it so my widget updates live as Yahoo Finance updates? Meaning it constants checks for changes and updates it live on the my GUI? – CSM Jan 20 '20 at 23:52
  • When there is new data, you can delete all the labels inside `frame` (`for child in frame.winfo_children(): child.destroy()`), then recreate the labels based on the new data. – acw1668 Jan 21 '20 at 00:14
  • Don't I have to re run the code every time I want new data to appear? Or will the fix you mentioned above allow me to leave my GUI open and it will track it live? – CSM Jan 21 '20 at 00:16
  • No. You need to set up scheduled task using either `after()` or threading to fetch the data and then update the frame. – acw1668 Jan 21 '20 at 01:05
-1

There is a method to create a scrollbar on your window:

from Tkinter import * 
root = Tk() 
scrollbar = Scrollbar(root) 
scrollbar.pack( side = RIGHT, fill = Y )
Kaustubh Ghole
  • 537
  • 1
  • 10
  • 25
  • Just adding a scrollbar widget won't work For one, you never define the command of the scrollbar. For another, a scrollbar can't scroll widgets in a frame. – Bryan Oakley Jan 20 '20 at 14:00