2015-06-29 101 views
1

我有一個功能,可以檢測3D切片機中的相機端口,但它似乎只運行一次。當我拔出/插入攝像頭時,端口數量應該在組合框(用Qt設計)中更新,但沒有任何變化。用C++刷新組合框?

功能我用檢測被點擊的相機端口時:

void qSlicerTrackingModuleWidget::onCameraPortClicked(){ 
    Q_D(qSlicerTrackingModuleWidget); 

    // Clear current entries 
    d->CameraPortComboBox->clear(); 

    int n = 0; 

    // Loop over camera ports until last one is found. Add all available ports to combo box and exit. 
    while(1){ 
    cv::VideoCapture cap = cv::VideoCapture(n); 


    if(!cap.isOpened()){ 
     return; 
    } 
    QString portNum = QString::fromStdString(std::to_string(n++)); 
    d->CameraPortComboBox->addItem(portNum); 
    qSlicerCoreApplication::processEvents(); 
    } 
} 

的設置功能,跑最後一棒,並分配GUI的實際功能。

connect(d->CameraPortComboBox, SIGNAL(clicked()), this, SLOT(onCameraPortClicked())); 

我需要它來刷新,想盡組合框上點擊時檢測到相機,但由於接口設置的,我不知道這是否是可能的。我不認爲不斷刷新該計劃是一個不錯的選擇,所以我沒有想法。有沒有辦法做到這一點?

+1

哎呀。你可以寫「QString portNum = QString :: number(n ++);」沒有std :: string中介,fwiw。 –

+0

感謝您的提示,但你確定有沒有辦法可以做到這一點? – Mia

+0

我認爲每次單擊它時刷新組合是可以的,但您需要在單獨的線程中執行檢測,然後在檢測完成後更新組合。爲了您自己的利益,請考慮'processEvents'調用是個bug。當初學者使用它們時,它們幾乎總是有缺陷。哎呀,我有一個60k行的交互式代碼庫,沒有一個'processEvents'和'waitFor ...'調用,並且只有'exec'調用用於主事件循環和'QDrag',不幸的是它是不必要的。 –

回答

1

您可以在另一個線程產生攝像機列表:

void qSlicerTrackingModuleWidget::onCameraPortClicked() { 
    QtConcurrent::run([this]{ 
    QStringList cameras; 
    for (int i = 0; true; ++i) { 
     auto cap = cv::VideoCapture(i); 
     if (! cap.isOpened()) break; 
     cameras << QString::number(i); 
    } 
    // This is a queued, thread-safe call. It will execute in the 
    // GUI thread. 
    QMetaObject::invokeMethod(this, "onCameraList", 
           Q_ARG(QStringList, cameras)); 
    }); 
} 

// another slot 
void qSlicerTrackingModuleWidget::onCameraList(const QStringList & cameras) { 
    Q_D(qSlicerTrackingModuleWidget); 
    d->CameraPortComboBox->clear(); 
    for (auto portNum : cameras) 
    d->CameraPortComboBox->addItem(portNum); 
} 

另外請注意,組合框不具有clicked()信號。您需要在組合框上安裝事件過濾器才能訪問您感興趣的事件。也許您也可以使用Enter事件:

class EventSignaller : public QObject { 
    Q_OBJECT 
    bool eventFilter(QObject * obj, QEvent * event) { 
    if (event->type() == QEvent::Enter) 
     emit entered(qobject_cast<QWidget*>(obj)); 
    if (event->type() == QEvent::MouseButtonPress) 
     emit clicked(qobject_cast<QWidget*>(obj)); 
    return QObject::eventFilter(obj, event); 
    } 
public: 
    EventSignaller(QObject* parent = 0) : QObject(parent) {} 
    Q_SIGNAL void entered(QWidget*); 
    Q_SIGNAL void clicked(QWidget*); 
    void track(QWidget * widget) { 
    widget->removeEventFilter(this); // ensure we're unique 
    widget->installEventFilter(this); 
    } 
}; 

qSlicerTrackingModuleWidget::qSlicerTrackingModuleWidget() : ... { 
    auto signaller = new EventSignaller(this); 
    connect(signaller, SIGNAL(entered(QWidget*)), // or SIGNAL(clicked(QWidget*)) 
        SLOT(updateCameraPorts())); 
    ... 
} 

void qSlicerTrackingModuleWidget::updateCameraPorts() { 
    ... 
} 
+0

我喜歡這個實現,並沒有意識到Qt爲這樣的事情提供了簡單的線程(我認爲它應該對於UI庫來說顯而易見:p),但我認爲這不會解決信號未被觸發的問題首先。只要被調用,我的代碼就會正確地更新列表,但是調用不會發生。你的代碼解決了這個問題,我只是想念它嗎?只是爲了清楚起見,這不是我連接到的按鈕,而是一個組合框 – Mia

+1

@GenevieveCcio它是由你決定的,你想觸發什麼標準。請記住,組合框沒有「點擊」信號。當鼠標進入框中時,您可能想要觸發重新掃描。沒有任何信號,但是您可以在組合框上過濾「Enter」來檢測這一點 - 無需對控件進行子類化。 –

+0

太棒了,謝謝。我會稍微測試一下並回復你。 – Mia