Динамически создавать контекстное меню в QT, связанное с кнопкой инструментов
В моем приложении у меня есть QToolButton, связанный с наличием USB-накопителя. Когда диск Pen вставлен, я хотел бы показать QToolButton и создать контекстное меню, связанное с содержимым диска Pen. У меня динамически создается другое меню, которое назначается кнопке.
Мой код работает хорошо в первый раз, но когда я создаю новое меню, оно не появляется. В этой последней версии кода, когда я показываю кнопку во второй раз, я получаю предыдущее меню (Dismount - единственный присутствующий элемент), и когда я нажимаю на элемент, он ничего не делает.
РЕДАКТИРОВАТЬ: Если я использую QAction вместо QWidgetAction, код работает нормально. Так что, похоже, что-то связанное с QWidgetAction QLabel, используемого внутри него.
Ниже приведена упрощенная версия моего кода:
/* member variables */
QMenu *m_pqmConMenUSB;
QLabel m_MenuItem;
/* costructor */
ui->tbDriveUSB->setContextMenuPolicy(Qt::CustomContextMenu);
m_pqmConMenUSB = NULL;
QObject::connect(ui->tbDriveUSB, SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(showUSBCM(const QPoint&)));
m_MenuItem.setStyleSheet("QLabel { background-color : black; color : white; }");
m_MenuItem.setText("Dismount");
QFont fonte = m_MenuItem.font();
fonte.setPixelSize(16);
m_MenuItem.setFont(fonte);
QPalette ChePalette = m_MenuItem.palette();
m_MenuItem.setMinimumSize(0,32);
ChePalette.setColor(m_MenuItem.backgroundRole(), Qt::black);
ChePalette.setColor(m_MenuItem.foregroundRole(), Qt::white);
m_MenuItem.setPalette(ChePalette);
/*member functions*/
void MainWindow::showUSBCM(const QPoint& pos)
{
// copied from an example
if (pos != QPoint(0,0)) {
// Execute context menu
if (m_pqmConMenUSB!=NULL) m_pqmConMenUSB->exec(pos);
}
}
void MainWindow::OnUSBMounted()
{
/* this static boolean is used to simulate a change in the menu content */
static bool tryToChange = false;
ui->tbDriveUSB->show();
m_pqmConMenUSB = new QMenu(this);
QWidgetAction *menuItemW = new QWidgetAction(this);
menuItemW->setDefaultWidget(&m_MenuItem);
menuItemW->setText("Dismount");
connect(menuItemW,SIGNAL(triggered()), this, SLOT(DoDismount()));
m_pqmConMenUSB->addAction(menuItemW);
if (tryToChange)
{
menuItemW = new QWidgetAction(this);
menuItemW->setDefaultWidget(&m_MenuItem);
menuItemW->setText("Update");
connect(menuItemW,SIGNAL(triggered()), this, SLOT(Update()));
m_pqmConMenUSB->addAction(menuItemW);
}
tryToChange = !tryToChange;
ui->tbDriveUSB->setMenu(m_pqmConMenUSB);
}
void MainWindow::OnUSBDismounted()
{
ui->tbDriveUSB->hide();
/* the first version of the code tries to destroy the menu with the following code, but it doesn't work
/*ui->tbDriveUSB->setMenu(NULL);
QAction *pAction;
foreach (pAction, m_pqmConMenUSB->actions())
pAction->disconnect(this);
delete(m_pqmConMenUSB);
m_pqmConMenUSB = NULL;*/
}
2 ответа
Как я уже говорил вчера, проблема была связана с QLabels
, В моем коде я использовал две переменные-члены QLabel
тип. QLabels не были указателями. Когда я удалил действие, QLabels не смог их снова показать. Я полагаю, это было связано с removeAction(d->menuAction);
функция, которая разрушает QWidget
связано с QWidgetAction
, Эта функция была вызвана, когда ui->tbDriveUSB->setMenu(NULL);
назывался. Я решил использовать QLabel
только для таблицы стилей и размера, но можно установить эти свойства в меню. Этого мне достаточно. Я думаю, что, делая новый QLabel
когда QWidgetAction
создать и удалить его, когда QWidgetAction
удаляется, может сделать предыдущий код работает. Я не проверял это.
Чтобы завершить ответ, ниже приведен мой текущий код, который хорошо работает
/* member variable */
QMenu *m_pqmConMenUSB;
/* constructor */
ui->tbDriveUSB->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(ui->tbDriveUSB, SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(showUSBCM(const QPoint&)));
m_pqmConMenUSB = new QMenu(this);
QFont fonte = m_pqmConMenUSB->font();
fonte.setPixelSize(16);
m_pqmConMenUSB->setFont(fonte);
m_pqmConMenUSB->setStyleSheet("QMenu { background-color : black; color : white; }");
m_pqmConMenUSB->setMinimumSize(0,32);
/*member functions*/
void MainWindow::showUSBCM(const QPoint& pos)
{
if (pos != QPoint(0,0))
{
// Execute context menu
if (m_pqmConMenUSB!=NULL) m_pqmConMenUSB->exec(pos);
}
}
void MainWindow::OnUSBMounted()
{
static bool tryToChange = true;
ui->tbDriveUSB->show();
QAction *menuItem = new QAction("Dismount",this);
connect(menuItem,SIGNAL(triggered()), this, SLOT(DoDismount()));
m_pqmConMenUSB->addAction(menuItem);
if (tryToChange)
{
QAction *menuItem2 = new QAction("upDate",this);
connect(menuItem2,SIGNAL(triggered()), this, SLOT(Update()));
m_pqmConMenUSB->addAction(menuItem2);
}
tryToChange = !tryToChange;
ui->tbDriveUSB->setMenu(m_pqmConMenUSB);
}
void MainWindow::OnUSBDismounted()
{
printf("SEI UNO SMONTATO\n\r");
ui->tbDriveUSB->setMenu(NULL);
QAction *pAction;
foreach (pAction, m_pqmConMenUSB->actions())
{
pAction->disconnect(this); // receiver
delete pAction;
}
ui->tbDriveUSB->hide();
m_pqmConMenUSB->clear();
}
Полезный шаблон для динамического заполнения меню, связанного с QToolButton
это сначала создать меню и прикрепить его к кнопке, но не заполнять его. Затем подключите слот к QMenu::aboutToShow()
сигнал. В реализации слота очистите содержимое меню и заполните его по мере необходимости для текущего состояния приложения.