Ich bin noch relativ neu bei Python und Tkinter. Trotzdem habe ich mir vorgenommen, mir eine Art sehr einfaches 3d-Grafik-Programm zu basteln, wo man ein paar simple 3d-Objekte wie Prismen (Quader, Würfel,...) angezeigt bekommen kann. Allerdings ist mein Ziel, das komplett ohne OpenGL und ohne andere Frameworks zu machen. Ich will es vollständig zu Fuß machen, einfach aus Spaß an der Freude.
Ich will mich als Betrachter in der 3d-Welt frei umherbewegen können. Dazu habe ich verschiedene Klassen angelegt, um den später langen Code besser zu gliedern und übersichtlicher zu machen.
Code: Alles auswählen
import Tkinter as tk
class World:
pass # Definieren des 'Bodens' der Welt, Weltkoordinatensystem
class sObject:
def __init__(self, ):
pass # Definieren der lokalen Koordinatensysteme für die 3d-Objekte
class Block(sObject):
def __init__(self):
self.eckpunkte = (...)
self.flaechen = (...)
class Lamp: # Beleuchtung
def __init__(self, position):
self.position = position
class Eye: # Beobachter
def __init__(self, position, ):
self.position = position
class Canvas(tk.Canvas):
def __init__(self, parent, *args, **kwargs):
tk.Canvas.__init__(self, parent, *args, **kwargs)
self.parent = parent
self.bind('<Button-1>', self.click_handle)
self.bind('<ButtonRelease-1>', self.release_handle)
self.bind('<B1-Motion>', self.motion_handle)
self.bind('<Up>', self.key_handle)
self.bind('<Down>', self.key_handle)
self.bind('<Left>', self.key_handle)
self.bind('<Right>', self.key_handle)
def click_handle(self, event):
#### Wie kann ich hier ein Funktion der Instanz der Klasse Handling erreichen?
def motion_handle(self, event):
#### same
def key_handle(self, event):
#### same
def release_handle(self, event):
#### same
class FrameSettings(tk.Frame): # Frame am rechten Rand für Einstellungen und weiteres
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
self.radiob = tk.IntVar()
self.radiob.set(1)
self.r1 = tk.Radiobutton(self,
text='Beobachter',
variable=self.radiob,
bg='seashell2',
value=1).grid(column=0, row=0, sticky='w')
self.r2 = tk.Radiobutton(self,
text='Block',
variable=self.radiob,
bg='seashell2',
value=2).grid(column=0, row=1, sticky='w')
self.r3 = tk.Radiobutton(self,
text='Lampe',
variable=self.radiob,
bg='seashell2',
value=3).grid(column=0, row=2, sticky='w')
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
class Handling: # Verarbeitung aller Inputs, Errechnen der neuen Werte für Canvas, also Zentralprojektion
def __init__(self):
self.edit_mode = 1 # 1: 'eye', 2: 'block', 3: 'lamp'
self.frame_duration = 1 / 25
self.running = True
self.root = MainApp()
self.root.geometry('2000x1000+100+100')
self.root.minsize(900, 250)
self.root.title('3d')
self.root.protocol('WM_DELETE_WINDOW', self.quit)
self.canvas = Canvas(self.root, bg='cornsilk').pack(side='left',
fill='both', expand=True)
self.framesettings = FrameSettings(self.root, bg='seashell2')
self.framesettings.pack(anchor='e', fill='y', expand=True)
print ('Handling almost initialized')
self.mainloop()
def wait_one_frame(self):
time.sleep(self.frame_duration)
def update_world(self):
pass
def draw_world(self):
pass
def mainloop(self):
while self.running:
print (self.edit_mode)
self.edit_mode = self.framesettings.radiob.get()
self.wait_one_frame()
self.update_world()
self.draw_world()
self.root.update()
def process_input_click(self, x, y):
pass # Verarbeitung von Klicks
def process_input_motion(self, x, y):
pass # Verarbeitung von Mausbewegung mit gedrücktem Button-1
def process_arrows(self, key):
pass # Verarbeitung der Pfeiltasten (Steuerung des Beobachters...
def process_b1_release(self, x, y):
pass # Verarbeitung von Button-1-Release
def quit(self):
self.running = False
self.root.destroy()
if __name__ == '__main__':
handling = Handling()
Ich dachte mir, um die optimale Kontrolle über das ganze Programm zu haben, mache ich eine Klasse (Handling), von der ich aus alle anderen Klassen instanziere, sodass ich bequem auf diese zurückgreifen kann. In Handling sollen die Inputs verarbeitet werden und mit Zentralprojektion alles ausgewertet werden.
Für meine Verhältnisse ist dieses Programm sehr ehrgeizig (weil schwierig). Deshalb würde ich mich über Tipps sehr freuen.
Meine Fragen:
Wie strukturiere ich mein Programm am besten?
Es gibt garantiert bessere Ansätze als meiner. Ist es sinnvoll und zweckmäßig, eine Steuerungsklasse zu machen oder sollte ich die anderen Klassen lieber außerhalb instanzieren?
Kennt ihr eine elegante Möglichkeit, bei <B1-Motion> delta x und delta y zu errechnen?
Wenn man mit event.y und event.y rangeht, bekommt man immer nur die aktuelle Position des Mauszeigers. Ich will aber wissen, um wie viel es sich zum letzten event.x und event.y verändert hat.
Ich habe eine Möglichkeit gefunden, allerdings ist diese ziemlich unelegant und lang.
Meine wichtigste Frage: Wie kann ich von der Klasse Canvas auf die Instanz von Handling zugreifen?
Ich habe in der Klasse Canvas die events gebunden
Code: Alles auswählen
self.bind('<ButtonRelease-1>', self.release_handle)
Code: Alles auswählen
Handling().process_input_click(x, y)
Code: Alles auswählen
Handling.process_input_click(x, y)
Wie kann ich das lösen? Wenn es auf diesem Wege nicht geht, wie kann ich das umgehen?
Ich benutze Python 2.7 auf MacOS.
Ich hoffe, so viele Fragen auf einmal zu stellen, ist ok
Vielen Dank für eure Antworten! Vergesst bitte nicht, dass ich neu in Python bin