首先,我对有重大问题的问题表示歉意,但事实并非如此。我正在阅读《 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();
}

他的这种解释完全使我难以理解(是我还是其他人对它的理解有问题?):



我的问题:在上面的示例中,我仍然不知道什么是信号映射器类,如何使用以及它的功能是什么?谁能用简单的术语解释上面的段落?如果您能通过简单的例子来教我有关Mapper类的基础知识,那将是很棒的事情吗?可能是外行的说法?

P.S :一个困惑是当我们有MDI窗口时,是否更改菜单(尽管已禁用/启用了操作),例如,对于一个特定文档,我们具有菜单“File / close”,对于其他文档,我们具有“File / remaper”?

最佳答案

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



如下设置了一个很好的示例(也可以从文档中查看):



因此,假设您将许多按钮封装在一个类中,比如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()方法进行设置。

现在剩下要做的就是将信号映射器映射到我们类(class)的信号上:
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.
  }
}

通过这种方式使用信号映射器,您不必声明和管理所有按钮及其单击的信号,只需声明一个信号即可。 ButtonWidget

唯一的缺点是信号映射器非常适合 bundle 多个信号,甚至在重新发出信号时都可以设置参数。我希望这给了QSignalMapper用法的一些直觉。

您的示例代码

说明(您的“para”)指出,所有 Action 均分别映射到特定的QWidget*。触发 Action 时,其各自的QWidget*将传递到QWorkspace::setActiveWindow(QWidget*)的插槽workspace,从而激活小部件。

还要注意,从 Action 到小部件的映射必须发生在代码中的某处。我假设它是用createActions()enableActions()完成的。

关于c++ - MDI窗口和QSignalMapper基础,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12652356/

10-12 21:51