Arrêter le script PyQGIS qui a une boucle infinie, à l'aide du clavier?

12

J'ai donc écrit un script qui fait ce que je veux encore et encore en utilisant un "while True:" dans un certain intervalle de temps (toutes les 5 secondes en utilisant time.sleep (5)). Jusqu'ici tout va bien, MAIS quand je veux l'arrêter, je ne peux pas.

J'ai essayé Control + C, Control + Break, Escape et il ignore pratiquement mon clavier. La seule façon de l'arrêter est de fermer QGIS. Des idées? De plus, lorsque le script frappe time.sleep (5), QGIS se retire et se fige pendant 5 secondes et je ne peux pas, par exemple, effectuer un panoramique sur la couche, mais je suppose que c'est normal.

Voici mon script:

from PyQt4.QtGui import *
from PyQt4.QtCore import *
from qgis.core import *
from qgis.utils import iface
import time


while True: 

    def change_color():
        active_layer = iface.activeLayer()
        pipeline=[]
        txt=open('C:/users/stelios/desktop/project/Sensor.txt','r')
        for line in txt.readlines():
            pipeline.append(line.split())
        print pipeline 
        pipeline2=[]
        for label,color in pipeline:
            if "0" in color:
                pipeline2.append([label,"green"])
            else:
                pipeline2.append([label,"red"])

        print pipeline2
        elatomatikoi=""
        categories=[]

        for label,color in pipeline2:
            if 'red' in color:
                elatomatikoi=elatomatikoi + label+","
            symbol = QgsSymbolV2.defaultSymbol(active_layer.geometryType())
            symbol.setColor(QColor(color))
            category = QgsRendererCategoryV2(int(label), symbol, label)
            categories.append(category)

        expression = 'id' 
        renderer = QgsCategorizedSymbolRendererV2(expression, categories)
        active_layer.setRendererV2(renderer)
        active_layer.setCacheImage(None)
        iface.mapCanvas().refresh()
        iface.legendInterface().refreshLayerSymbology(active_layer)
        elatomatikoi= elatomatikoi[:-1]

        for label,color in pipeline2:
            if 'red' in color:
                QMessageBox.critical(None,"Warning",("Leakage at pipe(s):%s\nCheck Pipeline status " %elatomatikoi))
                break
        txt.close()

    change_color()
    time.sleep(5)
Stelios M
la source
Quelles sont les conditions qui devraient déclencher une «sortie»?
nickves
1
il existe de nombreuses façons d'implémenter un processus sans blocage dans qgis. Vous obtenez le contrôle sans le laisser à la boucle d'événements Qt. Je suggère d'explorer: 1) créer une architecture événementielle ou 2) gérer votre processus dans un sous-processus python ou de manière simple) créer un script de boîte à outils de traitement et, si nécessaire, l'intégrer avec le choix 2
Luigi Pirelli
3
Les gars, je l'ai peut-être mal dit. Permettez-moi de reformuler la question avec un nouveau scénario: vous ouvrez la console Python dans QGIS, vous tapez: tandis que 1: imprimez "a" et vous appuyez sur Entrée. Ensuite, il imprime «a» pour toujours et à jamais. COMMENT L'ARRÊTER SANS QUITTER QGIS? Telle est la question et le vrai problème
Stelios M
Cela pourrait être plus une question générale sur Python, donc vous auriez plus de chance d'obtenir une réponse sur StackOverflow.
Martin
@Martin fera l'affaire. Mais c'est une question assez simple et cela m'étonne que les développeurs en chef de QGIS n'aient pas pensé au scénario de boucle infinie dans leur console python. Si vous exécutez en 1: imprimez 'a' sur votre machine, pouvez-vous l'arrêter avec le clavier ou est-ce la faute de mon système?
Stelios M

Réponses:

2

QGIS vous offre toute la puissance de python. Cela ouvre des possibilités incroyables mais comporte également des pièges potentiels. Ce qui peut rendre QGIS insensible, le geler ou même le planter. Fais-en bon usage!

Dans votre cas, au lieu d'envoyer le thread principal en veille pendant 5 secondes, vous feriez mieux de laisser QGIS faire autre chose (comme écouter vos frappes au clavier ou appuyer sur les boutons) et publier un événement de minuterie dans la boucle d'événement principal qui rendra le contrôle à votre script 5 secondes plus tard.

Vous pouvez utiliser l'exemple de cette réponse comme un bon point de départ. Pour l'arrêter, connectez simplement un événement à l' stop()emplacement du minuteur.

def change_color():
    print('I am now red')

timer = QTimer()
timer.timeout.connect(change_color)
timer.start(5000)

someButton.clicked.connect(timer.stop)

Ou appelez-le simplement manuellement depuis la console lorsque vous pensez qu'il est temps de l'arrêter

timer.stop()

Vous pouvez également installer un eventFilter () sur la fenêtre principale pour intercepter les pressions de touches si vous en avez besoin.

Matthias Kuhn
la source
0

Pour contourner ce problème, vous pouvez utiliser un widget QT avec un bouton d'annulation.

C'est un peu difficile, mais voici le script de widget que j'ai utilisé:

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_Form(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.setupUi(self)
        self.running = True
    def setupUi(self, Form):
        Form.setObjectName(_fromUtf8("Form"))
        Form.resize(100, 100)
        self.horizontalLayout_3 = QtGui.QHBoxLayout(Form)
        self.horizontalLayout_3.setObjectName(_fromUtf8("horizontalLayout_3"))
        self.horizontalLayout = QtGui.QHBoxLayout()
        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
        self.Cancel_btn = QtGui.QPushButton(Form)
        self.Cancel_btn.setMinimumSize(QtCore.QSize(0, 0))
        self.Cancel_btn.setMaximumSize(QtCore.QSize(425, 27))
        self.Cancel_btn.setObjectName(_fromUtf8("Cancel_btn"))
        self.horizontalLayout.addWidget(self.Cancel_btn)
        self.horizontalLayout_3.addLayout(self.horizontalLayout)
        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        Form.setWindowTitle(_translate("Form", "Cancel", None))
        self.Cancel_btn.setText(_translate("Form", "Cancel", None))
        self.Cancel_btn.clicked.connect(self.Cancel)


    def Cancel(self):
        self.running = False

Cela peut être importé dans votre script pyQgis (vous devrez ajouter le répertoire à sys.path) puis vous pouvez utiliser la variable en cours d'exécution pour arrêter votre boucle while:

import sys
sys.path.append("path/to/cancel_widget")

import cancel_widget

btn = cancel_widget.Ui_Form()
btn.show()

while btn.running:
    ...
user6072577
la source