首先,我为看起来很大的问题道歉,但事实并非如此。我正在阅读qt开发书的基础,在阅读第四章作者时,通过展示这个例子来讲述MDI窗口的基础知识:
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的信号映射对象 连接的。信号映射器用于将信号源连接到 另一个信号的论点。在此示例中,菜单的操作 对应于窗口菜单中每个窗口的项目与 实际文档窗口。这些操作又连接到mapper。 当动作发出触发信号时,发送动作 已与相应文档的QWidget *相关联 窗口。此指针用作映射中的参数(QWidget *) 信号映射对象发出的信号。
我的问题:我仍然没有得到什么是信号映射器类,它是如何使用的以及它在上面的例子中做了什么功能?任何人都可以使用简单的条款解释上述段落吗?如果你能用简单的例子教我关于mapper类的基础知识,那真是太棒了吗?可能是外行人的任期?
PS :混淆是当我们有MDI窗口时,做菜单更改(虽然操作被禁用/启用)例如假设一个特定文档我们有菜单“文件/关闭”和其他文档我们有“文件/重新加载”?
答案 0 :(得分:4)
QSignalMapper
用于使用可选参数重新发射信号。换句话说(来自documentation):
该类收集一组无参数信号,并重新发射它们 与对象对应的整数,字符串或窗口小部件参数 发出信号。
一个很好的例子(也来自文档 - 看一下)设置如下:
假设我们要创建一个包含a的自定义窗口小部件 按钮组(如工具调色板)。一种方法是连接 每个按钮的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*
将传递到QWorkspace::setActiveWindow(QWidget*)
的广告符workspace
,然后激活小部件。
另请注意,从操作到窗口小部件的映射必须在代码中的某处发生。我假设它可能在createActions()
或enableActions()
中完成。
答案 1 :(得分:1)
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"))
我打算添加一个更详细的例子,但Morten Kristensen比我快;)