update
authorNils Forssén <forssennils@gmail.com>
Thu, 7 Apr 2022 09:30:04 +0000 (11:30 +0200)
committerNils Forssén <forssennils@gmail.com>
Thu, 7 Apr 2022 09:30:04 +0000 (11:30 +0200)
laboration5/__pycache__/klasser.cpython-39.pyc
laboration5/klasser.py
laboration5/lab5.py [new file with mode: 0644]
laboration5/random-layout.py [new file with mode: 0644]
laboration5/uppg_2.py [new file with mode: 0644]
this.py [deleted file]

index c39acec1b8929ed3f56649b6e5558f8efa9cea5c..6b62f255b5f780d353758c275ca73cbf6a32da45 100644 (file)
Binary files a/laboration5/__pycache__/klasser.cpython-39.pyc and b/laboration5/__pycache__/klasser.cpython-39.pyc differ
index 6092d10cdaabcd55b94855776c65c84e7ce49c4d..d65affd93d25276ecba9be54188393d1bd66f699 100644 (file)
@@ -1,3 +1,6 @@
+import math
+
+
 class Pet:
     def __init__(self, name=""):
         self.kind = ""
@@ -17,3 +20,33 @@ class Pet:
             return "{} är en {} som har följande leksaker: {}!".format(
                 self.name, self.kind, ", ".join(self.toys)
             )
+
+
+class Vector2D:
+    def __init__(self, x, y):
+        self.x = x
+        self.y = y
+
+    def get_length(self):
+        return math.sqrt(math.pow(self.x, 2) + math.pow(self.y, 2))
+
+    def add(self, vector):
+        self.x += vector.x
+        self.y += vector.y
+
+    def add_to_new(self, vector):
+        new_v = Vector2D(self.x + vector.x, self.y + vector.y)
+        return new_v
+
+    def is_longer_than(self, vector):
+        return self.get_length() > vector.get_length()
+
+    def create_unit_vector(self):
+        l = self.get_length()
+        new_v = Vector2D(self.x / l, self.y / l)
+        return new_v
+
+    def __str__(self):
+        return f"({self.x}, {self.y})"
+
+    # def __str__():s
diff --git a/laboration5/lab5.py b/laboration5/lab5.py
new file mode 100644 (file)
index 0000000..3f45dd7
--- /dev/null
@@ -0,0 +1,263 @@
+"""Gränssnitt för att testa layoutalgoritmer.
+
+TDDE44 laboration 5
+
+LayoutTester tillhandahåller ett gränssnitt och en Frame som kvadratiska
+tkinter.Label-instanser ska layoutas i. En layout-funktion som sköter layouten
+av tkinter.Label-instanserna skickas som argument när en LayoutTester skapas.
+
+Layout-funktionen (argumentet layout_func till LayoutTester()) tar fem argument:
+
+squares      -- Lista som innehåller tkinter.Label-objekt
+frame_height -- Höjden (int) på fönstret som fyrkanterna ska
+                layoutas i.
+frame_width  -- Bredden (int) på den Frame som fyrkanterna ska
+                layoutas i.
+"""
+
+from random import choice, randint
+from tkinter.font import Font, NORMAL, BOLD, ITALIC, ROMAN
+from tkinter import Button, Checkbutton, Frame, Label, LabelFrame, OptionMenu
+from tkinter import Scale, Tk, IntVar, StringVar, BooleanVar
+from tkinter import N, E, W, S
+from tkinter import BOTH, HORIZONTAL, LEFT, RIGHT, TOP, BOTTOM, X, Y
+from colorsys import hsv_to_rgb
+
+# globala variabler för minsta och största kvadratsstorlek
+MIN_SQUARE_SIZE = randint(25, 40)
+MAX_SQUARE_SIZE = randint(80, 100)
+NUMBER_OF_SIZES = randint(3, 6)
+SIZE_STEP = (MAX_SQUARE_SIZE - MIN_SQUARE_SIZE) // (NUMBER_OF_SIZES - 1)
+MAX_NUM_SQUARES = 250
+
+
+class LayoutTester(object):
+    """Gränssnitt för testning av layoutfunktioner."""
+
+    def __init__(self, layout_func, debug=False):
+        """Skapa GUI och förbereder tkinter.Labels som ska layoutas.
+
+        layout_func -- Funktionen som ska placera kvadraterna, se
+                       modulbeskrivning ovan.
+        """
+        self.layout_func = layout_func
+        self.debug = debug
+
+        # storleksalternativ
+        self.size_options = [
+            size for size in range(MIN_SQUARE_SIZE, MAX_SQUARE_SIZE + 1, SIZE_STEP)
+        ] + ["random"]
+
+        # lista för kvadraterna
+        self.squares = []
+
+        # skapa gränssnittet och kör igång mainloop
+        self.ui_xpadding = 4
+        self.ui_ypadding = 4
+        self.init_ui()
+        # slumpa fram fönsterstorlek
+        w_size = "{}x{}".format(705 + randint(0, 300), 250 + randint(0, 500))
+        self.root.geometry(w_size)
+
+        self.root.mainloop()
+
+    def init_ui(self):
+        """Skapa gränssnittet och kör igång mainloop."""
+        self.root = Tk()
+        self.root.title("Laboration 5")
+        # root.resizable(width=False, height=False)
+
+        # Tk-variabler till kvadratsstorlek, antal kvadrater, start_left och
+        # start_top.
+        self.size_value = StringVar()
+        self.size_value.set(self.size_options[0])
+        self.number_of_squares = IntVar()
+        self.start_left = BooleanVar()
+        self.start_left.set(True)
+        self.start_top = BooleanVar()
+        self.start_top.set(True)
+
+        # Frame att lägga kvadraterna i
+        self.square_frame = Frame(
+            self.root,
+            # height=self.squares_frame_height,
+            # width=self.squares_frame_width,
+            bg="#eef",
+        )
+        if self.debug:
+            self.square_frame.bind("<Configure>", self.frame_changed)
+        self.square_frame.pack(
+            side=TOP, expand=1, fill=BOTH, padx=self.ui_xpadding, pady=self.ui_ypadding
+        )
+
+        # Frame med inställningar
+        self.controll_panel = LabelFrame(self.root, text="Inställningar")
+        self.init_controll_panel()
+        self.controll_panel.pack(
+            fill=BOTH, padx=self.ui_xpadding, pady=self.ui_ypadding
+        )
+
+        # Informationstext
+        infotext = (
+            "Kom ihåg att ändra fönstrets storlek när du testar! "
+            + "Se även utskrifterna i terminalen."
+        )
+        self.instructions = Label(self.root, text=infotext)
+        self.instructions.pack(anchor=W)
+
+    def init_controll_panel(self):
+        """Skapa kontrollpanel för inställningar."""
+        self.create_size_panel()
+        self.create_num_squares_panel()
+        # self.create_start_pos_panel()
+        self.create_run_quit_panel()
+
+    def create_size_panel(self):
+        """Skapa OptionMenu för storlek på kvadraterna."""
+        size_panel = Frame(self.controll_panel)
+        Label(size_panel, text="Kvadratsstorlek").pack(side=LEFT)
+        OptionMenu(size_panel, self.size_value, *self.size_options).pack(side=LEFT)
+        size_panel.pack(side=LEFT, padx=self.ui_xpadding, pady=self.ui_ypadding)
+
+    def create_num_squares_panel(self):
+        """Skapa kontroller för att välja antal kvadrater som skapas."""
+        num_squares_panel = Frame(self.controll_panel)
+        Label(num_squares_panel, text="Antal kvadrater").pack(side=LEFT, anchor=S)
+        Scale(
+            num_squares_panel,
+            variable=self.number_of_squares,
+            from_=4,
+            to=MAX_NUM_SQUARES,
+            orient=HORIZONTAL,
+        ).pack(side=LEFT, anchor=N)
+        num_squares_panel.pack(
+            side=LEFT, anchor=N, padx=self.ui_xpadding, pady=self.ui_ypadding
+        )
+
+    def create_start_pos_panel(self):
+        """Skapa kontroller för att välja var layouten börjar."""
+        start_panel = Frame(self.controll_panel)
+        Checkbutton(
+            start_panel,
+            text="Börja från vänster",
+            justify=LEFT,
+            variable=self.start_left,
+            onvalue=True,
+            offvalue=False,
+        ).pack(fill=X, anchor=N)
+        Checkbutton(
+            start_panel,
+            text="Börja uppifrån",
+            variable=self.start_top,
+            justify=LEFT,
+            onvalue=True,
+            offvalue=False,
+        ).pack(fill=X, anchor=N)
+        start_panel.pack(
+            side=LEFT, anchor=N, padx=self.ui_xpadding, pady=self.ui_ypadding
+        )
+
+    def create_run_quit_panel(self):
+        """Skapa knappar för att köra layout och avsluta programmet."""
+        button_panel = Frame(self.controll_panel)
+        Button(button_panel, text="Kör layoutfunktion", command=self.run_layout).pack(
+            fill=X
+        )
+        Button(button_panel, text="Avsluta", command=self.root.quit).pack(fill=X)
+        button_panel.pack(
+            side=RIGHT, anchor=N, padx=self.ui_xpadding, pady=self.ui_ypadding
+        )
+
+    def create_squares(self):
+        """Skapa tkinter.Label objekt som sparas i LayoutTester-instansen.
+
+        Antalet kvadrater som ska skapas, samt kvadraternas storlek hämtas från
+        gränssnittet.
+        """
+        number_of_squares = self.number_of_squares.get()
+        size = self.size_value.get()
+        square_counter = 0
+        hue_step = 1 / number_of_squares
+        hue_value = 0
+
+        # Skapa kvadrater och lägg dem i listan self.squares
+        while square_counter < number_of_squares:
+            # konververa hsv-färg till rgb-trippel (heltal 0-255)
+            rgb = [int(val * 255) for val in hsv_to_rgb(hue_value, 0.75, 0.70)]
+            # konvertera rgb-trippel till sträng
+            bg_color = "#{:x}{:x}{:x}".format(rgb[0], rgb[1], rgb[2])
+
+            # textfärg
+            fg_color = "#fff"
+
+            # sätt storleken på kvadraten
+            if size != "random":
+                square_size = int(size)
+            else:
+                square_size = choice(self.size_options[:-1])
+            # sätt storleken på texten baserat på kvadratstorleken
+            font_size = int(square_size * 0.6)
+
+            # skapa kvadraten
+            square = Label(
+                self.square_frame,
+                fg=fg_color,
+                bg=bg_color,
+                font=Font(family="Verdana", weight=NORMAL, size=font_size),
+                text=str(square_counter + 1),
+            )
+            # spara den i listan med kvadrater
+            self.squares.append(square)
+
+            # göm kvadraten utanför det synliga området och ställ in
+            # dess storlek
+            square.place(
+                x=-square_size, y=-square_size, height=square_size, width=square_size
+            )
+
+            # gå vidare till nästa kvadrat och färg
+            square_counter += 1
+            hue_value += hue_step
+
+        # uppdatera geometri-info för alla widgets (ser till att de vet hur
+        # stora de är)
+        square.update_idletasks()
+
+    def clear_squares(self):
+        """Ta bort existerande kvadrater."""
+        for square in self.squares:
+            square.destroy()
+        del self.squares[:]
+
+    def frame_changed(self, event):
+        if event.widget == self.square_frame or event.widget == self.root:
+            print(
+                "Resize. root: {}x{}, square_frame: {}x{}".format(
+                    self.root.winfo_width(),
+                    self.root.winfo_height(),
+                    self.square_frame.winfo_width(),
+                    self.square_frame.winfo_height(),
+                )
+            )
+
+    def run_layout(self):
+        """Skapa nya kvadrater och kör layoutfunktionen."""
+        # ta bort gamla kvadrater
+        self.clear_squares()
+
+        # skapa nya kvadrater
+        self.create_squares()
+
+        # placera ut kvadraterna
+        print(
+            "Running '{0}(<squares>, {1}, {2})'...".format(
+                self.layout_func.__name__,
+                self.square_frame.winfo_height(),
+                self.square_frame.winfo_width(),
+            )
+        )
+        self.layout_func(
+            self.squares,
+            self.square_frame.winfo_height(),
+            self.square_frame.winfo_width(),
+        )
diff --git a/laboration5/random-layout.py b/laboration5/random-layout.py
new file mode 100644 (file)
index 0000000..302573e
--- /dev/null
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+"""Laboration 5 -- TDDE44
+
+Exempel på slumpmässig layout-funktion. Layout-funktionen skickas som
+argument när en instans av lab5.LayoutTester skapas.
+"""
+
+# Läs denna fil för att se hur gränssnittet skapats.
+import lab5
+import random
+
+
+def random_layout(squares, frame_height, frame_width):
+    """Placera ut fyrkanterna i listan squares slumpmässigt.
+
+    Argument:
+    squares      -- Lista som innehåller tkinter.Label-objekt
+    frame_height -- Höjden (int) på den Fram som fyrkanterna ligger i
+    frame_width  -- Bredden (int) på den Frame som fyrkanterna ligger i
+    """
+
+    # Slumpa ut positioner för alla fyrkanter utan att de hamnar utanför framen
+    for square in squares:
+        square_size = square.winfo_width()
+        xpos = random.randint(0, frame_width - square_size)
+        ypos = random.randint(0, frame_height - square_size)
+        square.place(x=xpos, y=ypos)
+
+
+def row_layout(squares, frame_height, frame_width):
+    # Slumpa ut positioner för alla fyrkanter utan att de hamnar utanför framen
+    x, y = 0, 0
+    margin = 5
+    for square in squares:
+        square_size = square.winfo_width()
+        square.place(x=x, y=y)
+        x += square_size + margin
+        if x + margin + square_size > frame_width:
+            x = 0
+            y += square_size + margin
+
+
+def colonn_layout(squares, frame_height, frame_width):
+    x, y = 0, 0
+    margin = 5
+    for square in squares:
+        square_size = square.winfo_width()
+        square.place(x=x, y=y)
+        y += square_size + margin
+        if y + margin + square_size > frame_height:
+            y = 0
+            x += square_size + margin
+
+
+if __name__ == "__main__":
+    my_layout = lab5.LayoutTester(colonn_layout)
+    # layout_tester = lab5.LayoutTester(random_layout)
diff --git a/laboration5/uppg_2.py b/laboration5/uppg_2.py
new file mode 100644 (file)
index 0000000..20fed2d
--- /dev/null
@@ -0,0 +1,12 @@
+from klasser import Vector2D
+
+v1 = Vector2D(4, 3)
+v2 = Vector2D(0, 1)
+
+v3 = v1.add_to_new(v2)
+
+print(v1, v2)
+v4 = v1.create_unit_vector()
+print(v4)
+print(v4.get_length())
+print(v1.is_longer_than(v2))
diff --git a/this.py b/this.py
deleted file mode 100644 (file)
index e69de29..0000000