#Grafikk.py Av Thomas M. Bolstad #Version 0.1.1 18.06.2010: #Now everything should be working as intended. #Version 0.1 18.06.2010: #Most things work except the actual construction and manipulation of elements. import Tkinter as tk import math #Makes a Root which is withdrawn so it wont be displayed. Root = tk.Tk() Root.withdraw() class Window: #this makes a coordinate system from top left(0,0) #to bottom right (widht, height) def __init__(self, width, height, resizable = False): #The toplevel is basically just a window that lays underneath the #canvas widget. self.win = tk.Toplevel(Root, width=width, height=height) self.canvas = tk.Canvas(self.win, width=width, height=height) #To put the canvas on the toplevel window. self.canvas.pack() #Withdraws the window so it wont be displayed till the user applies the #ShowWin method. self.win.withdraw() #Makes the window not resizable if not resizable: self.win.resizable(0,0) #Shows the window def ShowWin(self): self.win.deiconify() #Forces the window into focus. Use with caution! def Focus(self): self.win.focus_force() #Updates the window with everything new that's happened, #e.g. creates a new frame. def Update(self): Root.update() #Configures the window using the config method in Tkinter #Pass up arguments, such as "bg="Black" or "bg=color_rgb(0,0,0)" #to make a black background. def Config(self, **arguments): self.canvas.config(**arguments) #Checks if the window is closed or not. Useful for jumping out of a while #loop if the user has quit by crossing the x in the window. def CheckOpen(self): state = self.win.winfo_exists() if state: return True return False #Binds a user function to a button. Since this script avoids the whole #mainloop though, it's probably best to use the included ButCheck which if #used properly, will just tell you when a button has been pushed in the #form of a string. def Key(self, name, function): self.win.bind(name, function) #Closes and quits the window. def close(self): Root.destroy() #This is for making 2D objects in the canvas widget. class Item: #Specify the type of item that gets made with a string, and provide #the instance of a window class that's being used. def __init__(self, item, window): """ Items are strings which are given by "line", "rectangle", "oval", "text", "polygon", "line" """ self.type = item self.canvas = window.canvas #This to make the following dictionary easier on the eyes. c = window.canvas #Dictionary of different canvas methods for use in the MakeObject #method. self.can_objects = {"line" : c.create_line, "rectangle" : c.create_rectangle, "oval" : c.create_oval, "text" : c.create_text, "polygon" : c.create_polygon, "line" : c.create_line, } if self.type not in self.can_objects: raise Exception("No such object in canvas widget") #Draws the object to the canvas widget. Takes coordinates, and then #keyword arguments such as fill, outline etc. def Make(self, *args, **kw): self.id = self.can_objects[self.type](*args, **kw) #Modifies the item with keyword arguments. Like fill, outline etc. def Config(self, **kw): self.canvas.itemconfigure(self.id, **kw) #Gives new coordinates to the object. def Coords(self, *args): self.canvas.coords(self.id, *args) #removes the object completely. If you just want to hide it, it's much #more effecient to use fill="" and outline="". def Del(self, **kw): self.canvas.delete(self.id, **kw) #To move the object dx pixels in x direction, and dy pixels in y direction. def Move(self, dx, dy): self.canvas.move(self.id, dx, dy) #Entry is a more specialised object. So a seperate class is made #to handle the entry widget. class Entry: #Basicly provide position and lenght of the entrybox. #It's not quantum mechanics. def __init__(self, x, y, length=10): self.x = x self.y = y self.width = length #Takes the window object as aan argument, and draws the entry box. def draw(self, window): frm = tk.Frame(window.win) self.e = tk.Entry(frm) self.e.pack() window.canvas.create_window(self.x, self.y, window=frm) #This gets the text in the entry box def getText(self): return self.e.get() #This sets the text in the entry box def setText(self, string): self.e.config(text=string) class ButCheck: #Make seperate function for mouse events def _leftmouse(self, event): self.cur_char = "left mouse" def _rightmouse(self, event): self.cur_char = "right mouse" #This function gets binded to all keyboard buttons. #There is also an update function for the Window class. #So you if you use a while loop, you should NEVER EVER #run this update function more than the amount of times #you run the update function for the window. Which preferably #should be once per while loop. def update(self, event=None): if event: self.cur_char = event.char self.cur_code = event.keycode else: self.cur_char = "Empty" self.cur_code = "Empty" #takes a win argument so it can bind the relevant functions at once. def __init__(self, win): #Weird buttons that only return a space or a weird character #paired up with their codes self.type = {37 : "left", 38 : "up", 39 : "right", 40 : "down", 32 : "space", 17 : "ctrl", 16 : "shift", 13 : "enter", 9 : "tab", 8 : "backspace", 18 : "alt", 112 : "f1", 113 : "f2", 114 : "f3", 115 : "f4", 116 : "f5", 117 : "f6", 118 : "f7", 119 : "f8", 120 : "f9", 121 : "f10", 122 : "f11", 123 : "f12", 33 : "page up", 34 : "page down", 35 : "end", 36 : "home", 46 : "delete", 145 : "scroll", 19 : "pause", 45 : "insert", 144 : "num lock", 3 : "break", 27 : "esc", 20 : "caps lock", 255 : "mouse on/off"} self.cur_char = "Empty" self.cur_code= "Empty" win.Key("", self.update) win.Key("", self._leftmouse) win.Key("", self._rightmouse) #returns a string containing the name of the last button to have been #pushed. If none have been pushed before the last update of the Window #class. "Empty" will be returned. def getChar(self): if self.cur_code in self.type: return self.type[self.cur_code] return self.cur_char def getType(self): return self.cur_code #Function to help converting rgb to specification used by tkinter. def rgb_convert(r, g, b): return "#%02x%02x%02x" % (r, g, b) #a simple test to showcase some of the features of this interpreter of Tkinter def Test(): #Makes pointer to window, sets background, shows the window, and forces #the window into focus. new = Window(400, 400) new.Config(bg="white") new.ShowWin() new.Focus() #Creates a new instance of ButCheck. This can give us info of which button #that has been pushed while the focus is in the window. but = ButCheck(new) #This boolean gets set to True, and will later be set to False if the #window is closed by the user, so the program will cut out of the loop. opened = True #makes a polygon in the window. poly = Item("polygon", new) #Gives the rgbcode for r=0, g=0, b=0 color0 = rgb_convert(0,0,0) #Makes the oval, with the relevant arguments for coordinates, and #the relevant keyword arguments. poly.Make(100, 100, 100, 200, 200, 200, 200, 100, fill=color0, outline=color0) #An iterator that will be used to manipulate the color of the poly object. i = 0 #The while loop while opened: #This updates everything the window needs to update about #item manipulation, keypresses, mouseclicks etc. new.Update() #This checks if the window is still open. opened = new.CheckOpen() #This gets the name and id of the button that's been pushed the last #run through of the loop. If none has been pushed, "Empty" will be #returned on both methods. N_input = but.getChar() T_input = but.getType() #The interesting stuff happends if there is an actual input if N_input != "Empty": i +=1 #This gives a circular motion of the poly object dx, dy = 2*math.sin(i*2*math.pi/256), 2*math.cos(i*2*math.pi/256) poly.Move(dx, dy) #this makes it change color gradually. color = i % 256 color0 = rgb_convert(color, color, color) poly.Config(fill=color0) #This updates the button so that on the next run through the loop, #the string that gets returned will be "Empty" unless another #button has been pushed. but.update() if __name__ == "__main__": Test() #For a bruke rgb funksjonen i tkinter, ma de tre verdiene konverteres #ved hjelp av en enkel linje: # #rgb_string = "#%02x%02x%02x" % (r, g, b), og sa sier du bare at #fill=rgb_string istedet for fill="black". #En del goye funksjoner: #Tekst storrelse 20, bla, tekst: "WTF", i punkt 100, 100 i window. #tekst = Item("text", window) #tekst.Make(100,100, text="WTF", font=("arial", 20, "normal"), fill="blue") #Rektangel med hjorner i 100, 100 og 200, 200 i window, blatt. #firkant = Item("rectangle", window) #firkant.Make(100,100,200,200, fill="blue", outline="blue") #Oval med "hjorner" i 100, 100 og 200, 200 i window, blatt. #oval = Item("oval", window) #oval.Make(100,100,200,200, fill="blue", outline="blue") #Polygon identisk med rektangelet ovenfor: #polygon = Item("polygon", window) #polygon.Make(100, 100, 100, 200, 200, 200, 200, 100, # fill="blue", outline="blue") #For a fylle et object med en rgb farge, bruker man #fill=color_rgb(r, g, b) istedet for fill="black", #hvor r, g og b er verdier mellom 0 og 256.