关闭窗口后方法仍在运行

Posted

技术标签:

【中文标题】关闭窗口后方法仍在运行【英文标题】:Method is still running after closing window 【发布时间】:2021-10-21 00:58:46 【问题描述】:

我无法理解窗口对象的工作原理。我通过 matplotlib 在辅助窗口上有一个实时绘图。该图每秒使用新的计算值更新。 我期望的是每当我关闭第二个窗口时停止运行并在我重新打开它时重新启动的方法。当我关闭第二个窗口时,我可以重置数组值,但如所示,这种计算值的方法仍在运行。

这是我的代码(最初使用传感器,我将其修改为生成随机数):

from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout
import sys
import random
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure


# The main window 
class Window(QWidget):
    def __init__(self):
        super().__init__()
 
        self.setGeometry(200,200, 400,300)
        self.setWindowTitle('Test')
        self.demo = None
        
        self.create_buttons()
        
    def create_buttons(self):
        btn1 = QPushButton('Open window', self)
        btn1.setGeometry(100,100, 100,100)
        btn1.clicked.connect(self.open_w)
        
    def open_w(self):
        if self.demo is None:
            self.demo = AppDemo()
        self.demo.show()
        
# Second window, where I plot the data
class AppDemo(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(650, 500)
        self.plotwidget = QWidget(self)
        self.chart = Matplotlibwidget()
        self.chart.plot_widget(self.plotwidget, self.chart)
        
    def closeEvent(self, event):
        event.accept()
        func.start_lists()
        print('Window closed')
        
# My widget for my graph        
class Matplotlibwidget(FigureCanvas):
    def __init__(self, parent=None):
        fig = Figure()
        self.axes = fig.add_subplot(111)
        
        FigureCanvas.__init__(self, fig)
        self.setParent(parent)
        FigureCanvas.updateGeometry(self)      
    
    def plot_widget(self, canvasWidget, graph):
        self.layoutvertical = QVBoxLayout(canvasWidget)
        self.layoutvertical.addWidget(graph)        
        timer = QtCore.QTimer(self)
        timer.timeout.connect(self.plotting)
        timer.start(1000)
              
    def plotting(self):
        self.y = func.calculate()
        func.appends(self.y)
        self.axes.cla()
        self.axes.plot(func.x, func.y)
        self.draw()

# This is a generic class I use to calculate the data, originally this is a class for my sensor
class FuncTime ():
    def __init__(self):
        self.start_lists()
         
    def start_lists(self):
        self.x, self.y = [0], [1]
        
    def calculate(self):
        return self.y[-1] + self.y[-1] * random.uniform(-0.1, 0.1)
        
    def appends(self, y):
        print(self.x[-1], ', ', self.y[-1])
        self.x.append(self.x[-1] + 1)
        self.y.append(y)

  
app = QApplication(sys.argv)
func = FuncTime()
window = Window()
window.show()
sys.exit(app.exec_())

【问题讨论】:

你永远不会告诉计时器停止,你关闭窗口的事实是无关紧要的。您也没有创建对计时器的任何持久引用(这是您停止它所需要的)。更改为self.timer = ...,然后在closeEvent() 中使用self.chart.timer.stop()。或者,在AppDemo 中使用self.setAttribute(Qt.WA_DeleteOnClose) 【参考方案1】:

窗口关闭并不意味着定时器停止,你必须使用QTimer的stop方法来实现它。

from functools import cached_property
import random
import sys

from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure


class Window(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(200, 200, 400, 300)
        self.setWindowTitle("Test")
        self.create_buttons()

    @cached_property
    def demo(self):
        return AppDemo()

    def create_buttons(self):
        btn1 = QPushButton("Open window", self)
        btn1.setGeometry(100, 100, 100, 100)
        btn1.clicked.connect(self.open_w)

    def open_w(self):
        self.demo.chart.start()
        self.demo.show()


class AppDemo(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(650, 500)

        self.chart = Matplotlibwidget()

        lay = QVBoxLayout(self)
        lay.addWidget(self.chart)

    def closeEvent(self, event):
        super().closeEvent(event)
        self.chart.stop()


class Matplotlibwidget(FigureCanvas):
    def __init__(self, parent=None):
        fig = Figure()
        self.axes = fig.add_subplot(111)
        FigureCanvas.__init__(self, fig)
        self.setParent(parent)
        self.updateGeometry()

    @cached_property
    def timer(self):
        return QTimer(interval=1000, timeout=self.handle_timeout)

    @cached_property
    def func_time(self):
        return FuncTime()

    def start(self):
        self.timer.start()

    def stop(self):
        self.timer.stop()
        self.func_time.reset()

    def handle_timeout(self):
        self.plotting()

    def plotting(self):
        self.y = self.func_time.calculate()
        self.func_time.appends(self.y)
        self.axes.cla()
        self.axes.plot(self.func_time.x, self.func_time.y)
        self.draw()


class FuncTime:
    def __init__(self):
        self.reset()

    def reset(self):
        self.x, self.y = [0], [1]

    def calculate(self):
        return self.y[-1] + self.y[-1] * random.uniform(-0.1, 0.1)

    def appends(self, y):
        print(self.x[-1], ", ", self.y[-1])
        self.x.append(self.x[-1] + 1)
        self.y.append(y)


app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

【讨论】:

非常感谢@eyllanesc,现在我明白了!并感谢您为我提供原始帖子。尝试放置一个更简单的代码版本有助于我理解其他一些事情。非常感谢!

以上是关于关闭窗口后方法仍在运行的主要内容,如果未能解决你的问题,请参考以下文章

如何在Mac上关闭应用程序?

关闭 QMainWindow 的正确方法

最简单的让Python程序运行完后命令行窗口(cmd窗口)不自动关闭的方法

求教:运行bat文件后如何让cmd窗口自动关闭?

Qt 应用程序在关闭所有窗口后仍保留在内存中

Linux使用screen实现关闭ssh连接的情况下,让程序继续在后台运行