Wie? -- > Objekt per drag and drop verschieben: Fortsetzu

Fragen zu Tkinter.
Antworten
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Zunächst ein "sorry" für das Neueröffnen eines alten Threads - ein Antworten auf den alten Thread ist mit meinem Browser oder was auch immer nicht mehr möglich - da hängt irgend etwas.
dd42 hat geschrieben:@ numerix: gute Idee, aber unpraktisch, und kaum verbesserte performance
Verstehe ich nicht. Meine Erläuterung dazu hatte die Performance gar nicht zum Gegenstand. Und: Wieso unpraktisch?

Sie dir doch mal meinen Entwurf dazu an - da gefällt mir zwar (noch) längst nicht alles und manches fehlt noch (z.B. Schriftgrößenanpassung, Hinzufügen und Entfernen von Rauten durch den Anwender), aber auf dieser Basis könnte man das ohne weiteres implementieren.

Kurze Erläuterungen zur Bedienung:
- Verschieben ist klar
- Text editieren: Doppelklick zum editieren, danach Einfachklick in die Raute oder <Esc> zum Abschließen
- Zum Verbinden zweier Rauten diese mit der rechten Maustaste markieren
- Zum Entfernen einer Verbindung diese mit der mittleren Maustaste anklicken

Code: Alles auswählen

import Tkinter as tk

class Connection(object):

    def __init__(self,table,item1,item2):
        self.table = table
        self.items = (item1,item2)
        for item in self.items:
            item.select()
        for connection in self.table.connections:
            if set((item1,item2)) == set(connection.items):
                return # connection already exists -> nothing to do
        self.line = self.table.create_line(item1.x,item1.y,item2.x,item2.y,
                    fill="gray",width=2)
        self.table.tag_lower(self.line)
        self.table.tag_bind(self.line,"<Enter>",self.enter)
        self.table.tag_bind(self.line,"<Leave>",self.leave)
        self.table.tag_bind(self.line,"<Button-2>",self.delete)
        self.table.connections.append(self)

    def enter(self,event):
        self.table.config(cursor="X_cursor")
        self.table.itemconfig(self.line,width=4)

    def leave(self,event):
        self.table.config(cursor="")
        self.table.itemconfig(self.line,width=2)

    def delete(self,event):
        self.table.delete(self.line)
        self.table.connections.remove(self)
        self.table.config(cursor="")


class Rhombus(object):

    counter = 0

    def __init__(self,table,x,y,size=90,background="yellow",border="blue"):
        """x,y is center of rhombus, size is length of one side in px"""
        Rhombus.counter += 1
        self.table = table
        self.x, self.y = x, y
        self.size = size
        self.rel = 0.75 # relation width to height of rhombus - may be changed
        a = self.size / (self.rel*self.rel+1)**.5
        points = [x-a,y,x,y+self.rel*a,x+a,y,x,y-self.rel*a]
        self.tag = "rhomb%03i" %Rhombus.counter
        self.text = "Double-Click\nto change text!"
        self.figure_rhomb = self.table.create_polygon(points,tag=self.tag,
                            fill=background,outline=border,width=2)
        self.figure_text = self.table.create_text(x,y,tag=self.tag,
                            justify="center",text=self.text)
        self.dragged = self.edit_begin = self.edit_end = self.selected = False
        self.table.tag_bind(self.tag,"<Button-1>",self.drag)
        self.table.tag_bind(self.tag,"<ButtonRelease-1>",self.drop)
        self.table.tag_bind(self.tag,"<Enter>",self.enter)
        self.table.tag_bind(self.tag,"<Leave>",self.leave)
        self.table.tag_bind(self.tag,"<Motion>",self.move)
        self.table.tag_bind(self.tag,"<Double-Button-1>",self.edit)
        self.table.tag_bind(self.tag,"<Button-3>",self.select)

    def enter(self,event):
        self.table.config(cursor="hand2")
        if not self.selected:
            self.table.itemconfig(self.figure_rhomb,width=4)

    def leave(self,event):
        self.table.config(cursor="")
        if not self.selected:
            self.table.itemconfig(self.figure_rhomb,width=2)

    def drag(self,event):
        if self.edit_begin:
            self.edit_begin = False
            self.edit_end = True
            return
        self.dragged = True
        self.table.tag_raise(self.tag)
        self.startx, self.starty = event.x, event.y

    def drop(self,event):
        if self.dragged:
            self.dragged = False
        if self.edit_end:
            self.exitedit()

    def move(self,event):
        if self.dragged:
            dx, dy  = event.x-self.startx, event.y-self.starty
            self.table.move(self.tag,dx,dy)
            self.startx, self.starty = event.x, event.y
            self.x, self.y = self.x+dx, self.y+dy
            for connection in self.table.connections:
                if self in connection.items:
                    x1,y1,x2,y2 = self.table.coords(connection.line)
                    if self == connection.items[0]:
                        self.table.coords(connection.line,self.x,self.y,x2,y2)
                    else:
                        self.table.coords(connection.line,x1,y1,self.x,self.y)

    def edit(self,event):
        if self.edit_begin: return
        self.edit_begin = True
        self.editor = tk.Text(self.table,width=12,height=2)
        self.editor.delete("0.0","end")
        self.editor.insert("0.0",self.text)
        self.editor_item = self.table.create_window(self.x,self.y,window=self.editor)
        self.editor.bind("<Key-Escape>",self.exitedit)
        self.editor.focus_set()

    def exitedit(self,event=None):
        self.edit_end = False
        self.text = self.editor.get("0.0","end").strip()
        self.editor.unbind("<Key-Escape>")
        self.table.itemconfig(self.figure_text,text=self.text)
        self.table.delete(self.editor_item)

    def select(self,event=None):
        if self.selected:
            self.selected = False
            self.table.itemconfig(self.figure_rhomb,outlinestipple="")
            self.table.itemconfig(self.figure_rhomb,width=2)
            if self.table.selection:
                self.table.selection = None
        else:
            self.selected = True
            self.table.itemconfig(self.figure_rhomb,outlinestipple="gray75")
            if self.table.selection:
                connection = Connection(self.table,self,self.table.selection)
                self.table.selection = None
            else:
                self.table.selection = self

class Table(tk.Canvas,object):

    def __init__(self,master):
        tk.Canvas.__init__(self,master,width=520,height=380,bg="white")
        self.pack(expand=True)
        self.selection = None # selection for connection
        self.connections = []
        self.rhombs = []
        for n in range(5):
            self.rhombs.append(Rhombus(self,80+90*n,70+60*n))

if __name__ == "__main__":
    root = tk.Tk()
    table = Table(root)
    root.mainloop()
dd42
User
Beiträge: 16
Registriert: Mittwoch 30. April 2008, 21:15

hi! :)

@ numerix: Danke für deinen Entwurf! Der ist wirklich gut. Von besserer Performance merkt man auf Mac zwar nix... aber das liegt halt am mac xD
Auf Linux und Windows geht dein Entwurf aber perfekt =)

Ich hab den Code mal erweitert:

Ausgelagert: http://dpaste.com/70988/

Was der Code kann:
- Es werden am Anfang mehrere Rhombuse und Rechtecke auf der canvas erzeugt (zum ausprobieren)
- Diese Formen lassen sich per Drag and Drop ziehen
- Mithilfe von Control-Button1 lassen sich Verbindungen zwischen Formen erzeugen
- Drückt man Shift wärend man eine Form bewegt dann rastet sie in ein Gitter ein und alle Verbindungen färben sich grün(damit sie auch mit schwarzem Gitter sichtbar sind gg)
- Bewegt man eine Form auserhalb der Canvas dann erweitert sich die Canvas

Diese Funktion geht aber sie hat nen bug:
-Hält man die Rechte Maustaste gedrückt und bewegt die Maus dann scrollt die canvas mit
:?: Am Anfang der Bewegung mit der rechten Maustaste gedrückt springt die Canvas, bitte helft mir das auszubessern - der für diesen Bug interessante Code ist innerhalb der Table Klasse... ihr müsst also nicht den ganzen Code durchackern :P

Liebe Grüße, David
Antworten