Page 1 of 1

Problem with aFields( ) in most recent version of FWH

Posted: Thu Jul 04, 2024 12:38 am
by TimStone
In the past I have used the following code to obtain the field names and types for an "in use" database. This is used to build a Filter statement in a variant of FiveDBU. It has worked correctly for many years.

Code: Select all | Expand


  nFlds := ::oDbf:Fcount( )
  aNames := Array( nFlds )  
  aTypes := Array( nFlds ) 
  aFields( aNames, aTypes  )

 
aFields would fill the array with the names of each field, and aTypes with the data type for that same field. Now it simply inserting 3 items into the aNames array ( labels ), and nothing else, although the database has 12 actual fields. What is inserted has no bearing to the actual fields.

As I said, it was never a problem until the latest FWH libs. I'm open to a better way if anyone has a suggestion. NOTE: I am using a database object in this class.

Tim

Re: Problem with aFields( ) in most recent version of FWH

Posted: Thu Jul 04, 2024 5:14 am
by Antonio Linares
Dear Tim,

This is working fine:

local aInfo := DbStruct()

XBrowse( aInfo )

Re: Problem with aFields( ) in most recent version of FWH

Posted: Thu Jul 04, 2024 5:22 am
by TimStone
With a data object ?

ODbf is opened in a class, and here we need to see it’s fields in a combobox to build a filter.

I did not see dbstruct() as a method in tdatabase class


Sent from my iPhone using Tapatalk

Re: Problem with aFields( ) in most recent version of FWH

Posted: Thu Jul 04, 2024 5:25 am
by Antonio Linares
Dear Tim,

DbStruct() is a Harbour function, so as long as you are in the right workarea it will work fine

Re: Problem with aFields( ) in most recent version of FWH

Posted: Thu Jul 04, 2024 5:57 am
by Antonio Linares
It can be easily added to Class TDataBase this way:

METHOD DbStruct() INLINE ( ::cAlias )->( DbStruct() )

or simply

METHOD Struct() INLINE ( ::cAlias )->( DbStruct() )

Re: Problem with aFields( ) in most recent version of FWH

Posted: Thu Jul 04, 2024 6:56 am
by nageswaragunupudi
Even without any changes to TDatabase class, you can use

Code: Select all | Expand

oDbf:DbStruct()
Note: If you are using unmodified tdatabase class, you can use any Harbour function as a method.
eg:

Code: Select all | Expand

odbf:dbstruct()

Re: Problem with aFields( ) in most recent version of FWH

Posted: Thu Jul 04, 2024 7:08 am
by nageswaragunupudi

Code: Select all | Expand

aFields( aNames, aTypes  )
Is aFields() your function?
There has never been a function with this name in FWH in any version till now.
Can you please let us know in which version of FWH the code you posted was working?

Re: Problem with aFields( ) in most recent version of FWH

Posted: Thu Jul 04, 2024 7:39 am
by nageswaragunupudi
In any case, if you want an array of only fieldnames and fieldtypes

Code: Select all | Expand

aFields := ArrTranspose( ASize( ArrTranspose( oDbf:aStruct ), 2 ) )
Test:

Code: Select all | Expand

   oDbf  := TDatabase():Open( nil, "STATES.DBF" )
   aFields := ArrTranspose( ASize( ArrTranspose( oDbf:aStruct ), 2 ) )
   XBROWSER aFields

Re: Problem with aFields( ) in most recent version of FWH

Posted: Thu Jul 04, 2024 6:55 pm
by TimStone
This is the complete method. It is actually derived from FiveDBU.prg, but customized only for .dbf files since that is all I use in the program.

The purpose is to allow the end user to build a filter string. The aNames array contains the names of the fields. The aTypes array holds the corresponding type for each field so it can be entered properly in the filter.

This worked perfectly until the last library I received from Antonio to correct another issue.

Here is the full method code:

Code: Select all | Expand

METHOD FilterDbf(  )

 MEMVAR oBrush, oMFont

 LOCAL cFilterField := SPACE(20), cFilterValue := SPACE( 50 ), cOpsType := "="
 LOCAL cFilterString := SPACE( 200 )
 LOCAL lDoFilter := .f., lClearFilter := .t.
 LOCAL cProcessString, nFilterField
 PRIVATE aTypes, aNames, nFlds, oFRec, cFilterType, cField2, cFField3
 PRIVATE aOpsType := { "=", "<", "<=", "<>", ">=", ">" }
 
  nFlds := ::oDbf:Fcount( )
  aNames := Array( nFlds )  
  aTypes := Array( nFlds ) 
  aFields( aNames, aTypes  )

  // Create the DIALOG
    DEFINE DIALOG oFRec OF ::oEwndChild RESOURCE "FEFILTERW" BRUSH oBrush TRANSPARENT TITLE "Search/Filter the Database" FONT oMFont
    oFRec:nHelpID := 1300

  // And the new value
  REDEFINE GET cFilterString ID 601 OF oFRec MESSAGE "Enter the new filter/search command line"

  // Select the field
  REDEFINE COMBOBOX cFilterField ITEMS aNames ID 602 OF oFRec ;
        STYLE CBS_DROPDOWN  MESSAGE "Select the field for selecting records"

  // Next select the operator
  REDEFINE COMBOBOX cOpsType ITEMS aOpsType ID 603 OF oFRec ;
        STYLE CBS_DROPDOWN  MESSAGE "Select the comparison operator"

  // Then get the value
    REDEFINE GET cFilterValue ID 604 OF oFRec MESSAGE "Enter the current value to match"

    REDEFINE BTNBMP RESOURCE "HROK" PROMPT "Process Filter" ID 610 of oFRec NOBORDER TRANSPARENT ;
             ACTION ( lDoFilter := .t., oFRec:end() )

    REDEFINE BTNBMP RESOURCE "HREXIT" PROMPT "Exit & Clear Filter" ID 611 of oFRec NOBORDER TRANSPARENT ;
             ACTION ( lClearFilter, oFRec:end() )

    ACTIVATE DIALOG oFRec ON INIT ( oFRec:center(wndmain()) )

    IF lDoFilter

        IF EMPTY( cFilterString )

      // We want the field number of the replacement field
      cFilterField := TRIM( cFilterField )
        nFilterField := Ascan( aNames, cFilterField )
        // We want the type of data of the selected field
        cFilterType := aTypes[ nFilterField ]

        // Make sure the new value matches the type of the field and is defined as vNewValue
        IF cFilterType = "C" .OR. cFilterType = "M"
           cFField3 := ( '"' + TRIM( cFilterValue ) + '"' )
        ELSEIF cFilterType = "D"
           cFField3 := DTOS( cFilterValue )
        ELSEIF cFilterType = "N" .OR. cFilterType = "L"
           cFField3 := cValToChar( cFilterValue )
        ELSE
             cFField3 := "     "
        ENDIF

      IF ! EMPTY( cFField3 )
            cProcessString := cFilterField + cOpsType + cFField3
      ELSE
        cProcessString := " "
      ENDIF

    ELSE

        cProcessString := cFilterString

    ENDIF

    IF EMPTY( cProcessString )
      lClearFilter := .t.
      ELSE
        ::oDbf:setfilter( cProcessString )
        ::oDbf:gotop( )
        lClearFilter := .f.
    ENDIF

  ENDIF

  IF lClearFilter
     ::oDbf:SetFilter( )
     ::oDbf:gotop( )
  ENDIF

RETURN NIL