如何绘制跟随鼠标光标的十字?

如何绘制跟随鼠标光标的十字?

问题描述:

我想在我的paintEvent()中画一个十字,它随着鼠标移动。我通过pyqt使用python。如何绘制跟随鼠标光标的十字?

我正在使用下面的代码,但结果不好。

from __future__ import division 
import sys 
import platform 

# Qt4 bindings for core Qt functionalities (non-GUI) 
import PyQt4.QtCore as QtCore 

# Python Qt4 bindings for GUI objects 
import PyQt4.QtGui as QtGui 
from PyQt4.QtGui import * 
from PyQt4.QtCore import * 
# import the Qt4Agg FigureCanvas object, that binds Figure to 
# Qt4Agg backend. It also inherits from QWidget 
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas 
# Matplotlib Figure object 
from matplotlib.figure import Figure 

class C_MplCanvas(FigureCanvas): 
    def __init__(self):  
     # setup Matplotlib Figure and Axis 
     self.fig = Figure() 
     #self.cursor = Cursor() 
     self.fig.set_facecolor('black') 
     self.fig.set_edgecolor('black') 
     #self.ax = self.fig.add_subplot(111) 
     #self.ax.patch.set_facecolor('black') 
     # initialization of the canvas 
     FigureCanvas.__init__(self, self.fig) 
     #super(FigureCanvas, self).__init__(self.fig) 


     # we define the widget as expandable 
     FigureCanvas.setSizePolicy(self, 
            QtGui.QSizePolicy.Expanding, 
            QtGui.QSizePolicy.Expanding) 
     # notify the system of updated policy 
     FigureCanvas.updateGeometry(self) 

     self.xx=0 
     self.yy=0 
     self.justDoubleClicked=False 

    def contextMenuEvent(self, event): 
     menu = QMenu(self) 
     oneAction = menu.addAction("&One") 
     twoAction = menu.addAction("&Two") 
     self.connect(oneAction, SIGNAL("triggered()"), self.one) 
     self.connect(twoAction, SIGNAL("triggered()"), self.two) 
     ''' 
     if not self.message: 
      menu.addSeparator() 
      threeAction = menu.addAction("Thre&e") 
      self.connect(threeAction, SIGNAL("triggered()"), 
         self.three) 
     ''' 
     menu.exec_(event.globalPos()) 


    def one(self): 
     self.message = QString("Menu option One") 
     self.update() 


    def two(self): 
     self.message = QString("Menu option Two") 
     self.update() 


    def three(self): 
     self.message = QString("Menu option Three") 
     self.update() 


    def paintEvent(self, event): 
     painter = QPainter(self) 
     painter.setRenderHint(QPainter.TextAntialiasing) 
     #painter.drawText(self.rect(), Qt.AlignCenter, text) 
     # 

     #painter.setPen('red') 

     pen=painter.pen() 
     painter.setPen(QColor(255, 0, 0)) 

     painter.drawLine(self.xx-100,self.yy,self.xx+100,self.yy) 
     painter.drawLine(self.xx,self.yy-100,self.xx,self.yy+100) 
     self.update() 

    def mouseReleaseEvent(self, event): 
     if self.justDoubleClicked: 
      self.justDoubleClicked = False 
     else: 
      self.setMouseTracking(not self.hasMouseTracking()) 
      self.update() 


    def mouseMoveEvent(self, event):  
     self.xx=event.pos().x() 
     self.yy=event.pos().y() 
     self.update() 




class C_MPL(QWidget): 

    def __init__(self, parent = None): 
     # initialization of Qt MainWindow widget 
     super(C_MPL, self).__init__(parent) 
     #QtGui.QWidget.__init__(self, parent) 

     # instantiate a widget, it will be the main one 
     #self.main_widget = QtGui.QWidget(self) 
     #vbl = QtGui.QVBoxLayout(self.main_widget) 
     # set the canvas to the Matplotlib widget 
     self.canvas = C_MplCanvas() 

     # create a vertical box layout 
     self.vbl = QtGui.QVBoxLayout() 
     # add mpl widget to vertical box 
     self.vbl.addWidget(self.canvas) 
     # set the layout to th vertical box 
     self.setLayout(self.vbl) 




if __name__ == "__main__": 
    import sys 

    ''' 
    def valueChanged(a, b): 
     print a, b 
    ''' 
    app = QApplication(sys.argv) 
    form = C_MPL() 
    #form.connect(form, SIGNAL("valueChanged"), valueChanged) 
    form.setWindowTitle("C_MPL") 
    #form.move(0, 0) 
    form.show() 
    #form.resize(400, 400) 
    app.exec_() 

@bmu:那太好了,就像我现在want.And还有另一个问题:

cid0=self.mpl_connect('axes_enter_event', self.enter_axes) 
    cid1=self.mpl_connect('button_press_event', self.onpick) 
    cid2=self.mpl_connect('motion_notify_event', self.onmove) 
    cid3=self.mpl_connect('draw_event', self.clear) 
    cid4=self.mpl_connect('key_press_event',self.press) 

奇怪的是“key_press_event”不能triggerd但所有其他事件可以。出现这种情况:macosx后端会忽略多个mpl_connect()调用 https://github.com/matplotlib/matplotlib/pull/585, 但我认为这与我不一样。 我得到cid0,1,2,3,4这是不同的彼此

那么,任何想法可以分享?我一个很疯狂,现在..... 以下是我的代码,U可以测试它如果u有同样的问题:

import sys 
import platform 

from PyQt4 import QtGui, QtCore 
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas 
from matplotlib.figure import Figure 
import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.backends.backend_qt4 import NavigationToolbar2QT as NavigationToolbar 
import time 
from PyQt4.QtCore import * 
from PyQt4.QtGui import * 




#Just a test 

class MplCanvas(FigureCanvas): 

    def __init__(self): 

     # initialization of the canvas 
     self.fig=Figure() 
     FigureCanvas.__init__(self,self.fig) 



     self.ax = self.fig.add_axes([.15, .15, .75, .75]) 
     self.canvas = self.ax.figure.canvas  



     #my added 
     #self.ax = self.fig.add_axes([.15, .15, .75, .75]) 
     #cursor = C_Cursor(self.LvsT, useblit=True, color='red', linewidth=2) 



     x=np.arange(0,20,0.1) 

     self.ax.plot(x,x*x,'o') 
     self.ax.set_xlim(-2,2) 
     self.ax.set_ylim(-2,2) 

     self.visible = True 
     self.horizOn = True 
     self.vertOn = True 
     self.useblit = True 

     #if self.useblit: 
      #lineprops['animated'] = True 


     self.lineh = self.ax.axhline(self.ax.get_ybound()[0], visible=False) 
     self.linev = self.ax.axvline(self.ax.get_xbound()[0], visible=False) 

     self.background = None 
     self.needclear = False 

     self.count = 0 

     cid0=self.mpl_connect('axes_enter_event', self.enter_axes) 
     cid1=self.mpl_connect('button_press_event', self.onpick) 
     cid2=self.mpl_connect('motion_notify_event', self.onmove) 
     cid3=self.mpl_connect('draw_event', self.clear) 
     cid4=self.mpl_connect('key_press_event',self.press) 

     self.draw() 

    def clear(self, event): 
     'clear the cursor' 
     if self.useblit: 
      self.background = self.canvas.copy_from_bbox(self.ax.bbox) 
     self.linev.set_visible(False) 
     self.lineh.set_visible(False) 

    def onmove(self, event): 
     'on mouse motion draw the cursor if visible' 
     print("move") 
     if event.inaxes != self.ax: 
      self.linev.set_visible(False) 
      self.lineh.set_visible(False) 

      if self.needclear: 
       self.canvas.draw() 
       self.needclear = False 
      return 
     self.needclear = True 
     if not self.visible: return 
     self.linev.set_xdata((event.xdata, event.xdata)) 

     self.lineh.set_ydata((event.ydata, event.ydata)) 
     self.linev.set_visible(self.visible and self.vertOn) 
     self.lineh.set_visible(self.visible and self.horizOn) 


     self._update() 




    def _update(self): 

     if self.useblit: 
      if self.background is not None: 
       self.canvas.restore_region(self.background) 
      self.ax.draw_artist(self.linev) 
      self.ax.draw_artist(self.lineh) 
      self.canvas.blit(self.ax.bbox) 
     else: 

      self.canvas.draw_idle() 

     return False 

     # 



    def enter_axes(self,event): 

     print "Enter" 

    def onpick(self,event): 
     print "click" 
     print 'you pressed', event.canvas 

     a = np.arange(10) 
     print a 
     print self.count 

     fig = plt.figure() 
     ax = fig.add_subplot(111) 
     ax.plot(a)  
     fig.show() 

    def press(self,event): 
     print ('press', event.key) 
     self.fig.canvas.draw() 




class MplWidget(QtGui.QWidget): 
    def __init__(self, parent = None): 
     QtGui.QWidget.__init__(self, parent)   

     self.vbl = QtGui.QVBoxLayout() 
     self.canvas = MplCanvas() 
     self.vbl.addWidget(self.canvas) 
     self.setLayout(self.vbl) 




if __name__ == "__main__": 

    app = QApplication(sys.argv) 
    form = MplWidget() 
    form.show() 
    #form.resize(400, 400) 
    app.exec_() 

@all:韩国社交协会所有。我决定加入后,这个问题:

self.canvas.setFocusPolicy(Qt.ClickFocus) 
self.canvas.setFocus() 

也许这有点错误BCS我需要cavans明确地SETFOCUS,也许如果不是:) 细节ü可以检查https://github.com/matplotlib/matplotlib/issues/707

+1

你QT直接需要什么?我认为使用matplotlib [事件处理](http://matplotlib.sourceforge.net/users/event_handling.html#event-handling-and-picking)会更简单,尤其是'motion_notify_event'。 – bmu 2012-08-10 13:52:27

+0

mpl_connect听起来不错,我会试试看。 – tianli 2012-08-11 13:49:12

+0

嗨,sjwarner 我可以使用图上的mpl_connect从matplotlib.backends.backend_qt4agg,如果是的话,可以给我一个例子。我编写了一个脚本,但它没有工作:( – tianli 2012-08-12 08:18:28

的问题...你想改变光标在你的小部件上的样子?如果是的话,最简单的办法就是做完全删除了的paintEvent的,并添加到的setCursor您的init方法:

class C_MplCanvas(FigureCanva): 
    def __init__(self): 
     # setup code 
     ... 
     self.setCursor(Qt.CrossCursor) 

这会告诉Qt来使用十字光标只要鼠标移到特定的部件。这实际上会取代箭头(可能或不可能是你想要的)。如果这不是你想要的,我会建议你做一些你创建一个你想要的PNG图像的东西,创建一个子QLabel,并在你的mouseMoveEvent中移动子控件。

如果您需要更多的帮助,请帮助我知道。

+0

TKS。事实上,我想实现这个功能:cursor = Cursor(ax,useblit = True,color ='red',linewidth = 2) – tianli 2012-08-11 03:11:02

这里是一个使用matplotlib event handling的示例(但是我想知道是否真的有用第二个游标)。

import numpy as np 
import matplotlib.pyplot as plt 


class MouseCross(object): 

    def __init__(self, ax, **kwargs): 
     self.ax = ax 
     self.line, = self.ax.plot([0], [0], visible=False, **kwargs) 

    def show_cross(self, event): 
     if event.inaxes == self.ax: 
      self.line.set_data([event.xdata], [event.ydata]) 
      self.line.set_visible(True) 
     else: 
      self.line.set_visible(False) 
     plt.draw() 

if __name__ == '__main__': 
    fig, ax = plt.subplots() 
    ax.plot(np.random.random(100) * 10.0) 
    # note that not every "normal" matplotlib marker will work 
    # math symbols work fine 
    cross = MouseCross(ax, marker=r'$\bigoplus$', markersize=30, 
         color='red',) 
    fig.canvas.mpl_connect('motion_notify_event', cross.show_cross) 
    plt.tight_layout() 
    plt.show() 

screenshot