我有一些struct
与enum
和std::string
,我曾经使用for()
循环填充QComboBox
es。像这样:
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
很大,这就会成为一个问题,所以我想知道是否有办法自动化这个过程。
我的问题主要来自为什么我只需要每个QComboBox
一个connect()
,QComboBox
es 如何知道,如果我填写它们,哪个条目做什么?
如果有帮助,这是一些虚假的代码,从这里和那里,我所拥有的:
// 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()
一起使用,并将其转换为带有qobject_cast<>
的QAction
对象类型。
此外,如果您想使用索引,我们可以使用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;
}