• 基于托管C++的增删改查及异步回调小程序


    基于托管的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()实现了委托回调,目的是添加完毕后,自动刷新主窗体数据。

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

    代码下载:https://files.cnblogs.com/scy251147/CPlusApp.zip

  • 相关阅读:
    Tensorflow的对二次函数的神经网络训练
    ubuntu16.04的Anaconda下的tensorflow安装py3.5
    数字信号处理C语言(3) ------FFT
    数字信号处理C语言(2) ------带高斯噪声的sin函数和组合sin函数
    数字信号处理C语言(1) ------均匀分布和高斯分布随机数
    CCIE学习笔记 ----TSHOOT
    CCIE学习笔记 ----BGP
    CCIE学习笔记 ----GRE over IPsec
    调试
    Java protobuf框架使用向导
  • 原文地址:https://www.cnblogs.com/scy251147/p/2268011.html
Copyright © 2020-2023  润新知