博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于托管C++的增删改查及异步回调小程序
阅读量:5966 次
发布时间:2019-06-19

本文共 6182 字,大约阅读时间需要 20 分钟。

基于托管的C++在一定程度上去除了Native C++语法的复杂性,并且提供了灵活多变的代码组织方式,以下就以一个进行数据库CRUD的小程序来管窥一下C++,我写的这个小程序其实是利用了C#WinForm编程的功力。

先看下软件运行截图吧:

(图1,当加载大数据量的数据时,界面会采用异步方式加载,并给用户提示,涉及到异步调用)

(图2,数据加载完成,会给用户提示)

(图3,更新操作的界面,更新完毕会自动刷新主窗体,涉及到委托回调)

首先来说明连接数据库问题,这里以Sybase为例:

对于Sybase来说,.net没有提供专门的类来操作,所以需要用到ODBC来操作。具体的操作步骤就是在系统DSN中创建一个数据库连接串,然后通过如下的代码来进行操作:

System::String^ connStr = "Driver={Sybase ODBC Driver ASE 12.0};Srvr=MYTestDB;database=TESTDB;uid=sa;pwd=*****;";

然后利用System::Data::Odbc命名空间下的一些方法类来进行操作。

这里我们先来创建数据库,并循环向其中添加1W条数据记录:

create table myTemp (    userId int  identity,    userName varchar(30),    userPass varchar(30),    userAddress varchar(500),    userSex bit,    userPhone varchar(13),    regDate datetime, ) lock allpages with identity_gap = 1 on 'default' set IDENTITY_INSERT myTemp off set IDENTITY_UPDATE myTemp off insert into myTemp ( userId,userName,userPass,userAddress,userSex,userPhone,regDate) values(1,'scy','2511','china, shanghai',1,'13101993996',getdate()) exec createDefaultObjectPermissions @objectName='myTemp' declare @count int select @count = 10000 begin while @count > 0 insert into myTemp ( userName,userPass,userAddress,userSex,userPhone,regDate) values('scy','2511','china, shanghai',1,'13101993996',getdate()) select @count = @count - 1 end

先看查询数据库的代码:

System::String^ querySQL = "select * from myTemp";                  System::String^ connStr = "Driver={Sybase ODBC Driver ASE 12.0};Srvr=MYTestDB;database=TESTDB;uid=sa;pwd=*****;";
          System::Data::Odbc::OdbcConnection^ conn = gcnew System::Data::Odbc::OdbcConnection(connStr);                  conn->Open();                  System::Data::Odbc::OdbcDataAdapter^ oda = gcnew System::Data::Odbc::OdbcDataAdapter(querySQL,conn);                  System::Data::DataSet^ ds =gcnew System::Data::DataSet(); try                  {
oda->Fill(ds,"trade"); } catch(System::Exception^ ex) {
MessageBox::Show(ex->Message,"Notification Error",MessageBoxButtons::OKCancel,MessageBoxIcon::Error); } conn->Close();

通过将查询的代码填充到DataSet容器中,可以很方便的用来进行离线数据的操作。

需要注意的是,如果是.net自身提供的静态类,需要用::(双冒号)来进行操作,如果想自动释放不用的对象,就在申明的时候加上^符号,加上了^符号以后,访问其方法得用->符号。

上面的这段代码,是查询数据库的,如果数据库记录非常多,那么当程序加载的时候,肯定会非常慢,可能会阻塞UI显示达数十秒之久,这个在用户体验上面是非常不友好的,如果解决这个问题呢?当然得用到异步加载功能,其实在Visual C++中实现异步加载和在C#中实现,没有什么区别:

首先,我们的耗时的代码在上面,我们把他写到了一个BindData()的方法里面。然后我们声明一个委托,以便能够对这个方式实现异步调用:

delegate void BindDelegate();

这样,我们就可以通过这个BindDelegate委托的BeginInvoke方法来实现,具体代码如下:

BindDelegate^ bindDelegate = gcnew BindDelegate(this,&CPlusApp::Form1::BindData);  IAsyncResult^ result = bindDelegate->BeginInvoke(gcnew System::AsyncCallback(this,&CPlusApp::Form1::CallBack),bindDelegate);  toolStripStatusLabel1->Text="Loading the Data to dataGridView now, pls wait...";

当委托在加载的时候,用户界面会出现提示“Loading the Data to dataGridView now, pls wait... “,那么当加载完毕以后,我们该怎么处理呢?我们首先应该还原委托对象,然后获取返回值,由于这里的BindData()方法返回空值,我们无需过多的业务处理,代码如下:

private: System::Void CallBack(System::IAsyncResult^ iar)          {
BindDelegate^ asyncResult = (BindDelegate^)iar->AsyncState; asyncResult->EndInvoke(iar); toolStripStatusLabel1->Text="Loading Complete..."; }

当然,写到这里,只能说明数据已经全部加载到了DataSet中,如何将数据集中的数据绑定到数据列表控件dataGridView1上呢?

说到这里,就出现了一个问题,如果直接绑定的话,势必需要跨越线程操作(从异步处理线程跨越到界面线程中),会出现错误提示。这里就需要我们通过判断dataGridView1控件是否需要跨线程,来通过委托方式进行,代码如下:

private:System::Void BindGridViewCrossThreads(DataSet^ ds)             {
if(dataGridView1->InvokeRequired) {
dataGridViewCrossThreadsDelegate^ crossThreads = gcnew dataGridViewCrossThreadsDelegate(this,&CPlusApp::Form1::BindGridViewCrossThreads); dataGridView1->Invoke(crossThreads,ds); } else {
dataGridView1->DataSource = ds->Tables["trade"]; } }

其中dataGridViewCrossThreadsDelegate委托定义如下,需要与函数Void BindGridViewCrossThreads(DataSet^ ds)参数数目、类型以及返回方式保持一致:

delegate void dataGridViewCrossThreadsDelegate(DataSet^ ds); // used for crossing threads

 

好了,做到这里,我们的界面已经能够正常的显示了,并且在加载数据和加载完成的时候,均有用户提示。

下面是添加和更新操作:

System::String^ userName = textBox1->Text;                  System::String^ userPass = textBox2->Text;                  System::String^ userAddr = textBox3->Text;                  System::String^ userPhone = textBox5->Text; int sex = rbtnMale->Checked?1:0;                  System::String^ connStr = "Driver={Sybase ODBC Driver ASE 12.0};Srvr=MYTestDB;database=TESTDB;uid=sa;pwd=*****;";                  System::Data::Odbc::OdbcConnection^ conn = gcnew System::Data::Odbc::OdbcConnection(connStr);                  conn->Open();                  System::Data::Odbc::OdbcCommand^ cmd =nullptr; if(button1->Text->Equals("Add"))                  {
System::String^ insertSQL = "insert into myTemp (userName,userPass,userAddress,userSex,userPhone,regDate) values('"+userName+"','"+userPass+"','"+userAddr+"',"+sex+",'"+userPhone+"',getdate())"; cmd = gcnew System::Data::Odbc::OdbcCommand(insertSQL,conn); } else if(button1->Text->Equals("Update")) {
if(userId == 0) return ; System::String^ insertSQL = "update myTemp set userName = '"+userName+"',userPass = '"+userPass+"',userAddress = '"+userAddr+"',userSex = "+sex+",userPhone = '"+userPhone+"' where userId = "+userId; cmd = gcnew System::Data::Odbc::OdbcCommand(insertSQL,conn); } int result = cmd->ExecuteNonQuery(); if(result > 0) {
MessageBox::Show(""+button1->Text+" Successfully!","Success",System::Windows::Forms::MessageBoxButtons::OK,System::Windows::Forms::MessageBoxIcon::Information); } else {
MessageBox::Show(""+button1->Text+" Fail,Please check!","Fail",System::Windows::Forms::MessageBoxButtons::OK,System::Windows::Forms::MessageBoxIcon::Error); return; } conn->Close(); TransEvent(); this->Close();

注意这里的TransEvent()实现了委托回调,目的是添加完毕后,自动刷新主窗体数据。

好了,暂时介绍到这里,希望在以后项目中能够提供一定的指导作用。

代码下载:

转载地址:http://temax.baihongyu.com/

你可能感兴趣的文章
hdu 1050 (preinitilization or postcleansing, std::fill) ...
查看>>
Form各键盘触发子所对应的“按键”
查看>>
【java IO】使用Java输入输出流 读取txt文件内数据,进行拼接后写入到另一个文件中...
查看>>
Linux系统下安装rz/sz命令及使用说明
查看>>
点击按钮抓不到页面的参数
查看>>
CentOS 6.5 下安装 Redis 2.8.7
查看>>
第一次模拟面试
查看>>
window.showModalDialog
查看>>
Pycharm选择pyenv安装的Python版本
查看>>
?Sized 和 Sized
查看>>
Java中如何防止内存泄漏的发生
查看>>
Java中Int转byte分析
查看>>
滑动窗口最大值的golang实现
查看>>
初学Phreeze 3
查看>>
会计的思考(17):还原会计报表的企业个性之一
查看>>
java对象初始化顺序的简单验证
查看>>
[CF452E]Three strings
查看>>
获取指定进程所对应的可执行(EXE)文件全路径(代码)
查看>>
ORA-01722:无效数字
查看>>
搭建golang+vscode开发环境
查看>>