【发布时间】:2016-04-28 06:13:23
【问题描述】:
我有一个 PyQt gui,我使用上下文菜单操作来执行一个功能。这个函数启动了一个 matplotlib 交互,我使用鼠标在图像上绘制。
问题是,当我通过 PyQt 上下文菜单操作 plt.show(block=True) 调用此函数时,不会阻止该线程上的执行,并且我无法与 matplotlib 窗口进行交互。
代码中发生的或多或少看起来像这样。当我右键单击 PyQt 小部件中的一个项目时,我会得到一个上下文菜单:
@QtCore.pyqtSlot(QtCore.QModelIndex, QtCore.QPoint)
def on_contextMenuClicked(widget, qtindex, pos):
menu = QtGui.QMenu(widget)
shortcut = QtGui.QKeySequence(0)
action = menu.addAction('edit mask', edit_mask_func, shortcut)
menu.exec_(widget.mapToGlobal(pos))
然后,当我单击编辑掩码函数时,它会调用此函数:
import matplotlib.pyplot as plt
import numpy as np
def edit_mask_func():
# code to start a matplotlib interaction
plt.ion()
fig = plt.figure(1)
ax = plt.subplot(111)
imgOver = np.zeros(img.shape, np.uint8) + 255
ax.imshow(img, interpolation='nearest', alpha=1)
ax.imshow(imgOver, interpolation='nearest', alpha=0.6)
ax.grid(False)
# This code handles the matplotlib interactive stuff
# like setting up callbacks
# eg: fig.canvas.mpl_connect('motion_notify_event', on_move)
# and doing blit stuff.
pntr = Painter(fig, ax, imgOver)
plt.title('Click on the image to draw. exit to finish')
# THIS SHOULD BLOCK, BUT IT DOES NOT IF A CALLED BY
# QT INSTEAD OF THE MAIN THREAD
plt.show(block=True)
return pntr.img
如果我从主线程调用edit_mask_func,它工作得很好。如果我通过 PyQt 线程调用该函数,这似乎只是一个问题。
可以说明的是,如果我尝试通过输入 raw_input / input 调用来强制程序在那里阻塞,我会在 stdout 中得到这个:
>>> input('hack to block... press enter when done')
QCoreApplication::exec: The event loop is already running
hack to block... press enter when doneQCoreApplication::exec: The event loop is already running
最终,我需要使用回调系统来集成这种交互,但我希望我现在可以做一些快速而肮脏的事情。有什么方法可以在不编写回调的情况下轻松做到这一点?
我目前正在运行 matplotlib_version 1.5.0 和 PyQt4_version 4.10.4
【问题讨论】:
-
您的代码有很多不清楚的地方,但看起来您正在从辅助线程进行与 GUI 相关的调用。 PyQt(matplotlib 使用)不是线程安全的,如果你继续沿着这条路走,你会得到段错误。如果您需要线程,请确保所有与 GUI 相关的代码都在主线程中执行,方法是从连接到主线程中的插槽的辅助线程发出信号。
标签: python multithreading matplotlib pyqt pyqt4