Python和科学计算认证群组  - 讨论区

标题:如何在chaco的plot中添加鼠标事件

2013年05月07日 星期二 14:56

在component中实现了一些事件用来完成图形绘制和操作。

功能已经在component中实验通过了。

但是component中没有提供类似plot中的x,y坐标和grid,的自动重绘。

因此希望将一系列的鼠标、按键事件移植到plot中。

在继承plot中除了normal_mouse_leave()方法之外

没有发现可以覆盖的方法,

在chaco中可以调用Tool实现一些需求,

但是不能完全满足,

所有希望在chaco的plot中添加或者捕获鼠标事件,或者在component中添加类似plot中的x\y坐标,和grid,的重绘功能。

不知道有没有好的办法。

请大家指点指点。

2013年05月08日 星期三 06:40

我觉得应该通过添加Tool实现响应鼠标事件,你可以仿照现有的Tool类,例如那个可以拖动缩放的Tool。

2013年05月12日 星期日 19:11

谢谢若愚哥哥,已经仿造你的书中的二次开发例子完成了同时实现“添删改查”的工具。

# -*- coding:utf-8 -*-

__author__ = 'Administrator'

__time__ = "上午9:55"

import numpy as np

from numpy import sort, array

from numpy.random import random

from traits.api import (HasTraits, Instance, List, Enum,

                        Float, Color, Tuple, Range, Property, Event, Int)

from traitsui.api import Item, View, HGroup

from chaco.api import Plot, ArrayPlotData, AbstractController

from chaco.api import AbstractOverlay, ScatterInspectorOverlay

###1###

from enable.api import ComponentEditor, Component, Line, Pointer, color_table

from enable.colors import ColorTrait

import copy

import sys

 

sys.path.append("..")

from Model.Polygon import Polygon

from Model.Point import Point

 

 

def convert_color(c):

    if c.__class__.__name__ == "QColor":

        return (c.red() / 255.0, c.green() / 255.0, c.blue() / 255.0)

    else:

        return (c[0] / 255.0, c[1] / 255.0, c[2] / 255.0)

 

 

class PolygonOverlay(AbstractOverlay):

    cur_line = Instance(Line, args=())

    metadata = Property(depends_on='component')

    line_color = ColorTrait("blueviolet")

    polygons = List(Polygon)

    move_polygon_points = np.array([])

 

    def _get_metadata(self):

        return self.component.index.metadata

 

    def overlay(self, other_component, gc, view_bounds=None, mode="normal"):

        if "cur_line" in self.metadata and self.metadata["cur_line"] != []:

            self.cur_line.points = copy.copy(self.metadata["cur_line"])

            gc.save_state()

            self.cur_line.line_color = self.line_color

            self.cur_line.vertex_color = self.line_color

            self.cur_line._draw(gc)

            gc.restore_state()

        if "polygons" in self.metadata:

            for i in self.metadata["polygons"]:

                print i.line.points, "polygons"

            self.polygons = self.metadata["polygons"]

            gc.save_state()

            gc.set_antialias(True)

            gc.set_stroke_color(color_table["dodgerblue"])

            gc.set_fill_color(color_table["lightskyblue"])

            gc.set_alpha(0.4)

            gc.set_line_width(2)

            gc.set_line_dash(None)

            for i in self.polygons:

                if [] != i.line.points:

                    gc.lines(i.get_points())

                else:

                    print 'null'

            gc.draw_path()

            gc.restore_state()

        if self.metadata.has_key("move_polygon") and self.metadata["move_polygon"] is not None:

            print self.metadata["move_polygon"], "move_polygon"

            self.move_polygon_points = copy.copy(self.metadata["move_polygon"])

            gc.save_state()

            gc.set_antialias(True)

            #gc.set_stroke_color(convert_color(self.polygon_color) + (0.8,))

            #gc.set_fill_color(convert_color(self.polygon_color) + (0.4,))

            gc.set_stroke_color(color_table["dodgerblue"])

            gc.set_fill_color(color_table["lightskyblue"])

            gc.set_alpha(0.4)

            gc.set_line_width(2)

            gc.set_line_dash(None)

            gc.lines(self.move_polygon_points)

            gc.draw_path()

            gc.restore_state()

 

 

class PolygonController(AbstractController):

    metadata = Property(depends_on='component')

 

    def _get_metadata(self):

        return self.component.index.metadata

 

 

    polygons = List(Polygon)

    moving_x = Float

    moving_y = Float

    index = Int

    moving_polygon = Instance(Polygon)

    temp_polygon = Instance(Polygon)

    polygon_color = Color((0, 0, 0))

    #画线参数

    draw_polygon = Instance(Polygon)

    points = List()

    draw_point = (0, 0)

    line_color = ColorTrait("blueviolet")

    cur_line = Instance(Line, args=())

    #cur_line.line_color = ColorTrait("blueviolet")

    event_state = Enum("Normal", "Draw", "Drawing", "Move", "Moving", "Removeing", "Exchange", "Dragging")

    cur_line_update = Event

    moving_polygon_update = Event

    _removeing_polygon_updata = Event

    _normal_flush_updata = Event

    _ecchange_polygon_updata = Event

    #类参数

    distans_point = Int(4)

    # Cursor shape for non-tool use.

    original_cursor = Pointer("arrow")

    # Cursor shape for drawing.

    normal_cursor = Pointer("pencil")

    # Cursor shape for deleting points.

    delete_cursor = Pointer("bullseye")

    # Cursor shape for moving points.

    move_cursor = Pointer("sizing")

 

    def __init__(self, component, *args, **kw):

        super(PolygonController, self).__init__(component, *args, **kw)

        self.metadata["line_color"] = copy.copy(self.line_color)

        self.metadata["fuck"] = random(20)

        print self.metadata["fuck"], "fuck"

        self.draw_polygon = Polygon()

        self.event_state = "Normal"

 

    def Find_Polygon(self, x, y):

        from kiva.agg import points_in_polygon

 

        for polygon in self.polygons[::-1]:

            if polygon is not None:

                self.temp_polygon = polygon

                self.index = self.polygons.index(polygon)

                if points_in_polygon((x, y), polygon.get_points()):

                    print "find it"

                    return polygon

        print "find Nothing"

        return None

 

    def Move_right_down(self, event):

        polygon = self.Find_Polygon(event.x, event.y)

        if polygon is not None:

            self.moving_x = event.x

            self.moving_y = event.y

            self.moving_polygon = copy.copy(polygon)

            self.event_state = "Moving"

            #self._update_cur_line()

            self.Moving_mouse_move(event)

 

 

    def Moving_mouse_move(self, event):

        print event.x, event.y, self.moving_x, self.moving_y, "x,y"

        self.moving_polygon.update_x_y(event.x - self.moving_x, event.y - self.moving_y)

        self.moving_x = event.x

        self.moving_y = event.y

        print self.moving_polygon.line.points, 'moving_mouse'

        self._update_move_polygon()

 

 

    def Moving_right_up(self, event):

        """

        移动操作结束,回到normal状态

        """

        self.event_state = "Normal"

        #self.polygons[self.moving_polygon]=self.moving_polygon

        print self.index, "index"

        self.polygons.remove(self.temp_polygon)

        #self.polygons[self.index].line.points = copy.copy(self.moving_polygon.line.points)

        self.polygons.append(self.moving_polygon)

 

        for i in self.metadata["polygons"]:

            print i.line.points, "polygons_move"

        self._update_move_polygon()

        self._re_set_MoveTool()

 

    def _re_set_MoveTool(self):

        #self.moving_polygon.line.points = []

        #self.index = 0

        self.metadata["move_polygon"] = None

 

 

    def Draw_left_down(self, event):

 

 

        over = self._over_point(event)

        if over is not None:

            if event.control_down:

                # Delete the point

                self.points.pop(over)

                #self.cur_line.points = list(self.component.map_screen(array(self.points)))

                self.cur_line.points = copy.copy(self.points)

                self._update_cur_line()

            else:

                self.event_state = "Dragging"

                self._dragged = over

                self._drag_new_point = False

                self.Dragging_mouse_move(event)

        else:

            self.points.append((event.x, event.y))

            #print self.points[0].x,self.points[0].y

            print len(self.points)

            self.event_state = "Drawing"

            self.Drawing_mouse_move(event)

        return

 

 

    def Dragging_left_up(self, event):

        self.event_state = "Draw"

 

 

    def Dragging_mouse_move(self, event):

        """ Handles the user moving the mouse while in the 'dragging' state.

 

        The screen is updated to show the new mouse position as the end of the

        line segment being drawn.

        """

        #mouse_position = self._map_data((event.x, event.y))

        mouse_position = [event.x, event.y]

        self.points[self._dragged] = mouse_position

        #self.line.points = list(self.component.map_screen(array(self.points)))

        self.cur_line.points = copy.copy(self.points)

        self._update_cur_line()

 

    def Draw_mouse_move(self, event):

        over = self._over_point(event)

        if over is not None:

            if event.control_down:

                event.window.set_pointer(self.delete_cursor)

            else:

                event.window.set_pointer(self.move_cursor)

        else:

            event.handled = False

            event.window.set_pointer(self.normal_cursor)

        self._update_cur_line()

        return

 

    def Drawing_mouse_move(self, event):

        print self.points[-1]

        self.points[-1] = [event.x, event.y]

        self.cur_line.points = copy.copy(self.points)

        self._update_cur_line()

 

    def Drawing_left_up(self, event):

        self.event_state = "Draw"

        #self.request_redraw()

        self._update_cur_line()

 

    def _update_cur_line(self):

        self.metadata["cur_line"] = copy.copy(self.cur_line.points)

        self.cur_line_update = True

 

    def _update_move_polygon(self):

        self.metadata["polygons"] = copy.copy(self.polygons)

        print self.moving_polygon.line.points, "abck"

        self.metadata["move_polygon"] = copy.copy(self.moving_polygon.line.points)

        self.moving_polygon_update = True

 

    def _is_near_point(self, point, event):

        """ Determines if the pointer is near a specified point.

        """

        event_point = (event.x, event.y)

 

        return ((abs(point[0] - event_point[0]) + \

                 abs(point[1] - event_point[1])) <= self.distans_point)

 

    def _over_point(self, event):

        """ Return the index of a point in *points* that *event* is 'over'.

 

        Returns None if there is no such point.

        """

        for i, point in enumerate(self.cur_line.points):

            if self._is_near_point(point, event):

                result = i

                break

        else:

            result = None

        return result

 

    def Draw_key_pressed(self, event):

        #print event.character

        if "Enter" == event.character:

            self.draw_polygon.line = copy.copy(self.cur_line)

            self.polygons.append(self.draw_polygon)

            self._re_set_Draw_Tool()

            self.metadata["polygons"] = copy.copy(self.polygons)

            self._update_cur_line()

            self.event_state = "Normal"

 

    def _re_set_Draw_Tool(self):

        self.draw_polygon = Polygon()

        self.points = []

        self.draw_point = [0, 0]

        self.line_color = "blueviolet"

        self.cur_line = Line()

 

    def Normal_key_pressed(self, event):

        print event.character

        if "m" == event.character:

            self.event_state = "Move"

        if "d" == event.character:

            self.event_state = "Draw"

        if "r" == event.character:

            self.event_state = "Removeing"

        if "e" == event.character:

            self.event_state = "Exchange"

            # Removeing Function

        self.metadata["fuck"] = random(20)

        print self.metadata["fuck"]

 

    def Removeing_left_down(self, event):

        polygon = self.Find_Polygon(event.x, event.y)

        if polygon is not None:

            self.polygons.remove(polygon)

            self._updata_removeing_polygon()

        self.event_state = "Normal"

 

    def _updata_removeing_polygon(self):

        self.metadata["polygons"] = copy.copy(self.polygons)

        self._updata_removeing_polygon = True

 

    def _updata_normal_flush(self):

        self._normal_flush_updata = True

 

    def _event_state_changed(self):

        if self.event_state == "Normal":

            self._updata_normal_flush()

 

    #编辑状态

    def Exchange_left_down(self, event):

        polygon = self.Find_Polygon(event.x, event.y)

        print polygon.line.points, "exchange"

        if polygon is not None:

            self.draw_polygon = copy.copy(polygon)

            self.cur_line = copy.copy(self.draw_polygon.line)

            self.points = copy.copy(self.cur_line.points)

            self.polygons.remove(polygon)

            self.event_state = "Draw"

            self._updata_exchange_polygon()

            self._update_cur_line()

 

    def _updata_exchange_polygon(self):

        self.metadata["polygons"] = copy.copy(self.polygons)

        self._exchange_polygon_updata = True

2013年05月12日 星期日 19:17

不过在里面又遇到了新的问题,

上下有两个plot,

按照设计:

plot_top中显示

plot_bottom中绘图,

问题在于,plot_bottom中的数据存放于scatter.index.metatdata["data"]中
希望在plot_bottom更新界面的时候,将数据提供给plot_top绘图

我是通过在:

def __init__(self, datasource, **traits):

        super(PlotForm, self).__init__(**traits)

        self.datasource = datasource

        。。。。。。

        self.data= self.scatter.index.metadata

        print self.data["data"]

    def _data_changed(self,old,new):

        print self.temp_fuck["data"],"print data"

但是我没办法捕获到data的变化,

我在操作绘图中,metadata中的data确实已经更新了的。

请在看一下。谢谢。

2013年05月12日 星期日 22:20

结合了若愚大哥书中的chaco_tools_lasso_selection.py

在初始化函数中添加了如下:

self.polygonController.on_trait_change(self._data_changed, "_update_move_polygon")

实时更新完成了。

如下红色区域有误,请重新填写。

    你的回复:

    请 登录 后回复。还没有在Zeuux哲思注册吗?现在 注册 !

    Zeuux © 2024

    京ICP备05028076号