2012-09-29 48 views
1

首先,我對很大的問題表示歉意,但事實並非如此。我在讀預科的Qt開發的書,並在閱讀第四章筆者通過展示這個例子告訴MDI窗口的基礎知識:MDI窗口和QSignalMapper基礎知識

MdiWindow::MdiWindow(QWidget *parent) : QMainWindow(parent) { 
    setWindowTitle(tr("MDI")); 
    QWorkspace* workspace = new QWorkspace; 
    setCentralWidget(workspace); 
    connect(workspace, SIGNAL(windowActivated(QWidget *)), this, SLOT(enableActions())); 
    QSignalMapper* mapper = new QSignalMapper(this); 

    //my problem is in this line 
    connect(mapper, SIGNAL(mapped(QWidget*)), workspace, SLOT(setActiveWindow(QWidget*))); 

    createActions(); 
    createMenus(); 
    createToolbars(); 
    statusBar()->showMessage(tr("Done")); 
    enableActions(); 
} 

他對這個解釋完全躲避我(是我或其他人有問題的認識它也是如何呢?):

接下來,創建一個名爲QSignalMapper的信號映射對象並連接到 。信號映射器用於將信號源與另一個信號的參數聯繫起來。在本例中,窗口菜單中與每個窗口對應的菜單項目 的動作與 實際文檔窗口相關聯。這些動作又與映射器相關聯。 當動作發出觸發信號時,發送動作 已與相應文檔 窗口的QWidget *相關聯。該指針用作信號映射對象發射的映射(QWidget *) 信號中的參數。

我的問題:我還是不明白什麼是信號映射器類,它是如何使用的,什麼是功能,它做在上面的例子?任何人都可以用簡單的術語解釋上述段落嗎?如果你可以用簡單的例子教我關於mapper類的基礎知識,那麼它會很棒!可能是通俗的說法?我們有MDI窗口,做菜單改變(儘管動作被禁用/啓用),例如假設對於一個特定的文檔,我們有菜單「File/close」,對於其他文檔我們有「File/remaper「?

+0

你能對你最後的「附言:」詳細點嗎?我沒有得到你那個段落中的問題。 –

+1

對於每個Qt問題,[Qt的優秀文檔](http://qt-project.org/doc/qt-4.8/qsignalmapper.html)通常是最好的起點。 –

回答

4

QSignalMapper用於重新發射具有可選參數的信號。換言之(從documentation):

此類採集一組參數的信號,並重新發射它們 與整數,字符串或相應於發送該信號的對象 插件參數。

一個很好的例子(也由DOC - 看看它)的設置如下:

假設我們要創建一個包含 組按鈕(如自定義窗口小部件工具調色板)。一種方法是將 每個按鈕的clicked()信號連接到它自己的自定義插槽;但在這個 示例中,我們希望將所有按鈕連接到一個插槽,並通過單擊按鈕參數化該插槽。

所以,想象一下,你有許多封裝在一個類的按鈕,說ButtonWidget,用自定義信號void clicked(const QString &text)。這裏的定義是:

class ButtonWidget : public QWidget { 
    Q_OBJECT 

public: 
    ButtonWidget(QStringList texts, QWidget *parent = 0); 

signals: 
    void clicked(const QString &text); 

private: 
    QSignalMapper *signalMapper; 
}; 

構造可以然後像下面的定義:

ButtonWidget::ButtonWidget(QStringList texts, QWidget *parent) 
    : QWidget(parent) 
{ 
    signalMapper = new QSignalMapper(this); 

    QGridLayout *gridLayout = new QGridLayout; 
    for (int i = 0; i < texts.size(); ++i) { 
    QPushButton *button = new QPushButton(texts[i]); 
    connect(button, SIGNAL(clicked()), signalMapper, SLOT(map())); 
    signalMapper->setMapping(button, texts[i]); 
    gridLayout->addWidget(button, i/3, i % 3); 
    } 

    connect(signalMapper, SIGNAL(mapped(const QString &)), 
      this, SIGNAL(clicked(const QString &))); 

    setLayout(gridLayout); 
} 

那麼這裏發生了什麼?我們構建網格佈局和我們的QPushButton類型的按鈕。每個信號的clicked()信號連接到信號映射器。

使用QSignalMapper的力量之一是您可以將參數傳遞給重新發射的信號。在我們的例子中,每個按鈕應該發出不同的文本(由於我們信號的定義),所以我們使用setMapping()方法來設置它。

現在所有剩下要做的就是將信號映射器映射到我們班的信號:

connect(signalMapper, SIGNAL(mapped(const QString &)), 
     this, SIGNAL(clicked(const QString &))); 

假設我們有一個名爲測試類TestClass然後ButtonWidget可正是如此使用:

TestClass::TestClass() { 
    widget = new ButtonWidget(QStringList() << "Foo" << "Bar"); 
    connect(widget, SIGNAL(clicked(const QString &)), 
      this, SLOT(onButtonClicked(const QString &))); 
} 

void TestClass::onButtonClicked(const QString &btnText) { 
    if (btnText == "Foo") { 
    // Do stuff. 
    } 
    else { 
    // Or something else. 
    } 
} 

通過這種方式使用信號映射器,您不必聲明和管理所有按鈕及其單擊的信號,只需一個信號pr。 ButtonWidget

buttom線是信號映射器非常適合捆綁多個信號,甚至可以在重新發射參數時設置參數。我希望對QSignalMapper的使用有一定的直覺。


你的示例代碼

的解釋(你的「對」)指出,所有的動作都各自獨立映射到特定QWidget*。當觸發動作時,其各自的QWidget*將被傳遞到workspace的插槽QWorkspace::setActiveWindow(QWidget*),其反過來激活小部件。

另請注意,從動作到小部件的映射必須發生在代碼中的某處。我認爲它可能在createActions()enableActions()中完成。

+0

在代碼'connect(button,SIGNAL(clicked()),signalMapper,SLOT(map()));''button'對象的類型是什麼? ,如果'ButtonWidget'那麼你已經說過'ButtonWidget'沒有任何信號'connect()'而不是一個自定義信號'void clicked(const QString&text)'。還有你的代碼'signalMapper-> setMapping(button,texts [i]);'它是相應的解釋,上面解釋了代碼本身。 –

+0

你是否代表嫖娼? 。你看我正在讀一本初學者書,所以請用簡單,小而完整的例子來支持你的理論,而不是簡單的理論。上面的例子解決了這個問題,將會是非常棒的附加組件。謝謝 –

+0

你看過我指出的文檔頁嗎?它也顯示了類型的完整示例。在他們的例子中,內部按鈕的類型是'QPushButton',它的信號是'connect()'。是的,所以之後你有一個'ButtonWidget'的實例,你可以通過這個實例將信號與字符串連接到一個插槽,並且可以用一種方法對不同的按鈕做出反應,而不是每個按鈕。 'setMapping()'設置當我們觸發'clicked()'信號時傳遞的參數。 –

1

A QSignalMapper允許您在需要時向信號添加一些信息。該對象內部有一個像QMap<QObject*,QVariant>的地圖。然後,您將一個對象連接到該對象,並且在調用此插槽時,它將重新發出具有相關值的信號。

工作流程:

mySignalMapper: 
    [ obj1 -> 42  ] 
    [ obj2 -> "obiwan" ] 
    [ obj3 -> myWidget ] 

connect(obj1,mySignal,mySignalMapper,SLOT(map())); // idem for obj2 and obj3 

(obj2 emits "mySignal") 
-> (mySignalMapper::map slot is called) 
-> (sender() == obj2, associated data = "obiwan") 
-> (mySignalMapper emits mapped("obiwan")) 

我要添加一個更詳細的例子,但莫滕克里斯滕森比我更快;)