Using DBGrid in Unbound Mode

This sample was contributed by Adrian Roman.

It took me some time to notice all this, and because I couldn't find anywhere documentation about DBGrid unbound programming in VC++ (only in VB), I think that will be nice to share my observations with others.

First, even documentation says that it accepts (almost) any type of Variant as bookmark, it seems that it is not true. DaoRecordsets have SAFEARRAY as bookmarks (GetBookmark returns Variant which contains VT_ARRAY | VT_UI1), and did not work with DBGrid (the grid simply converts the variant to VT_BSTR).

It may work with VT_I4, or something like this, but because somewhere it says that strings are the best, I used them. Of course, I converted the bookmarks to strings and back.

SchedQ is a dynaset (CDaoRecordset) resulted from a query.

If you find any bugs or have some ideas, please share your findings with me.

And, I almost forgotten! IMPORTANT! If you generate RowBuffer class from OCX's type library, modify the constructor that gets LPDISPACH as parameter to call base class constructor with the second one setted to FALSE (it is implicitly TRUE). Or else, the whole thing will crash when RowBuffer object gets destroyed.

Some supplementary tips: use BeforeColUpdate and KeyPress events to validate a field and, respectively, to filter key input.

Please don't send me e-mails with questions about using it in bound mode. Just add on the dialog the Microsoft Remote Data Control before inserting the dbgrid, and play a little with properties. You'll figure out how to use it.

For those who want to modify columns at run-time: The generated GetColumns() member function of dbgrid's class is really a GetColumn function (returns a LPDISPATCH to a single column - so you can use this LPDISPATCH to construct Column objects, not Columns). If you want to obtain the LPDISPATCH to Columns collection, rename it as GetColumn, and rewrite GetColumns like this one:

LPDISPATCH CMsDgridCtrl::GetColumns()
{
   LPDISPATCH result;
   InvokeHelper(0x8,DISPATCH_PROPERTYGET,VT_DISPATCH,
                (void*)&result,NULL,NULL);
   return result;
}

You can use the returned LPDISPATCH to construct the Columns object.

Now, the code for feeding the grid with data, deletind records, and obtaining data back when writes occur:

void CMyView::OnUnboundReadDataDbgridMy(LPDISPATCH RowBuf,
                                        VARIANT FAR* StartLocation,
                                        BOOL ReadPriorRows)

{
   // TODO: Add your control notification handler code here
   RowBuffer buf(RowBuf);
   VARIANT varbok;
   varbok.vt=VT_ARRAY | VT_UI1;
   long Row,RowsFetched;
   VARIANT var;
   RowsFetched=0;
   if(StartLocation->vt==VT_NULL){
      if(ReadPriorRows){
         try{
            SchedQ->MoveLast();
         }catch(CDaoException* e){
            e->Delete();
         }
      }else{
         try{
            SchedQ->MoveFirst();
         }catch(CDaoException* e){
            e->Delete();
         }
      }
   }else{
      // Find the position to start reading based on the
      // StartLocation bookmark and ReadPriorRows parameter
      try{
         VectorFromBstr(StartLocation->bstrVal,&varbok.parray);
         SchedQ->SetBookmark(COleVariant(varbok));
         if(ReadPriorRows)SchedQ->MovePrev();
         else SchedQ->MoveNext();
      }catch(CDaoException* e){
         e->Delete();
      }
   }
   // Transfer data from our data set array to the RowBuf
   // object which DBGrid uses to display the data
   for(Row = 0; Row<buf.GetRowCount() ;Row++){
      if(SchedQ->IsEOF() || SchedQ->IsBOF())break;
      var.vt=VT_I4;
      var.lVal=SchedQ->m_WorkCodeID;
      if(buf.GetColumnCount()>0)buf.SetValue(Row, 0,var);
      COleVariant olvi(SchedQ->m_TimeIn);
      var=*((LPVARIANT)olvi);
      if(buf.GetColumnCount()>1)buf.SetValue(Row, 1,var);
      COleVariant olvo(SchedQ->m_TimeOut);
      var=*((LPVARIANT)olvo);
      if(buf.GetColumnCount()>2)buf.SetValue(Row, 2,var);
      // Set bookmark using CurRow which is also our
      // array index
      var.vt=VT_BSTR;
      BstrFromVector(((LPVARIANT)SchedQ->GetBookmark())->
                     parray,&var.bstrVal);
      buf.SetBookmark(Row,var);
      RowsFetched++;
      if(ReadPriorRows)SchedQ->MovePrev();
      else SchedQ->MoveNext();
   }
   buf.SetRowCount(RowsFetched);
}


void CMyView::OnUnboundWriteDataDbgridMy(LPDISPATCH RowBuf,
                                         VARIANT FAR* WriteLocation)
{
   // TODO: Add your control notification handler code here
   RowBuffer buf(RowBuf);
   VARIANT varbok;
   varbok.vt=VT_ARRAY | VT_UI1;
   COleVariant var;
   CString str;
   try{
      VectorFromBstr(WriteLocation->bstrVal,&varbok.parray);
      SchedQ->SetBookmark(COleVariant(varbok));
   }catch(CDaoException* e){
      e->Delete();
      buf.SetRowCount(0);
      return;
   }

   //****************************************************
   //Here was a portion of code that validated the record
   //****************************************************
   // Only columns that have been changed will be updated.
   // Otherwise, the value will be set to NULL
   try{
      SchedQ->Edit();
   }
   catch(CDaoException* e){
      e->Delete();
      buf.SetRowCount(0);
      return;
   } 
   if(buf.GetValue(0L, 0).vt!=VT_NULL){
      var=buf.GetValue(0, 0);
      str=CString(var.bstrVal);
      SchedQ->m_WorkCodeID=atol(str);
   }
   if(buf.GetValue(0L, 1).vt!=VT_NULL){
      var=buf.GetValue(0, 1);
      str=CString(var.bstrVal);
      SchedQ->m_TimeIn.ParseDateTime(str);
   }
   if(buf.GetValue(0L, 2).vt!=VT_NULL){
      var=buf.GetValue(0, 2);
      str=CString(var.bstrVal);
      SchedQ->m_TimeOut.ParseDateTime(str);
   }
   try{
      SchedQ->Update();
   }catch(CDaoException *e){
      SchedQ->CancelUpdate();
      e->Delete();
      buf.SetRowCount(0);
   }
}


void CMyView::OnUnboundAddDataDbgridMy(LPDISPATCH RowBuf,
                                       VARIANT FAR* NewRowBookmark) 
{
   // TODO: Add your control notification handler code here
   RowBuffer buf(RowBuf);
   COleVariant var;
   CString str;
   NewRowBookmark->vt=VT_NULL;

   //****************************************************
   //Here was a portion of code that validated the record
   //****************************************************
   try{
      SchedQ->AddNew();
      SchedQ->Update();
      SchedQ->SetBookmark(SchedQ->GetLastModifiedBookmark());
      SchedQ->Edit();
   }catch(CDaoException* e){
      e->Delete();
      buf.SetRowCount(0);
      return;
   } 
   SchedQ->m_EmployeeID=m_pSet->m_EmployeeID;
   try{
      if(buf.GetValue(0L, 0).vt!=VT_NULL){ 
         var=buf.GetValue(0, 0);
      }else{
         var.vt=VT_I4; 
         var.lVal=0;
         Column col(m_SchedGrid.GetColumns(var));
         var=col.GetDefaultValue();
      }
      str=(char*)_bstr_t(var.bstrVal);
      SchedQ->m_WorkCodeID=atol(str);
      if(buf.GetValue(0L, 1).vt!=VT_NULL){
         var=buf.GetValue(0, 1);
      }else{
         var.vt=VT_I4; 
         var.lVal=1;
         Column col(m_SchedGrid.GetColumns(var));
         var=col.GetDefaultValue();
      }
      str=(char*)_bstr_t(var.bstrVal);
      SchedQ->m_TimeIn.ParseDateTime(str);
      if(buf.GetValue(0L, 2).vt!=VT_NULL){
         var=buf.GetValue(0, 2);
      }else{
         var.vt=VT_I4; 
         var.lVal=2;
         Column col(m_SchedGrid.GetColumns(var));
         var=col.GetDefaultValue();
      }
      str=(char*)_bstr_t(var.bstrVal);
      SchedQ->m_TimeOut.ParseDateTime(str);
      var.vt=VT_I4;
      SchedQ->Update();
   }catch(CDaoException *e){
      e->Delete();
      SchedQ->CancelUpdate();
      SchedQ->Delete();
      buf.SetRowCount(0);
   }
   NewRowBookmark->vt=VT_BSTR;
   BstrFromVector(((LPVARIANT)SchedQ->GetBookmark())->parray,
                   &(NewRowBookmark->bstrVal));
}


void CMyView::OnUnboundDeleteRowDbgridMy(VARIANT FAR* Bookmark)
{
   // TODO: Add your control notification handler code here
   VARIANT varbok;
   varbok.vt=VT_ARRAY | VT_UI1;
   VectorFromBstr(Bookmark->bstrVal,&varbok.parray);
   try{
      SchedQ->SetBookmark(COleVariant(varbok));
      SchedQ->Delete();
   }catch(CDaoException* e){
      Bookmark->vt=VT_NULL;
      e->Delete();
   }
}


Comments

  • Columns Class

    Posted by Sreenivas on 03/19/2004 01:12am

    Dear Sir,
        Your code helps me a lot.But one problem I am facing is I able to get collection object as you said,All the functions are working fine except SetAdd method in "Columns" class.When I try to call that function it is giving error "Invalid number of parameters".The Code snippet is follows :
    
    LPDISPATCH pDisp = m_myGrid.GetColumns();
    Columns pColumns(pDisp);
    pColumns.SetAdd(0);
    
    I look forward to get a solution from you.
    
    Thanks and Regards,
    Sreenivas

    Reply
  • Plse , send me full sorce code

    Posted by Legacy on 02/23/2004 12:00am

    Originally posted by: Rajan Kapadia

    please send me full source code of your application.

    Reply
  • can u send full source code for this

    Posted by Legacy on 02/21/2004 12:00am

    Originally posted by: selva

    can u send full source code to my mail id.

    Reply
  • DBGrid

    Posted by Legacy on 02/13/2004 12:00am

    Originally posted by: Vladimir

    Please send me the source code

    Thanks
    Vladimir

    Reply
  • thank you

    Posted by Legacy on 01/31/2004 12:00am

    Originally posted by: omid

    please send me full source of this project
    thank you
    bye

    Reply
  • Please send me full code for this project,please......

    Posted by Legacy on 01/28/2004 12:00am

    Originally posted by: andreas ginting

    please sent to my email. I really want to program in VC but I don't have enough references and sample. so please help me


    best regards

    andreas ginting, jakarta indonesia

    Reply
  • Please send me full code for this project,please......

    Posted by Legacy on 01/28/2004 12:00am

    Originally posted by: andreas ginting

    please sent to my email. I really want to program in VC but I don't have enough references and sample. so please help me


    best regards

    andreas ginting, jakarta indonesia

    Reply
  • DataAcquisition

    Posted by Legacy on 01/17/2004 12:00am

    Originally posted by: SG Prasad

    Can Anyone pls send the code in Vb for Data Acquisition and transfer from PLC(programmable logic controller) to Database 
    

    • henhao

      Posted by luyi9798 on 04/03/2005 01:29am

      henhao

      Reply
    Reply
  • How to Add DBGrid functionalities in VC++ Programs

    Posted by Legacy on 10/13/2003 12:00am

    Originally posted by: Nitin Verma

    i will be goin' thru ur code at a later time...appeals good

    Reply
  • The source please for final proyect's school

    Posted by Legacy on 09/16/2003 12:00am

    Originally posted by: Neftaly

    Hi,
    Please, can you send me the source code.
    It's very important for me

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • U.S. companies are desperately trying to recruit and hire skilled software engineers and developers, but there is simply not enough quality talent to go around. Tiempo Development is a nearshore software development company. Our headquarters are in AZ, but we are a pioneer and leader in outsourcing to Mexico, based on our three software development centers there. We have a proven process and we are experts at providing our customers with powerful solutions. We transform ideas into reality.

  • On-demand Event Event Date: August 27, 2015 With the cloud enabling companies to spin up servers and stand up data stores more quickly, mobile apps can be created faster, reducing the time-to-value. But three major obstacles stand in the way for many organizations: The backlog of app project requests confronting every enterprise regardless of their internal app development capabilities Finding and employing better, faster tools to speed and simplify the process of developing those apps. The emergence of …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date