简体   繁体   中英

Qt Checkable QActions

I have two QActions in a right-click menu. I'm trying to check one action and show a tick next to it. While positive is checked and if I check positive a second time, it should return the program to the default mode and remove the tick. If negative is checked after positive, the tick should move to negative. I revised similar questions but I could not figure it out. I'll be grateful for your help.

  void MainInterfaceWindow::ShowContextMenu(const QPoint &pos)
  {    
    QMenu contextMenu(tr("Context menu"), this);
    QAction action1("Positive", this);
    QAction action2("Negative", this);
    contextMenu.addAction(&action1);
    contextMenu.addAction(&action2);
    connect(&action1, SIGNAL(triggered()), this, SLOT(positiveSlope()));
    connect(&action2, SIGNAL(triggered()), this, SLOT(negativeSlope()));
    m_mouseLocation=pos;
    contextMenu.exec(mapToGlobal(pos));
}

void MainInterfaceWindow::positiveSlope()
{
    ui->openGLWidget->m_positive_slope=true;
    ui->openGLWidget->m_negative_slope=false;
}

void MainInterfaceWindow::negativeSlope()
{   
    ui->openGLWidget->m_negative_slope=true;
    ui->openGLWidget->m_positive_slope=false;
}

You literally have to do what you said: uncheck the other action. Since the actions are specific to the given context menu, you should capture them. IIRC, the actions automatically check and uncheck each time you click on them, so that should be already happening without any additional code.

The actions have to be made checkable: they are not by default.

It'd also be a good idea not to reenter the event loop, ie not use the exec methods anywhere but at the root event loop in each thread (including the main thread, where the event loop is started by QCoreApplication::exec ).

In the code below, connections often go between two objects, so that the functor is destroyed if either the source or destination object is destroyed - ensuring by construction that the functors won't have access to action pointers if any of them were dangling. Also, since the context menu request handler functor uses m_mouseLocation , that field must precede m_contextMenu to ensure by construction that the functor won't access the member after it got destructed.

class MainInterfaceWindow : public ... {
  QPoint m_mouseLocation; // must be before m_contextMenu
  QMenu m_contextMenu{this};
  ...
  void setupContextMenu();
};

MainInterfaceWindow::MainInterfaceWindow(QWidget *parent) :
  BaseClass(..., parent)
{
  setupContextMenu();
  ...
}

void MainInterfaceWindow::setupContextMenu()
{
  m_contextMenu.setTitle(tr("Context menu");
  setContextMenuPolicy(Qt::CustomContextMenu);
  connect(this, &QWidget::customContextMenuRequested, &m_contextMenu, [=](const QPoint &pos){
    m_mouseLocation = pos;
    contextMenu.popup(mapToGlobal(pos));
  });
  auto *posAction = new QAction(tr("Positive"));
  auto *negAction = new QAction(tr("Negative"));
  for (auto *action : {posAction, negAction}) {
    action->setCheckable(true);
    m_contextMenu.addAction(action);
  }
  connect(posAction, &QAction::triggered, negAction, [=]{
    negAction->setChecked(false);
    ui->openGLWidget->m_positive_slope = posAction->checked();
    ui->openGLWidget->m_negative_slope = negAction->checked();
  });
  connect(negAction, &QAction::triggered, posAction, [=]{
    posAction->setChecked(false);
    ui->openGLWidget->m_positive_slope = posAction->checked();
    ui->openGLWidget->m_negative_slope = negAction->checked();
  });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM