• 6912阅读
  • 9回复

[紧急求助]一个pushButton,我点击一次,却提交了两次,百思不得其解 [复制链接]

上一主题 下一主题
离线houapple
 
只看楼主 倒序阅读 楼主  发表于: 2009-10-15
原代码如下:
[code]
void MainWindow_Admin::on_okButton_user_clicked()
{
    QMessageBox msgBox;
    if (power != 2) {
        msgBox.setText(tr("对不起,你没有此权限!"));
        msgBox.exec();
        return;
    }

    char sql[QUERYLEN];

    int user_type = typeBox_addUser->currentIndex();
    QString id = lineEdit_addID->text();
    QString name = lineEdit_name->text();
    QString pwd = lineEdit_pwd->text();

    if (user_type == 0) {
        QString department = lineEdit_department->text();
        QString stuclass = lineEdit_class->text();
        sprintf(sql, "insert into student(id, pwd, name, class ,department) values(\"%s\", \"%s\", \"%s\", \"%s\", \"%s\")", id.toStdString().c_str(), pwd.toStdString().c_str(), name.toStdString().c_str(), stuclass.toStdString().c_str(), department.toStdString().c_str());
    } else if (user_type == 1) {
        QString department = lineEdit_department->text();
        sprintf(sql, "insert into teacher(id, pwd, name, department) values(\"%s\", \"%s\", \"%s\", \"%s\")",
id.toStdString().c_str(), pwd.toStdString().c_str(), name.toStdString().c_str(), department.toStdString().c_str());
    } else {
        QString power = lineEdit_department->text();
        sprintf(sql, "insert into admin values(\'%s\', \'%s\', \'%s\', %d)", id.toStdString().c_str(), name.toStdString().c_str(), pwd.toStdString().c_str(), power.toInt());
    }

    bool isconnect = db.open();
    if (isconnect) {
        QSqlQuery query;
        QString s(sql);
   
        if (query.exec(s)) {
            msgBox.setText(tr("增加用户成功!"));
        } else {
            msgBox.setText(query.lastError().databaseText());
        }
    } else {
        msgBox.setText(db.lastError().databaseText());
    }
    msgBox.exec();                           
}
[/code]

信号和槽如下
    connect(okButton_user, SIGNAL(clicked()), this, SLOT(on_okButton_user_clicked()));
离线dbzhang800

只看该作者 1楼 发表于: 2009-10-15
注释掉!
  //connect(okButton_user, SIGNAL(clicked()), this, SLOT(on_okButton_user_clicked()));
离线houapple
只看该作者 2楼 发表于: 2009-10-15
为什么注释掉阿?
离线rqzrqh

只看该作者 3楼 发表于: 2009-10-15
连接了两次,因为槽用on_okButton_user_clicked()这种写法就已经连接了一次了
离线houapple
只看该作者 4楼 发表于: 2009-10-15
为什么呢?
难道命名还有规定吗?
请详解!
离线rqzrqh

只看该作者 5楼 发表于: 2009-10-15
没有。但这个是设计器做的事
QT自动连接信号与槽

查看Qt4的一些示例项目的时候,使用设计器打开其UI文件,在文件中竟然找不到signal和slot的连接。但是最终的程序,slot却又能准确的响应信号。打开通过ui文件自动生成的c++文件,其中也找不到connect语句,到底是怎么一回事?
经过逐语句的分析。终于发现连接的原因就在于setUi函数的最后一句
QMetaObject::connectSlotsByName(MainWindow);
找到该静态函数
void QMetaObject::connectSlotsByName(QObject *o)
{
    if (!o)
        return;
    const QMetaObject *mo = o->metaObject();
    Q_ASSERT(mo);
    const QObjectList list = qFindChildren<QObject *>(o, QString());
    for (int i = 0; i < mo->methodCount(); ++i) {
/*
slot是方法的名字,在以下的内容中,会把它分成三部分(依次判断该方法是否满足这三部分的条件):
第一部分:on_
第二部分:子对象名
第三部分:信号名
*/
        const char *slot = mo->method(i).signature();
        Q_ASSERT(slot);
//以下一行用来判断slot的前三位是否是on_,如果不是,就跳过这个方法。
        if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
            continue;
        bool foundIt = false;
//遍历子对象。
        for(int j = 0; j < list.count(); ++j) {
            const QObject *co = list.at(j);
//得到子对象名。
            QByteArray objName = co->objectName().toAscii();
            int len = objName.length();
//要求slot跳过前3位(on_)后,接下来的子字符串和子对象名相同,并且接着该子字符串又是一个_
//如果达不到这个要求,continue
            if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != '_')
                continue;
            const QMetaObject *smo = co->metaObject();
            int sigIndex = smo->indexOfMethod(slot + len + 4);
            if (sigIndex < 0) { // search for compatible signals
                int slotlen = qstrlen(slot + len + 4) - 1;
//搜索该子对象所能引发的信号
                for (int k = 0; k < co->metaObject()->methodCount(); ++k) {
//方法类型如果符合要求
                    if (smo->method(k).methodType() != QMetaMethod::Signal)
                        continue;
//如果slot最后的子字符串和信号名相同
                    if (!qstrncmp(smo->method(k).signature(), slot + len + 4, slotlen)) {
                        sigIndex = k;
                        break;
                    }
                }
            }
            if (sigIndex < 0)
                continue;
//连接操作
            if (QMetaObject::connect(co, sigIndex, o, i)) {
                foundIt = true;
                break;
            }
        }
//连接成功
        if (foundIt) {
            // we found our slot, now skip all overloads
            while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
                  ++i;
        }
//连接失败
else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
            qWarning("QMetaObject::connectSlotsByName: No matching signal for %s", slot);
        }
    }
}
得出此结论:自动生成的文件中,该函数总会存在setUi函数的最后一句。
该函数的作用就是寻找setUi的唯一指针参数MainWindow所指向对象的成员函数,
该成员函数的名字如果满足以下条件,就做连接操作。
函数名规则:on_子对象名_信号名
函数签名(即返回值与参数要符合slot要求)
所以,我们可以这样做:在qt设计器中添加按纽或者菜单项或者按纽项后,不用在设计器中手动做连接操作。
我们只要在主窗口类中添加符合条件的成员函数即可。
函数名规则:on_子对象名_信号名
函数签名(即返回值与参数要符合slot要求)
例如:
在设计器中添加一个菜单项,其对应的action为actionNew
那么在主窗口类中添加以下的函数
public slots:
       void on_actionNew_triggered();
当切换这个菜单时,会自动执行上面的成员函数。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/myuml/archive/2009/06/10/4259079.aspx
离线dbzhang800

只看该作者 6楼 发表于: 2009-10-15
离线houapple
只看该作者 7楼 发表于: 2009-10-15
      谢谢楼上各位的回复,终于明白了!
      当初命名时因为控件较多所以才这样命名,不料到“撞”上了自动连接,之前也有个这样的命名,但因为是从数据库里面里取数据来显示,所以未发觉取了两次。这次像一个数据表写入两行相同的记录所以导致出错!
       学无止境阿!
       再次感谢!
离线houapple
只看该作者 8楼 发表于: 2009-10-15
恩,我在想哪种使用方式程序运行的效率高呢?
离线foxyz

只看该作者 9楼 发表于: 2009-10-15
这个问题,这里有多人问过了,建议先搜索下
快速回复
限100 字节
 
上一个 下一个