GTK3和Python交互-类的体系结构-Matplotlib Canvas上GTK3的PopupMenu

陈ia

我正在Mac OS X Sierra下使用Python和GTK3,以便将节点数据库显示为图表。它是一个MVP架构。

我使用matplotlib来显示我的身材。由于我的显示器是交互式的,因此我必须接收信号。我决定直接从matplotlib画布接收信号,而不是使用GTK GUI,因为GTK事件没有足够的参数。实际上,我想使用matplotlib在画布上接收信号并显示GTK的弹出菜单。

您必须查看的函数是MainFigurePressed。我的想法是,我使用功能Detecte()使用DrawChronoMap程序在画布上接收到信号,而不是通过连接Viewhandler弹出GTK GUI调用View的菜单。为了启动程序,我的控制器将调用我的视图,我想知道如何在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

类控制器:

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.
陈ia

我将添加一些图片,以便更好地解释我的问题。

嵌入我的GTK环境中的画布

这是我的GTK环境,其中的画布(白色)使用matplotlib进行显示。我的画布与matplotlib一起显示。画布接收鼠标事件,它将改变画布的显示。

弹出菜单的显示我们可以在此处看到一个弹出菜单。因此,在这里棘手的是,不再有我的画布接收该事件,而实际上是我的GTK环境

所以问题在这里:

我想显示不同的菜单,具体取决于我单击的对象的类型。如果是接收事件的画布,我可以轻松地做到这一点,因为我可以直接计算事件是在节点上还是在边缘上,但是如果它是GTK事件,我将无法再检测到该事件是在节点上还是在事件上。在边缘。

所以我该怎么做?我应该建立一个新类来连接GTK事件和canvas事件吗?

谢谢

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章