Topic: blocco gui  (Letto 1430 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline absolom

  • python habilis
  • **
  • Post: 68
  • Punti reputazione: 0
    • Mostra profilo
blocco gui
« il: Novembre 17, 2010, 12:14 »
Salve a tutti!

ho scritto una piccola applicazione che riempie una coda di  "cose da fare", e appena conclusa questa operazione, avvia un ciclo che dura fintanto che questa coda non viene svuotata. Pilotando un hardware esterno, quest'ultima operazione può richiedere parecchi minuti prima di essere completata!

Volevo creare una gui, semplicissima, una finestra con un treeWidget che ogni volta che un operazione viene eseguita, mi aggiunge un nuovo elemento nel treeWidget stampandomi i dati ottenuti...

Il fatto è che la GUI dopo poco, si blocca... diventa tutta scura (sono su una ubuntu)... credo che il problema sia il fatto che la gui alla fine è un loop, e l'applicazione che svuota la coda è anch'essa un loop... qualcuno ha avuto problemi simili?

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: blocco gui
« Risposta #1 il: Novembre 17, 2010, 13:02 »
Tutti quelli che scrivono applicazioni con GUI.
E la soluzione e' progettare l'applicazione per funzionare con il runloop della libreria usata; in particolare di fatto ti metti a lavorare in modo asincrono ed event-driven.

Offline absolom

  • python habilis
  • **
  • Post: 68
  • Punti reputazione: 0
    • Mostra profilo
Re: blocco gui
« Risposta #2 il: Novembre 17, 2010, 13:34 »
ciao riko,

integrare l'applicazione del runloop di qt... purtroppo non ho idea di cosa stiamo parlando  :thinking:

da dove posso cominciare? hai qualcosa da consigliare??

Offline absolom

  • python habilis
  • **
  • Post: 68
  • Punti reputazione: 0
    • Mostra profilo
Re: blocco gui
« Risposta #3 il: Novembre 17, 2010, 14:28 »
ho trovato questo
http://it.w3support.net/index.php?db=so&id=569650

ma mi ha stimolato l'attenzione questo articolo:
http://www.diotavelli.net/PyQtWiki/Threading%2C_Signals_and_Slots

il secondo articolo spiega il metodo dei signal Slot fra thread... potrebbe essere la soluzion, spostare la procedura su un Qthread, e attraverso i segnali interagire col thread principale che sarebbe la gui
« Ultima modifica: Novembre 17, 2010, 14:57 da absolom »

Offline absolom

  • python habilis
  • **
  • Post: 68
  • Punti reputazione: 0
    • Mostra profilo
Re: blocco gui
« Risposta #4 il: Novembre 17, 2010, 16:36 »
Ho fatto la prova seguendo il metodo dei SIGNAL, SLOT tra thread... la gui non si blocca più mentre il thread lavora, solo che quando il thread lancia l'EMIT mi da questo errore:
[codice]
QObject::connect: Cannot queue arguments of type 'elem'
(Make sure 'elem' is registered using qRegisterMetaType().)
[/codice]

qualcuno sa come si usa qRegisterMetaType() in pyqt??

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: blocco gui
« Risposta #5 il: Novembre 17, 2010, 16:40 »
Ma perche' poi sta mania dei thread... boh.

Offline absolom

  • python habilis
  • **
  • Post: 68
  • Punti reputazione: 0
    • Mostra profilo
Re: blocco gui
« Risposta #6 il: Novembre 17, 2010, 16:43 »
Ogni monacu chi "fui"... sapi i fatti soi...  :)

Offline mauroTec

  • python erectus
  • ***
  • Post: 120
  • Punti reputazione: 0
    • Mostra profilo
Re: blocco gui
« Risposta #7 il: Novembre 17, 2010, 18:49 »
Citazione
Ogni monacu chi "fui"... sapi i fatti soi... 
Già la segretezza, non puoi rivelare pezzi di codice, sei in trappola e ti ci sei messo tu.
La sfera di cristallo, si rifiuta in certe occasioni di rivelare l'oscuro, e quindi rimane solo l'intuito.

Non ho idea di cosa sia 'elem' in quell'errore, prova a rileggere la doc su QObject che ti potrebbe tornare utile anche come alternativa ai thread.
dalla doc di Qt, QObject:
Citazione
sophisticated interval driven timers that make it possible to elegantly integrate many tasks in an event-driven GUI
Che è quello il linea genereale intendeva riko.

Offline absolom

  • python habilis
  • **
  • Post: 68
  • Punti reputazione: 0
    • Mostra profilo
Re: blocco gui
« Risposta #8 il: Novembre 17, 2010, 20:00 »
ma quale segretezza...  :glasses-cool: ovviamente scherzavo!
forse non sarò normale  :devil: ma mi viene semplice ragionare con i thread!

il codice con cui ho provato è composto da questa classe, che è il QThread:
[codice]from PyQt4.QtCore import *
from PyQt4.QtGui import *

class myApp(QThread):
    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        self.exiting=False

    def __del__(self):
        self.exiting = True
        self.wait()

    def run(self):
        p=myObject()
        self.emit(SIGNAL("newItem(elem)"), p)[/codice]

Nella classe che istanzia la GUI:
[codice]# Import Qt modules
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# Import pyuic4 compiled GUI
from Gui.WindowApparence import Ui_MainWindow

import App

class Main(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
   # Setup pyuic4 generated code
   self.ui = Ui_MainWindow()
   self.ui.setupUi(self)

        self.myTh = App.myApp()

   self.connect(self.ui.startButton, SIGNAL("clicked()"), self.start)
   self.connect(self.myTh, SIGNAL("newItem(elem)"), self.myprint)

    def start(self):
        self.myTh.start()

    def myprint(self, elem):
        print elem[/codice]

Lancio la gui, clicco sul pulsante "Start", si avvia il mio thread, il quale crea l'oggetto "p=myObject" e lancia il SIGNAL con allegato questo parametro...

In pratica il famoso elem è l'istanza di una classe mia, che, visto l'errore che mi viene restituito, non essendo un "tipo" che python conosce, bisogna prima "registrarlo", solo che non sto capendo come!  :sarcastic:

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: blocco gui
« Risposta #9 il: Novembre 17, 2010, 21:05 »
Se ti venisse davvero facile ragionare con i thread, non avresti errori, no? ;)
Il problema e' che i thread danno la *falsa* idea di essere facili da usare e facili da capire.

Anche guardando la maggior parte del codice threaded che "la maggior parte delle volte funziona", si potrebbero, con tempo e voglia trovare bachi a pacchi.

Hai una libreria (Qt) che supporta un bellissimo modello ad eventi. Perche' andare a complicare la vita con i thread non e' chiaro.

Poi voglio dire io normalmente i vari SIGNAL li ho visti con dentro il nome del tipo, non dell'istanza.

elem sembra un oggetto. Poi sono anche un po' stanco di fare l'esegeta con codice che non puo' funzionare perche' non e' completo.

Offline absolom

  • python habilis
  • **
  • Post: 68
  • Punti reputazione: 0
    • Mostra profilo
Re: blocco gui
« Risposta #10 il: Novembre 17, 2010, 21:33 »
Oggi ci ho dato dentro è la stanchezza mi sta sbriciolando!

Poi voglio dire io normalmente i vari SIGNAL li ho visti con dentro il nome del tipo, non dell'istanza.
Questa non fa una piega!  :embarrassed:

Nel frattempo ho capito la soluzione:
nel SIGNAL non va specificato nessun elenco di parametri, in questo modo viene trasmesso un NonType. Per recuperare il tipo di origine (quello che in java chiamerei Casting), nella funzione che viene richiamata dal SIGNAL ci va il seguente codice:
[codice]
def myprint(self, elem):
    if elem is None:
        elem = myObject()
    print elem
[/codice]

Hai una libreria (Qt) che supporta un bellissimo modello ad eventi. Perche' andare a complicare la vita con i thread non e' chiaro.
qui mi viene la curiosità! datemi uno spunto che mi rimetto a studiare!  8)

Offline nkint

  • python neanderthalensis
  • ****
  • Post: 368
  • Punti reputazione: 1
    • Mostra profilo
Re: blocco gui
« Risposta #11 il: Novembre 17, 2010, 22:34 »
http://www.python-it.org/forum/index.php?topic=11.0
nella sezione delle qt sicuramente trovi delle buone guide per iniziare a capire il sistema di eventi in qt che p fatto molto bene

e comunque non ho ben capito è nell'init di myObject che chiami l'hardware esterno da parecchi minuti?
ma comunque..

così è come funzionano le gui:



l'ho preso da qui: http://www.informit.com/articles/article.aspx?p=1149122
non è che me lo sia andato a leggere tutto, è semplicemente la prima cosa che ho trovato su google,
ma ad una prima occhiata mi sembra abbastanza semplice e chiaro (e corretto, forse.. ^__^)

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
ui
« Risposta #12 il: Novembre 18, 2010, 00:24 »
Si. Lo schema lo e'.

In particolare, tornando a noi... la cosa dovrebbe (quasi) funzionare.

Comunque... non capisco questo:

[codice]   1. def myprint(self, elem): 
   2.     if elem is None: 
   3.         elem = myObject() 
   4.     print elem  [/codice]

Dopo di che... in PyQt puoi emettere uno short-circuited signal. Questo segnale lo specifichi *senza*
parentesi e gli puoi passare qualunque combinazione di oggetti Python.

Quindi sarebbe:
[codice]         self.emit(SIGNAL("newItem"), p) [/codice]

A questo punto mi sembra davvero una pessima idea avere sta myprint chiamata sia con parametro
None che con parametro vero. Non dovresti *mai* fargli avere None. Semmai nell call-site gli passi
tu il famoso myObject() nuovo; altrimenti e' un macello.

BTW, in Python avresti comunque scritto:

[codice]elem = myObject() if elem is None else elem[/codice]

bruttarello, ma ci si abitua.

Come ultima considerazione... IMHO stai andando pericolosamente in direzione spaghetti code.

Offline mauroTec

  • python erectus
  • ***
  • Post: 120
  • Punti reputazione: 0
    • Mostra profilo
Re: blocco gui
« Risposta #13 il: Novembre 18, 2010, 02:44 »
Citazione
Se ti venisse davvero facile ragionare con i thread, non avresti errori, no?
Il bello che gli errori non sono dovuti all'uso dei thread, ma di quello che in Qt è alla base di tutta la gerarchia della classi che possono emettere segnali, cioè QObject, tutti i widget ereditano QObject, puoi anche creare una classe non widget ereditando QObject, guarda caso anche QThread eredita QObject.
Il QThread non si inventa nulla per girare shared, in quanto (non ho verificato guardando il codice C++) sfrutta il ciclo ad eventi e il QTimer di QObject, invece fornisce supporto per altre necessità, vedi shared memory.

Ora io dico a quest'ora, ma prima di mettersi a trafficare con i thread, non sarebbe opportuno studiare bene Qt gradatamente (si può fare anche così sbattendoci il muso).

Dico solo almeno le basi, sperimenta un pò con QObject e con segnali, con le GUI, crea un tuo widget custom e vedi che succede.  Trova online anche qualcosa di generico sulla struttura dei toolkit.

Io dico che nel giro di due anni se hai tempo ogni giorno, puoi imparare un pò di C++, io ho letto due libri online (corposi) più un paio semplici, in circa 6 mesi, non è necessario capire tutto ciò che leggi, ma sta sicuro che rimangono le cose importanti. Questo ti mette in condizioni di poter leggere la doc ufficiale in quanto quella di pyqt è orribile, e di sbirciare nel codice C++ di Qt.

Ora mi viene in mente quello che mi disse riko:
Citazione
Comunque in generale piu' vuoi essere raffinato e piu' sputi il sangue perche' e' roba tosta.
 

Poi in post precedenti avevo fatto emegere un problema che potrebbe verificarsi vanificando tutto il lavora. In genere PC/software che comanda hardware esterno con feedback, richiede programmazione a basso livello e in casi dove la movimentazione può comportare errori seri si deve ricorrere ad ambienti realtime, l'hardware ha la priorità assoluta, se per ipotesi hai un servizio avviato in background questo si sveglia, è comincia ad impegnare la cpu, no non deve accadere, il servizio viene messo in attesa altrimenti il processo che gestisce hardware in realtime ne potrebbe risentire.     

Scusate il post lungo, farò astinenza per 5 giorni.

Poi io non voglio che tutto sto casino è venuto fuori per chiamare un metodi tra padre figlio, no perchè QThread ha parent=None mentre potrebbe essere self, il figlio ha parente il padre. Dal padre puoi chiamare un metodo del figlio e dal figlio puoi chiamare un metodo del padre.

Citazione
Hai una libreria (Qt) che supporta un bellissimo modello ad eventi. Perche' andare a complicare la vita con i thread non e' chiaro.
Io andrei a vedere come ricava Qt il Thread, andrei a sbirciare QObject, Qtimer, QThread e QSharedMemory.

Ok ho finito.
Ciao