使用当前焦点窗口小部件上下文菜单自动填充菜单栏中的“编辑”菜单

时间:2011-07-28 15:40:06

标签: c++ qt

我一直在寻找实现Qt应用程序“编辑”菜单的方法。 “编辑”菜单包含“复制”,“剪切”,“粘贴”等项目,并且需要转发到当前活动的窗口小部件。

我似乎无法找到一种标准或优雅的方式来做到这一点。根据这个问题,这是不可能的:

How to implement the "Edit" menu with "Undo", "Cut", "Paste" and "Copy"?

我最近有想法在显示“编辑”菜单时在当前活动小部件上触发上下文菜单事件,通过:

// create menus in MainWindow constructor
...
edit_menu = menuBar()->addMenu(tr("&Edit"));
connect(edit_menu, SIGNAL(aboutToShow()), this, SLOT(showEditMenu()));
...

// custom slot to handle the edit menu
void MainWindow::showEditMenu()
{
    QWidget* w = QApplication::focusWidget();

    // show the context menu of current focus widget in the menubar spot
    QPoint global_pos = edit_menu->mapToGlobal(edit_menu->rect().bottomLeft());
    QPoint pos = w->mapFromGlobal(global_pos);

    QApplication::sendEvent(w, new QContextMenuEvent(QContextMenuEvent::Keyboard, pos, global_pos));
}

这显示当前小部件的上下文菜单很棒,但有一些问题。例如,它将焦点从菜单栏上移开,或者如果您先点击不同的菜单栏项目,则菜单栏会有焦点等。

一个部分解决方案是从窗口小部件中获取上下文菜单,并将其项目动态复制到编辑菜单中。有没有办法做到这一点?

在Qt中构建编辑菜单有更好的方法吗?

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

好吧,如果你只需要创建菜单,你总是可以从小部件的actions采取行动。要为小部件创建编辑操作,您可以执行以下操作:

void MainWindow::addActions (QWidget* widget)
{

    QAction * copyAction = new QAction("copy",widget);
    if(connect(copyAction,SIGNAL(triggered()),widget,SLOT(copy())))
    {
        widget->addAction(copyAction);
        qDebug()<<"success connection";
    }
}

foreach (QObject * obj, centralWidget()->children())
{
    QWidget * w = dynamic_cast<QWidget*>(obj);
    if (w)
        addActions(w);
}

然后你总是可以用焦点小部件的动作更新编辑菜单的动作

这可能不优雅,但它比不可能的更好。示例中的主要不良假设是复制槽名为copy

答案 1 :(得分:1)

我认为一个优雅的解决方案是为您需要具有复制/粘贴/ ...功能的小部件提供基类,并让它们在激活时注册自己的某个父类,并在停用时注册。然后,可以将操作连接到主窗口中的插槽,该插槽将它们转发到已注册的窗口小部件。如果当前没有注册窗口小部件,您甚至可以使菜单项变灰(例如,因为活动窗口小部件没有所需的功能)。

注册/取消注册(未经测试)的示例:

class ActionWidget;

class ActionWidgetManager
{
public:
  ActionWidgetManager() : actionWidget_(0){}
  void registerWidget(ActionWidget* widget){ actionWidget_ = widget; }
  void unregisterWidget(ActionWidget* widget)
    { if (actionWidget_ == widget) actionWidget_ = 0; }
  bool hasActiveWidget() const{ return actionWidget_ != 0; }
  ActionWidget* getActiveWidget(){ return actionWidget_; }
private:
  ActionWidget* actionWidget_;
};

class ActionWidget : public QWidget
{
public:      
  ActionWidget(ActionWidgetManager* manager, QWidget* parent=0)
     : manager_(manager), QWidget(parent) {}
  ~ActionWidget(){ manager_->unregisterWidget(this); }
  void Widget::changeEvent(QEvent *event)
  {
    QWidget::changeEvent(event);
    if(event->type() == QEvent::ActivationChange){
      if(isActiveWindow()) {
        manager_->registerWidget(this);
      }
      else {
        manager_->unregisterWidget(this);
      }
    }
  }

  virtual void doCopy() = 0;
  virtual void doPaste() = 0;
  virtual void doUndo() = 0;
  virtual void doCut() = 0;

private:
  ActionWidgetManager* manager_;
};

使用信号和插槽等效的东西。