PyQGIS-Skript mit Endlosschleife über die Tastatur stoppen?

12

Also habe ich ein Skript geschrieben, das in einem bestimmten Zeitintervall (alle 5 Sekunden mit time.sleep (5)) immer wieder mit einem "while True:" macht, was ich will. So weit so gut, ABER wenn ich damit aufhören will, kann ich es einfach nicht.

Ich habe Strg + C, Strg + Pause, Escape ausprobiert und meine Tastatur wird praktisch ignoriert. Die einzige Möglichkeit, dies zu stoppen, besteht darin, QGIS zu schließen. Irgendwelche Ideen? Wenn das Skript auf time.sleep (5) trifft, verzögert sich QGIS und friert 5 Sekunden lang ein, und ich kann beispielsweise die Ebene nicht schwenken, aber ich gehe davon aus, dass dies normal ist.

Hier ist mein Skript:

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.
quelle
Welche Bedingungen sollten einen "Exit" auslösen?
Nickves
1
Es gibt viele Möglichkeiten, einen No-Blocking-Prozess in qgis zu implementieren. Sie erhalten das Steuerelement, ohne es der Qt-Ereignisschleife zu überlassen. Ich schlage vor, Folgendes zu untersuchen: 1) Erstellen einer ereignisgesteuerten Architektur oder 2) Verwalten Ihres Prozesses in einem Python-Unterprozess oder auf einfache Weise) Erstellen eines Processing Toolbox-Skripts und ggf. Integrieren in Auswahl 2
Luigi Pirelli
3
Leute, vielleicht habe ich es falsch gesagt. Lassen Sie mich die Frage mit einem neuen Szenario umformulieren: Sie öffnen die Python-Konsole in QGIS, geben Folgendes ein: während 1: "a" drucken und die Eingabetaste drücken. Dann druckt es 'a' für immer und ewig. WIE STOPPEN SIE ES, OHNE QGIS ZU BEENDEN? Das ist die Frage und das eigentliche Problem
Stelios M
Dies ist möglicherweise eher eine allgemeine Python-Frage, sodass Sie möglicherweise mehr Glück haben, eine Antwort auf StackOverflow zu erhalten.
Martin
@ Martin wird es tun. Aber es ist eine ziemlich einfache Frage, und es wundert mich, dass QGIS-Chefentwickler nicht an das Endlosschleifenszenario in ihrer Python-Konsole gedacht haben. Wenn Sie ausführen, während 1: 'a' in Ihrem Gerät drucken, können Sie es mit der Tastatur stoppen oder ist es die Schuld meines Systems?
Stelios M

Antworten:

2

QGIS bietet Ihnen die volle Leistung von Python. Dies eröffnet erstaunliche Möglichkeiten, birgt aber auch potenzielle Fallstricke. Dies kann dazu führen, dass QGIS nicht mehr reagiert, einfriert oder sogar abstürzt. Benutze es weise!

In Ihrem Fall sollten Sie QGIS lieber etwas anderes tun lassen (z. B. Ihre Tastenanschläge oder Tastendrücke abhören), anstatt den Haupt-Thread für 5 Sekunden in den Ruhezustand zu versetzen, und ein Timer-Ereignis an die Hauptereignisschleife senden, an die die Steuerung zurückgegeben wird Ihr Skript 5 Sekunden später.

Sie können das Beispiel aus dieser Antwort als guten Ausgangspunkt verwenden. Um es zu stoppen, verbinden Sie einfach ein Ereignis mit dem stop()Steckplatz des Timers.

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

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

someButton.clicked.connect(timer.stop)

Oder rufen Sie es einfach manuell von der Konsole aus auf, wenn Sie glauben, dass es Zeit ist, es zu stoppen

timer.stop()

Sie können auch einen eventFilter () im Hauptfenster installieren , um bei Bedarf Tastendrücke abzufangen.

Matthias Kuhn
quelle
0

Als Workaround können Sie ein QT-Widget mit einer Abbrechen-Schaltfläche verwenden.

Es ist ein bisschen rau, aber hier ist das Widget-Skript, das ich verwendet habe:

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

Dies kann in Ihr pyQgis-Skript importiert werden (Sie müssen das Verzeichnis an sys.path anhängen) und dann können Sie die laufende Variable verwenden, um Ihre while-Schleife zu stoppen:

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

import cancel_widget

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

while btn.running:
    ...
user6072577
quelle