2011-11-21 13 views
13

Mam prostą aplikację, która uruchamia proces, który może trwać kilka minut przed zakończeniem. Próbuję więc podać użytkownikowi wskaźnik, że przetwarza on żądanie, na przykład zmienia kursor na klepsydrę.Jak zmienić kształt kursora za pomocą PyQt?

Ale nie mogę go uruchomić poprawnie. Wszystkie moje próby zakończyły się błędem lub nie przyniosły skutku. I wydaje się wywoływać niepoprawnie cursorshapes PyQt4.Qt.WaitCursor zwraca błąd, że moduł go nie zawiera.

Jaki jest prawidłowy sposób wskazania użytkownikowi, że proces jest uruchomiony?

Odpowiedz

34

myślę QApplication.setOverrideCursor jest to, czego szukasz: rozwiązanie

from PyQt4.QtCore import Qt 
from PyQt4.QtGui import QApplication 
... 
QApplication.setOverrideCursor(Qt.WaitCursor) 
# do lengthy process 
QApplication.restoreOverrideCursor() 
+0

Dzięki, że działa idealnie. – TimothyAWiseman

+0

Uwaga: Działa to w PyQt4. Jednak PySide 1.2.2 pod Linuxem (Ubuntu 16.10) mówi "Błąd X: BadCursor (nieprawidłowy parametr kursora) 6" "Główny kod operacji: 2 (X_ChangeWindowAttributes)" "Identyfikator zasobu: 0xa". Karmienie PySide setOverrideCursor (Qt.WaitCursor) zamiast setOverrideCursor (QCursor (Qt.WaitCursor)) działa - pomimo dokumentacji mówiącej, że QCursor() jest potrzebny. W niektórych okolicznościach występuje podobny błąd przywracania. Wygląda na to, że jest to znany błąd PySide. – Ubuntourist

+0

@Ubuntourist. Dzięki - mogę potwierdzić błąd w PySide. Klasa 'QCursor' ma konstruktor kopiowania, który pobiera wartość wyliczenia' Qt.CursorShape', więc nie jest konieczne używanie samego 'QCursor'. Przypuszczam, że tworzenie 'QCursor' po stronie Qt jest tym, co naprawia problem PySide. – ekhumoro

9

ekhumoro jest prawidłowe. To rozwiązanie jest modyfikacją ze względu na styl. Użyłem tego, co zrobił ekhumor, ale użyłem dekoratora Pythona.

from PyQt4.QtCore import Qt 
from PyQt4.QtGui import QApplication, QCursor, QMainWidget 

def waiting_effects(function): 
    def new_function(self): 
     QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) 
     try: 
      function(self) 
     except Exception as e: 
      raise e 
      print("Error {}".format(e.args[0])) 
     finally: 
      QApplication.restoreOverrideCursor() 
    return new_function 

Umieszczę dekorator na dowolnej metodzie, w której chciałbym, aby spinner był aktywny.

class MyWigdet(QMainWidget): 

    # ... 

    @waiting_effects 
    def doLengthyProcess(self): 
     # do lengthy process 
     pass 
+1

Dekorator to świetny pomysł, dzięki. Polecam wywołanie 'function (* args, ** kwargs)', zwracanie wartości zwracanej 'function' i zawijanie jej wywołania w bloku' try ... finally' dla jeszcze większej dobroci. Nie mogę tego powiedzieć w tym komentarzu, więc następnym razem spróbuję edytować twoje rozwiązanie. –

+1

Zmiana bloku try na 'return function (* args, ** kwargs)' może być przydatna, lub przynajmniej w moim przypadku. –

0

Lepiej w ten sposób:

def waiting_effects(function): 
    def new_function(*args, **kwargs): 
     QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) 
     try: 
      return function(*args, **kwargs) 
     except Exception as e: 
      raise e 
      print("Error {}".format(e.args[0])) 
     finally: 
      QApplication.restoreOverrideCursor() 
    return new_function 
7

Podczas odpowiedzi Camerona i David są idealne do ustawiania kursora oczekiwania na całej funkcji, uważam, że kierownik kontekst działa najlepiej na ustawienie kursora czekać na fragmenty kod:

from contextlib import contextmanager 
from PyQt4 import QtCore 
from PyQt4.QtGui import QApplication, QCursor 

@contextmanager 
def wait_cursor(): 
    try: 
     QApplication.setOverrideCursor(QCursor(QtCore.Qt.WaitCursor)) 
     yield 
    finally: 
     QApplication.restoreOverrideCursor() 

Następnie umieścić długiego kodu z procesu w bloku:

with wait_cursor(): 
    # do lengthy process 
    pass 
+0

Jest to najprostszy, najbardziej elegancki i wszechstronny – Schollii