我之前写代码的时候,网上收集资料的时候,发现qt连接数据库编程有两种方式,一种是qt下自己的库文件,还有一种是自己写,就是自己是自己的基类。
我采用的是第二种,就是自己写类
步骤:QT里面调用数据库的库文件,这个是设置路径window下的数据库是:
找到安装路径下的库文件,然后添加路径进来就可以了
在这个里面添加路径,加上这个命令就可以了。linux下则添加:
LIBS += -lmysqlclient
这个主要看编译环境,linux和window的编译可以理解成,和系统没有关系,是qt库的问题,比如qt4的工程用qt5来编译也有少量这种情况,人家有可能为了规范更改了文件名,也有可能为了扩展增加了某些文件,你在不同的系统或者不同的版本,说白了就是不同的安装包安装的qt有可能缺少或者增加某些文件。主要是库文件的调用问题。
我们要建立一个mymysql的基类
然后再mymysql里面添加
#include <windows.h> #include <C:/mysql/include/mysql.h>
这个是window的头文件,还有这两个顺序不能错,否则编译不能通过。
linux下使用mysql.h的方法 #include <mysql/mysql.h>
这个是linux定义头文件的方法,采用相对路径
int mymysql::sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName)
{
connection = mysql_real_connect(&mysql, Hostname, User, Password, DBName, 0, 0,0);
if (connection == NULL)
{
memset(buf, 0, sizeof(buf));
strcpy(buf, mysql_error(&mysql));
//QMessageBox::information(0, "", mysql_error(&mysql));
return -1;
}else
{
mysql_query(connection, "set names utf8");
return 0;
}
}
mysql_real_connect()
此函数尝试与运行在主机上的MySQL数据库引擎建立连接。 此函数成功完成之后,才能使用mysql的其他函数。
函数原型:
MYSQL *mysql_real_connect(MYSQL *mysql, const cahr *host, const cahr *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)
参数解释:
mysql: 已有mysql结构的地址
host: 主机名或者地址
user:用户的MYSQL登陆ID
passwd:用户的密码
db:数据库的名称
port:如果port不是0,其值将用作TCP/IP连接的端口号
unix_socket:如果次参数不为空,该字符串描述了应使用的套接字或命名管道
client_flag:通常为0
set names utf8指定了客户端和服务器之间传递字符的编码规则为UTF8。 这个必须要加,要不然可能会出现乱码和接受不到数据的现象。
mysql_error(&mysql)这个函数是打印乱码的信息,打个比方,我们登入数据库的时候,输出密码,就会返回错误信息(会指明哪里出错)
void mymysql::sql_disconnet()
{
if (connection)
{
mysql_close(connection);
connection = NULL;
}
}
这个我们在注销登入的时候,就用这个函数,我们设置的注销登入的槽函数里面就放人这个函数就可以了。
int mymysql::sql_exec(const char *SQL)
{
if (mysql_query(connection, SQL) != 0)
{
memset(buf, 0, sizeof(buf));
strcpy(buf, mysql_error(&mysql));
return -1;
}
return 0;
}
int mymysql::sql_open(const char *SQL, QStandardItemModel **p)
{
if (mysql_query(connection, SQL) != 0)
{
memset(buf, 0, sizeof(buf));
strcpy(buf, mysql_error(&mysql));
return -1;
}
MYSQL_RES *result = mysql_store_result(connection);
if (result == NULL)//没有查询结果
{
memset(buf, 0, sizeof(buf));
strcpy(buf, mysql_error(&mysql));
return -1;
}
int rowcount = mysql_affected_rows(connection);//这个函数返回SQL语句执行后又多少行
int fieldcount = mysql_field_count(connection);//这个函数返回SQL语句执行后有多少列
*p = new QStandardItemModel(rowcount, fieldcount);//根据SQL语句返回的行列总数,动态的建一个modul出来.
MYSQL_FIELD *field;
int i = 0;
int j = 0;
for(i = 0;i<fieldcount;i++)
{
field = mysql_fetch_field(result);
(*p)->setHeaderData(i, Qt::Horizontal, field->name);
}
for(i = 0;i<rowcount;i++)//循环遍历每一行
{
MYSQL_ROW row = mysql_fetch_row(result);
for(j = 0;j<fieldcount;j++)//循环遍历一行当中所有的列
{
(*p)->setData((*p)->index(i, j, QModelIndex()), row[j]);
}
}
mysql_free_result(result);//释放通过mysql_store_result函数分配的内存空间
return 0;
}
这里用的的函数是mysql_query,mysql_query()如果里面放的是查询之类的语句,那返回的是资源,说白了就是你要查的数据结果集;如果里面放的是增删改之类的语句,那返回的是true或者false了。所以下面要加判断函数。
void MainWindow::script_msg(const char *SQL)
{
int res = 0;
if ((strncmp(SQL, "SELECT", 6) == 0) || (strncmp(SQL, "select", 6) == 0))
{
QStandardItemModel *modul = NULL;
res = db.sql_open(SQL, &modul);//如果是SELECT,那么执行sql_open这个函数
QTableView *view1 = new QTableView;
view1->setAttribute(Qt::WA_DeleteOnClose);//view在close的时候自动会delete,这个时候如果view有modul的话,这个modul会被view自动释放。
mdiArea->addSubWindow(view1);
view1->setStyleSheet("border-image: url(3.jpg);");//设置widget背景图片
//view1继承自widget,如果没有modul,那么view不会显示任何数据.
view1->setModel(modul);
view1->show();
mdiArea->activeSubWindow()->resize(width() - 100, height() - 100);
}else
{
res = db.sql_exec(SQL);//如果用户执行的是非SELECT。那么执行sql_exec函数
}
if (res == -1)
{
QMessageBox::information(this, "执行失败", db.geterror());
}else
{
QMessageBox::information(this, "提示", "执行成功");
}
}
这里要区分select,查询操作的数据要给model----->>>view显示。
在里面有一个小技巧,就是数据库的数据怎么给model了,因为是两个不同的类,类与类传输数据的时候,一般是单向的,我们而且很少尽可能不去用友原,所以这里用来指针来传输数据。我们建立一个动态的view,应该怎么样去建立了,因为必须要有一个动态的model才行,可以找查找命令得到多少行和列:
int rowcount = mysql_affected_rows(connection);//这个函数返回SQL语句执行后又多少行
int fieldcount = mysql_field_count(connection);//这个函数返回SQL语句执行后有多少列
这样我们就可以用来个for循环嵌套一下就可以了,遍历所有的数据,然后数据在传给model。
(*p)->setData((*p)->index(i, j, QModelIndex()), row[j]);
这一条i,j代表行和列,然后填充数据。model和view之间传输要建立索引机制