c++ - 用枚举填充 QMenu

标签 c++ qt enums qmenu

我有几个struct,带有enumstd::string,我用来填充QComboBox使用 for() 循环与他们一起使用。像这样:

struct Struct
{
    enum Enum
    {
        ENTRY1,
        ENTRY2,
        ...
        ENTRY_ALL
    };
    std::string names[ENTRY_ALL] {...};
};
for(int i=0; i<Struct::ENTRY_ALL; ++i)
    comboBox->insertItem(i, names[i].c_str());

它起作用了,但是考虑到最近的进展,我需要更多的条目、更多的 struct、更多的组合框,而且它变得很丑陋,所以我决定切换到 QMenu.

查看文档和示例,我发现我必须为每个条目提供一个 connect(),为每个条目提供一个 QAction 等等,如果我enum 很大,这会成为一个问题,所以我想知道是否有办法自动执行此过程。

我的问题主要来自于为什么我只需要一个 connect() 用于每个 QComboBox 以及 QComboBoxes 如何知道,如果我填写它们,哪个条目做什么?


如果有帮助的话,这是我所拥有的一些伪造代码:

// tank class, header:
class Class
{
private:
    // main entries
    struct MainStruct
    {
        enum Enum {MAIN1, MAIN2, MAIN3, MAIN_ALL};
        std::string names[MAIN_ALL] {"Main 1", "Main 2", "Main 3"};
    };
    // secondary entries
    struct SubStruct
    {
        enum Enum {SUB1, SUB2, SUB3, SUB_ALL};
        std::string names[SUB_ALL] {"Sub 1", "Sub 2", "Sub 3"};
    };
    // family of entries for SUB2
    struct FamStruct
    {
        enum Enum {FAM1, FAM2, FAM3, FAM_ALL};
        std::string names[FAM_ALL] {"Fam 1", "Fam 2", "Fam 3"};
    }
public:
    MainStruct mainEntries;
    SubStruct subEntries;
    FamStruct famEntries;
};

// inside the main window, there was a QComboBox doing this:
// header
QComboBox *cbMain, *cbSub, *cbFam;
// source
Class cls {Class()};
cbMain = new QComboBox; // same for cbSub, cbFam
// retranslateUi() (manually edited, not automatic), called each time the menu was clicked
void MainApp::retranslateUi()
{
    cbMain.clear();
    for(unsigned char i=0; i<cls.mainEntries.MAIN_ALL; ++i)
    {
        cbMain->insertItem(i, tr(cls.mainEntries.names[i].c_str()) );
        cbMain->setItemData(i, tr(cls.mainEntries.tooltips[i].c_str()), Qt::ToolTipRole);
    }
    // same for cbSub, cbFam
}
// a function that did what was supposed to do when a combo box entry was clicked
void MainApp::func() { /* execution with variables changed by the combo */ }
/* There were additional functions taking care of the rest.
 * Whenever an entry from the combo was clicked, somehow it "knew" that the entry was
 * changed and func(), when executed, it ran with the variables changed by combo.
 */
void MainApp::updateSub()
{
    switch(cbMain->currentIndex())
    {
    case cls.mainEntries.MAIN1: /*subentry stuff*/ break;
    case cls.mainEntries.MAIN2: /*subentry stuff*/ break;
    case cls.mainEntries.MAIN3: /*subentry stuff*/ break;
    }
}
void MainApp::updateFam()
{
    switch(cbSub->currentIndex())
    {
    case cls.subEntries.SUB1: /*fam entry stuff*/ break;
    case cls.subEntries.SUB2: /*fam entry stuff*/ break;
    case cls.subEntries.SUB3: /*fam entry stuff*/ break;
    }
}
/* The connect() were attached to specific combos. When an entry in cbMain was
 * clicked, cbSub and cbFam were properly updated and func() was run with
 * the proper values, when cbSub was clicked, cbFam was updated and func()
 * was run accordingly. Similar to an instant refresh.
 */
connect(cbMain, SIGNAL(activated(int)), this, SLOT(retranslateUi()));
connect(cbMain, SIGNAL(activated(int)), this, SLOT(updateSub()));
connect(cbMain, SIGNAL(activated(int)), this, SLOT(func()));
connect(cbSub, SIGNAL(activated(int)), this, SLOT(updateFam()));
connect(cbSub, SIGNAL(activated(int)), this, SLOT(func()));
connect(cbFam, SIGNAL(activated(int)), this, SLOT(func()));

每当我不得不为子菜单添加新的条目系列,甚至是带有子条目的主菜单时,事情都会变得复杂,所以我认为这样的菜单:

Menu:   Submenu:                AnotherSubmenu:
menu 1  submenu 1               altsub 1
menu 2  submenu 2 > family 1    altsub 2
menu 3  submenu 3   family 2    ...
                    family 3

会更好,更整洁。 Menu 中的条目调用适当的 Submenu,它有自己的 Family,无论它们在哪里,Submenu 都可以调用又一层 AnotherSubmenu

最佳答案

您可以连接所有QAction 的触发信号到同一个插槽,并能够拥有 sender() 的对象, 并将其转换为 QAction带有 qobject_cast<> 的对象类型.

此外,如果您想使用索引,我们可以使用 setObjectName()objectName()

void {your Widget}::createAction()
    QMenu *menu = new QMenu(this);
    for(int i=0; i < 10; ++i){
        QAction *action = new QAction(QString("action %1").arg(i));
        action->setObjectName(QString("%1").arg(i));
        connect(action, &QAction::triggered, this, &{your Widget}::onTriggeredAction);
        menu->addAction(action);
    }
}

void {your Widget}::onTriggeredAction()
{
    QAction *obj = qobject_cast<QAction *>(sender());
    int index = obj->objectName().toInt();
    qDebug()<<index;
}

关于c++ - 用枚举填充 QMenu,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43684721/

相关文章:

c++ - 在 Debug 中覆盖 memcpy 工作但在 Release 中不工作?

c++ - 当用户按下 Ctrl 并单击时获取鼠标坐标

c++ - 如何使用 qregexp 验证电子邮件地址

grails - Groovy/Grails - 使用枚举运行应用程序时出错

c++ - 将 lambda 绑定(bind)到函数以获得返回结果

c++ - OpenCV 从中心 x,y 绘制矩形

c++ - Qt 5.9 - 由于不赞成调用 glLoadIdentity 而在 0x0 出现异常

Ubuntu 上的 Qt 和 OpenSSL 不兼容版本

hibernate - 查询 Hibernate Criteria API 中的枚举方法

enums - 如何在 Rust 中指定枚举的表示类型以与 C++ 接口(interface)?