- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在构建一个运行生产者( worker )的小型 GUI 应用程序,该 GUI 按需使用输出并绘制它(使用 pyqtgraph)。
由于生产者是一个阻塞函数(需要一段时间才能运行),我(据说)将它移到了自己的线程中。
当从生产者调用 QThread.currentThreadId() 时,它输出与主 GUI 线程相同的数字。因此,首先执行 worker,然后执行所有绘图函数调用(因为它们在同一个线程的事件队列中排队)。我该如何解决这个问题?
部分运行示例:
gui thread id 140665453623104
worker thread id: 140665453623104
这是我的完整代码:
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import pyqtSignal
import pyqtgraph as pg
import numpy as np
from functools import partial
from Queue import Queue
import math
import sys
import time
class Worker(QtCore.QObject):
termino = pyqtSignal()
def __init__(self, q=None, parent=None):
super(Worker, self).__init__(parent)
self.q = q
def run(self, m=30000):
print('worker thread id: {}'.format(QtCore.QThread.currentThreadId()))
for x in xrange(m):
#y = math.sin(x)
y = x**2
time.sleep(0.001) # Weird, plotting stops if this is not present...
self.q.put((x,y,y))
print('Worker finished')
self.termino.emit()
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.q = Queue()
self.termino = False
self.worker = Worker(self.q)
self.workerThread = None
self.btn = QtGui.QPushButton('Start worker')
self.pw = pg.PlotWidget(self)
pi = self.pw.getPlotItem()
pi.enableAutoRange('x', True)
pi.enableAutoRange('y', True)
self.ge1 = pi.plot(pen='y')
self.xs = []
self.ys = []
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.pw)
layout.addWidget(self.btn)
self.resize(400, 400)
def run(self):
self.workerThread = QtCore.QThread()
self.worker.moveToThread(self.workerThread)
self.worker.termino.connect(self.setTermino)
# moveToThread doesn't work here
self.btn.clicked.connect(partial(self.worker.run, 30000))
# moveToThread will work here
# assume def worker.run(self): instead of def worker.run(self, m=30000)
# self.btn.clicked.connect(self.worker.run)
self.btn.clicked.connect(self.graficar)
self.workerThread.start()
self.show()
def setTermino(self):
self.termino = True
def graficar(self):
if not self.q.empty():
e1,e2,ciclos = self.q.get()
self.xs.append(ciclos)
self.ys.append(e1)
self.ge1.setData(y=self.ys, x=self.xs)
if not self.termino:
QtCore.QTimer.singleShot(1, self.graficar)
if __name__ == '__main__':
app = QtGui.QApplication([])
window = MainWindow()
QtCore.QTimer.singleShot(0, window.run);
sys.exit(app.exec_())
最佳答案
问题是 Qt 尝试根据 slot
存在于哪个线程来选择连接类型(当您调用 signal.connect(slot)
时)。因为您已使用 partial
将插槽包装在 QThread 中,您要连接的插槽驻留在 MainThread(GUI 线程)中。您可以覆盖连接类型(作为 connect()
的第二个参数,但这无济于事,因为 partial
创建的方法将始终存在于 MainThread 中,因此将连接类型设置为 Qt.QueuedConnection
没有帮助。
我能看到的解决这个问题的唯一方法是设置一个中继信号,其唯一目的是有效地将没有参数的发射信号(例如来自按钮的点击信号)更改为具有一个参数的信号(您的 m
参数)。这样你就不需要用 partial()
包装 QThread 中的插槽。
代码如下。我在主窗口类中创建了一个带有一个名为“relay”的参数(int)的信号。按钮 clicked
信号连接到主窗口类中的一个方法,这个方法有一行代码发出我创建的自定义信号。您可以扩展此方法 (relay_signal()
) 以获取整数作为 m
(在本例中为 500)传递给 QThread,从任何您喜欢的地方!
代码如下:
from functools import partial
from Queue import Queue
import math
import sys
import time
class Worker(QtCore.QObject):
termino = pyqtSignal()
def __init__(self, q=None, parent=None):
super(Worker, self).__init__(parent)
self.q = q
def run(self, m=30000):
print('worker thread id: {}'.format(QtCore.QThread.currentThreadId()))
for x in xrange(m):
#y = math.sin(x)
y = x**2
#time.sleep(0.001) # Weird, plotting stops if this is not present...
self.q.put((x,y,y))
print('Worker finished')
self.termino.emit()
class MainWindow(QtGui.QWidget):
relay = pyqtSignal(int)
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.q = Queue()
self.termino = False
self.worker = Worker(self.q)
self.workerThread = None
self.btn = QtGui.QPushButton('Start worker')
self.pw = pg.PlotWidget(self)
pi = self.pw.getPlotItem()
pi.enableAutoRange('x', True)
pi.enableAutoRange('y', True)
self.ge1 = pi.plot(pen='y')
self.xs = []
self.ys = []
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.pw)
layout.addWidget(self.btn)
self.resize(400, 400)
def run(self):
self.workerThread = QtCore.QThread()
self.worker.termino.connect(self.setTermino)
self.worker.moveToThread(self.workerThread)
# moveToThread doesn't work here
# self.btn.clicked.connect(partial(self.worker.run, 30000))
# moveToThread will work here
# assume def worker.run(self): instead of def worker.run(self, m=30000)
#self.btn.clicked.connect(self.worker.run)
self.relay.connect(self.worker.run)
self.btn.clicked.connect(self.relay_signal)
self.btn.clicked.connect(self.graficar)
self.workerThread.start()
self.show()
def relay_signal(self):
self.relay.emit(500)
def setTermino(self):
self.termino = True
def graficar(self):
if not self.q.empty():
e1,e2,ciclos = self.q.get()
self.xs.append(ciclos)
self.ys.append(e1)
self.ge1.setData(y=self.ys, x=self.xs)
if not self.termino or not self.q.empty():
QtCore.QTimer.singleShot(1, self.graficar)
if __name__ == '__main__':
app = QtGui.QApplication([])
window = MainWindow()
QtCore.QTimer.singleShot(0, window.run);
sys.exit(app.exec_())
我还修改了 graficar
方法以在队列中仍有数据时继续绘图(即使在线程终止后)。我认为这可能就是您需要 QThread 中的 time.sleep
的原因,它现在也被删除了。
另外关于您在代码中关于放置 moveToThread
的位置的评论,现在它的位置是正确的。它应该在将 QThread 槽连接到信号的调用之前,其原因在这个堆栈溢出帖子中讨论:PyQt: Connecting a signal to a slot to start a background operation
关于python - PyQt:将 partial() 用于插槽时,moveToThread 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23317195/
我的 node.js 应用程序中有一个 Handlebars / mustache 布局文件,如下所示: {{> header}} {{> navbar}} {{{body}}} {{> footer
我的 node.js 应用程序中有一个 Handlebars / mustache 布局文件,如下所示: {{> header}} {{> navbar}} {{{body}}} {{> footer
我有一个主文件,home.html.erb在里面我渲染了大约 15 个部分。这些部分非常小,我想知道是否可以将它们全部放在一个文件中,然后部分地呈现部分部分。 例如,我会制作 _big_partial
在下面的 TypeScript 代码片段中,我需要从一个对象分配给另一个对象,其中它们都是 Partial .在这里,我的直觉是 typescript 应该能够理解正在发生的事情,因为在第 (B) 行
在我的应用程序中,用户通过 AJAX 呈现 _show.html.erb 部分。我现在想要的是在该部分中有一个按钮,单击时将其关闭。 我遇到的问题:如果我将按钮放在部分之外,一切都会正常 - 我可以
我有人造 curry Programming Clojure书。 user=> (defn faux-curry [& args] (apply partial partial args)) #'us
我在尝试实现 AJAX 时遇到了一些困难,其中“link_to” View 被渲染,并且在该 View 中我有另一个 AJAX 调用。 我有菜单侧边栏,其中有这样的内容: "> 在applicatio
我是 asp.net MVC 的新手,请告诉我应该在何处使用局部 View 以及在何处渲染局部 View 。提前致谢 最佳答案 This link might help. Html.RenderPar
我在下拉菜单的 Onchange 事件上更新 DIV 元素。而我正在使用partial 来替换DIV 中的内容。这是我的 ajax 调用: var cach_this = this;
我正在使用 UI-Router AngularJS 的框架,以呈现嵌套的部分。我在渲染父部分及其子部分时遇到问题。这是我的代码: window.app.config(['$stateProvider'
是否存在包含可从Partial中访问的Partial名称的变量?。在_foo.haml中:
我有/views/layouts/_navigation.html.erb,其中生成了部分用户配置文件:
我有一组我想用部分渲染的项目: @items = ['a','b','c'] @items, :partial => 'item' %> 我想用升序对元素进行编号。所以输出应该是: 3: a 2:
尝试使用 .Netcore 制作 Web 应用程序 当我运行该应用程序时,出现此错误。帮我 这不是错误而是警告。但帮我解决 我在下面添加了我的代码 @ViewBag.Title
标题有点令人困惑。 我正在尝试实现一些类似 reddit 的评论系统。这样您就可以查看 Post 并向其添加多态的 Comment 。或者,评论另一条评论。 我的观点是这样的: Post:
我需要编写一个算法来引导机器人穿过“迷宫”(一个有起点、目标、空白区域和不可穿越的空间或“墙壁”的矩形网格)。它可以在任何基本方向(N、NW、W、SW、S、SE、E、NE)上移动,每次移动的成本不变。
?sort指出partial参数可以是NULL或用于部分排序的索引向量。 我试过了: x <- c(1,3,5,2,4,6,7,9,8,10) sort(x) ## [1] 1 2 3 4
MVC4,单击下拉项时,JavaScript 函数在 View 的“脚本”部分中调用。函数对 Controller Action 进行ajax调用,返回Json数据。我需要将一些返回值传递给 Html
我正在使用 Automapper 将数据从 objectA 传输到 objectB classe ObjectA { string Title; string Summary; } cla
我想使用 TortoiseSVN 提交文件的一部分,有什么方法可以做到这一点吗? 我将举一个例子来更清楚地说明我为什么要这样做。 我有一个文件,其中包含一些在构建过程中被替换的定义,如下所示: #de
我是一名优秀的程序员,十分优秀!