DeathResister
DeathResister

Reputation: 67

Tkinter reading row in order from a csv files

I am trying to create a troubleshooter for some devices, there is an entry box which uses your keyword to go to the correct frame which works fine, but i need some help to read each separate step from the csv file which has that specific problem. To do this, i made a button which reads the first step in the csv file, however, i want to make another button called "Next Step", which displays the next step in the csv file every time it's clicked. I also would like to know how i can get rid of the "First Step" button so there is no confusion and so that it makes sense. I have tried assigning a variable equal to True and made a while loop to make it so the button only displays when the variable is set to true, which didn't work at all. Any ideas on how to make this work, everything is much appreciated.

Here is my code

class wetDevice(tk.Frame):

def __init__(self, parent, controller):
    tk.Frame.__init__(self, parent)
    self.controller = controller
    label = tk.Label(self, text="How to fix a wet phone", fg="purple", font=controller.title_fontT)
    label.pack(side="top", fill="x", pady=10)


    def stepOne():
        with open("Wet Device.csv", "r") as f:
            csvreader = csv.reader(f, delimiter=",")
            for row in csvreader:
                if "1" in row[0]:
                    test = str(row[1])
                    stepOneL = tk.Label(self, text=test)
                    stepOneL.place(x = 10, y = 70, width = 500, height = 20)

    #def nextStep():



    stepOneB = tk.Button(self, text="First Step",
                         command=lambda: stepOne())
    stepOneB.place(x = 230, y = 130, width = 60, height = 20)


    mButton = tk.Button(self, text="Go to the Main Troubleshoot Menu",
                       command=lambda: controller.show_frame("MainTMenu"))
    mButton.place(x = 285, y = 210, width = 200, height = 25)  

the csv file is in this format(with only 5 steps):

Step, Instructions
1, instruction
2, instruction
3, instruction
4, instruction
5, instruction

I also would really appreciate it if you guys could help me out with opening the csv file which is in another folder in the same project folder.

Any help is much appreciated

Upvotes: 0

Views: 1089

Answers (2)

MatthewG
MatthewG

Reputation: 815

There are many problems with your code.

You can't use .pack() and .place() in the same frame

Within the __init__() of the wetDevice class there are times you use .pack() and times you use .place(). So all placed elements do not show in your window.

Simply change those elements to either .place() or .pack()

I have made adjustments to your code, so that it will work the way I believe you want it to.

  1. I changed stepOne() to just be step(), the way I have written the code you will only need this one method for changing the to the next step
    def step():
        row = next(self.csvreader)
        test = str(row[1])
        self.instruction.configure(text=test)
        stepOneB.configure(text="Next Step")
  1. I have changed how the way your wetDevice works, it now has a self.instruction variable that is a tk.Label element, this is where the current instruction is displayed. I also added self.csvreader this is to hold the csv, at the current step you are at.
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="How to fix a wet phone", fg="purple")
        label.pack(side="top", fill="x", pady=10)
        self.instruction = tk.Label(self, text="", fg="purple") # the new instruction Label
        self.instruction.pack() 

        f = open("Wet Device.csv", "r")
        self.csvreader = csv.reader(f, delimiter=",") # new csv element

Here is the full working code, that I believe will work as you want.

import tkinter as tk
import csv


class wetDevice(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="How to fix a wet phone", fg="purple", font=controller.title_fontT)
        label.pack(side="top", fill="x", pady=10)
        self.instructions_frame = tk.Frame(self)
        self.instructions_frame.place(x = 230, y = 55)
        self.instruction_labels = []
        f = open("Wet Device.csv", "r")
        self.csvreader = csv.reader(f, delimiter=",")

        def step():
            try:
                row = next(self.csvreader)
                test = str(row[1])
                if len(self.instruction_labels) >= 5:
                    temp = self.instruction_labels.pop(0)
                    temp.destroy()
                instruction_temp = tk.Label(self.instructions_frame, text=test, fg="black")
                instruction_temp.pack()
                self.instruction_labels.append(instruction_temp)
                stepOneB.configure(text="Next Step")

            except StopIteration:
                stepOneB.configure(state="disabled", text="No Steps")

        # def nextStep():

        stepOneB = tk.Button(self, text="First Step", fg="green",
                             command=lambda: step())
        stepOneB.place(x=230, y=175, width=60, height=20)

        mButton = tk.Button(self, text="Go to the Main Troubleshoot Menu",
                            command=lambda: controller.show_frame("MainTMenu"))
        mButton.place(x=285, y=210, width=200, height=25)

I have made adjustments to the code so it will work as you wanted (I think).

I have made some assumptions of my own however.

  • I made it display only the last 5 instructions

And unfortunately since I did this quickly I haven't completely fixed the fact you get an error, however I made a "hacky" fix for now. The fix I made was that if it attempts to get the next row of the csv and it causes an error then it will disable the nextStep Button and set its text to "No Steps".

Upvotes: 1

Talon
Talon

Reputation: 1894

You could add the csvreader onto the object, get the first line within the init mithod, add it to the window and reference the object each time you press the next-button. Then you can access the csv elements one at a time and don't need to e.g. iterate over all rows to find row with row[0] = "1" and can pick off where you left it.

...
self.csvreader = csv.reader(f, delimiter=",")
data = next(self.csvreader)
# set text with data
...

def nextStep():
    data = next(self.csvreader)
    # change text with data

Keep in mind that, when the csv is exhausted, it will raise an exception.

Upvotes: 0

Related Questions