Python Forum
Insert csv data rows into a tree widget - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Insert csv data rows into a tree widget (/thread-6187.html)



Insert csv data rows into a tree widget - LMP2016 - Nov-09-2017



I'm a beginner so dont beat me up too much :) .I have a program where a user enters a product number into a field and clicks a search button, the program then opens a csv file (see below), looks for that product number and should then only display (by inserting that data into a treeview) the data relevant, stopping once blank rows occur - this indicates the end of the part information and the start next part.

Example of the csv is below (excuse the use of the error box)
Error:
Product PartDesc Drawings Issues Documents 1-1841111-2 bad feeling Dwg1 Iss A c:\company\docs\tfpp\widget1.xls Dwg2 Iss B c:\company\docs\tfpp\bob.pdf Dwg25 Iss Z c:\company\docs\tfpp\itsatrap.pdf 1-1841111-4 tribble Dwg3 Iss C c:\company\docs\tfpp\wibble.xls 1-1841111-5 nothing Dwg4 Iss D c:\company\docs\tfpp\rocket.pdf Dwg5 Iss E c:\company\docs\tfpp\dwg1.doc
Unfortunately when I run the code I can only get a single csv row to display and have not been able to work out how get subsequent rows, stopping at a blank row. I am however, not convinced that the below code although its displays a single line as expected is operating correctly.

def search(self):
        if self.SOentry.get() != "":
            x = self.dwgtree.get_children()
            for item in x:
                self.dwgtree.delete(item)
            self.partdesc.delete(0,'end')
                
            with open("c:\python\projects\somedwgs.csv") as csvfile:
                    reader = csv.DictReader(csvfile)
                    for row in reader:
                        result=(row['Product'])
                        if self.SOentry.get() == result:
                                descr=(row['PartDesc'])
                                descDwg=(row['Drawings'])
                                descIss=(row['Issues'])
                                descDscr=(row['Documents'])
                                self.partdesc.insert(0,descr)
                                while True:
                                    #if row['PartDesc'] != "":
                                    if descDwg != "":
                                        self.dwgtree.insert("",'end',values=(descDwg,descIss,descDscr))
                                        next(reader)
                                        break



RE: Insert csv data rows into a tree widget - Larz60+ - Nov-09-2017

Show at least enough code to run the sample


RE: Insert csv data rows into a tree widget - LMP2016 - Nov-09-2017

Apologises, full code follow
import tkinter
import tkinter.font
from tkinter import ttk
import csv
from csv import DictReader
import sys
import os
import subprocess

tree_columns = ("Drawing", "Issue", "Document type")
sonumber = 0

class TFPP:

    def __init__(self):
        self.tree = None
        self._setup_widgets()
        self._build_tree()
     
    def _setup_widgets(self):
        
        #this is the setup & layout for the top part of the application i.e. the textbox and buttons.
        # setting up the 1st frame
        frame1=ttk.Frame()
        frame1.pack(fill='both', expand=False)

        AmpicsLabel = ttk.Label(frame1,justify="left", anchor="s", text=("Ampics Number :"))
        #sonumber = stringvar()
        self.SOentry=ttk.Entry(frame1,justify="left", width=15, textvariable = sonumber)
        Searchbutton = ttk.Button(frame1,text="Search",command='_do_search')
        AmpicsLabel.pack(side="left", padx=5)
        self.SOentry.pack(side="left", padx=5)
        Searchbutton = ttk.Button(frame1,text="Search", command=self.search)
        Searchbutton.pack(side="right", padx=3, pady=1)
        #
        #
        # setting up the 2nd frame
        frame2=ttk.Frame()
        frame2.pack(fill='both', expand=False)
        def _clear_text():
            self.partdesc.delete(0, 'end')
            self.SOentry.delete(0, 'end')
            x = self.dwgtree.get_children()
            for item in x:
                self.dwgtree.delete(item)

        DescLabel = ttk.Label(frame2,justify="left", anchor="sw", text=("Part Description : "))
        self.partdesc = ttk.Entry(frame2,background='#fff',justify="left", width=57)
        Resetbutton = ttk.Button(frame2,text="Reset",command=_clear_text)

        DescLabel.pack(side="left", padx=5)
        self.partdesc.pack(side="left", padx=5,pady=5)
        Resetbutton.pack(side="right", padx=3, pady=1)
        #
        #
        # setting up the 3rd frame
        frame3=ttk.Frame()
        frame3.pack(fill='both', expand=False)
        Quitbutton = ttk.Button(frame3,text="Quit", command=app.destroy)
        Quitbutton.pack(side="right", padx=3, pady=1) 
        #
        #
        # this is the setup & layout for the drawing list part.
        container = ttk.Frame()
        container.pack(fill='both', expand=False)
        self.dwgtree = ttk.Treeview(columns=tree_columns, show="headings")
        vsb = ttk.Scrollbar(orient="vertical", command=self.dwgtree.yview)
        self.dwgtree.grid(column=0, row=0, sticky='nsew', in_=container)
        vsb.grid(column=1, row=0, sticky='ns', in_=container)
        container.grid_columnconfigure(0, weight=1)
        container.grid_rowconfigure(0, weight=1)   

        #
        #
        # configures the layout of the tree
    def _build_tree(self):
        for col in tree_columns:
            self.dwgtree.heading(col,anchor="w", text=col.title(),
                command=lambda c=col: sortby(self.tree, c, 0))

            self.dwgtree.column("Drawing",width=120,anchor="w", stretch="no")
            self.dwgtree.column("Issue",width=75, anchor="w", stretch="no")
            self.dwgtree.column("Document type",anchor="w",width=300)
            self.treeview=self.dwgtree

        #
        #
        # this reads the csv file and loads the data into the tree
    def search(self):
        if self.SOentry.get() != "":
            x = self.dwgtree.get_children()
            for item in x:
                self.dwgtree.delete(item)
            self.partdesc.delete(0,'end')
                
            with open("c:\python\projects\somedwgs.csv") as csvfile:
                    reader = csv.DictReader(csvfile)
                    for row in reader:
                        result=(row['Product'])
                        if self.SOentry.get() == result:
                                descr=(row['PartDesc'])
                                descDwg=(row['Drawings'])
                                descIss=(row['Issues'])
                                descDscr=(row['Documents'])
                                self.partdesc.insert(0,descr)
                                while True:
                                    if descDwg != "":
                                        self.dwgtree.insert("",'end',values=(descDwg,descIss,descDscr))
                                        next(reader)

                                        break
              
      
       
    
if __name__ == "__main__":
    app = tkinter.Tk()
    app.title("Production Drawings")
    app.geometry("550x330")
    app.iconbitmap('telogo.ico')
    tfpp = TFPP()
    app.mainloop()



RE: Insert csv data rows into a tree widget - Larz60+ - Nov-09-2017

quick look, general
You have searchbutton defined twice

I did a search for 1-1841111-2
At line 91, the tree (x)  is not populated
self.SOentry.get() = {str} '1-1841111-2'
# ... first read of data file:
OrderedDict([('Product\t           PartDesc\t      Drawings\t   Issues\t       Documents', '1-1841111-2\t    bad feeling\t   Dwg1\t      Iss A\t    c:\\company\\docs\\tfpp\\widget1.xls')])
It then crashes on result = (row['Product'])
because Product is part of a string.
I would do this differently. Give me some time, I'm about to eat dinner


RE: Insert csv data rows into a tree widget - Larz60+ - Nov-10-2017

Ok,

I had my dinner.

here's how I would read this file.
The code would have been more compact if the structure were the same from line to line.
Since you are using tkinter, you obviously won't be using the show_current_product function,
but I put it there to show how to access the dictionary.
In addition, I wrote this so that the dictionary could handle multiple products with minor modifications.
Here's the code:
from pathlib import Path


class TryRead:
    def __init__(self):
        self.header = None
        self.product_dict = {}
        self.file = Path('.') / 'somedwgs.csv'

    def search(self, product_id):
        with self.file.open() as f:
            # skip first line (header)
            next(f)
            self.product_dict = {}
            product_found = False
            for line in f:
                line = line.strip().split('\t')
                if not product_found:
                    if line[0] != product_id:
                        continue
                product_found = True
                llen = len(line)
                if llen == 1:
                    break
                elif llen == 5:
                    product = line[0]
                    part_desc = line[1]
                    self.product_dict[product] = {}
                    self.product_dict[product]['PartDesc'] = part_desc
                    self.product_dict[product]['Drawings'] = {}
                    self.product_dict[product]['Drawings'][line[2]] = {}
                    self.product_dict[product]['Drawings'][line[2]]['Issues'] = line[3]
                    self.product_dict[product]['Drawings'][line[2]]['Documents'] = line[4]
                else:
                    self.product_dict[product]['Drawings'][line[0]] = {}
                    self.product_dict[product]['Drawings'][line[0]]['Issues'] = line[1]
                    self.product_dict[product]['Drawings'][line[0]]['Documents'] = line[2]
            # print(f'product_dict: {self.product_dict}')

    def show_current_product(self):
        if not self.product_dict:
            print('Please select a product')
        else:
            for key, value in self.product_dict.items():
                print(f'Product: {key}')
                for skey, svalue in value['Drawings'].items():
                    print(f'    {skey}')
                    for ikey, ivalue in svalue.items():
                        print(f'        {ikey}: {ivalue}')

if __name__ == '__main__':
    tr = TryRead()
    tr.search('1-1841111-2')
    tr.show_current_product()
and the results:
Output:
Product: 1-1841111-2     Dwg1         Issues: Iss A         Documents: c:\company\docs\tfpp\widget1.xls     Dwg2         Issues: Iss B         Documents: c:\company\docs\tfpp\bob.pdf     Dwg25         Issues: Iss Z         Documents: c:\company\docs\tfpp\itsatrap.pdf
Just in case there are any file differences, attached is  a copy of what I used
[attachment=280]


RE: Insert csv data rows into a tree widget - LMP2016 - Nov-10-2017

thank you for your help, its close to what I'm looking for except that I will be inserting the data into a tree widget that has three columns. So in my case if I searched for 1-1841111-2 I would be aiming to see :
DRAWING.........ISSUE.............DOCUMENT TYPE
Dwg 1.................Iss A.................c:\company\docs\tfpp\widget1.xls
Dwg 2.................Iss B.................c:\company\docs\tfpp\bob.pdf
Dwg 25...............Iss Z.................c:\company\docs\tfpp\itsatrap.pdf

with other part searches bring up other data in the above layout


RE: Insert csv data rows into a tree widget - Larz60+ - Nov-10-2017

But it's a simple process to manipulate the dictionary into any format that you need.
from pathlib import Path


class TryRead:
    def __init__(self):
        self.header = None
        self.product_dict = {}
        self.file = Path('.') / 'somedwgs.csv'
        self.out_field_size = 22

    def search(self, product_id):
        with self.file.open() as f:
            # skip first line (header)
            next(f)
            self.product_dict = {}
            product_found = False
            for line in f:
                line = line.strip().split('\t')
                if not product_found:
                    if line[0] != product_id:
                        continue
                product_found = True
                llen = len(line)
                if llen == 1:
                    break
                elif llen == 5:
                    product = line[0]
                    part_desc = line[1]
                    self.product_dict[product] = {}
                    self.product_dict[product]['PartDesc'] = part_desc
                    self.product_dict[product]['Drawings'] = {}
                    self.product_dict[product]['Drawings'][line[2]] = {}
                    self.product_dict[product]['Drawings'][line[2]]['Issues'] = line[3]
                    self.product_dict[product]['Drawings'][line[2]]['Documents'] = line[4]
                else:
                    self.product_dict[product]['Drawings'][line[0]] = {}
                    self.product_dict[product]['Drawings'][line[0]]['Issues'] = line[1]
                    self.product_dict[product]['Drawings'][line[0]]['Documents'] = line[2]
            # print(f'product_dict: {self.product_dict}')

    def generate_output(self):
        if not self.product_dict:
            print('Please select a product')
        else:
            for key, value in self.product_dict.items():
                for skey, svalue in value['Drawings'].items():
                    dlen = self.out_field_size - len(skey)
                    dlen2 = self.out_field_size - len(svalue['Issues'])
                    outstr = f"{skey}{'.' * dlen}{svalue['Issues']}{'.' * dlen2}{svalue['Documents']}"
                    yield outstr

    def show_formatted_product(self):
        for line in self.generate_output():
            print(line)

    def show_current_product(self):
        if not self.product_dict:
            print('Please select a product')
        else:
            for key, value in self.product_dict.items():
                print(f'Product: {key}')
                for skey, svalue in value['Drawings'].items():
                    print(f'    {skey}')
                    for ikey, ivalue in svalue.items():
                        print(f'        {ikey}: {ivalue}')

if __name__ == '__main__':
    tr = TryRead()
    tr.search('1-1841111-2')
    tr.show_current_product()
    print('')
    tr.show_formatted_product()
output (sans the header):
Output:
Product: 1-1841111-2     Dwg1         Issues: Iss A         Documents: c:\company\docs\tfpp\widget1.xls     Dwg2         Issues: Iss B         Documents: c:\company\docs\tfpp\bob.pdf     Dwg25         Issues: Iss Z         Documents: c:\company\docs\tfpp\itsatrap.pdf Dwg1..................Iss A.................c:\company\docs\tfpp\widget1.xls Dwg2..................Iss B.................c:\company\docs\tfpp\bob.pdf Dwg25.................Iss Z.................c:\company\docs\tfpp\itsatrap.pdf