Øving 5 - OOP, GUI og filhåndtering

VIKTIG!

Minst 5 av 6 oppgaver må løses for å få godkjent øvingen. Husk å sjekk at alle deloppgaver er løst.

Dersom ikke annet er oppgitt skal koden for hver programmeringsoppgave bestå av èn celle med hele programkoder.

Celler med "In [ ]:" foran er kode-celler som kan kjøre kode. Ellers er cellene tekstbokser. En celle (både tekst og kode) kjøres hvis du markerer den og trykker SHIFT+ENTER. Se guide for utfyllende informasjon om hvordan man bruker jupyter notebooks.

Last ned øvingen fra jupyter til din pc som .pdf-fil (se guide) og last den opp i Blackboard for å levere den.

I denne øvingen er det flere filer assosiert, og disse andre filene ligger også i .zip-mappen for denne øvingen. Som i forrige øving må oppgave 5 og 6 gjøres i et lokalt IDE på din datamaskin, og så kan koden kopieres tilbake hit.

Oppgave 1

a) Hva er fordelen med objektorientert programmering sammenlignet med prosedyrebasert programmering?

b) Hva er forskjellen på en klasse og en instans?

c) Hva er en klassevariabel?

d) Forklar hva "self" parameteret er og hvorfor det er nødvendig i objekter.

Oppgave 1 svar

A) Fordelen med objekter kontra funksjoner(prosedyrer) er at objekter inneholder både dataene og koden den trenger for å fungere, og gir kode utenfor objektet tilgang til data gjennom sine metoder.

B) En instans er et objekt av en klasse, en klasse kan sees på som en mal for instanser.

C) En klassevariabel er en variabel som er felles for alle instanser eller objekter av en klasse. Endres den for et objekt, endres den for alle.

D) "self "er objektets referanse til seg selv, og når et "self" argument sendes til en metode i klassen brukes det for å identifisere instansen. "self" er også nødvendig for å aksessere (de andre) attributtene og verdiene til disse for hver instans.

Oppgave 2

Filhåndtering

Filen du trenger for å løse denne opgpaven ligger .zip-mappen.

Ta utgangspunkt i filen oppgave2.txt. Utfør følgende og print ut det resulterende innholdet i filen:

a) Hva er forskjellen på resultatet av kjøringen ved å bruke alternativ A sammenlignet med alternativ B i koden i "Kodebit 1" på tekstfilen?

b) Print alle linjene som er tekst til konsoll

c) Beregn summen av alle tallene i filen og skriv resultatet til slutten av filen

d) Print innholdet i filen ut til konsoll

Hint: for å sjekke om et element er tekst kan man bruke funksjonen .isalpha(), og for å sjekke om et element er tall kan man bruke funksjonen .isdigit() For å sjekke om et element er et mellomrom kan man bruke .isspace(). For å fjerne mellomrom eller newline('\n')-elementer før og etter et element kan man bruke .strip()

In [ ]:
## Kodebit 1 ##

file = open('oppgave2.txt', 'r')

## Alternativ A ##
alt1 = file.read(150)

## Alternativ B ##
alt2 = file.readlines()

file.close()
In [ ]:
## Oppgave 2 svar

## a) Forskjellen er at alternativ A leser innholdet i filen element for element, og innholdet i parentesen angir 
    # angir hvor mange elementer som skal leses. Alternativ B leser innholdet linje for linje.

## b)

file = open('oppgave2.txt','r')

tall = []

for i in file.readlines():
    if i.strip().isdigit():
        tall.append(int(i))
    else:
        print('Tekst:',i)
        
file.close()
        
## c)

print(tall)

tallSum = sum(tall)
print(tallSum)

with open('oppgave2.txt', 'a') as file:
    file.write(str(tallSum))

    
## d)

file = open('oppgave2.txt', 'r')
print(file.readlines())

file.close()

Oppgave 3

a) Lag en klasse "frukt" som kan inneholde forskjellige typer frukter. Egenskapene fruktene kan ha er: navn, form, farge og vekt.

b) Lag instanser av frukt-klassen ved hjelp av input fra bruker. Brukeren skal bli bedt bedt om å skrive navnet på frukten, og verdier for alle egenskapene frukten har.

c) Når frukt-klassen inneholder fem ulike frukter skal du skrive ut følgende til konsoll:

  • Navnet og fargen på fruktene i klassen
  • Vekten på alle fruktene og gjennomsnittlig vekt
In [ ]:
## Oppgave 3 svar

## a)

import numpy as np

class Fruit:
    # Setter attibuttene til objektet
    def __init__(self, name, shape, color, weight): 
        self.name = name
        self.shape = shape
        self.color = color
        self.weight = weight
    
    # Set-funksjoner
    def set_name(self, name): 
        self.name = name
    def set_shape(self, shape):
        self.shape = shape
    def set_color(self, color):
        self.color = color
    def set_weight(self, weight):
        self.weight = weight
    
    # Get-funksjoner
    def get_name(self):
        return self.name
    def get_shape(self):
        return self.shape
    def get_color(self):
        return self.color
    def get_weight(self):
        return self.weight
    
## b) 

fruitList = [] # Initierer tom liste som skal holde lister over fruktene

for count in range(1,6):# Henter inn 5 runder med input fra bruker                     
    print('Frukt nummer', count, ':')
    name = input('Name: ') 
    shape = input('Shape: ')
    color = input('Color: ')
    weight = int(input('Weight: '))

    
    fruits = Fruit(name, shape, color, weight) # Lager objektet for frukten
    fName = fruits.get_name()
    fShape = fruits.get_shape() 
    fColor = fruits.get_color() 
    fWeight = fruits.get_weight()
    
    fruitList.append([fName,fShape,fColor,fWeight]) #legger atributtene til frukten til en liste i listen
    
## c)

weightList = [] # Initierer tom liste som skal holde vekten på fruktene

for fruit in fruitList:
    print('Fruktene er:',fruit[0],', som er ',fruit[1],'i formen og veier ca', fruit[3], 'gram,')
    weightList.append(fruit[3])

print('Gjennomsnittlig vekt på fruktene er:', np.mean(weightList))

Oppgave 4

Glade primtall

Filene du trenger for å løse denne oppgaven ligger i .zip-mappen.

I denne oppgaven skal du sammenligne innholdet i to filer, og skrive resultatet av sammenligningen til en ny fil. Filen primtall.txt inneholder primtallene fra 1-1000. Filen gladetall.txt inneholder de "glade tallene" (Happy Numbers, wikipedia: https://en.wikipedia.org/wiki/Happy_number) fra 1-1000.

Finn tallene som er "glade primtall" - altså de som både er glade tall og primtall, og som dermed eksisterer i begge filene. Skriv disse tallene til konsoll, og til en ny fil og lagre den som "gladePrimtall.txt".

In [ ]:
## Oppgave 4 svar

# Åpne filen med primtall
fil1 = open('primtall.txt','r')

prim = [] # Initier liste for primtallene

# Hent ut primtallene fra filen og legg til i lista
for i in fil1.readlines(): 
    prim.append(int(i))

fil1.close() # Lukker primtall-filen

print('Primtallene er:', prim,'\n')

# Åpne filen med glade tall
fil2 = open('gladetall.txt','r')

glade = [] # Initier liste for glade tall

# Hent ut glade tall fra filen og legg til i lista
for i in fil2.readlines():
    glade.append(int(i))
    
# Lukker glade tall-filen
fil2.close()

print('Glade tall er:', glade,'\n')

# Initierer liste for glade primtall
gladeprim = []

# For hvert primtall, sjekk om det samme tallet eksisterer i glade tall-lista
for i in prim:
    if i in glade:
        gladeprim.append(str(i)) # Legger tall som både er prim og glade til i glade primtall-lista

print('Glade primtall er:', gladeprim)


# Åpner en ny fil
fil3 = open('gladePrimtall.txt', 'a')

# Skriver glade primtall til filen med newline slik at de kommer på hver sin linje
for i in gladeprim:
    fil3.write(i +'\n')

# Lukker filen med glade primtall
fil3.close()

Oppgave 5

GUI og filbehandling

I denne oppgaven skal du lage et brukergrensesnitt (GUI) som lar brukeren skrive inn et navn i én widget og en adresse i en annen widget. Dette skal skrives til slutten av en fil når brukeren trykker på en knapp med navn "Send inn". Skriv inn 5 navn og adresser og print innholdet av filen til konsoll.

In [ ]:
## Oppgave 5 svar
import tkinter

# Hent infoen som blir skrevet inn og send til filen
def getInfoInp():
    peopleList = [] # Tøm lista for hver gang funksjonen kalles
    name = nameEntry.get() # Hent info om navn fra navn-widget
    adress = adressEntry.get() # Hent info om adresse fra adresse-widget

    peopleList.append(str(name+', ')) #
    peopleList.append(str(adress+'\n'))

    for i in peopleList: # Send infoen til funksjonen som skriver til filen
        printToFile(i)

# Funksjonen som skriver info til filen
def printToFile(info):

    file = open('people.txt', 'a+')

    file.write(info)

    file.close()

# Fjern infoen fra widget så man kan skrive ny og kall funksjonen for å hente infoen som er lagt inn
def newPerson():
    nameEntry.delete(0, 'end')
    adressEntry.delete(0,'end')

    return getFileCont()

# Les infoen fra filen og print den
def getFileCont():
    file = open('people.txt', 'r')

    cont = file.readlines()

    print(cont)

    file.close()


# Start et lerret
mainWindow = tkinter.Tk()

# Definer widget for navn
nameLabel = tkinter.Label(mainWindow, text='Navn: ')
nameEntry = tkinter.Entry(mainWindow, width=10)
nameLabel.pack()
nameEntry.pack()

# Definer widget for adresse
adressLabel = tkinter.Label(mainWindow, text = 'Adresse: ')
adressEntry = tkinter.Entry(mainWindow, width = 10)
adressLabel.pack()
adressEntry.pack()

# Definer knapp for "Send inn"
sendBtn = tkinter.Button(mainWindow, text = 'Send', command = getInfoInp) # Kallen funksjonen for å legge infoen i lista
sendBtn.pack()

# Definer knapp for å kunne skrive ny input
newBtn = tkinter.Button(mainWindow,text = 'New person', command = newPerson) # Kaller funksjonen for å legge inn ny person
newBtn.pack()

tkinter.mainloop()

Oppgave 6

GUI og objekter

En lærer ønsker et program som beregner total poengsum i et fag. Elevene har fått bokstavkarakter (A-F) på 10 innleveringer, og grensen for å få bestått faget er 35 poeng. Hjelp læreren å skrive programmet.

Lag et GUI i Tkinter som læreren kan bruke. Programmet skal gjøre følgende:

  • Opprette en klasse "elever" som har instanser med attributtene "total poengsum" og "status bestått"
  • Ta inn et navn eller en id på eleven
  • Ta inn 10 bokstavkarakterer fra A-F i hver sin widget
  • Ut fra bokstavkaraterene, regne ut total poengsum for faget (A = 6 poeng, F = 0 poeng)
  • Lage en ny instans for eleven, som inneholder total poengsum og status for om faget er bestått eller ikke for faget
  • Gi beskjed til læreren, i GUI'et, om hva total poengsum var
  • Gi beskjed til læreren, i GUI'et, om faget var bestått eller ikke
In [ ]:
## Oppgave 6 svar
import tkinter

class elever:
    def __init__(self, navn, poengTot, bestatt):
        self.navn = navn
        self.poengTot = poengTot
        self.bestatt = bestatt

# Funksjon som sender infoen fra GUI-et til elev-instans.
def nyElev():
    navn = navnInput.get()
    poengsum, bestatt = poeng()

    elevList.append(elever(navn, poengsum, bestatt))

    for i in elevList:
        elevList.append(elev.navn, elev.bestatt, elev.poengTot)

# Funksjon som regner ut total poengsum og returnerer bestått-info
def poeng():

    poengList = []
    poengsum = 0
    bestatt = ''

    for i in karList:
        kar = (i.get())
        poengList.append(kar)

    for i in poengList:
        if i.upper() == 'A':
            poengsum += 6
        elif i.upper() == 'B':
            poengsum += 4.8
        elif i.upper() == 'C':
             poengsum += 3.6
        elif i.upper() == 'D':
            poengsum += 2.4
        elif i.upper() == 'E':
            poengsum += 1.2
            bestatt = 'Nei'
    if poengsum >= 35:
        bestatt = 'Ja'

    return poengsum, bestatt

def clear():
    navnInput.delete(0, 'end')
    for i in karList:
        i.delete(0, 'end')

### GUI ###

# Definerer hovedvinduet
main_window = tkinter.Tk()

elevList = []
karList = []

# Definerer navn-widget
navnLbl = tkinter.Label(main_window, text = 'Elev')
navnInput = tkinter.Entry(main_window, width = 10)

png = poeng()[0]
best = poeng()[1]

# Definerer område der poeng og status for bestått skal vises
totPoengLbl = tkinter.Label(main_window, text = 'Poengsum '+str(png))
bestattLbl = tkinter.Label(main_window, text = 'Bestått status ' + str(best))

# Definerer knapper
sendBtn = tkinter.Button(main_window, text = 'Send', command = nyElev)
resetBtn = tkinter.Button(main_window, text = 'Clear', command = clear)
quitBtn = tkinter.Button(main_window, text = 'Quit', command = main_window.destroy)

# Pack'er alt
navnLbl.pack()
navnInput.pack()

# Definerer widgets for hvert karakter-område og pack'er
for i in range(1, 11):
    karLbl = tkinter.Label(main_window, text = 'Karakter '+str(i))
    i = tkinter.Entry(main_window, width = 5)
    karLbl.pack()
    karList.append(i)
    i.pack()

totPoengLbl.pack()
bestattLbl.pack()
sendBtn.pack()
resetBtn.pack()
quitBtn.pack()

# Kjører GUI-et
tkinter.mainloop()