如何绘制跟随鼠标光标的十字?
Posted
技术标签:
【中文标题】如何绘制跟随鼠标光标的十字?【英文标题】:How can I draw a cross which follows my mouse cursor? 【发布时间】:2012-08-10 08:35:48 【问题描述】:我想在我的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:太好了,就像我想要的那样。现在还有另一个问题:
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”不能被触发,但所有其他事件都可以。有一个案例:macosx 后端忽略多个 mpl_connect() 调用 https://github.com/matplotlib/matplotlib/pull/585, 但我认为这与我不同。 我得到了 cid0,1,2,3,4,它们彼此不同
那么,有什么想法可以分享吗?我现在很疯狂...... 以下是我的代码,如果你有同样的问题,你可以测试它:
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:Tks 全部。添加后我解决了这个问题:
self.canvas.setFocusPolicy( Qt.ClickFocus )
self.canvas.setFocus()
也许这是一个小错误,因为我需要明确地把注意力集中在 cavans 上,如果不是的话,也许:) 详情可以查看https://github.com/matplotlib/matplotlib/issues/707
【问题讨论】:
直接需要qt吗?我认为使用 matplotlib event handling 会更简单,尤其是motion_notify_event
。
mpl_connect 听起来不错,我会试试的。
嗨,sjwarner 我可以在 FigureCanvas 中使用 mpl_connect ,其中 matplotlib.backends.backend_qt4agg ,如果可以,你能给我一个例子吗?我编写了一个脚本,但它不起作用。:(
嗨天丽,我收到了你的评论。如果你想对用户发表评论,你应该使用@username。
谢谢。@bmu。我已经解决了这个问题。但我非常困惑。现在是 'key_press_event' 不能被触发,但是 'motion_notify_event' 可以。为什么?????它看起来就像一个幽灵,我现在疯了,OOPs self.mpl_connect('axes_enter_event', self.enter_axes) self.mpl_connect('button_press_event', self.onpick) self.mpl_connect('motion_notify_event', self.onmove) self .mpl_connect('draw_event', self.clear) self.mpl_connect('key_press_event',self.press)
【参考方案1】:
这是一个使用 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()
【讨论】:
【参考方案2】:问题...您是否要更改光标在小部件上的外观?如果是这样,最简单的方法是完全摆脱 paintEvent,并将 setCursor 添加到您的 init 方法中:
class C_MplCanvas(FigureCanva):
def __init__( self ):
# setup code
...
self.setCursor(Qt.CrossCursor)
这将告诉 Qt 在鼠标悬停在特定小部件上时使用交叉光标。这实际上将替换箭头(可能是也可能不是您想要的)。如果这不是您想要的,我建议您创建一个您想要的 PNG 图像,创建一个子 QLabel,然后在 mouseMoveEvent 中移动子小部件。
如果您需要更多关于该问题的帮助,请知道。
【讨论】:
Tks.其实我想实现的功能是这样的:cursor = Cursor(ax, useblit=True, color='red', linewidth=2)以上是关于如何绘制跟随鼠标光标的十字?的主要内容,如果未能解决你的问题,请参考以下文章
如何将鼠标光标设置为在 GtkDrawingArea 上交叉?