Остановка сценария PyQGIS с бесконечным циклом с использованием клавиатуры?

12

Поэтому я написал скрипт, который делает то, что я хочу, снова и снова, используя «while True:» в определенный промежуток времени (каждые 5 секунд, используя time.sleep (5)). Пока все хорошо, НО, когда я хочу остановить это, я просто не могу.

Я пробовал Control + C, Control + Break, Escape, и он практически игнорирует мою клавиатуру. Единственный способ остановить это - закрыть QGIS. Любые идеи? Кроме того, когда скрипт запускает time.sleep (5), QGIS отстает и зависает на 5 секунд, и я не могу, например, панорамировать слой, но я предполагаю, что это нормально.

Вот мой сценарий:

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)
Стелиос М
источник
Какие условия должны вызывать «выход»?
nickves
1
Есть много способов реализовать процесс без блокировки в qgis. Вы получаете элемент управления, не оставляя его в цикле событий Qt. Я предлагаю изучить: 1) создать управляемую событиями архитектуру или 2) управлять своим процессом в подпроцессе python или простым способом) создать сценарий Processing Toolbox и при необходимости интегрировать с выбором 2
Луиджи Пирелли,
3
Ребята, может быть, я сказал это неправильно. Позвольте мне перефразировать вопрос новым сценарием: вы открываете консоль Python в QGIS, вводите: while 1: печатаете «a» и нажимаете ввод. Затем он печатает «а» во веки веков. КАК ВЫ ОСТАНОВИТЕ ЭТО БЕЗ ВЫХОДА ИЗ QGIS? Вот в чем вопрос и в чем проблема
Stelios M
Это может быть больше общего вопроса Python, так что вам лучше повезет получить ответ на StackOverflow.
Мартин
@ Мартин будет делать. Но это довольно прямой вопрос, и меня удивляет, что разработчики QGIS не думали о сценарии бесконечного цикла в своей консоли Python. Если вы выполните «1»: напечатайте «a» на своем компьютере, можете ли вы остановить его с помощью клавиатуры или это ошибка моей системы?
Стелиос М

Ответы:

2

QGIS предлагает вам всю мощь Python. Это открывает удивительные возможности, но также сопряжено с потенциальными подводными камнями. Что может привести к тому, что QGIS перестанет отвечать на запросы, заморозить или даже вызвать сбой. Использовать его с умом!

В вашем случае вместо того, чтобы отправлять основной поток в спящий режим на 5 секунд, лучше позволить QGIS делать что-то еще (например, прослушивание нажатий клавиш или нажатий кнопок) и публиковать событие таймера в цикле основного события, которое вернет элемент управления обратно. ваш сценарий 5 секунд спустя.

Вы можете использовать пример из этого ответа в качестве хорошей отправной точки. Чтобы остановить это, просто подключите какое-то событие к stop()слоту таймера.

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

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

someButton.clicked.connect(timer.stop)

Или просто вызовите его вручную с консоли, когда вы думаете, что пришло время остановить его

timer.stop()

Вы также можете установить eventFilter () в главном окне, чтобы перехватывать нажатия клавиш, если вам это нужно.

Матиас Кун
источник
0

В качестве обходного пути вы можете использовать виджет QT с кнопкой отмены.

Это немного грубо, но вот скрипт виджета, который я использовал:

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

Это может быть импортировано в ваш скрипт pyQgis (вам нужно добавить каталог в sys.path), а затем вы можете использовать переменную running, чтобы остановить цикл while:

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

import cancel_widget

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

while btn.running:
    ...
user6072577
источник