GTK3 &Python 交互式 - 类 的体系结构 - matplotlib Canvas 上 GTK3 的弹出菜单
GTK3 &Python interactive - architecture of classes - PopupMenu Of GTK3 on matplotlib Canvas
我在 mac OS X Sierra 下使用 Python 和 GTK3,以便将节点数据库显示为图表。它是一个 MVP 架构。
我用matplotlib来显示我的图形。由于我的显示器是交互式的,所以我必须接收信号。我决定直接从我的 matplotlib canvas 接收信号,而不是使用 GTK GUI,因为 GTK 事件没有足够的参数。实际上,我想使用 matplotlib 在 canvas 上接收信号并显示 GTK 的弹出菜单。
你要看的函数是MainFigurePressed。这个想法是我在 canvas 上使用函数 Detecte() 在程序 DrawChronoMap 上接收到信号,然后通过连接 Viewhandler 弹出调用 View 的 GTK GUI 菜单。为了启动我的程序,我的控制器将调用我的 view.I 我想知道如何在我的 class DrawChronoMap 中传递我的 class Viewhandler 参数?
我该怎么办?我应该如何更改架构才能做到这一点?
实际上我有三个 classes :
class 查看():
def __init__(self, MainController):
#set windows
self.window = Gtk.Window()
self.window.connect("delete-event", Gtk.main_quit)
self.window.set_default_size(10000, 10000)
self.window.set_title('ChronoMap')
#Init Glade file # Get windows from glade
self.interface = Gtk.Builder()
self.interface.add_from_file("interface1.glade")
self.mainWindow = self.interface.get_object("mainWindow")
self.aboutchronomap = self.interface.get_object("aboutchronomap")
self.fichierdialogue=self.interface.get_object("fichierdialogue")
self.sw=self.interface.get_object("mainFigure")
self.toolbar=self.interface.get_object("MatplotlibToolbar")
self.sw3=self.interface.get_object("scrolledwindow1")
self.sw4=self.interface.get_object("scrolledwindow2")
self.add_node_window=self.interface.get_object("add_node_window")
self.add_edge_window=self.interface.get_object("add_edge_window")
self.modify_edge_window=self.interface.get_object("modify_edge_window")
self.modify_node_window=self.interface.get_object("modify_node_window")
self.add_reference_node_edge=self.interface.get_object("add_reference_node_edge")
self.popupmenuCartoNode=self.interface.get_object("popupmenuCartoNode")
self.popupmenuCartoEdge=self.interface.get_object("popupmenuCartoEdge")
self.popupmenuCartoOtherplace=self.interface.get_object("popupmenuCartoOtherplace")
self.popupmenuChronoNode=self.interface.get_object("popupmenuChronoNode")
self.popupmenuChronoZoneBC=self.interface.get_object("popupmenuChronoZoneBC")
self.popupmenuChronoCursor=self.interface.get_object("popupmenuChronoCursor")
#Global controller
self.controller=MainController
#Init CartoCanvas
self.figCarto = Figure(figsize=(20,20), dpi=80)
self.axCarto = self.figCarto.add_subplot(111)
self.canvasCarto = FigureCanvas(self.figCarto)
# Init ChronoCanvas
self.figChrono = Figure(figsize=(20,20), dpi=80)
self.axChrono = self.figChrono.add_subplot(111)
self.canvasChrono = FigureCanvas(self.figChrono)
#Create a New graph on the controller
self.controller.create_new_graph("CartoChronomap")
#add node & edges
nodeA=self.controller.create_evenement("outdated research material", "01-01-2016 00:00:00", "01-02-2016 00:00:00", 1, "BLAH BLAH BLAH", "http://")
nodeB= self.controller.create_evenement("Projected tsunami frequency too low", "08-08-2016 00:00:00", "09-10-2016 00:00:00", 1, "OK", "http://")
nodeC=self.controller.create_evenement("EV C", "08-07-2016 00:00:00", "09-08-2016 00:00:00", 1, "HOOOOO", "http://")
nodeD=self.controller.create_evenement("Accident", "08-10-2016 00:00:00", "09-11-2016 00:00:00", 1, "HOOOOO", "http://")
self.controller.create_edge(nodeA,nodeB, "LeLien", "Une mega explosion", "[]")
self.controller.create_edge(nodeB,nodeA, "InverseLien", "Une giga explosion", "[]")
self.controller.create_edge(nodeC,nodeD, "LienTest", "Ceci est un lien test", "[]")
self.controller.calculate_position('spring_layout');
#Connect to draw chronograph
self.FdessinChrono=Draw_chrono.DrawChronoMap(self.axChrono,self.controller)
#Connect to draw Cartograph
self.FdessinCarto = Draw_cartograph.DrawCartoMap(self.axCarto, self.controller)
#draw
self.FdessinCarto.draw_cartograph()
self.FdessinChrono.draw_chronograph()
#MouseFunction Carto
self.FdessinCarto.zoom_wheel()
self.FdessinCarto.pan_drag()
#self.FdessinCarto.drag_node()
self.FdessinCarto.ChangeNodeColor()
self.FdessinCarto.node_popup_mouse_over()
self.FdessinCarto.edge_popup_mouse_over()
#Global carto event & chrono event
self.CartoEvent = self.FdessinCarto.Detect()
self.ChronoEvent = self.FdessinChrono.Detect()
print(self.CartoEvent,self.ChronoEvent)
#MouseFunction Chrono
self.FdessinChrono.cursor()
self.FdessinChrono.ChangeColor()
#self.FdessinChrono.pan_drag()
self.FdessinChrono.node_popup_mouse_over()
#Display Mode
self.display_Mode = None
#Creating the ListStore model
#node_liststore
self.node_liststore = Gtk.ListStore(str, str, str,str,str,str)
if len(self.FdessinCarto.pos) != 0:
for i,node in enumerate(self.FdessinCarto.pos):
self.node_liststore.append([str(node.title),str(node.start_time),str(node.end_time),str(node.node_group),str(node.description),str(node.attachment_list)])
#edge_liststore
self.edge_liststore = Gtk.ListStore(str, str, str,str,str)
if len(self.FdessinCarto.edgelist) !=0:
edge_prop=self.FdessinCarto.controller.edge_data(nodeA,nodeB)
edge_prop1=self.FdessinCarto.controller.edge_data(nodeB,nodeA)
self.edge_liststore.append([edge_prop['label'],str(nodeA.title),str(nodeB.title),edge_prop['description'],edge_prop['attachment_list']])
self.edge_liststore.append([edge_prop1['label'],str(nodeA.title),str(nodeB.title),edge_prop1['description'],edge_prop1['attachment_list']])
#creating the filtre
self.node_filter = self.node_liststore.filter_new()
self.edge_filter = self.edge_liststore.filter_new()
#setting the filter function, note that we're not using the
self.node_filter.set_visible_func(ViewHandler.node_filter_func)
self.edge_filter.set_visible_func(ViewHandler.edge_filter_func)
#creating the treeview for Node, making it use the filter as a model, and adding the columns
self.treeviewNode = Gtk.TreeView.new_with_model(self.node_liststore)
for i, column_title in enumerate(["Nom", "Date début", "Date fin", "Type de noeud", "Description du noeud","fichier"]):
self.Noderenderer = Gtk.CellRendererText()
self.Noderenderer.set_property("editable", True)
column = Gtk.TreeViewColumn(column_title, self.Noderenderer, text=i)
self.treeviewNode.append_column(column)
#self.Noderenderer.connect("edited", self.onButtonCreateNode)
#creating the treeview for edge
self.treeviewEdge = Gtk.TreeView.new_with_model(self.edge_liststore)
for i, column_title in enumerate(["Nom", "Noeud 1", "Noeud 2", "Description du lien","fichier"]):
self.Edgerenderer = Gtk.CellRendererText()
self.Edgerenderer.set_property("editable", True)
column = Gtk.TreeViewColumn(column_title, self.Edgerenderer, text=i)
self.treeviewEdge.append_column(column)
# Connect with signals
self.interface.connect_signals(ViewHandler(self))
#setting up the layout, putting the treeview in a scrollwindow
self.sw3.add(self.treeviewNode)
self.sw4.add(self.treeviewEdge)
self.sw3.show_all()
self.sw4.show_all()
self.window.add(self.sw)
self.sw.show_all()
# All ready - open interface
Gtk.main()
def update_data(self):
self.CartoEvent = self.FdessinCarto.Detect()
self.ChronoEvent = self.FdessinChrono.Detect()
print(self.CartoEvent,self.ChronoEvent)
class ViewHandler():
def __init__(self, ViewConnection):
self.View = ViewConnection
def resetplot(self):
axCarto.cla()
axCarto.set_xlim(0,10)
axCarto.set_ylim(0,10)
axCarto.grid(True)
axChrono.cla()
axChrono.set_xlim(0,10)
axChrono.set_ylim(0,10)
axChrono.grid(True)
# All button signals of GTK
#Signal to open windows "creation of node"
def create_node_button_press_event(self,widget):
self.View.add_node_window.show_all()
#Signal to open window "creation of link"
def create_link_button_press_event(self,widget):
self.View.add_edge_window.show_all()
def onButtonCreateNode(self,widget):
self.resetplot()
nom=self.View.interface.get_object('name_node1').get_text()
node_type=self.View.interface.get_object('node_type1').get_text()
start_time_node=self.View.interface.get_object('start_time_node1').get_text()
end_time_node=self.View.interface.get_object('end_time_node1').get_text()
#print(nom,node_type,start_time_node,end_time_node)
self.View.node_liststore.append([nom, start_time_node, end_time_node, node_type, "BLAH BLAH BLAH", "http://"])
self.View.FdessinCarto.controller.create_evenement(nom, start_time_node, end_time_node, node_type, "BLAH BLAH BLAH", "http://")
self.View.FdessinChrono.controller.create_evenement(nom, start_time_node, end_time_node, node_type, "BLAH BLAH BLAH", "http://")
self.View.canvasCarto.draw()
self.View.canvasChrono.draw()
self.View.add_node_window.destroy()
self.View.sw.show_all()
self.View.sw3.show_all()
def onButtonAddFileEdge(self,widget):
pass
def onButtonCreateEdge(self,widget):
nom=self.View.interface.get_object('name_edge2').get_text()
edge_description=self.View.interface.get_object('edge_type2').get_text()
node1_edge=self.View.interface.get_object('node1_edge_entry').get_text()
node2_edge=self.View.interface.get_object('node2_edge_entry2').get_text()
#create signal with liststore
self.View.edge_liststore.append([node1_edge,node2_edge, nom, edge_description, "[]"])
#create link with canvas
self.View.FdessinCarto.controller.create_edge(node1_edge,node2_edge, nom, edge_description, "[]")
self.View.FdessinChrono.controller.create_edge(node1_edge,node2_edge, nom, edge_description, "[]")
self.View.canvasCarto.draw()
self.View.canvasChrono.draw()
#register it in the treeStore
edge_prop=list(self.View.FdessinCarto.controller.edge_data(node1_edge,node2_edge))
self.View.sw.show_all()
self.View.add_edge_window.destroy()
#Signal to contextual menu
def onMainFigurePressed(self,widget,event):
print(event.type, event.button, event.window, event.x, event.y, event.time,event.get_state(),event.time)
#update event
self.View.update_data()
self.CartoEvent = self.View.FdessinCarto.Detect()
self.ChronoEvent = self.View.FdessinChrono.Detect()
print(self.View.CartoEvent,self.View.ChronoEvent,self.CartoEvent,self.ChronoEvent)
if event.type == Gdk.EventType.ENTER_NOTIFY:
print("yes, enter")
if event.type == Gdk.EventType.LEAVE_NOTIFY:
print("No, out")
if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
if self.display_Mode == "carto" :
print("oui, carto " )
self.View.popupmenuCartoNode.popup(None, None, None, None, event.button, event.time)
elif self.display_Mode == "chrono" :
print( "oui chrono")
self.View.popupmenuChronoNode.popup(None, None, None, None, event.button, event.time)
else:
return None
def onButtonModifyNode(self,widget,event):
#print("modify windows show all")
self.View.modify_node_window.show_all()
def onButtonDeleteNode(self,widget,event):
#print("button pressed delete")
self.View.FdessinCarto.deleteNode()
def onButtonLinkNode(self,widget,event):
#print("hello")
self.View.add_edge_window.show_all()
def onButtonCopyNode(self,widget,event):
#print("copy")
self.View.FdessinCarto.copynode()
#print("copy it")
def onButtonOtherplaceCreateNode(self,widget,event):
self.View.add_node_window.show_all()
def onButtonAttributsNode(self,widget,event):
self.View.FdessinCarto.display_node_attributs()
#Signal of menubars
def on_node_file_button_press_event(self,widget):
self.View.add_node_window.show_all()
def on_create_edge_button_press_event(self,widget):
self.View.add_edge_window.show_all()
def on_Open_button_press_event(self,widget,event):
self.View.fichierdialogue.show_all()
#signal of about
def on_gtk_about_button_release_event(self,widget,event):
self.View.aboutchronomap.show_all()
# close window
def on_close_button_press_event(self,widget,event):
self.View.on_quit_button_press_event (widget,event)
def on_quit_button_press_event (self,widget,event):
#pop up menu
dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.INFO,Gtk.ButtonsType.OK_CANCEL, "Vous partez?")
dialog.format_secondary_text("Voulez vous toujours partir?")
response=dialog.run()
if response == Gtk.ResponseType.OK:
Gtk.main_quit()
elif response == Gtk.ResponseType.CANCEL:
dialog.destroy()
dialog.destroy()
return True
def on_confirmation_deletenode_button_press_event (self,widget,event):
#pop up menu
dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.INFO,Gtk.ButtonsType.OK_CANCEL, "Suppression du noeud?")
dialog.format_secondary_text("Voulez vous vraiment supprimer le noeud?")
response=dialog.run()
if response == Gtk.ResponseType.OK:
Gtk.main_quit()
elif response == Gtk.ResponseType.CANCEL:
dialog.destroy()
dialog.destroy()
return True
def on_mainWindow_destroy(self, widget):
Gtk.main_quit()
def on_carto_display_button_press_event(self,widget,event):
self.display_Mode = "carto"
child=self.View.sw.get_child()
child1 = self.View.toolbar.get_child()
#print(child)
if child != None:
self.View.toolbar.remove(child1)
self.View.sw.remove(child)
self.box.remove(self.View.canvasChrono)
self.box=Gtk.Box()
self.View.sw.add(self.box)
self.box.pack_start(self.View.canvasCarto, True, True, 0)
#Add toolbar
toolbar = NavigationToolbar(self.View.canvasCarto, self.View.window)
self.View.toolbar.add_with_viewport(toolbar)
self.View.sw.show_all()
def on_chrono_display_button_press_event(self,widget,event):
self.display_Mode= "chrono"
child = self.View.sw.get_child()
child1 = self.View.toolbar.get_child()
if child != None:
self.View.toolbar.remove(child1)
self.View.sw.remove(child)
self.box.remove(self.View.canvasCarto)
self.View.FdessinChrono.draw_chronograph()
self.box=Gtk.Box()
self.View.sw.add(self.box)
self.box.pack_start(self.View.canvasChrono, True, True, 0)
#Add toolbar
toolbar = NavigationToolbar(self.View.canvasChrono, self.View.window)
self.View.toolbar.add_with_viewport(toolbar)
self.View.sw.show_all()
class DrawChronoMap:
def __init__(self,ax, controller):
#Global controller
self.controller = controller
#Global graph
self.G = self.controller.total_graph()
#Global model
self.model=self.controller.model
#Global Axis
self.ax = ax
#Global figure
self.fig = self.ax.get_figure()
#Gloal canvas
self.canvas = self.ax.get_figure().canvas
#Global list
self.nodelist = self.controller.get_node_list()
self.edgelist=self.controller.get_edge_list()
#Global empty collection
#Global nodecollection
self.nodecollection=None
#Gloabl datanode
self.datanode = []
#Global empty list
self.eventnode_with_rectangle=[]
self.start_date=[]
self.end_date=[]
self.event_name=[]
#Global data axes
self.axis_x=[]
#Global label axis y
self.yticks = None
# Drag time
self.drag_time=0
self.press = []
self.drag_press = []
self.xdrag=0
self.ydrag=0
#event data
self.xdata=0
self.ydata=0
#event if we selecte edge
self.node1=None
self.node2=None
#cursor
self.ly = self.ax.axvline(color='k') # the vert line
self.txt = self.ax.text(0.7, 0.9, '', transform=self.ax.transAxes)
#Node attibute popup
self.popup = self.ax.text(0, 0, '', style='italic',bbox = {'facecolor':'y', 'alpha':0.5, 'pad':10})
#Edge attribute popup
self.popupedge = self.ax.text(0, 0, '', style='italic',bbox = {'facecolor':'y', 'alpha':0.5, 'pad':10})
def draw_chronograph(self):
#update graph
self.G = self.controller.total_graph()
#update data of nodecollection
self.nodelist = self.controller.get_node_list()
for i in range(len(self.nodelist)):
self.event_name.append(self.nodelist[i].title)
bottom = ((i-1)*0.5) + 1.0
width = self.nodelist[i].end_time - self.nodelist[i].start_time
left=self.nodelist[i].start_time
height=0.3
rectangle = self.ax.bar(left,height,width,bottom)
rectangle.bottom = bottom
rectangle.i = i
self.eventnode_with_rectangle.append([self.nodelist[i],rectangle])
self.nodelist[i].pos=i
self.datanode.append(self.nodelist[i].start_time)
self.datanode.append(self.nodelist[i].end_time)
#pos of i in the dictionnary
taille=len(self.event_name)
pos=arange(0.5,(taille+2)*0.5+0.5,0.5)
self.yticks=yticks(pos,self.event_name)
locsy,labelsy=self.yticks
self.ax.set_yticks(pos)
self.ax.set_yticklabels(labelsy, size='small')
self.ax.axis('tight')
self.ax.set_ylim(0, taille*0.5+0.5)
self.ax.grid(color = 'g', linestyle = ':')
font = font_manager.FontProperties(size='small')
self.ax.legend(loc=1,prop=font)
#format the x-axis
self.ax.set_xlim(min(self.datanode), max(self.datanode))
self.ax.xaxis.tick_top()
# Finish up
self.ax.invert_yaxis()
self.fig.autofmt_xdate()
#init cursor
self.ly.set_xdata((min(self.datanode)+ max(self.datanode))/2)
self.txt.set_text('y=%s' % ((min(self.datanode)+ max(self.datanode))/2))
self.canvas.draw()
def ChangeColor(self):
def on_press(event):
#update self.press
self.press=[]
x=event.xdata
y=event.ydata
self.press=[x,y]
#print(event.button)
if event.button == 1:
for i,rectangle in self.eventnode_with_rectangle:
if (i.start_time< self.press[0] <i.end_time) and ((i.pos-1)*0.5+1-0.15< self.press[1] <(i.pos-1)*0.5+1+0.15) :
rectangle=self.ax.barh(((i.pos-1)*0.5)+1.0, i.end_time - i.start_time, left=i.start_time, height=0.3, align='center', color='red', alpha = 0.75)
rectangle=self.ax.barh(((i.pos-1)*0.5)+1.0, i.end_time - i.start_time, left=i.start_time, height=0.3, align='center', color='blue', alpha = 0.75)
self.canvas.draw()
else :
return None
def on_release(event):
self.press = []
self.canvas.draw()
self.canvas.mpl_connect('button_press_event', on_press)
self.canvas.mpl_connect('button_release_event', on_release)
def Detect(self):
def event(event):
actual_node = None
x=event.xdata
y=event.ydata
for i,rectangle in self.eventnode_with_rectangle:
if (i.start_time<x<i.end_time) and ((i.pos-1)*0.5+1-0.15<y<(i.pos-1)*0.5+1+0.15) :
actual_node = i
break
print("function drawchrono %s" %actual_node)
return actual_node
self.canvas.mpl_connect('button_press_event', event)
import BasicModel as md
import View as vw
import networkx as nx
import matplotlib.pyplot as plt
import forceatlas.forceatlas as nxfa2
import undo
import re
import copy
class 控制器:
def __init__(self, model):
"""
Initialization: Gets the model
:param model: Model class to use
"""
# Loads the model
self.model = model
if __name__ == '__main__':
# Init Model
MainModel = md.Model()
# Init Controller
MainController = Controller(MainModel)
# Init View
MainView = vw.View(MainController)
# Program Running.
我将添加一些图片以更好地解释我的问题。
Canvas embedded in my GTK environment
这是我的 GTK 环境,canvas(白色)使用 matplotlib 来显示内容。我的canvas是用matplotlib显示的。 canvas 接收鼠标事件,它会改变 canvas 的显示。
Display of the popup menu
我们可以在这里看到一个弹出菜单。 那么这里有什么棘手的地方,接收事件的不再是我的canvas,而是实际上我的GTK 环境。
所以问题就在这里:
我想根据单击的对象类型显示不同的菜单。如果是接收事件的 canvas 我可以很容易地做到这一点,因为我可以直接计算事件是在节点上还是在边缘上,但是如果它是 GTK 事件,我就无法再检测事件是否是在节点或边上。
那我该怎么办? 我应该构建一个新的 class 以连接 GTK 事件和 canvas 事件吗?
谢谢
我在 mac OS X Sierra 下使用 Python 和 GTK3,以便将节点数据库显示为图表。它是一个 MVP 架构。
我用matplotlib来显示我的图形。由于我的显示器是交互式的,所以我必须接收信号。我决定直接从我的 matplotlib canvas 接收信号,而不是使用 GTK GUI,因为 GTK 事件没有足够的参数。实际上,我想使用 matplotlib 在 canvas 上接收信号并显示 GTK 的弹出菜单。
你要看的函数是MainFigurePressed。这个想法是我在 canvas 上使用函数 Detecte() 在程序 DrawChronoMap 上接收到信号,然后通过连接 Viewhandler 弹出调用 View 的 GTK GUI 菜单。为了启动我的程序,我的控制器将调用我的 view.I 我想知道如何在我的 class DrawChronoMap 中传递我的 class Viewhandler 参数?
我该怎么办?我应该如何更改架构才能做到这一点?
实际上我有三个 classes :
class 查看():
def __init__(self, MainController):
#set windows
self.window = Gtk.Window()
self.window.connect("delete-event", Gtk.main_quit)
self.window.set_default_size(10000, 10000)
self.window.set_title('ChronoMap')
#Init Glade file # Get windows from glade
self.interface = Gtk.Builder()
self.interface.add_from_file("interface1.glade")
self.mainWindow = self.interface.get_object("mainWindow")
self.aboutchronomap = self.interface.get_object("aboutchronomap")
self.fichierdialogue=self.interface.get_object("fichierdialogue")
self.sw=self.interface.get_object("mainFigure")
self.toolbar=self.interface.get_object("MatplotlibToolbar")
self.sw3=self.interface.get_object("scrolledwindow1")
self.sw4=self.interface.get_object("scrolledwindow2")
self.add_node_window=self.interface.get_object("add_node_window")
self.add_edge_window=self.interface.get_object("add_edge_window")
self.modify_edge_window=self.interface.get_object("modify_edge_window")
self.modify_node_window=self.interface.get_object("modify_node_window")
self.add_reference_node_edge=self.interface.get_object("add_reference_node_edge")
self.popupmenuCartoNode=self.interface.get_object("popupmenuCartoNode")
self.popupmenuCartoEdge=self.interface.get_object("popupmenuCartoEdge")
self.popupmenuCartoOtherplace=self.interface.get_object("popupmenuCartoOtherplace")
self.popupmenuChronoNode=self.interface.get_object("popupmenuChronoNode")
self.popupmenuChronoZoneBC=self.interface.get_object("popupmenuChronoZoneBC")
self.popupmenuChronoCursor=self.interface.get_object("popupmenuChronoCursor")
#Global controller
self.controller=MainController
#Init CartoCanvas
self.figCarto = Figure(figsize=(20,20), dpi=80)
self.axCarto = self.figCarto.add_subplot(111)
self.canvasCarto = FigureCanvas(self.figCarto)
# Init ChronoCanvas
self.figChrono = Figure(figsize=(20,20), dpi=80)
self.axChrono = self.figChrono.add_subplot(111)
self.canvasChrono = FigureCanvas(self.figChrono)
#Create a New graph on the controller
self.controller.create_new_graph("CartoChronomap")
#add node & edges
nodeA=self.controller.create_evenement("outdated research material", "01-01-2016 00:00:00", "01-02-2016 00:00:00", 1, "BLAH BLAH BLAH", "http://")
nodeB= self.controller.create_evenement("Projected tsunami frequency too low", "08-08-2016 00:00:00", "09-10-2016 00:00:00", 1, "OK", "http://")
nodeC=self.controller.create_evenement("EV C", "08-07-2016 00:00:00", "09-08-2016 00:00:00", 1, "HOOOOO", "http://")
nodeD=self.controller.create_evenement("Accident", "08-10-2016 00:00:00", "09-11-2016 00:00:00", 1, "HOOOOO", "http://")
self.controller.create_edge(nodeA,nodeB, "LeLien", "Une mega explosion", "[]")
self.controller.create_edge(nodeB,nodeA, "InverseLien", "Une giga explosion", "[]")
self.controller.create_edge(nodeC,nodeD, "LienTest", "Ceci est un lien test", "[]")
self.controller.calculate_position('spring_layout');
#Connect to draw chronograph
self.FdessinChrono=Draw_chrono.DrawChronoMap(self.axChrono,self.controller)
#Connect to draw Cartograph
self.FdessinCarto = Draw_cartograph.DrawCartoMap(self.axCarto, self.controller)
#draw
self.FdessinCarto.draw_cartograph()
self.FdessinChrono.draw_chronograph()
#MouseFunction Carto
self.FdessinCarto.zoom_wheel()
self.FdessinCarto.pan_drag()
#self.FdessinCarto.drag_node()
self.FdessinCarto.ChangeNodeColor()
self.FdessinCarto.node_popup_mouse_over()
self.FdessinCarto.edge_popup_mouse_over()
#Global carto event & chrono event
self.CartoEvent = self.FdessinCarto.Detect()
self.ChronoEvent = self.FdessinChrono.Detect()
print(self.CartoEvent,self.ChronoEvent)
#MouseFunction Chrono
self.FdessinChrono.cursor()
self.FdessinChrono.ChangeColor()
#self.FdessinChrono.pan_drag()
self.FdessinChrono.node_popup_mouse_over()
#Display Mode
self.display_Mode = None
#Creating the ListStore model
#node_liststore
self.node_liststore = Gtk.ListStore(str, str, str,str,str,str)
if len(self.FdessinCarto.pos) != 0:
for i,node in enumerate(self.FdessinCarto.pos):
self.node_liststore.append([str(node.title),str(node.start_time),str(node.end_time),str(node.node_group),str(node.description),str(node.attachment_list)])
#edge_liststore
self.edge_liststore = Gtk.ListStore(str, str, str,str,str)
if len(self.FdessinCarto.edgelist) !=0:
edge_prop=self.FdessinCarto.controller.edge_data(nodeA,nodeB)
edge_prop1=self.FdessinCarto.controller.edge_data(nodeB,nodeA)
self.edge_liststore.append([edge_prop['label'],str(nodeA.title),str(nodeB.title),edge_prop['description'],edge_prop['attachment_list']])
self.edge_liststore.append([edge_prop1['label'],str(nodeA.title),str(nodeB.title),edge_prop1['description'],edge_prop1['attachment_list']])
#creating the filtre
self.node_filter = self.node_liststore.filter_new()
self.edge_filter = self.edge_liststore.filter_new()
#setting the filter function, note that we're not using the
self.node_filter.set_visible_func(ViewHandler.node_filter_func)
self.edge_filter.set_visible_func(ViewHandler.edge_filter_func)
#creating the treeview for Node, making it use the filter as a model, and adding the columns
self.treeviewNode = Gtk.TreeView.new_with_model(self.node_liststore)
for i, column_title in enumerate(["Nom", "Date début", "Date fin", "Type de noeud", "Description du noeud","fichier"]):
self.Noderenderer = Gtk.CellRendererText()
self.Noderenderer.set_property("editable", True)
column = Gtk.TreeViewColumn(column_title, self.Noderenderer, text=i)
self.treeviewNode.append_column(column)
#self.Noderenderer.connect("edited", self.onButtonCreateNode)
#creating the treeview for edge
self.treeviewEdge = Gtk.TreeView.new_with_model(self.edge_liststore)
for i, column_title in enumerate(["Nom", "Noeud 1", "Noeud 2", "Description du lien","fichier"]):
self.Edgerenderer = Gtk.CellRendererText()
self.Edgerenderer.set_property("editable", True)
column = Gtk.TreeViewColumn(column_title, self.Edgerenderer, text=i)
self.treeviewEdge.append_column(column)
# Connect with signals
self.interface.connect_signals(ViewHandler(self))
#setting up the layout, putting the treeview in a scrollwindow
self.sw3.add(self.treeviewNode)
self.sw4.add(self.treeviewEdge)
self.sw3.show_all()
self.sw4.show_all()
self.window.add(self.sw)
self.sw.show_all()
# All ready - open interface
Gtk.main()
def update_data(self):
self.CartoEvent = self.FdessinCarto.Detect()
self.ChronoEvent = self.FdessinChrono.Detect()
print(self.CartoEvent,self.ChronoEvent)
class ViewHandler():
def __init__(self, ViewConnection):
self.View = ViewConnection
def resetplot(self):
axCarto.cla()
axCarto.set_xlim(0,10)
axCarto.set_ylim(0,10)
axCarto.grid(True)
axChrono.cla()
axChrono.set_xlim(0,10)
axChrono.set_ylim(0,10)
axChrono.grid(True)
# All button signals of GTK
#Signal to open windows "creation of node"
def create_node_button_press_event(self,widget):
self.View.add_node_window.show_all()
#Signal to open window "creation of link"
def create_link_button_press_event(self,widget):
self.View.add_edge_window.show_all()
def onButtonCreateNode(self,widget):
self.resetplot()
nom=self.View.interface.get_object('name_node1').get_text()
node_type=self.View.interface.get_object('node_type1').get_text()
start_time_node=self.View.interface.get_object('start_time_node1').get_text()
end_time_node=self.View.interface.get_object('end_time_node1').get_text()
#print(nom,node_type,start_time_node,end_time_node)
self.View.node_liststore.append([nom, start_time_node, end_time_node, node_type, "BLAH BLAH BLAH", "http://"])
self.View.FdessinCarto.controller.create_evenement(nom, start_time_node, end_time_node, node_type, "BLAH BLAH BLAH", "http://")
self.View.FdessinChrono.controller.create_evenement(nom, start_time_node, end_time_node, node_type, "BLAH BLAH BLAH", "http://")
self.View.canvasCarto.draw()
self.View.canvasChrono.draw()
self.View.add_node_window.destroy()
self.View.sw.show_all()
self.View.sw3.show_all()
def onButtonAddFileEdge(self,widget):
pass
def onButtonCreateEdge(self,widget):
nom=self.View.interface.get_object('name_edge2').get_text()
edge_description=self.View.interface.get_object('edge_type2').get_text()
node1_edge=self.View.interface.get_object('node1_edge_entry').get_text()
node2_edge=self.View.interface.get_object('node2_edge_entry2').get_text()
#create signal with liststore
self.View.edge_liststore.append([node1_edge,node2_edge, nom, edge_description, "[]"])
#create link with canvas
self.View.FdessinCarto.controller.create_edge(node1_edge,node2_edge, nom, edge_description, "[]")
self.View.FdessinChrono.controller.create_edge(node1_edge,node2_edge, nom, edge_description, "[]")
self.View.canvasCarto.draw()
self.View.canvasChrono.draw()
#register it in the treeStore
edge_prop=list(self.View.FdessinCarto.controller.edge_data(node1_edge,node2_edge))
self.View.sw.show_all()
self.View.add_edge_window.destroy()
#Signal to contextual menu
def onMainFigurePressed(self,widget,event):
print(event.type, event.button, event.window, event.x, event.y, event.time,event.get_state(),event.time)
#update event
self.View.update_data()
self.CartoEvent = self.View.FdessinCarto.Detect()
self.ChronoEvent = self.View.FdessinChrono.Detect()
print(self.View.CartoEvent,self.View.ChronoEvent,self.CartoEvent,self.ChronoEvent)
if event.type == Gdk.EventType.ENTER_NOTIFY:
print("yes, enter")
if event.type == Gdk.EventType.LEAVE_NOTIFY:
print("No, out")
if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
if self.display_Mode == "carto" :
print("oui, carto " )
self.View.popupmenuCartoNode.popup(None, None, None, None, event.button, event.time)
elif self.display_Mode == "chrono" :
print( "oui chrono")
self.View.popupmenuChronoNode.popup(None, None, None, None, event.button, event.time)
else:
return None
def onButtonModifyNode(self,widget,event):
#print("modify windows show all")
self.View.modify_node_window.show_all()
def onButtonDeleteNode(self,widget,event):
#print("button pressed delete")
self.View.FdessinCarto.deleteNode()
def onButtonLinkNode(self,widget,event):
#print("hello")
self.View.add_edge_window.show_all()
def onButtonCopyNode(self,widget,event):
#print("copy")
self.View.FdessinCarto.copynode()
#print("copy it")
def onButtonOtherplaceCreateNode(self,widget,event):
self.View.add_node_window.show_all()
def onButtonAttributsNode(self,widget,event):
self.View.FdessinCarto.display_node_attributs()
#Signal of menubars
def on_node_file_button_press_event(self,widget):
self.View.add_node_window.show_all()
def on_create_edge_button_press_event(self,widget):
self.View.add_edge_window.show_all()
def on_Open_button_press_event(self,widget,event):
self.View.fichierdialogue.show_all()
#signal of about
def on_gtk_about_button_release_event(self,widget,event):
self.View.aboutchronomap.show_all()
# close window
def on_close_button_press_event(self,widget,event):
self.View.on_quit_button_press_event (widget,event)
def on_quit_button_press_event (self,widget,event):
#pop up menu
dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.INFO,Gtk.ButtonsType.OK_CANCEL, "Vous partez?")
dialog.format_secondary_text("Voulez vous toujours partir?")
response=dialog.run()
if response == Gtk.ResponseType.OK:
Gtk.main_quit()
elif response == Gtk.ResponseType.CANCEL:
dialog.destroy()
dialog.destroy()
return True
def on_confirmation_deletenode_button_press_event (self,widget,event):
#pop up menu
dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.INFO,Gtk.ButtonsType.OK_CANCEL, "Suppression du noeud?")
dialog.format_secondary_text("Voulez vous vraiment supprimer le noeud?")
response=dialog.run()
if response == Gtk.ResponseType.OK:
Gtk.main_quit()
elif response == Gtk.ResponseType.CANCEL:
dialog.destroy()
dialog.destroy()
return True
def on_mainWindow_destroy(self, widget):
Gtk.main_quit()
def on_carto_display_button_press_event(self,widget,event):
self.display_Mode = "carto"
child=self.View.sw.get_child()
child1 = self.View.toolbar.get_child()
#print(child)
if child != None:
self.View.toolbar.remove(child1)
self.View.sw.remove(child)
self.box.remove(self.View.canvasChrono)
self.box=Gtk.Box()
self.View.sw.add(self.box)
self.box.pack_start(self.View.canvasCarto, True, True, 0)
#Add toolbar
toolbar = NavigationToolbar(self.View.canvasCarto, self.View.window)
self.View.toolbar.add_with_viewport(toolbar)
self.View.sw.show_all()
def on_chrono_display_button_press_event(self,widget,event):
self.display_Mode= "chrono"
child = self.View.sw.get_child()
child1 = self.View.toolbar.get_child()
if child != None:
self.View.toolbar.remove(child1)
self.View.sw.remove(child)
self.box.remove(self.View.canvasCarto)
self.View.FdessinChrono.draw_chronograph()
self.box=Gtk.Box()
self.View.sw.add(self.box)
self.box.pack_start(self.View.canvasChrono, True, True, 0)
#Add toolbar
toolbar = NavigationToolbar(self.View.canvasChrono, self.View.window)
self.View.toolbar.add_with_viewport(toolbar)
self.View.sw.show_all()
class DrawChronoMap:
def __init__(self,ax, controller):
#Global controller
self.controller = controller
#Global graph
self.G = self.controller.total_graph()
#Global model
self.model=self.controller.model
#Global Axis
self.ax = ax
#Global figure
self.fig = self.ax.get_figure()
#Gloal canvas
self.canvas = self.ax.get_figure().canvas
#Global list
self.nodelist = self.controller.get_node_list()
self.edgelist=self.controller.get_edge_list()
#Global empty collection
#Global nodecollection
self.nodecollection=None
#Gloabl datanode
self.datanode = []
#Global empty list
self.eventnode_with_rectangle=[]
self.start_date=[]
self.end_date=[]
self.event_name=[]
#Global data axes
self.axis_x=[]
#Global label axis y
self.yticks = None
# Drag time
self.drag_time=0
self.press = []
self.drag_press = []
self.xdrag=0
self.ydrag=0
#event data
self.xdata=0
self.ydata=0
#event if we selecte edge
self.node1=None
self.node2=None
#cursor
self.ly = self.ax.axvline(color='k') # the vert line
self.txt = self.ax.text(0.7, 0.9, '', transform=self.ax.transAxes)
#Node attibute popup
self.popup = self.ax.text(0, 0, '', style='italic',bbox = {'facecolor':'y', 'alpha':0.5, 'pad':10})
#Edge attribute popup
self.popupedge = self.ax.text(0, 0, '', style='italic',bbox = {'facecolor':'y', 'alpha':0.5, 'pad':10})
def draw_chronograph(self):
#update graph
self.G = self.controller.total_graph()
#update data of nodecollection
self.nodelist = self.controller.get_node_list()
for i in range(len(self.nodelist)):
self.event_name.append(self.nodelist[i].title)
bottom = ((i-1)*0.5) + 1.0
width = self.nodelist[i].end_time - self.nodelist[i].start_time
left=self.nodelist[i].start_time
height=0.3
rectangle = self.ax.bar(left,height,width,bottom)
rectangle.bottom = bottom
rectangle.i = i
self.eventnode_with_rectangle.append([self.nodelist[i],rectangle])
self.nodelist[i].pos=i
self.datanode.append(self.nodelist[i].start_time)
self.datanode.append(self.nodelist[i].end_time)
#pos of i in the dictionnary
taille=len(self.event_name)
pos=arange(0.5,(taille+2)*0.5+0.5,0.5)
self.yticks=yticks(pos,self.event_name)
locsy,labelsy=self.yticks
self.ax.set_yticks(pos)
self.ax.set_yticklabels(labelsy, size='small')
self.ax.axis('tight')
self.ax.set_ylim(0, taille*0.5+0.5)
self.ax.grid(color = 'g', linestyle = ':')
font = font_manager.FontProperties(size='small')
self.ax.legend(loc=1,prop=font)
#format the x-axis
self.ax.set_xlim(min(self.datanode), max(self.datanode))
self.ax.xaxis.tick_top()
# Finish up
self.ax.invert_yaxis()
self.fig.autofmt_xdate()
#init cursor
self.ly.set_xdata((min(self.datanode)+ max(self.datanode))/2)
self.txt.set_text('y=%s' % ((min(self.datanode)+ max(self.datanode))/2))
self.canvas.draw()
def ChangeColor(self):
def on_press(event):
#update self.press
self.press=[]
x=event.xdata
y=event.ydata
self.press=[x,y]
#print(event.button)
if event.button == 1:
for i,rectangle in self.eventnode_with_rectangle:
if (i.start_time< self.press[0] <i.end_time) and ((i.pos-1)*0.5+1-0.15< self.press[1] <(i.pos-1)*0.5+1+0.15) :
rectangle=self.ax.barh(((i.pos-1)*0.5)+1.0, i.end_time - i.start_time, left=i.start_time, height=0.3, align='center', color='red', alpha = 0.75)
rectangle=self.ax.barh(((i.pos-1)*0.5)+1.0, i.end_time - i.start_time, left=i.start_time, height=0.3, align='center', color='blue', alpha = 0.75)
self.canvas.draw()
else :
return None
def on_release(event):
self.press = []
self.canvas.draw()
self.canvas.mpl_connect('button_press_event', on_press)
self.canvas.mpl_connect('button_release_event', on_release)
def Detect(self):
def event(event):
actual_node = None
x=event.xdata
y=event.ydata
for i,rectangle in self.eventnode_with_rectangle:
if (i.start_time<x<i.end_time) and ((i.pos-1)*0.5+1-0.15<y<(i.pos-1)*0.5+1+0.15) :
actual_node = i
break
print("function drawchrono %s" %actual_node)
return actual_node
self.canvas.mpl_connect('button_press_event', event)
import BasicModel as md
import View as vw
import networkx as nx
import matplotlib.pyplot as plt
import forceatlas.forceatlas as nxfa2
import undo
import re
import copy
class 控制器:
def __init__(self, model):
"""
Initialization: Gets the model
:param model: Model class to use
"""
# Loads the model
self.model = model
if __name__ == '__main__':
# Init Model
MainModel = md.Model()
# Init Controller
MainController = Controller(MainModel)
# Init View
MainView = vw.View(MainController)
# Program Running.
我将添加一些图片以更好地解释我的问题。
Canvas embedded in my GTK environment
这是我的 GTK 环境,canvas(白色)使用 matplotlib 来显示内容。我的canvas是用matplotlib显示的。 canvas 接收鼠标事件,它会改变 canvas 的显示。
Display of the popup menu 我们可以在这里看到一个弹出菜单。 那么这里有什么棘手的地方,接收事件的不再是我的canvas,而是实际上我的GTK 环境。
所以问题就在这里:
我想根据单击的对象类型显示不同的菜单。如果是接收事件的 canvas 我可以很容易地做到这一点,因为我可以直接计算事件是在节点上还是在边缘上,但是如果它是 GTK 事件,我就无法再检测事件是否是在节点或边上。
那我该怎么办? 我应该构建一个新的 class 以连接 GTK 事件和 canvas 事件吗?
谢谢