2010-08-24 13 views
44

Abbiamo un oggetto QCheckBox, quando l'utente lo controlla o rimuove il controllo, vogliamo chiamare una funzione così colleghiamo la nostra funzione al segnale stateChanged (int state). D'altra parte, secondo alcune condizioni, cambiamo anche lo stato dell'oggetto QCheckBox all'interno del codice, e questo causa il segnale indesiderato.Prevenire i segnali di accensione in Qt

C'è qualche modo per prevenire il segnale di sparo in alcune condizioni?

risposta

69

È possibile utilizzare il segnale clicked perché viene emesso solo quando l'utente ha effettivamente fatto clic sulla casella di controllo, non quando lo si controlla manualmente utilizzando setChecked.

Se proprio non si desidera che il segnale viene emesso in un momento specifico, è possibile utilizzare QObject::blockSignals in questo modo:

bool oldState = checkBox->blockSignals(true); 
checkBox->setChecked(true); 
checkBox->blockSignals(oldState); 

Lo svantaggio di questo approccio è che tutti segnali saranno bloccati. Ma immagino che non sia importante nel caso di un QCheckBox.

+4

La disconnessione quindi collegare scenario proposto da liaK sembra meglio di bloccare tutti i segnali per questo compito specifico. – Longfield

+3

@Longfield: Penso che usare il segnale "cliccato" sia il migliore per questo compito specifico. – Job

+1

beh, lo stato potrebbe anche essere modificato dal programma, non necessariamente dall'utente attraverso l'interfaccia utente. Comunque, stiamo parlando di dettagli qui e immagino che metdos abbia trovato una soluzione che gli si addica. – Longfield

12

È possibile QObject::disconnect rimuovere la connessione corrispondente segnale slot e possono QObject::connectnuovamente una volta finito ...

5

In QObject classi derivate, si può chiamare blockSignals(bool) per impedire l'oggetto da emettere segnali. Così, per esempio:

void customChangeState(bool checked) 
{ 
    blockSignals(true); 
    ui->checkBox->setCheckState(Qt::Checked); 
    // other work 
    blockSignals(false); 
} 

Il metodo di cui sopra avrebbe cambiato lo stato di assegno senza cliccato, stateChanged, o altri segnali che vengono emessi.

+2

Questo non bloccherà ui-> checkBox dall'emettere i segnali, quindi non funzionerà come previsto. si dovrebbe chiamare UI->> checkBox- blockSignals (true) o utilizzare QSignalBlocker (a partire da Qt5.3) – HappyCactus

29

È sempre possibile bloccare l'emissione del segnale su QObjects utilizzando QObject::blockSignals(). Si noti che per essere corretti, è necessario ricordare lo stato precedente (restituito dalla chiamata alla funzione) e ripristinarlo quando si è terminato.

Al mio lavoro, preferiamo RAII per questo genere di cose. Una semplice classe per farlo potrebbe essere simile a questo:

class SignalBlocker 
{ 
public: 
    SignalBlocker(QObject *obj) : m_obj(obj), m_old(obj->blockSignals(true)) 
    { 
    } 

    ~SignalBlocker() 
    { 
     m_obj->blockSignals(m_old); 
    } 

private: 
    QObject *m_obj; 
    bool m_old; 
}; 

Edit: partire con Qt 5.3, vedere QSignalBlocker (h/t per HappyCactus nei commenti)

+2

v'è alcuna ragione specifica per seguire in questo modo ?? Basta chiedere B'cos siamo abituati a 'QObject :: disconnessione()' in questi scenari Kinda .. – liaK

+6

Dipende da quante cose potrebbero essere collegate ai segnali dell'oggetto, come che si sta che è stato scollegato quelli appropriati, e quanto sia facile ricollegarli di nuovo. Io penso che di solito sia più facile, ma anche usare la disconnessione. –

+0

Sì bene .. Grazie .. :) – liaK

-1

Quando qualche elemento dell'interfaccia utente non deve rispondere alle utente è opportuno disabilitarlo. In modo che l'utente sappia che questo elemento non accetta input.

+2

Quello che dici è vero, ma non rilevante alla domanda del PO. – bdesham

11

Durante l'apprendimento di Qt, mi sono imbattuto in questo problema con un insieme di widget interconnessi che volevo aggiornare "atomicamente". Mi è piaciuta la soluzione di @ cjhuitt, ma ho scoperto che va ancora meglio con un po 'di zucchero sintattico basato su proxy objects. Ecco l'approccio che ho usato ...

In primo luogo, ho definito un modello di classe per un oggetto proxy di blocco. Come Caleb, questo blocca i segnali sulla costruzione, e quindi ripristina il loro stato precedente sulla distruzione.Tuttavia, sovraccarica anche all'operatore -> per restituire un puntatore all'oggetto bloccato:

template<class T> class Blocker { 
    T *blocked; 
    bool previous; 
public: 
    Blocker(T *blocked) 
     : blocked(blocked), 
      previous(blocked->blockSignals(true)) {} 
    ~Blocker() { blocked->blockSignals(previous); } 
    T *operator->() { return blocked; } 
}; 

successiva, ho definito una piccola funzione template per costruire e restituire un Blocker:

template<class T> inline Blocker<T> whileBlocking(T *blocked) { 
    return Blocker<T>(blocked); 
} 

Mettendo tutto insieme , userei in questo modo:

whileBlocking(checkBox)->setChecked(true); 

o

whileBlocking(xyzzySpin)->setValue(50); 

Questo mi ottiene tutti i vantaggi di Raii, con abbinato automaticamente il blocco e ripristinare intorno alla chiamata di metodo, ma non ho bisogno di nominare eventuali bandiere involucro o statali. È bello, facile e dannatamente infallibile.

+2

È molto elegante, grazie – galinette

2

Qt5.3 ha introdotto la classe QSignalBlocker che fa esattamente ciò che era necessario in un modo sicuro un'eccezione.

if (something) { 
    const QSignalBlocker blocker(someQObject); 
    // no signals here 
} 
0

Anche in QT5, è un po 'macchinoso quando ci sono molte/molte cose da bloccare. Ecco una versione multi-oggetto che è concisa da usare:

class SignalBlocker 
{ 
public: 
    SignalBlocker(QObject *obj) 
    { 
    insert(QList<QObject*>()<<obj); 
    }  
    SignalBlocker(QList<QObject*> objects) 
    { 
    insert(objects); 
    }  
    void insert(QList<QObject*> objects) 
    { 
    for (auto obj : objects) 
     m_objs.insert(obj, obj->signalsBlocked()); 
    blockAll(); 
    }  
    void blockAll() { 
    for(auto m_obj : m_objs.keys()) 
     m_obj->blockSignals(true); 
    }  
    ~SignalBlocker() 
    { 
    for(auto m_obj : m_objs.keys()) 
     m_obj->blockSignals(m_objs[m_obj]); 
    }  
private: 
    QMap<QObject*,bool> m_objs;  
}; 

utilizzo:

void SomeType::myFunction() 
{ 
    SignalBlocker tmp(QList<QObject*>() 
    << m_paramWidget->radioButton_View0 
    << m_paramWidget->radioButton_View1 
    << m_paramWidget->radioButton_View2 
    ); 
    // Do more work, ... 
} 
Problemi correlati