2013-01-04 37 views
6

我有一個包含許多子菜單的QMenu。這些是動態創建的,即名稱菜單來自數據庫並在循環中創建。現在我想點擊菜單時點擊觸發()或類似的插槽,但我需要將QString菜單名稱傳遞給插槽,以便執行菜單特定的操作。我試過this,即將QAction *傳遞給觸發事件並使用了setData,但我得到運行時錯誤。如何通過QSignalMapper或其他方式將QString從QMenu傳遞到Qt插槽

對象::連接:沒有這樣的信號的QAction ::觸發(的QAction *)

for(int j=0; j<channelTypes[i].getNumChannels() ; j++){ 
     QAction *subMenuAct = subMenu->addAction(tr(c_name)); // c_name the menu name 
     subMenuAct->setData(ch_name); 
     connect(subMenuAct, SIGNAL(triggered(QAction *)), this, SLOT(playChannel(QAction *))); // playChannel is the slot 
} 

void <ClassName>::playChannel(QAction *channelAction) 
{ 
    QString str = channelAction->data().toString(); 
    qDebug() << "Selected - " << str; 
} 

可替換地,我還試圖QSignalMapper其中signalMapper是在構造初始化的數據成員

signalMapper = new QSignalMapper(this); 

for(int j=0; j<channelTypes[i].getNumChannels() ; j++){ 
     QAction *subMenuAct = subMenu->addAction(tr(c_name)); 

     connect(subMenuAct, SIGNAL(triggered()), signalMapper, SLOT(map())); 
     signalMapper->setMapping(subMenu, ch_name); 
     connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(playChannel(QString))); 
} 

在第二種情況下,我沒有收到任何錯誤,但是插槽功能playChannel沒有被調用。如果有人能幫助解決這個問題,我會很感激。

更新1:唯一的區別,我從我看到其它實例中看到的是,通常人們都從幾個小部件的單個插槽連接信號(說不同的按鈕)。在我的情況下,我將幾個子菜單(具有不同的名稱)連接到單個插槽。這應該有什麼區別?

更新2:它在QSignalMapper的解決方案below中建議的更正之後工作。另外事實是我使用SubMenu作爲setMapping的參數,其中應該使用MenuAction項目。但是現在我正在多次觸發事件,即多次選擇子菜單類別的主菜單中的條目。如果頻道類型是帶有四個條目的英語(主菜單)),HBO,明星電影等(子菜單),並且我選擇HBO,則使用字符串HBO觸發四次事件。它工作正常,如果我爲每個子菜單創建一個單獨的信號映射器。但我希望能夠使用單個映射器,並且我在這裏做了一些不正確的事情。一些更多的細節在評論中給出答案。

+0

您需要縮小有問題的代碼併發布最小代碼示例,以便重現問題。除了在每次迭代中不需要將signalMapper連接到某個插槽,一切看起來都很好。你確定你改變了插槽簽名嗎? –

+0

謝謝 - 這些是兩個單獨的最小代碼示例,它們以任何方式重現問題。我沒有辦法縮小它的範圍。一個人通過信號映射器嘗試,另一個人使用QAction *。首先顯示運行時間錯誤,第二個完全沒有,但沒有任何工作。是的,我確定插槽簽名每個都改變了,例如一個是QString,另一個是QAction *。如果不是這樣,我會遇到編譯錯誤。 – fayyazkl

+0

關於在每次迭代中連接signalMapper,我將如何指定ch_name的每次迭代具有不同的名稱,並且應該在從菜單中選擇時產生相同的名稱? – fayyazkl

回答

5

QAction添加到菜單後,只需將QMenu連接到插槽。你不單獨連接每個動作插槽:

for(int j=0; j<channelTypes[i].getNumChannels() ; j++){ 
    ch_name = <name from the database for the channel j>; 
    QAction *subMenuAct = subMenu->addAction(tr(ch_name)); 
    subMenuAct->setData(ch_name); 
} 

connect(subMenu, SIGNAL(triggered(QAction *)), 
     this, SLOT(playChannel(QAction *)), Qt::UniqueConnection); 

由於我不知道你怎麼樣,如果你刪除subMenu每個動態菜單充滿時,Qt::UniqueConnection確保插槽將無法重新連接多次。


對於信號映射器版本,您只應將動作連接到循環中的映射器。從映射器到插槽的連接只能進行一次。

for(int j=0; j<channelTypes[i].getNumChannels() ; j++){ 
    ch_name = <name from the database for the channel j>; 
    QAction *subMenuAct = subMenu->addAction(tr(ch_name)); 
    connect(subMenuAct, SIGNAL(triggered()), signalMapper, SLOT(map())); 
    signalMapper->setMapping(subMenuAct, ch_name); 
} 
connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(playChannel(QString))); 

而對於這種情況下,槽playChannel應該接受一個QString而不是QAction*

+0

謝謝 - 我的一個錯誤是signalMapper-> setMapping(subMenu,ch_name);即我在subMenu上映射,而不是subMenuAct。休息的作品,但現在的問題是,信號被稱爲四次反對一次點擊。要清楚,我有一個外部循環創建主菜單。上面發佈的循環是帶有子菜單的內部循環。對於子菜單的一個選擇,事件應該被觸發一次,但被多次調用,因爲主子菜單中有條目。 – fayyazkl

+0

說如果英語頻道有四個不同的頻道名稱,並且我選擇了「HBO」,它將四次調用HBO,而不是一次。目前,如果我創建了多個信號映射器,並在子菜單循環中創建了每個映射器,但我不認爲這是正確的方式。如果可以更正,將不勝感激 – fayyazkl

+0

@fayyazkl您應該將最後一次連接呼叫移動到任何循環之外,並且/或者將'Qt :: UniqueConnection'添加到連接呼叫以避免同一信號到同一插槽的多個連接(如果連接被製成N次,信號的一個觸發將調用該時隙N次)。 – alexisdm

相關問題