2016-10-30 2 views
0

Я использую Python & GTK3 под Mac OS X Sierra, чтобы отобразить базу данных узлов как диаграмму. Это MVP-архитектура.GTK3 & Python interactive - архитектура классов - PopupMenu GTK3 на matplotlib Canvas

Я использую matplotlib для отображения моей фигуры. Поскольку мой дисплей интерактивен, я должен получать сигналы. Я решил получать сигналы непосредственно из моего полотна matplotlib вместо использования GTK GUI, поскольку событие GTK не имеет достаточных параметров. На самом деле я хочу получать сигналы на моем холсте с помощью matplotlib и показывать всплывающее меню GTK.

Функция, которую вы должны посмотреть, - MainFigurePressed. Идея заключается в том, что я получил сигналы на моем холсте с помощью программы DrawChronoMap с помощью функции Detecte(), чем всплывающее меню моего GUI GUI, вызывающего View, путем подключения Viewhandlers. Чтобы запустить мою программу, мой контроллер вызовет мой просмотр. Мне интересно, как я могу передать аргумент моего класса Viewhandler в моем классе DrawChronoMap?

Как мне это сделать? Как мне изменить свою архитектуру для этого?

У меня есть три класса собственно:

класса 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)   

класс обработки просмотров():

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 

класс контроллера :

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

Это моя среда GTK с холстом (в белом) с помощью Matplotlib для отображения вещей. Мой холст отображается с помощью matplotlib. Холст принимает события мыши, и это изменит отображение холста.

Display of the popup menu Здесь вы можете увидеть всплывающее меню. Итак, что здесь сложно,, это НЕ БОЛЬШЕ мой холст, который получает событие, но на самом деле это моя среда GTK.

Так что проблема здесь:

Я хочу, чтобы отобразить различные меню в зависимости от типа объекта, который я нажимаю на. Я могу сделать это легко, если это холст, который принимает событие, поскольку я могу непосредственно вычислить, является ли событие на узле или ребре, но если это событие GTK, я больше не могу определить, находится ли событие на узле или на краю.

Итак, что мне делать? Должен ли я построить новый класс для подключения события события и холста GTK?

Благодаря

Смежные вопросы