• No results found

Förbättrad orderhantering

N/A
N/A
Protected

Academic year: 2022

Share "Förbättrad orderhantering"

Copied!
38
0
0

Loading.... (view fulltext now)

Full text

(1)

Förbättrad orderhantering

Andreas Gustavsson

Högskoleexamen Datornätverk

Luleå tekniska universitet Institutionen för system- och rymdteknik

(2)

Andreas Gustavsson LTU Skellefteå Datornätverk 120HP

1 september 2011

(3)

kunna hämta och lämna orderunderlagen samt fylla i arbetsrapporten. Jag vill med denna rapport visa hur jag tänkt och implementerat min lösning runt företagets nuvarande förutsättningar.

Jag vill tacka Per Eriksson, VD Norr-Don AB, samt alla anställda för att jag fick göra mitt examensarbete där. Hoppas att resultaten ska hjälpa och förenkla deras arbete.

(4)

For this task i chose the Python programming language to create the application needed as we read a Python course in the beginning of our education.

Sammanfattning

Mitt examensarbete gjorde jag på Norr-Don AB. Jag kontaktade Per Eriksson, VD:n på Norr-Don, som ville ha en enklare lösning för montörerna att hantera ordrar och rapportera arbetet.

Jag valde att använda Python för att koda en applikation till detta ändamål då vi i utbildningen läst en kurs i just Python.

(5)

Abstract ii

Sammanfattning ii

1 Introduktion 1

1.1 Bakgrund . . . 1

1.2 Problemställning . . . 2

1.3 Syfte . . . 2

1.4 Förkortningar . . . 2

2 Genomförandet 3 2.1 Inledning . . . 3

2.2 Verktyg . . . 3

2.2.1 Python IDLE . . . 3

2.2.2 Eclipse IDE . . . 3

2.3 Design . . . 4

2.3.1 GUI . . . 5

2.3.2 Klasser och funktioner . . . 6

2.4 Distribution . . . 12

3 Resultat 12 4 Diskussion 13 5 Källförteckning 15 6 Bilagor 16 6.1 Bilaga 1 . . . 16

6.2 Bilaga 2 . . . 26

6.3 Bilaga 3 . . . 27

6.4 Bilaga 4 . . . 28

6.5 Bilaga 5 . . . 30

6.6 Bilaga 6 . . . 32

(6)

1 Introduktion

Jag kontaktade Per Eriksson, Norr-Don AB, och fick i uppgift av honom att förbättra hanteringen av orderunderlag, främst till montörsidan men att det även kunde gå utveckla till att innefatta administrationssidan.

Norr-Don AB är ett litet företag beläget i Åmliden, Norsjö Kommun.

Dom tillverkar och säljer olika produkter inom El, exempelvis kablage, bygg- och kombicentraler och även många kundanpassade lösningar.

1.1 Bakgrund

Tidigare har dom skrivit ut orderunderlagen på papper och lagt dessa i plastmappar. För att spara pengar och på miljön valde dom att lägga dessa i kataloger på deras server istället. Varje arbetsplats har dessutom en bärbar dator för att kunna hämta och lämna orderunderlagen från servern. Varje orderkatalog innehåller pdf-filer med ritningar, materiallistor och annat som är specifikt för den ordern.

En montör som ska hämta en tillverkningsorder öppnar då katalogen med ordrar och flyttar en order till sin egna katalog. Montören skriver då in i ett exceldokument, när ordern påbörjats samt en signatur för att visa vem som påbörjat ordern. När ordern är klar ska orderkatalogen flyttas till en katalog för faktureringsunderlag. Dessutom ska det i excel dokumentet skrivas in när ordern var monterad klart, vikten på paketet och testresultat.

Bild 1.1.1

Företagets katalogstruktur

(7)

1.2 Problemställning

I detta förfarande finns ett par scenarion som skulle kunna uppstå. Exem- pelvis när en montör ska manuellt flytta kataloger kan det fort gå fel. Antin- gen kan den hamna i fel katalog eller av misstag raderas helt. Detta skapar jobb i onödan och bör kunna undvikas.

En annan sak jag upptäckte var att de som redigerade excel filen for- materade texten lite olika. Detta gör den mycket svår att överskåda och får den att se lite slarvig ut. Dessutom händer det ibland att någon missar eller fyller i fel kolumner vilket även där skapar onödigt arbete.

1.3 Syfte

Mitt syfte med arbetet är att underlätta hela förfarandet för montören.

Genom att applikationen ska sköta allt som tidigare gjordes manuellt bör många av problemen kunna undvikas. Formateringen i exceldokumentet blir enhetlig och katalogerna flyttas till och från montörens katalog på rätt sätt.

1.4 Förkortningar

LTU - Luleå Tekniska Universitet

IDE - Integrated Development Environment GUI - Graphical User Interface

(8)

2 Genomförandet

2.1 Inledning

Applikationen är helt skriven i Python[1]. Python är ett programspråk som enligt utvecklarna har flera bra egenskaper:

• very clear, readable syntax

• strong introspection capabilities

• intuitive object orientation

• natural expression of procedural code

• full modularity, supporting hierarchical packages

• exception-based error handling

• very high level dynamic data types

• extensive standard libraries and third party modules for virtually every task

• extensions and modules easily written in C, C++ (or Java for Jython, or .NET languages for IronPython)

• embeddable within applications as a scripting interface

Eftersom vi under första terminen läste en kurs i just Python gjorde att valet var enkelt. Dessutom är Python det enda programspråk jag har någon erfarenhet av. Ännu en fördel är att det är “cross-platform”, vilket gör att det fungerar på olika plattformar, vare sig det är Windows eller Linux.

2.2 Verktyg

2.2.1 Python IDLE

Med Python-paketet följer även IDLE med. Det är en mycket enkel IDE för just Python, men den täcker många användares behov. Till en början använde jag mig av IDLE, främst eftersom det skeppades med Python men även för att jag hade jobbat med det tidigare.

2.2.2 Eclipse IDE

Under tiden jag kodade halkade jag in på en diskussion om bästa IDE för Python. Jag tänkte att man skulle testa en annan, lite mer avancerad, mer funktionsrik utvecklingsmiljö. Jag hittade en som verkade vara en kompetent IDE som dessutom var gratis att använda.

(9)

Eclipse[2] är en open-source utvecklad IDE främst för java och c++, men med Pydev går det alldeles utmärkt att koda i python. Jag tycker att man med Eclipse fick en mycket bättre vy över koden, samt att den har många andra bra funktioner som underlättar arbetet.

2.3 Design

Hur ska man utforma en applikation för att den ska vara lätt att använda, även för de som har liten datorvana? Jag började skissa på papper ungefär hur jag tänkte att gränssnittet skulle se ut, detta gav lite större överblick på hur alla funktioner skulle fungera ihop med gränssnittet.

Bild 2.3.0.1

Tidig skiss på gränssnittet

När en montör först startar programmet får den upp en dialogruta för att välja bassökväg, där alla kataloger som används finns, samt vilken excelfil som ska skrivas och läsas ifrån. För att slippa hårdkoda applikationen att passa till varje användare beslöt jag mig att göra en universiell funktion på det hela.

Genom att lägga in en funktion för att kunna välja användare, där valen av användare genereras av de kataloger som finns i bassökvägen, slipper man detta. Ifall två anställda skulle byta arbetsplats går det även bra i efterhand att byta användare.

(10)

Efter lite funderingar och hackande av kod kom jag fram till ett upplägg jag tycker fungerade bra. Detta blev den slutgiltiga varianten på applikatio- nens gränssnitt.

Bild 2.3.0.2

Slutgiltig version av gränssnittet 2.3.1 GUI

Det finns flera moduler till Python att bygga gränssnitt av. wxPython, PyQt och Tkinter är de som verkade vanligast att använda sig av. Vilket som är bäst är nog en smakfråga och beroende på hur komplicerad applikation man ska göra.

wxPython

Jag började med att testa wxPython[4]. I början kändes det relativt enkelt att använda, men det började bli mycket med alla event-handlers. Det blev snabbt mer invecklat och svårt att hålla reda på dessa. Däremot fick jag känslan att wxPython erbjuder fler funktioner än många andra GUI:s, samt att det arbetar närmare operativsystemet.

Tkinter

Valet föll då på Tkinter [3] istället. Det är en inofficiell standard modul för att bygga gränssnitt i Python, den är inkluderad i Python-paketet. Mycket av syntaxen från wxPython känns igen, men det var mycket lättare med eventen och callbacks i Tkinter. För att binda en funktion till exempelvis en knapp behövdes det bara anges command=<funktion> i <options> för knappen. (Ex: knapp1 = Button(<ParentFrame>, <options>) )

(11)

2.3.2 Klasser och funktioner

Min applikation delade jag upp i olika klasser. Detta för att få en bättre blick över applikationen, det blir lättare att lägga till och ändra kod i den. Hela applikationen initieras från __main__. (Se Bilaga 3 ) i filen NDProd.py. Jag listar här de klasser jag använder mig av.

askBaseDir (Bilaga 4)

Klassen askBaseDir används för att kontrollera om det konfigurerats någon sökväg samt ifall rätt kataloger finns i sökvägen. Den är i princip uppdelad i två delar.

Första delen i klassens initfunktion körs först ett try, except statement som kontrollerar ifall en korrekt sökväg är konfigurerad genom att helt enkelt försöka lista filer och kataloger i den. I annat fall höjs en varningsdialog med felmeddelande och sedan höjs en dialogruta där användaren får välja en ny sökväg.

I den andra delen finns en if-sats som ifall ingen sökväg finns höjer en dialogruta för att fråga efter sökväg. Trycker användaren avbryt stängs hela applikationen ned. Sökvägen kontrolleras sedan i funktionen validateDirec- tory. Funktionen tar den tidigare valda sökvägen som parameter. I klassen main finns en dictionary, "main.setPath", vars värden är de kataloger som ska finnas i sökvägen. Genom en for-loop kontrolleras den valda sökvägen mot dessa värden. Den returnerar True ifall katalogerna finns, annars re- turneras False. Returneras True kommer användaren till huvudfönstret. Ifall

"validateDirectory" returnerar False visas en dialogruta med felmedde- lande och användaren får på nytt välja sökväg.

MainWin (Bilaga 1)

Klassen MainWin innehåller alla widgets för huvudfönstret samt de vari- abler som används i dessa widgets.

Den innehåller även två dicitonarys. "setPath", vilken innehåller nam- nen på de kataloger som ska finnas i huvudsökvägen, samt "colID" som har nycklar som identifierar vilken kolumn som ska skrivas till i excelfilen samt värden som visar vad kolumnerna heter.

Variabeln "excelFile" är sökvägen till den excelfil som skrivs och läses från. Sedan finns en del variabler med värdet "IntVar()" eller "StringVar()", dessa används till label widgetarna och ifall de ändras uppdateras dessa au- tomatiskt i labelwidgeten. Mycket smidigt får jag säga.

Ett par variabler som används i huvudfönstret är dessa:

• OrderFolder

Innehåller en tuple med de kataloger som finns i den valda orderkata- logen. Den sätts som värde till listboxwidgeten "OrderList".

(12)

• UserFolder

Innehåller en tuple med de orderkataloger som finns i användarens katalog. Denna sätts som värde till listboxwidgeten "UserList".

• currentUserFolder

En sträng med sökvägen till användarens katalog.

• workDir

En sträng med sökvägen till huvudkatalogen vilken innehåller alla or- derkataloger, användarnas kataloger samt faktureringskatalogen och excelfilen.

• currentUserSign

En strängvariabel som innehåller användarens signatur och används för att fylla i exceldokumentet när en order flyttas till användarens katalog.

Funktioner i klassen “MainWin”

• __init__

Ritar upp alla widgets i huvudfönstret.

• infoLabels

Genererar labels flr att visa information om ordern. Det görs på samma sätt som beskrivs ovan.

• clearEntries

Rensar textboxarna som användaren fyller i när ordern är klar. (Bild 2.3.2.1)

• setDate

Gjordes för att användaren inte skulle behöva fylla i dagens datum, utan det görs då automatiskt. Men ifall den av någon anledning behöver ändras, är det bara att ändra den innan man skickar ordern vidare.

• onOrderToUserFolder

Fyller i excelfilen med dagens datum samt användarens signatur och höjer sedan en inforuta, där OK skriver till excelfilen och flyttar katalo- gen. Kan ej excelfilen skrivas till höjs ett felmeddelande och katalogen flyttas inte.

• onOrderFinished

Värdena som användaren fyllt textboxarna (Bild 2.3.2.1) skrivs till excelfilen och flyttar sedan ordern till faktureringskatalogen. Även här höjs en inforuta innan excelfilen skrivs till och ett felmeddelande ifall excelfilen inte går att skriva till. Då flyttas inte heller ordern.

(13)

• orderSel

Anropas när användaren markerar en order i listboxarna (se bild x.x.x).

Jag gjorde en if-sats som kollar ifall ett värde i OrderListboxen är mark- erad och returnerar värdet, om inte något markerats i den returneras värdet på markeringen i den andra listboxen istället.

• onOrderHighlight

Denna funktion har som uppgift att hämta information om ordern som markerats i en listbox från excelfilen.

• setUser

Funktionen anropas av knappen "välj användare". Den öppnar en dialogruta där användare väljs. Hur den fungerar förklaras i klassen

"userSelect" nedan.

• noUser

Om ingen användare valts när en order ska flyttas till en användarkata- log anropas denna funktion. Den höjer en infomeddelande och anropar sedan funktionen "setUser".

• move2user

Huvudfunktionen för denna är att flytta ordern från orderkatalogen till användarens katalog. Finns ingen användare konfigurerad anropas

"noUser", annars flyttas den order som är markerad i Order Listboxen.

Pythonmodulen "os.path.join" används för att slå ihop de strängar som skickas till den sökväg som ordern ska flyttas till.

• move2fakt

Precis som funktionen ovan, fast ordern skickas från användarens kat- alog till faktureringskatalogen. Den anropar "onOrderFinished" och flyttar sedan katalogen ifall den returnerar "True".

• UpdateUserFolder

Den uppdaterar listboxen som listar katalogerna i användarmappen.

Bild 2.3.2.1

(14)

userSelect (Bilaga 4)

Denna klass innehåller widgets för att rita upp fönstret där man väljer användare. Den innehåller ett par funktioner för detta.

• Frames

Definerar de frames som fönstret ska innehålla. I Tkinter är "Frame"

en typ av behållare där man lägger olika widgets. Detta för att dela upp och kunna placera ut exempelvis en knapp på rätt ställe.

• radiobuttons

Den anropar funktionen "generateUsers" och av det den funktionen returnerar ritas radiobutton widgets upp i fönstret för de användare som går att välja bland.

• buttons

Funktionen ritar upp en OK och Cancel knapp i fönstret. OK kallar funktionen "setUser" och Cancel kallar funktionen "Cancel".

• Cancel

Denna funktion stänger fönstret.

• setUser

Funktionerna sätter variablerna i mainfönstret. Dessa variabler är

"main.currentUserSign", vilket är den signatur som skrivs till ex-

celfilen. "main.currentUser", namnet på användaren, samt "main.currentUserFolder", vilket är sökvägen till användarens katalog.

• generateUsers

Funktionen returnerar en dictionary, samt två listor. Dictionaryn in- nehåller en integer som nyckel och katalognamnet som värde till den.

Den ena listan, "radiolist", har namnen på radioknapparna (radio1, radio2.. osv.) Dessa läggs till listan beroende på hur många användark- ataloger som finns. Andra listan, "labellist", fylls med namnen på användarna. Dessa namn hämtas ur namnet på användarkatalogerna.

configFile (Bilaga 2)

Detta objekt innehåller funktioner och variabler som används för att läsa och skriva från en konfigurationsfil. Filen läses in vid uppstart och skrivs till när programmet stängs ner. Den innehåller ett par funktioner för detta ändamål.

• __init__

Initierar klassen och definerar en instans av modulen ConfigParser.

• read

Läser från configfilen och sätter värdena till variablerna i applikationen.

(15)

• write

Sparar värdena på de variabler som berörs för att sedan kunna skriva dessa till en konfigurationsfil.

• writeToFile

Skriver värdena till konfigurationsfilen.

När sedan applikationen ska startas görs det från filen "NDProd_main.py".

Satsen " if __name__ == ’__main__’: ", kollar ifall filen NDProd_main.py körs som huvudprogram. Pythontolken sätter variabeln __name__ till ’__main__’

ifall den körs som huvudprogram. Om så är fallet exekveras koden i det if- blocket vilket initierar huvudfönstret i applikationen och dess widgets. Den läser även från konfigurationsfilen och frågar efter bassökvägen och sökvägen till exceldokumentet.

Ifall det var många widgets med samma funktion men med olika namn och labels gjorde jag en for-loop som itererade över ett dictionary vars nyckel var "rowID". Det är den rad som widgeten ligger på i dess grid. Värdena är en lista där index 0 är namnet på widgetklassen och index 1 är texten i widgeten, ifall det är en knapp, label eller liknande. Denna lösning tycker jag ser kodmässigt snyggare ut, samt att ifall man ska lägga till ännu en widget är det bara att lägga till det i dictionaryn.

readExcel (Bilaga 5)

"excelMod.py" innehåller en klass jag använder för att läsa och skriva till excelfilen. Jag använder mig av modulerna xlrd [4], xlwt[4], xlutils[4]

samt tkMessageBox.

Xlrd, xlwt och xlutils är python bibliotek som används för att läsa, skapa och modifiera exceldokument med hjälp av python. Klassen innehåller ett par olika funktioner som behövs av huvudapplikationen.

• __init__

Initieraren av klassen. Har en variabel som heter "colID", vilken ska innehålla de kolumner som ska skrivas till. Variabeln "variables" är de värden som läses ur excelfilen. Dessa läser sedan huvudapplikationen av.

• readDok

Funktionen öppnar ett exceldokument för att skrivas eller läsas ifrån.

Den anropar sedan "readFile" vilket beskrivs nedanför.

• readFile

Funktionen tar "orderNr" samt ett kommando som argument. "OrderNr"

är det ordernummer som ska läsas av i excelfilen. Kommandot är antin- gen en 0:a för att läsa ur filen, eller en 1:a ifall den ska skrivas till.

(16)

• setVariables

Tar "sheet" och "rowIndex" som argument där "sheet" är det excel- blad som ska läsas och "rowIndex" är den rad ordernumret ligger på.

Funktionen lägger sedan värdena i dictionaryn "colID".

• writeExcel

Denna funktion är den som skriver till excelfilen. På grund av begrän- sningar i excelmodulerna går det inte att redigera excelfilen utan man måste kopiera den och för att sedan skriva över orginalfilen. Funktio- nen tar argumenten "sheet", "index" och "rowIndex". "sheet" är excelbladet där ordern finns representerad, "index" är numret på ex- celbladet och "rowIndex" är den rad ordernumret finns på. En for-loop itererar sedan över "colID" dictionaryn för att sedan skriva värdena i den till excelfilen. Värdena i "colID" är de som sätts när klassen instantieras av den funktion som vill skriva till excelfilen.

(17)

2.4 Distribution

För att underlätta distributionen av programmet letade jag med ljus och lykta efter ett enkelt installationsscript, eller liknande, för att installera app- likationen på klienterna. Till slut hittade jag ett mycket smidigt verktyg för detta ändamål, InnoSetup[3].

Med i installationspaketet följer även InnoIDE, det fungerar som en utvecklingsmiljö för att enkelt skripta sitt installationsprogram. Jag använde mig av en “wizard” som frågar efter namnet på applikationen, vilka filer och kataloger som ska packeteras i installationsfilen samt vilken fil som startar applikationen. Det frågar även om vilken vilken grundkatalog den ska lägga applikationen i vid installationen.

Trots att det går att göra rätt avancerade installationsscript är det enkelt att snabbt komma igång och skapa en installationsfil.

3 Resultat

Programmet testkördes kontinuerligt under utvecklingen på både min miljö hemma och lokalt på en laptop. Min miljö hemma består av en Linux Server med Ubuntu Server 11.04 med samba för att dela ut kataloger på nätver- ket, en klientdator som kör windows 7 professional och en D-Link DIR655 konsumentrouter.

Företaget har en server som kör Windows Server 2003, klienter i form av laptops som kör Windows XP Professional och en trådlös accesspunkt tillverkad av D-Link.

Jag installerade applikationen på företagets klientdatorer och testade den under en arbetsdag. Applikationen fungerade som väntat vid testkörning i min hemmamiljö. Dock uppstod många problem i företagets miljö. Fram- förallt klagade den på att sökvägarna inte fanns, detta verkar ha något med teckenkodningen att göra. För att undvika problemet fick jag döpa om ett par sökvägar och ta bort tecknen ÅÄÖ i dessa.

Applikationen fungerade som förväntat i min miljö hemma, men på före- taget gjorde den inte det. Dock fanns inte tid kvar att åtgärda alla fel som hittades.

(18)

4 Diskussion

Norr-Don är som sagt ett mindre företag, men alla hjälpmedel som fören- klar och snabbar upp i deras vardag är välkomna. Det stora målet med min applikation var just detta. Att för montörerna utveckla en applikation som skulle underlätta och snabba upp orderhanteringen och rapporteringen av dessa.

Min erfarenhet av att programmera sträcker sig inte längre än det vi läste i kursen som ingick i programmet. Däremot tycker jag att det verkade som en riktigt utmaning. Mitt första mål med hela examensarbetet var att få en uppfattning om det var genomförbart på den tid examensarbetet pågick.

Genom att konsultera Google[5] gick det bra att få en bild av omfattningen på arbetet bakom. Jag började sedan med att koda applikationens grafiska del. Det var just den delen jag såg som det största hindret. Som tur är var Tkinter väl dokumenterat på många håll och kanter, det gjorde att det var lätt att komma igång och koda.

När jag börjat få en hyfsat bra struktur på den grafiska delen började jag klura på de funktioner applikationen skulle ha. Kraven var att den skulle kunna flytta katalogerna samt rapportera till en excelfil. Delen med att flytta kataloger var enkelt. Python har många inbyggda moduler och en av dessa,

“os”, har många bra funktioner bland annat för att flytta kataloger och lista sökvägar.

Vad som däremot orsakade en del huvudbry till en början var hur man skulle kunna skriva till och läsa en excelfil. Svaret på den frågan blev PythonEx- cel, som innefattar modulerna “xlwt”, “xlwr” och “xlutils”. Ett problem jag stötte på då var att jag började koda min applikation i Python 3.2. Dessa moduler var skrivna för Python 2.6. Detta gjorde att jag fick skriva om ap- plikationen för Python 2.6, vilket tog en del tid i anspråk. Dessa moduler var även dom rätt bra dokumenterade, det gick då rätt bra att förstå dess funktion.

Jag hade nu en applikation med ett grafiskt interface, som kunde flytta kataloger, läsa och skriva till och från ett exceldokument. En sak jag tyckte mig sakna då var ett sätt att distribuera applikationen till alla användare. Ett alternativ till detta heter Inno Setup[3]. Med detta program följer även en IDE. För att skapa min installationsfil startade jag en “wizard”, eller guide, för att skapa denna. Efter guiden kunde jag sedan modifiera delar av instal- lationsprogrammet.

När jag sedan gick in i testfasen av programmet stötte jag på stor patrull.

Hemma gick det bra att köra det och dess funktioner fungerade som dom skulle. Men när jag sedan började testa skarpt på företagets miljö blev det

(19)

tvärstopp. Det gick inte flytta katalogerna och klientdatorerna kom inte åt excelfilen. Jag fick då tillåtelse att flytta excelfilen vilket löste det problemet.

Men det gick fortfarande inte att flytta katalogerna. Men då min tid höll på att rinna ut hann jag inte med att felsöka detta helt. Det jag tror var att teckenkodningen av någon anledning inte stämde överens med programmets.

Eftersom katalognamnen innehöll specialtecken som ÅÄÖ fungerade det inte som tänkt.

Jag tycker att jag lärt mig massor av detta arbete. Framförallt att det är en god idé att ha lite erfarenhet av att programmera applikationer. En sak som jag skulle lagt ner mer tid på var hela planeringen, nu blev egentligen det mesta improviserat. Men att ha skrivit upp en projektplan, kollat upp vad som hade behövts av Python för att klara alla funktioner, hade varit mycket i värde. Problem som att Python Excel modulerna inte var kompatibla med Python 3.2 hade upptäckts direkt och sparat mycket tid. Applikationen går i sitt nuvarande utförande inte att köra på företaget och jag tror inte heller att det finns någon möjlighet att slutföra det just nu.

(20)

5 Källförteckning

1. Python Programming Language - Official Website, Python Software Foundation, 2011, Hämtad 01 Juni 2011 från:

http://www.python.org

2. Eclipse Downloads, The Eclipse Foundation, Hämtad 01 Juni 2011 från:

http://www.eclipse.org

3. Inno Setup, jrsoftware.org, Hämtad 01 Juni 2011 från:

http://www.jrsoftware.org/isinfo.php

4. Python Excel modules, http://www.python-excel.org/, Hämtad 04 Juni 2011 från:

http://pypi.python.org/pypi/

5. Google, www.google.com, Hämtad 26 Juni 2011 från:

http://www.google.com

(21)

6 Bilagor

6.1 Bilaga 1

MainWin class object, innehåller alla widgets, variabler och funktioner för huvudfönstret.

Från NDProd_main.py

class MainWin:

"""

Innehåller hela programfönstret och alla variabler som används.

"""

def __init__(self, master):

""" Initieringsfunktionen för fönstret.

Anropar funktionen "init" som skapar MainFrame, samt Frame1, 2 och 3 med innehåll.

"""

##-- Kataloger som ska finnas i workingDir self.setPath = {

1:’1. Kombi’, 2:’2. Kablage’, 3:’3. Apparatskåp’, 4:’4. Elfördelning’,

6:’6. Administration Fakuteringsunderlag’

}

##-- Lista på vilka kolumner som ska läsas av i Exceldokumentet.

self.colID = { 0:’TVO’, 1:’OrderNr’, 2:’Kund’, 12:’LeveransDag’

}

##-- Sökväg till excelfil.

self.excelFile = ’’

##-- Variabler

self.SetOrderFolder = IntVar() self.OrderFolderList = StringVar() self.UserFolderList = StringVar() self.currentUser = StringVar() self.orderFinishedVar = StringVar() self.packageWeightVar = StringVar() self.testedOKVar = StringVar()

##-- String Variabler för infoLabel self.TVO = StringVar()

self.OrderNr = StringVar() self.Kund = StringVar() self.LeveransDag = StringVar()

self.OrderFolder = ’’

self.UserFolder = ’’

self.currentUserFolder = ’’

self.workDir = ’’

self.currentUserSign = ’’

##-- Initieringsfunktion för Fönstret anropas här.

self.init(master)

(22)

def init(self, master):

"""

Initieringsfunktion för allt innehåll i huvudfönstret.

"""

mainframe = self.mainframe = Frame(master)

mainframe.grid(column=0, row=0, padx=10, pady=10, sticky=(N, S, E, W))

##-- FRAME 1 --##

self.Frame1 = Frame1 = Frame(mainframe)

Frame1.grid(column=0, row=0, sticky=(W, E, N, S)) Frame1.columnconfigure(2, weight=3)

##-- FRAME 1 innehåll --##

self.nd_logo = nd_logo = PhotoImage(file=’images/norr-don.gif’) self.logo = logo = Label(self.Frame1, relief=GROOVE, image=nd_logo) logo.grid(column=0, row=0, columnspan=3)

##-- blank frame under logo

blankframe1 = Frame(Frame1, height=20)

blankframe1.grid(column=0, row=1, columnspan=3)

##---

##-- blank frame mellan chooseUserButton & chooseUserFrame blankframe6 = Frame(self.Frame1, width=5)

blankframe6.grid(column=1, row=2, sticky=(W))

##---

##-- Knapp som anropar funktionen för att välja användare self.chooseUserButton = button1 = Button(

self.Frame1,

text=’Välj Användare’, command=self.setUser )

button1.grid(column=0, row=2, ipadx=2, sticky=(W, E, N)) self.updateUserFolderButton = button2 = Button(

self.Frame1,

text=’Uppdatera Katalog’, command=self.UpdateUserFolder )

button2.grid(column=0, row=3, ipadx=2, sticky=(W,E,N))

##-- LabelFrame

self.chooseUserFrame = chooseUserFrame = LabelFrame(

self.Frame1,

text=’Vald Användare’

)

chooseUserFrame.grid(column=2, row=2, rowspan=2, sticky=(W, E))

##-- Label som visar vald användare self.UserLabel = UserLabel = Label(

self.chooseUserFrame, textvariable=self.currentUser )

UserLabel.grid(column=0, row=0, padx=5, sticky=(W, E))

blankframe2 = Frame(Frame1, height=10)

blankframe2.grid(column=0, row=3, columnspan=3)

##---

##-- FRAME 2 --##

self.Frame2 = Frame2 = Frame(mainframe)

Frame2.grid(column=0, row=1, sticky=(W, E, N, S)) Frame2.grid_columnconfigure(0, weight=0)

Frame2.grid_columnconfigure(1, weight=0)

(23)

Frame2.grid_columnconfigure(2, weight=1)

##-- FRAME 2 CONTENTS --##

##-- LabelFrame2, ram

LabelFrame2 = LabelFrame(Frame2, text=’Välj Order’)

LabelFrame2.grid(column=0, row=0, ipadx=5, ipady=5, sticky=(W, N))

"""

Frame med radiobuttons för att välja Orderkatalog

"""

radioFrame = Frame(LabelFrame2)

radioFrame.grid(column=0, row=0, rowspan=2, sticky=(W))

##-- Dictionary med value, radiobutton namn och text.

radios = {

0:[’radio1’, ’Kombi’], 1:[’radio2’, ’Kablage’], 2:[’radio3’, ’Apparatskåp’], 3:[’radio4’, ’Elfördelning’]

}

##-- For-loop som genererar radiobuttons.

vals = 1

for rowid, label in radios.items():

label[0] = Radiobutton(

radioFrame, text=label[1],

variable=self.SetOrderFolder, value=vals,

command=self.UpdateOrderFolder ).grid(

column=0, row=rowid, padx=5, sticky=(W) )

vals += 1

"""

Ram med vilka ordrar som finns i vald orderkatalog,

samt "välj orderkatalog" radioknappar och "välj order" knapp

"""

self.orderlistFrame = orderlistFrame = Frame(

LabelFrame2, borderwidth=1, relief=SUNKEN )

orderlistFrame.configure(background="white") orderlistFrame.grid(column=2, row=0, sticky=(N))

#-- Scrollist för OrderList Listbox orderlistScrollbar = Scrollbar(

orderlistFrame, orient=VERTICAL )

#-- OrderList med Ordrar från vald orderkatalog (radiobuttons) self.OrderList = OrderList = Listbox(

orderlistFrame,

listvariable=self.OrderFolderList, borderwidth=0,

activestyle="none",

(24)

highlightthickness=0, width=4,

height=5,

yscrollcommand=orderlistScrollbar.set )

##-- Klick på listitem visar info om ordern, hämtas från excelfilen.

OrderList.bind(’<ButtonRelease-1>’, self.onOrderHighlight)

#-- Positionering för OrderList samt scrollbar till OrderList.

OrderList.grid(column=0, row=0, padx=5, pady=5, sticky=(W, E)) orderlistScrollbar.config(command=OrderList.yview)

orderlistScrollbar.grid(column=1, row=0, sticky=(N, S))

##-- Knapp för att flytta Order till Användarkatalog,

##-- använder funktionen move2user för detta.

self.MoveButton = MoveButton = Button(

LabelFrame2, text=’Välj Order’, command=self.move2user )

MoveButton.grid(column=2, row=1, sticky=(N, W, E))

##-- SLUT LABELFRAME2 --##

blankframe3 = Frame(LabelFrame2, width=15)

##--- blankframe3.grid(column=1, row=0, sticky=(W,E))

##-- INFOLABELFRAME --##

"""

Informationsruta, värden hämtas från ExcelFil baserat på markerad order i chooseOrderList

"""

self.infoLabelFrame = infoLabelFrame = LabelFrame(Frame2, text=’Order Info’,) infoLabelFrame.grid(column=2, row=0, padx=5, sticky=(W,E,S,N))

self.infoFrame = infoFrame = Frame(infoLabelFrame)

infoFrame.grid(column=0, row=0, padx=5, pady=15, sticky=(W)) self.variablesFrame = variablesFrame = Frame(infoLabelFrame) variablesFrame.grid(column=1, row=0, pady=15, sticky=(W)) self.infoLabels()

blankframe2 = Frame(Frame2, height=10)

blankframe2.grid(column=0, row=1, columnspan=3)

##---

## FRAME 3 ##

self.Frame3 = Frame3 = Frame(mainframe) Frame3.grid(column=0, row=2, sticky=(W, E))

self.LabelFrame3 = LabelFrame3 = LabelFrame(

Frame3,

text=’Påbörjade Ordrar’

)

LabelFrame3.grid(column=0, row=0, ipadx=5, ipady=5, sticky=(W,E,N))

blankframe4 = Frame(LabelFrame3, height=5) blankframe4.grid(column=0, row=0, sticky=(N))

##--- self.userlistFrame = userlistFrame = Frame(

LabelFrame3,

(25)

borderwidth=1, relief=SUNKEN )

userlistFrame.configure(background="white")

userlistFrame.grid(column=0, row=1, padx=5, sticky=(N))

userlistScrollbar = Scrollbar(

userlistFrame, orient=VERTICAL )

self.UserList = UserList = Listbox(

userlistFrame,

listvariable=self.UserFolderList, borderwidth=0,

activestyle="none", highlightthickness=0, width=4,

height=5,

yscrollcommand=userlistScrollbar.set )

UserList.grid(column=0, row=0, padx=5, pady=5, sticky=(W)) UserList.bind(’<ButtonRelease-1>’, self.setDate)

userlistScrollbar.config(command=UserList.yview) userlistScrollbar.grid(column=1, row=0, sticky=(N, S))

containerFrame = Frame(LabelFrame3)

containerFrame.grid(column=1, row=1, ipadx=5, ipady=5, sticky=(N, S, E, W)) InfoLabel = Label(

containerFrame,

text=’När en order är klar, markera den på listan och tryck "KLAR"’, wraplength=120,

anchor=W )

InfoLabel.grid(column=0, row=0, padx=10, sticky=(W, N, S, E)) self.finishedOrderButton = button2 = Button(

containerFrame, text=’KLAR’,

command=self.move2fakt )

button2.grid(column=0, row=1, padx=10)

"""

valuesFrame innehåller Entries som fylls i excelfilen.

"""

self.valuesFrame = valuesFrame = Frame(LabelFrame3)

valuesFrame.grid(column=2, row=0, rowspan=2, sticky=(W,N,S,E))

self.orderFinished = Label(

valuesFrame,

text=’Order Klar: ’, anchor=E

).grid(

column=2, row=0, sticky=E ) self.orderFinishedEntry = Entry(

valuesFrame,

textvariable=self.orderFinishedVar, width=10,

justify=CENTER ).grid(

column=3,

(26)

row=0, sticky=W ) self.packageWeight = Label(

valuesFrame, text=’Vikt i kg: ’, anchor=E

).grid(

column=2, row=1, sticky=E ) self.packageWeightEntry = Entry(

valuesFrame,

textvariable=self.packageWeightVar, width=10,

justify=CENTER ).grid(

column=3, row=1, sticky=W ) self.testedOK = Label(

valuesFrame, text=’Test: ’, anchor=E ).grid(

column=2, row=2, sticky=E ) self.testedOKEntry = Entry(

valuesFrame,

textvariable=self.testedOKVar, width=10,

justify=CENTER ).grid(

column=3, row=2, sticky=W )

root.update_idletasks()

for child in self.mainframe.winfo_children():

child.grid_configure(padx=5, pady=5)

def infoLabels(self):

"""

GENERERAR LABELS FÖR ATT VISA INFO OM ORDER DETTA GÖRS MHA EN FOR-LOOP & ETT DICTIONARY

"""

infoList = {

0:[’varTVO’, self.TVO, ’infoTVO’, ’TVO: ’],

1:[’varOrderNr’,self.OrderNr, ’infoOrderNr’, ’OrderNr: ’], 2:[’varKund’,self.Kund, ’infoKund’, ’Kund: ’],

3:[’varLevDag’, self.LeveransDag, ’infoLevDag’, ’LeveransDag: ’]

}

for rowx, label in infoList.items():

label[0] = Label(self.variablesFrame, textvariable=label[1], fg=’#f00’)

(27)

label[0].grid(column=0, row=rowx, sticky=(W))

label[2] = Label(self.infoFrame, text=label[3], anchor=E) label[2].grid(column=1, row=rowx, sticky=(E))

def clearEntries(self):

""" Rensar Entries efter att ordern är klar """

self.orderFinishedVar.set(’’) self.packageWeightVar.set(’’) self.testedOKVar.set(’’)

def setDate(self, event):

"""

Sätter automatiskt dagens datum i self.orderFinishedEntry

"""

currentDate = str(date.today())

currentDate = currentDate.split(’-’)[-1]

self.orderFinishedVar.set(currentDate) self.onOrderHighlight(event)

def onOrderToUserfolder(self):

"""

Funktion som anropas av move2user för att flytta order till montörens katalog.

Den fyller sedan in dagens datum samt vilken montör som påbörjade arbetet i excelfilen.

"""

currentDate = str(date.today())

currentDate = currentDate.split(’-’)[-1]

cellsToWrite = {

7:self.currentUserSign, 8:currentDate

}

orderInfo = readExcel(cellsToWrite) selection = self.OrderList.curselection()

if tkMessageBox.askokcancel(

title=’Verkligen klar?’,

message=’Vill du verkligen flytta Ordern till \

%s och skriva till Exceldokumentet?’ % (self.currentUser.get()) ) == True:

if len(selection) == 1:

value = int(selection[0])

Order = str(self.OrderFolder[value]) try:

if orderInfo.readDok(self.excelFile, Order, ’1’) == True:

return True

except Exception as error:

tkMessageBox.showerror(title=’ERROR’, message=error)

else:

return False, ’Aborted’

def onOrderFinished(self):

"""

Hämtar info från Entrylabels och skickar dessa att skrivas till excelfil

"""

var1 = str(self.orderFinishedVar.get()) var2 = str(self.packageWeightVar.get()) var3 = str(self.testedOKVar.get()) try:

for string in (var1, var2, var3):

(28)

if string == ’’:

question = tkMessageBox.askokcancel(

’Empty MessageBox’,

message=’En eller flera textrutor är ej ifyllda’

) if question == True:

break else:

return False else:

pass

##-- Anger vilka celler som ska skrivas till samt skickar

##-- med dessa vid definitionen av orderInfo.

cellsToWrite = {9:var1, 10:var2, 11:var3}

orderInfo = readExcel(cellsToWrite) selection = self.UserList.curselection()

if tkMessageBox.askokcancel(

title=’Verkligen klar?’,

message=’Vill du verkligen flytta Ordern och skriva till Exceldokumentet?’

) == True:

if len(selection) == 1:

value = int(selection[0])

Order = str(self.UserFolder[value])

if orderInfo.readDok(self.excelFile, Order, ’1’) == True:

return True

else:

tkMessageBox.showerror(title=’Avbröts’, message=’Avbröts av användaren!’) except Exception as error:

tkMessageBox.showerror(title=’Error’, message=error)

def orderSel(self):

"""

Kollar vilken variabel som markerats i User- eller OrderList.

Returnerar sel1[0] och 1 för OrderList, sel2[0], 2 för UserList

"""

sel1 = self.OrderList.curselection() sel2 = self.UserList.curselection()

if len(sel1) == 1:

return sel1[0], 1 else:

return sel2[0], 2

def onOrderHighlight(self, event):

"""

Hämtar information om Order i columner angivna i self.colID

"""

selection = self.orderSel() orderInfo = readExcel(self.colID)

if len(selection[0]) == 1:

value = int(selection[0])

if selection[1] == 1:

Order = str(self.OrderFolder[value]) else:

Order = str(self.UserFolder[value]) orderInfo.readDok(self.excelFile, Order, ’0’)

(29)

if len(orderInfo.variables) == 0:

self.TVO.set(’’) self.OrderNr.set(’’) self.Kund.set(’’) self.LeveransDag.set(’’) else:

for key, value in orderInfo.variables.items():

if key == 0:

self.TVO.set(value) if key == 1:

self.OrderNr.set(value) if key == 2:

self.Kund.set(value) if key == 12:

self.LeveransDag.set(value)

def setUser(self):

""" Öppnar dialogruta för att välja användare """

userSelect(root)

def noUser(self):

""" Ifall ingen användare är vald när en katalog ska

flyttas anropas denna funktion av move2user och move2fakt """

if tkMessageBox.askokcancel(

title=’Välj Användare Först!’,

message=’Tryck OK för att välja användare’

) == True:

self.setUser() else: pass

def move2user(self):

"""

Funktion för att flytta ordermapp till användarens katalog Kontrollerar först ifall en användare har valts.

"""

if self.currentUser.get() == ’’:

self.noUser()

else:

selection = self.OrderList.curselection()

if len(selection) == 1:

value = int(selection[0]) Order = self.OrderFolder[value]

OrderFolder = self.setPath[self.SetOrderFolder.get()]

##-- Genererar sökvägen till den mapp som ska flyttas

sourceFolder = os.path.join(self.workDir, OrderFolder, Order)

##-- Flyttar mappen till Montörens egen mapp try:

if self.onOrderToUserfolder() == True:

shutil.move(sourceFolder, self.currentUserFolder) tkMessageBox.showinfo(

title=’Flyttade Order’,

message=’Flyttade %s till %s’ % (Order, self.currentUser.get()) )

self.UpdateUserFolder() self.UpdateOrderFolder() except Exception as error:

tkMessageBox.showerror(title=’ERROR’, message=error)

(30)

else:

return

def move2fakt(self):

"""

Flyttar färdig order till faktureringsunderlagsmappen samt skriver till excelfilen information från Entry boxarna.

"""

if self.currentUser.get() == ’’:

self.noUser()

else:

selection = self.UserList.curselection()

if len(selection) == 1:

value = int(selection[0]) Order = self.UserFolder[value]

TargetFolder = os.path.join(self.workDir, self.setPath[6])

##-- Genererar sökvägen till den mapp som ska flyttas sourceFolder = os.path.join(self.currentUserFolder, Order)

##-- Flyttar mappen till Montörens egen mapp

##-- och skriver sedan till excelfilen try:

if self.onOrderFinished() == True:

shutil.move(sourceFolder, TargetFolder)

##-- Uppdaterar Listboxarna och tar bort entries.

self.UpdateUserFolder() self.clearEntries()

except Exception as error:

tkMessageBox.showerror(title=’Error’, message=error) else:

return

def UpdateOrderFolder(self):

""" Uppdaterar Orderkatalog listboxen """

value = self.SetOrderFolder.get() self.OrderFolder = tuple(

os.listdir(

os.path.join (

self.workDir, self.setPath[value]

) ) )

self.OrderFolderList.set(self.OrderFolder)

def UpdateUserFolder(self):

""" Uppdaterar Användarkatalog listboxen """

self.UserFolder = tuple(

os.listdir(

self.currentUserFolder )

)

self.UserFolderList.set(

self.UserFolder )

(31)

6.2 Bilaga 2

Python class object för att läsa och skriva configfil.

(Från NDProd_main.py:)

class configFile:

"""

Objekt för att läsa och skriva till config fil.

"""

def __init__(self):

self.config = ConfigParser.SafeConfigParser()

def read(self, configFile):

"""

Läser från config fil

"""

try:

self.config.read(configFile)

main.currentUser.set(self.config.get(’Directories’, ’user’))

main.currentUserFolder = self.config.get(’Directories’, ’userfolder’) main.workDir = self.config.get(’Directories’, ’workingdir’)

main.excelFile = self.config.get(’Directories’, ’excelpath’) main.currentUserSign = self.config.get(’Directories’, ’usersign’) main.UpdateUserFolder()

except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):

pass

def writeToFile(self):

""" Skriver till filen """

with open(’NDProd.cfg’, ’w’) as configfile:

self.config.write(configfile)

def write(self):

"""

Sätter vilka värden som ska skrivas till config fil.

"""

if self.config.has_section(’Directories’):

self.config.set(’Directories’, ’workingdir’, main.workDir) self.config.set(’Directories’, ’user’, main.currentUser.get()) self.config.set(’Directories’, ’userfolder’, main.currentUserFolder) self.config.set(’Directories’, ’excelpath’, main.excelFile)

self.config.set(’Directories’, ’usersign’, main.currentUserSign) self.writeToFile()

root.destroy() else:

""" Skapar sektion ifall den inte finns """

self.config.add_section(’Directories’) self.writeToFile()

self.write()

(32)

6.3 Bilaga 3

Initieringsfunktion för applikationen.

(Från NDProd_main.py)

"""

Initieringsfunktion för applikationen

"""

if __name__ == ’__main__’:

config = configFile()

root = Tk()

root.title("Norr-Don Produktion") root.iconwindow()

root.protocol("WM_DELETE_WINDOW", config.write) #Vid avslut, skriv till config.

root.wm_iconbitmap(’images/cable.ico’) root.resizable(width=FALSE, height=FALSE) root.geometry(’+250+200’)

##-- Anropar MainWin för att bygga upp huvudfönstret.

main = MainWin(root)

##-- Uppdaterar värden från .cfg fil try:

config.read(’NDProd.cfg’) if main.excelFile == ’’:

main.excelFile = tkFileDialog.askopenfilename(

filetypes=[(’excel files’, ’.xls*’)], title=’Specifiera Exceldokument’

)

##-- Kollar ifall excelfilen går öppna.

open(main.excelFile, ’r’) except (WindowsError, IOError):

##-- Öppnar dialogruta för att välja excelfil vid error.

main.excelFile = tkFileDialog.askopenfilename()

##-- Frågar efter bassökväg.

askBaseDir()

##-- Startar applikationen root.mainloop()

(33)

6.4 Bilaga 4

Klass som används för att välja bassökväg via dialogruta.

(Från NDProd_main.py)

class askBaseDir():

"""

Kontrollerar ifall sökvägen kan nås, eller innehåller rätt kataloger.

Uppnås inte dessa mål frågar den efter ny sökväg.

"""

def __init__(self):

try:

#-- Kollar ifall sökvägen finns genom att försöka lista filer i sökvägen.

os.listdir(main.workDir)

#-- Vid exception öppnas en inforuta med felmeddelandet och

#-- sedan dialogruta för att välja sökväg.

except Exception as error:

message = str(error)+’\n Tryck OK för att välja sökväg’

tkMessageBox.showerror(title=’Error’, message=message) main.workDir = str(tkFileDialog.askdirectory())

#-- Skickar workDir strängen till funktionen validateDirectory

#-- för att kontrollera att alla kataloger finns i sökvägen if main.workDir == ’’:

workDir = str(tkFileDialog.askdirectory()) validDir = self.validateDirectory(workDir)

#-- Om användaren trycker Avbryt i dialogrutan där

#-- sökväg väljs öppnas ed MessageBox med ett felmeddelande.

if workDir == ’’:

ask = tkMessageBox.askokcancel(

title=’Felaktig sökväg’,

message=’Tryck OK för att välja sökväg, AVBRYT för att avsluta’

)

if ask == False:

root.destroy() #-- Avslutar applikationen.

else:

askBaseDir()

##-- Ifall inte alla kataloger finns i sökvägen öppnas en MessageBox med ett felmeddelande.

if validDir == False:

tkMessageBox.showerror(

title=’Ogiltig sökväg’,

message=’En eller flera Orderkataloger saknas eller Fel sökväg, Välj igen!’

)

askBaseDir() else:

main.workDir = workDir else:

#-- Kollar ifall nuvarande sökväg innehåller rätt kataloger.

if self.validateDirectory(main.workDir) == True:

pass else:

workDir = str(tkFileDialog.askdirectory()) askBaseDir(workDir)

(34)

def validateDirectory(self, directory):

"""

Funktion för att kontrollera att rätt kataloger finns i sökvägen.

main.setPath innehåller vilka kataloger som ska finnas där.

"""

for dirs in main.setPath.values():

if dirs in os.listdir(directory):

return True else:

return False

(35)

6.5 Bilaga 5

Python class object för att läsa och skriva exceldokumentet.

(Från excelMod.py:)

# -*- coding: cp1252 -*-

import xlrd import xlwt

from xlwt import easyxf import xlutils.copy as xlutils import tkMessageBox

class readExcel:

def __init__(self, colID):

self.colID = colID self.variables={}

def readDok(self, excelFile, orderNr, command):

try:

self.excFile = xlrd.open_workbook(excelFile, formatting_info=True) self.excelFile = excelFile

if self.readFile(orderNr, command) == True:

return True

except Exception as error:

tkMessageBox.showerror(title=’ERROR’, message=error)

def readFile(self, orderNr, command):

try:

""" Itererar över antalet flikar i excelfilen """

for index in range(self.excFile.nsheets):

sheet = self.excFile.sheet_by_index(index)

""" Itererar raderna i varje flik. """

for rowIndex in range(sheet.nrows):

""" Kollar ifall orderNr finns på rad x, kolumn 0 """

if orderNr in str(sheet.cell_value(rowIndex, 0)):

""" Kollar om cellen på rad x, kolumn 13 är ifylld """

if str(sheet.cell_value(rowIndex, 13)) == ’’:

"""

Är den tom skickas data vidare antingen för att läsas (0) eller skrivas (1) till exceldokumentet.

True returneras ifall funktionen lyckades.

"""

if int(command) == 0:

if self.setVariables(sheet, rowIndex) == True:

return True

if int(command) == 1:

if self.writeExcel(sheet, index, rowIndex) == True:

return True

else:

pass else:

pass except Exception as error:

print error

def setVariables(self, sheet, rowIndex):

""" Itererar colID dictionary vilken innehåller de kolumner som ska skrivas till """

for col in self.colID.keys():

(36)

"""

Om datat i cellen är float konverteras den till en integer

och sedan till sträng. Detta läggs sedan till variables dictionaryn.

"""

if type(sheet.cell_value(rowIndex, col)) == type(1.1):

cell = str(int(sheet.cell_value(rowIndex, col)))

if col == 12:

cell = cell+’ ’+str(sheet.name) self.variables[col] = cell

else:

self.variables[col] = cell

else:

self.variables[col] = str(sheet.cell_value(rowIndex, col))

def writeExcel(self, sheet, index, rowIndex):

"""

sheet = Vilken flik som innehåller ordernumret.

index = Indexnr på fliken med ordernumret.

rowIndex = Vilken rad ordernumret finns på.

"""

File = xlutils.copy(self.excFile) #-- Kopierar data i excelfil till ny workbook.

Sheet = File.get_sheet(index) #-- Den flik som ska redigeras

style = easyxf(’borders: left thin, right thin, top thin, bottom thin;’

’font: name Arial, bold true, height 240;’

’alignment: horizontal center;’

)

"""

itererar över dictionaryn med de kolumner som ska skrivas till dessa läggs till den nya workbooken.

"""

for col, value in self.colID.items():

Sheet.write(rowIndex, col, value, style) try:

""" Sparar den nya excelfilen """

File.save(self.excelFile) tkMessageBox.showinfo(

title=’Värden skrevs till cell’,

message=’Skrivning till excelfil lyckades!’

) return True

except Exception as error:

tkMessageBox.showerror(title=’Error’, message=error)

References

Related documents

Men, för att ta klivet till möbel- produkter som är anpassade för en cirkulär affärsmodell krävs att det tillverkande företaget skapar tekniska förutsättningar och utvecklar

En annan knäckfråga gäller hur nyinflödet till gruppen långtidssjuka kan minskas och hur de som hamnat i denna kategori ska kunna återföras till arbetslivet innan de hunnit

Liknande beskrivningar görs i vår studie där barnen uttrycker att man behöver kunna, för att man ska läsa och skriva när man går i skolan, samt för att man behöver göra

&amp; Smith (2013) som anser att när kunden söker information online är det viktigt att som aktör ta reda på tajmingen och hur frekvent kundens informationssökande sker för att

Forskningen visar att det ofta är en stor fördel att få möjlighet att lära sig läsa på sitt modersmål. Man menar att färdigheterna måste ses i relation till såväl

• Vilka möjligheter och svårigheter anser lärare i årskurs F-2 att ASL bidrar till för elever med läs- och skrivsvårigheter när de ska lära sig läsa och skriva.. •

En slutsats jag drar utifrån det här skrivprojektet är att det man behöver av tid och ensamhet för att skriva, för att kunna gå in i och vara inne i sin text är svårt att få

Detta för att han menar att skrivandet bör vara det primära i språkutvecklingen hos elever som är i stånd till att börja lära sig läsa och skriva.. Huvudsakliga kompetenser i