2016-10-30 4 views
0

ノードのデータベースをダイアグラムとして表示するには、Mac OS X Sierraの下でPython & GTK3を使用しています。これはMVPアーキテクチャです。GTK3&Python interactive - クラスのアーキテクチャ - matplotlib上のGTK3のポップアップキャンバス

私はfigureを表示するためにmatplotlibを使用します。私のディスプレイはインタラクティブなので、信号を受信する必要があります。私は、GTKイベントには十分なパラメータがないため、GTK GUIを使用してmatplotlibキャンバスから直接信号を受信することに決めました。実際に私はmatplotlibを使ってキャンバスに信号を受け取り、GTKのポップアップメニューを表示したいと思っています。

あなたが見る必要がある機能は、MainFigurePressedです。このアイデアは、Viewhandlerを接続してGTK GUIコール・ビューのメニューをポップアップするよりも、Detecte()関数を使ってDrawChronoMapというプログラムで私のキャンバスに信号を受け取ったということです。私のプログラムを起動するために、私のコントローラが私のビューを呼び出すでしょう。私のクラスDrawChronoMapで私のクラスViewhandlerをどのように引数に渡すことができますか?

どうすればよいですか?そうするために私のアーキテクチャをどのように変更する必要がありますか?

クラスView():

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)   

クラスの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() 

クラス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 

クラスコントローラー

私は実際には3つのクラスを持っています:

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. 
+0

私は自分のプログラムの最後の部分を忘れています。私は私のビューを呼び出すコントローラを持っています。 –

+0

これは取るにはかなりの量で、質問に答えるのが難しいです。あなたはそれを少し編集することができますか、おそらくあなたが持っているアーキテクチャの最小の例を作ってください? – ptomato

答えて

0

私の問題をよりよく説明するためにいくつかの写真を追加します。

Canvas embedded in my GTK environment

これは、物事を表示するには、matplotlibのを使用して(白)キャンバスと私のGTK環境です。私のキャンバスはmatplotlibで表示されます。キャンバスはマウスイベントを受け取り、キャンバスの表示を変更します。

Display of the popup menu ポップアップメニューが表示されます。 だからここでは厄介なのは、それはイベントを受信する私のキャンバスではありませんが、実際には私のGTK環境です。

だから、問題はここにある:

私は上をクリックし、オブジェクトの種類に応じて異なるメニューを表示します。イベントがノードまたはエッジにあるかどうかを直接計算できるので、イベントを受け取るキャンバスの場合は簡単に実行できますが、GTKイベントの場合は、イベントがノードにあるかどうかを検出できません。端に

どうすればよいですか? GTKイベントとキャンバスイベントを接続するために新しいクラスを作成する必要がありますか?

ありがとうございました

関連する問題