【问题标题】:MDI window and QSignalMapper basicsMDI 窗口和 QSignalMapper 基础知识
【发布时间】:2012-09-21 01:37:03
【问题描述】:

首先我很抱歉这个看起来很长的问题,但事实并非如此。我正在阅读《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 的信号映射对象,并 连接的。信号映射器用于将信号源连接到 另一个信号的参数。在这个例子中,菜单的动作 窗口菜单中每个窗口对应的项目都绑定到 实际文档窗口。这些动作又连接到映射器。 当动作发出触发信号时,发送动作 已经关联到对应文档的QWidget* 窗户。此指针用作映射(QWidget*)中的参数 信号映射对象发出的信号。

我的问题:我仍然不明白什么是信号映射器类,它是如何使用的,以及在上面的示例中它的功能是什么?。任何人都可以用简单的术语解释上述段落吗?如果你能用简单的例子教我关于 mapper 类的基础知识,那就太棒了?可能是外行?

PS :当我们有 MDI 窗口时,会产生混淆(尽管操作被禁用/启用),例如假设对于一个特定文档,我们有菜单“文件/关闭”,而对于其他文档我们有“文件/重映射器”?

【问题讨论】:

  • 你能详细说明你的最后一个“P.S.”吗?我没明白你在那段中的问题是什么。
  • 对于每一个 Qt 问题,Qt's excellent documentation 通常是最好的起点。

标签: c++ qt


【解决方案1】:

QSignalMapper 用于重新发出带有可选参数的信号。换句话说(来自documentation):

该类收集一组无参数信号,并重新发出它们 与对象对应的整数、字符串或小部件参数 发出了信号。

一个很好的例子(也来自文档 - 看看它)设置如下:

假设我们要创建一个自定义小部件,其中包含一个 一组按钮(如工具调色板)。一种方法是连接 每个按钮的 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.

最重要的是,信号映射器非常适合捆绑多个信号,您甚至可以在它重新发出信号时设置参数。我希望对QSignalMapper的用法有一些直觉。


您的示例代码

解释(您的“para”)指出所有操作都单独映射到特定的QWidget*。当触发一个动作时,其各自的QWidget* 将被传递到workspace 的插槽QWorkspace::setActiveWindow(QWidget*),从而激活小部件。

另请注意,从操作到小部件的映射必须发生在代码中的某个位置。我假设它是在createActions()enableActions() 中完成的。

【讨论】:

  • 在代码connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));button 对象的类型是什么? ,如果 ButtonWidget 那么正如你已经说过的 ButtonWidget 没有任何信号 connect() 而是自定义信号 void clicked(const QString &amp;text) 。还有你的代码signalMapper-&gt;setMapping(button, texts[i]);,它的相应解释在代码本身上面已经解释过了。
  • 你在卖淫吗? .你看我正在读一本初学者的书,所以请用简单、小而完整的例子来支持你的理论,而不是简单的理论。您的上述示例如何解决问题等将是很棒的附加组件。谢谢
  • 您看过我指出的文档页面了吗?它也显示了带有类型的完整示例。在他们的示例中,内部按钮的类型为QPushButton,其信号为connect()。是的,所以之后您有一个 ButtonWidget 的实例,您可以从该实例将带有字符串的信号连接到一个插槽,并在一个方法中对不同的按钮做出反应,而不是为每个按钮设置一个插槽。 setMapping() 设置在我们的例子中触发clicked() 信号时将传递的参数。
  • 不,我不是嫖娼。我想在这里帮你。我的示例展示了如何使用信号映射器来简化代码,但我将在我的帖子中让您更清楚。
  • 非常感谢您现在的详细回答和帮助,再次感谢:)
【解决方案2】:

QSignalMapper 允许您在需要时向信号添加一些信息。该对象内部有一个类似QMap&lt;QObject*,QVariant&gt; 的映射。然后你将一个对象连接到它,当槽被调用时,它会重新发出带有相关值的信号。

工作流程:

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 比我快;)

【讨论】:

    猜你喜欢
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-16
    • 2018-05-25
    • 2014-11-28
    • 2014-02-14
    相关资源
    最近更新 更多