Clipper On Line • Ver Tópico - MediaMonkey / Aplicativos

MediaMonkey / Aplicativos

Discussão sobre interface com o Cliente.

Moderador: Moderadores

 

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 14 Ago 2020 12:22

Continuo usando o MediaMonkey pra músicas.
Mas continuo olhando de outra forma....

mediamonkey.png


Em destaque o recurso de lista automática.
Esse recurso é só com a versão paga, ou com crack.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 14 Ago 2020 12:25

auto1.png


Configuração de filtros, configuração de ordem, configuração de limites.
Detalhe no filtro: pode ser CADA um individual, ou TODOS ao mesmo tempo.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 14 Ago 2020 12:27

auto2.png


CADA filtro, tem lá o campo referência, o tipo de análise a ser feita, e com o que vai ser comparado.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 14 Ago 2020 13:11

Pra curiosidade:

Tem a opção AUTO DJ, que automaticamente adiciona músicas pra tocar.
Configurei pra selecionar 5 músicas dessa lista "Play List", é feita uma escolha randômica.

A PLaylist:

Ela busca, em todas as músicas, em ordem das que defini como melhores, e mais tocadas, num limite de 100 músicas.
100 músicas, aprox. 5 minutos cada, a lista inicial atende mais de um dia de música.

A lista não considera execuções multiplas de 5, significa que uma música tocada 5 vezes, ou 10 vezes, sai da lista.
Se deixar assim eternamente, vai acabar tocando todas as músicas, 5 vezes cada uma e parar.

Ainda assim, a ordem principal é de "pulos". Se pular uma música, ela vai pro fim da fila geral, quanto mais pular, mais pro fim da fila ela vai. Fim da fila significa que se tem 2.000 músicas, precisa tocar 1900 músicas 5 vezes, pra chegar nas 100 últimas, onde talvez ela seja a próxima.

As múltiplas de 5.... se eu quiser que entre na fila novamente, é só acrescentar na lista.
Supondo que sejam 5 execuções, ao tocar mais uma vez, aumenta pra 6 e entra na lista até trocar 10 vezes.

É tudo automático, basta ficar ouvindo música, pular alguma, ou repetir alguma que tocou 5 vezes.

Uma lista das piores pode ser as mais puladas e menos tocadas... candidatas pra exclusão.
A gente acaba sempre guardando clássicas, por serem clássicas e não porque gostamos de ouvir toda hora....

Já cheguei a ter mais de 50.000 músicas, mas hoje tem só cerca de 2.000, e mesmo assim, várias são porque meu filho é quem gosta.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 14 Ago 2020 13:11

Bom....
Agora vamos ao que interessa.

E uma coisa assim no aplicativo?
Isso pode ser considerado como um gerador de relatórios, totalmente definido pelo usuário.
Ele vai ter resumos do jeito que ele quer/precisa, prontos para uso.

Estou começando a olhar essa lista do MediaMonkey por este ponto de vista.

Só pra lembrar: o MediaMonkey usa SQLite3 e comandos SQL, é isso que deixa tudo flexível.
Mas é lógico... escolher músicas não dá pra comparar com escolher informações do aplicativo... mas é pra pensar.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 17 Ago 2020 16:52

Não achei minha postagem da outra vez, mas um parecido que fiz foi este.
Infelizmente, está um pouco preso ao meu aplicativo, está nas opções de teste.
Deixo a maioria das coisas assim, porque minha pasta temporária é limpa automaticamente, com qualquer teste que eu faça lá....

/*
PTESFILTRO - Teste do filtro automatico
José Quintas
*/

#include "hbclass.ch"
#include "inkey.ch"
#define FIELD_NAME       1
#define FIELD_COMPARE    2
#define FIELD_SELECTED   3
#define FIELD_RANGEFROM  4
#define FIELD_RANGETO    5
// Until 8, to define list

#define COMPARE_NO_FILTER          1 //
#define COMPARE_EQUAL              2 // =
#define COMPARE_GREATHER_OR_EQUAL  3 // >=
#define COMPARE_LESS_OR_EQUAL      4 // <=
#define COMPARE_GREATHER           5 // >
#define COMPARE_LESS               6 // <
#define COMPARE_NOT_EQUAL          7 // !=
#define COMPARE_RANGE              8 // >= rangefrom .AND. <= rangeto
#define COMPARE_HAS_TEXT           9 // text $ field
#define COMPARE_NOT_HAS_TEXT      10 // ! text $ field
#define COMPARE_BEGIN_WITH_TEXT   11 // field = text*
#define COMPARE_IN_TEXT           12 // field $ text
#define COMPARE_NOT_IN_TEXT       13 // ! field $ text

MEMVAR acFields

PROCEDURE PTESFILTRO

   LOCAL oFilter

   IF ! AbreArquivos( "jpctplano" )
      RETURN
   ENDIF
   oFilter := FilterClass():New()
   oFilter:Execute()
   CLOSE DATABASES

   RETURN

CREATE CLASS FilterClass

   VAR    acFilterConfig   INIT {}
   METHOD Init()
   METHOD Filter()                                 // filter result
   METHOD FilterAsString()                         // an string with filter to be displayed
   METHOD FilterOptionsAsArray( lIncludeAll )      // an array to use as options to select
   METHOD FilterOptions()                          // an array with filter types
   METHOD Show( nRowi, nColi, nRowf, nColf )       // diplay filter string
   METHOD ChooseFilter()                           // user select filter options
   METHOD SelectFields()
   METHOD GetFieldFilter( nOpcCompare, nFieldCompare, xFieldIni, xFieldEnd )
   METHOD Execute()
   METHOD Browse( nTop, nLeft, nBottom, nRight )

   ENDCLASS

METHOD Init() CLASS FilterClass

   LOCAL acStru, nCont, xValue

   acStru := dbStruct()
   FOR nCont = 1 TO Len( acStru )
      xValue := EmptyValue( FieldGet( nCont ) )
      Aadd( ::acFilterConfig, { FieldName( nCont ), COMPARE_NO_FILTER, .F., xValue, xValue, xValue, xValue, xValue } )
   NEXT

   RETURN NIL

METHOD Filter() Class FilterClass

   LOCAL oElement, lReturn := .T., xValue

   FOR EACH oElement IN ::acFilterConfig
      xValue := FieldGet( FieldPos( oElement[ FIELD_NAME ] ) )
      DO CASE
      CASE oElement[ FIELD_COMPARE ] == COMPARE_NO_FILTER
      CASE oElement[ FIELD_COMPARE ] == COMPARE_EQUAL ;             lReturn := ( xValue == oElement[ FIELD_RANGEFROM ] )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_GREATHER_OR_EQUAL ; lReturn := ( xValue >= oElement[ FIELD_RANGEFROM ] )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_LESS_OR_EQUAL ;     lReturn := ( xValue <= oElement[ FIELD_RANGEFROM ] )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_GREATHER ;          lReturn := ( xValue >  oElement[ FIELD_RANGEFROM ] )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_LESS ;              lReturn := ( xValue <  oElement[ FIELD_RANGEFROM ] )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_NOT_EQUAL ;         lReturn := ( xValue != oElement[ FIELD_RANGEFROM ] )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_RANGE ;             lReturn := ( xValue >= oElement[ FIELD_RANGEFROM ] .AND. xValue <= oElement[ FIELD_RANGETO ] )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_HAS_TEXT ;          lReturn := ( Trim( oElement[ FIELD_RANGEFROM ] ) $ xValue )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_NOT_HAS_TEXT ;      lReturn := ( ! Trim( oElement[ FIELD_RANGEFROM ] ) $ xValue )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_BEGIN_WITH_TEXT ;   lReturn := ( Substr( xValue, 1, Len( Trim( oElement[ FIELD_RANGEFROM ] ) ) ) == Trim( oElement[ FIELD_RANGEFROM ] ) )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_IN_TEXT;            lReturn := ( xValue $ oElement[ FIELD_RANGEFROM ] )
      CASE oElement[ FIELD_COMPARE ] == COMPARE_NOT_IN_TEXT;        lReturn := ( ! xValue $ oElement[ FIELD_RANGEFROM ] )
      ENDCASE
      IF ! lReturn
         EXIT
      ENDIF
   NEXT

   RETURN lReturn

METHOD FilterAsString() CLASS FilterClass

   LOCAL xValue, oElement

   xValue := ""
   FOR EACH oElement IN ::acFilterConfig
      IF oElement[ FIELD_COMPARE ] != COMPARE_NO_FILTER
         xValue += oElement[ FIELD_NAME ] + " "
         xValue += ::FilterOptions()[ oElement[ FIELD_COMPARE ] ] + " "
         IF oElement[ FIELD_COMPARE ] == COMPARE_RANGE
            xValue += Trim( Transform( oElement[ FIELD_RANGEFROM ], "" ) ) + " to "
            xValue += Trim( Transform( oElement[ FIELD_RANGETO ], "" ) )
         ELSE
            xValue += Trim( Transform( oElement[ FIELD_RANGEFROM ], "" ) )
         ENDIF
         xValue += ", "
      ENDIF
   NEXT

   RETURN xValue

METHOD FilterOptionsAsArray( lIncludeAll ) CLASS FilterClass

   LOCAL xValue, acTxtFiltros := {}, oElement

   hb_Default( @lIncludeAll, .T. )
   FOR EACH oElement IN ::acFilterConfig
      xValue := oElement[ FIELD_NAME ] + " "
      IF oElement[ FIELD_COMPARE ] == COMPARE_NO_FILTER
         xValue += " No Filter "
      ELSE
         xValue += ::FilterOptions()[ oElement[ FIELD_COMPARE ] ] + " "
         IF oElement[ FIELD_COMPARE ] == COMPARE_RANGE
            xValue += Trim( Transform( oElement[ FIELD_RANGEFROM ], "" ) ) + " to " + xValue + Trim( Transform( oElement[ FIELD_RANGETO ], "" ) )
         ELSE
            xValue += Trim( Transform( oElement[ FIELD_RANGEFROM ], "" ) )
         ENDIF
      ENDIF
      IF oElement[ FIELD_COMPARE ] != COMPARE_NO_FILTER .OR. lIncludeAll
         Aadd( acTxtFiltros, xValue )
      ENDIF
   NEXT

   RETURN acTxtFiltros

METHOD FilterOptions() CLASS FilterClass

   LOCAL xValue := { "No Filter", "equal", "Greather or Equal", "Less or Equal", "Greather", "Less", "Not Equal", "Range", "Have Text", "Haven't Text", "Begin With", "In Text", "Not In Text" }

   RETURN xValue

METHOD Show( nRowi, nColi, nRowf, nColf ) CLASS FilterClass

   LOCAL cText, nLen, nCont

   nLen := nColf - nColi + 1
   cText := ::FilterAsString()
   FOR nCont = nRowi TO nRowf
      @ nCont, nColi SAY Substr( cText, ( nCont - nRowi ) * nLen + 1, nLen )
   NEXT

   RETURN NIL

METHOD ChooseFilter() CLASS FilterClass

   LOCAL nOpcField := 1, nOpcCompare, nCont, acTxtActive, nOpcActive := 1, lOk, oElement

   wOpen( 5, 0, 20, 80, "Filter" )
   DO WHILE .t.
      acTxtActive := ::FilterOptionsAsArray( .f. )
      aSize( acTxtActive, Len( acTxtActive ) + 4 )
      FOR nCont = 1 TO 4
         AIns( acTxtActive, 1 )
      NEXT
      acTxtActive[ 1 ] := "Select Fields"
      acTxtActive[ 2 ] := "Finish Filter"
      acTxtActive[ 3 ] := "Change Filter"
      acTxtActive[ 4 ] := "Reset"
      nOpcActive := Min( nOpcActive, Len( acTxtActive ) )
      Scroll( 7, 1, 19, 79, 0 )
      Achoice( 7, 1, 19, 79, acTxtActive, .t. ,,@nOpcActive )
      DO CASE
      CASE LastKey() == K_ESC
         EXIT
      CASE nOpcActive == 1
         ::SelectFields()
         LOOP
      CASE nOpcActive == 2
         lOk := .F.
         FOR EACH oElement IN ::acFilterConfig
            IF oElement[ FIELD_SELECTED ]
               lOk := .T.
               EXIT
            ENDIF
         NEXT
         IF ! lOk
            Alert( "If you do not select fields, no filter to show" )
            LOOP
         ENDIF
         EXIT
      CASE nOpcActive == 4
         FOR EACH oElement IN ::acFilterConfig
            oElement[ FIELD_COMPARE ] := COMPARE_NO_FILTER
         NEXT
         LOOP
      ENDCASE
      wOpen( 5, 0, 20, 80, "Field To Filter" )
      DO WHILE .t.
         Achoice( 7, 1, 19, 79, ::FilterOptionsAsArray(), .t.,, @nOpcField )
         IF LastKey() == K_ESC
            EXIT
         ENDIF
         wOpen( 6, 10, 20, 60, "Filter Type" )
         DO WHILE .t.
            Achoice( 8, 11, 19, 59, ::FilterOptions, .t.,, @nOpcCompare )
            IF LastKey() == K_ESC
               EXIT
            ENDIF
            ::GetFieldFilter( nOpcCompare, ;
               @::acFilterConfig[ nOpcField, FIELD_COMPARE ], ;
               @::acFilterConfig[ nOpcField, FIELD_RANGEFROM ], ;
               @::acFilterConfig[ nOpcField, FIELD_RANGETO ] )
            EXIT
         ENDDO
         wClose()
      ENDDO
      wClose()
   ENDDO
   wClose()

   RETURN LastKey() != K_ESC

METHOD SelectFields() CLASS FilterClass

   LOCAL oElement
   PRIVATE acFields := {}

   FOR EACH oElement IN ::acFilterConfig
      AAdd( acFields, iif( oElement[ FIELD_SELECTED ], "*", " " ) + " " + oElement[ FIELD_NAME ] )
   NEXT
   wOpen( 7, 10, 20, 80, "Select Fields" )
   AChoice( 8, 11, 19, 79, acFields, "", { | ... | UDFSelectField( ... ) } )
   wClose()
   FOR EACH oElement IN acFields
      ::acFilterConfig[ oElement:__EnumIndex, FIELD_SELECTED ] := ( Left( oElement, 1 ) == "*" )
   NEXT

   RETURN NIL

METHOD GetFieldFilter( nOpcCompare, nFieldCompare, xFieldIni, xFieldEnd ) CLASS FilterClass

   LOCAL GetList := {}

   DO CASE
   CASE nOpcCompare == COMPARE_NO_FILTER
      nFieldCompare := nOpcCompare
   CASE nOpcCompare == COMPARE_RANGE
      nFieldCompare := nOpcCompare
      wOpen( 10, 20, 16, 80, "From/To" )
      SetColor( "W/B,N/W,,,W/B" )
      IF ValType( xFieldIni ) == "C"
         IF Len( xFieldIni ) > 48
            @ 12, 22 GET xFieldIni PICTURE "@!S 48"
            @ 14, 22 GET xFieldEnd PICTURE "@!S 48"
         ELSE
            @ 12, 22 GET xFieldIni PICTURE "@!"
            @ 14, 22 GET xFieldEnd PICTURE "@!"
         ENDIF
      ELSE
         @ 12, 22 GET xFieldIni
         @ 14, 22 GET xFieldEnd
      ENDIF
      READ
      wClose()
   CASE nOpcCompare == COMPARE_HAS_TEXT .OR. nOpcCompare == COMPARE_NOT_HAS_TEXT .OR. nOpcCompare == COMPARE_BEGIN_WITH_TEXT
      IF ValType( xFieldIni ) != "C"
         Alert( "Valid only for String" )
      ELSE
         wOpen( 10, 20, 15, 80, "Value To Compare" )
         nFieldCompare := nOpcCompare
         SetColor( "W/B,N/W,,,W/B" )
         @ 12, 22 GET xFieldIni PICTURE "@!"
         READ
         wClose()
      ENDIF
   OTHERWISE
      nFieldCompare := nOpcCompare
      wOpen( 10, 20, 15, 80, "Value To Compare" )
      SetColor( "W/B,N/W,,,W/B" )
      IF ValType( xFieldIni ) == "C"
         @ 12, 22 GET xFieldIni PICTURE "@!"
      ELSE
         @ 12, 22 GET xFieldIni
      ENDIF
      READ
      wClose()
   ENDCASE

   RETURN NIL

METHOD Execute() CLASS FilterClass

   LOCAL nQtdRec

   DO WHILE .T.
      IF ! ::ChooseFilter()
         EXIT
      ENDIF
      SET FILTER TO ::Filter()
      COUNT TO nQtdRec
      SetColor( SetColorNormal() )
      @ 1, 0 SAY "Records in Filter:" + Str( nQtdRec )
      ::Show( MaxRow() - 2, 0, MaxRow(), MaxCol() )
      ::Browse( 2, 0, MaxRow() - 4, MaxCol() )
      SET FILTER TO
   ENDDO

   RETURN NIL

METHOD Browse( nTop, nLeft, nBottom, nRight ) CLASS FilterClass

   LOCAL oBrowse, oElement, nKey

   oBrowse := tBrowseDb( nTop, nLeft, nBottom, nRight )
   FOR EACH oElement IN ::acFilterConfig
      IF oElement[ FIELD_SELECTED ]
         oBrowse:AddColumn( TBColumnNew( oElement[ FIELD_NAME ], FieldBlock( oElement[ FIELD_NAME ] ) ) )
      ENDIF
   NEXT
   GOTO TOP
   DO WHILE .T.
      DO WHILE ! oBrowse:Stable
         oBrowse:Stabilize()
      ENDDO
      nKey := Inkey(0)
      IF nKey == K_ESC
         EXIT
      ENDIF
      oBrowse:ApplyKey( nKey )
   ENDDO
   Scroll( nTop, nLeft, nBottom, nRight, 0 )

   RETURN NIL

STATIC FUNCTION UDFSelectField( nModo, nElemento, nSelecao )   // Used in METHOD SelectFields()

   IF LastKey() == K_SPACE
      acFields[ nElemento ] := iif( Left( acFields[ nElemento ], 1 ) == "*", " ", "*" ) + Substr( acFields[ nElemento ], 2 )
   ELSEIF LastKey() == K_ESC .OR. Lastkey() == K_ENTER
      RETURN 0
   ENDIF
   HB_SYMBOL_UNUSED( nModo + nSelecao )

   RETURN 2


Basicamente é abrir um arquivo e chamar o filtro.
Dá pra escolher os campos, e escolher os filtros pra cada campo.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 17 Ago 2020 17:01

Não sobrou quase nenhum DBF pra teste, só o contábil mesmo.

menu principal

filtro1.png


primeira opção: escolher quais os campos vão aparecer

filtro2.png


encerrou, é o browse

filtro3.png


pode escolher um campo pra filtro

filtro4.png


por exemplo, o filtro de/até

filtro5.png


o filtro igual

filtro6.png


Encerrou a configuração, aparece do jeito que escolheu.

É parecido com o do MediaMonkey, só não o mesmo visual.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 17 Ago 2020 17:14

Uma diferença básica é que neste é apenas um tipo de filtro por campo.
Pra ficar igual, teria que criar outro array, com cada filtro que for feito, permitindo o mesmo campo várias vezes.
Nem seria complicado, é exatamente o array que tem hoje, que ficaria isolado dos campos.
Talvez a seleção do filtro fique mais fácil, ou talvez a mesma coisa.

Vou tentar criar isso, por enquanto só como curiosidade/desafio.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 17 Ago 2020 17:21

Seria a mesma coisa, só trocar o achoice por PROMPT talvez, ou por abrir uma janela, já que não tem combobox em console.

      wOpen( 5, 0, 20, 80, "Field To Filter" )
      DO WHILE .t.
         Achoice( 7, 1, 19, 79, ::FilterOptionsAsArray(), .t.,, @nOpcField )
         IF LastKey() == K_ESC
            EXIT
         ENDIF
         wOpen( 6, 10, 20, 60, "Filter Type" )
         DO WHILE .t.
            Achoice( 8, 11, 19, 59, ::FilterOptions, .t.,, @nOpcCompare )
            IF LastKey() == K_ESC
               EXIT
            ENDIF
            ::GetFieldFilter( nOpcCompare, ;
               @::acFilterConfig[ nOpcField, FIELD_COMPARE ], ;
               @::acFilterConfig[ nOpcField, FIELD_RANGEFROM ], ;
               @::acFilterConfig[ nOpcField, FIELD_RANGETO ] )
            EXIT
         ENDDO
         wClose()
      ENDDO
      wClose()
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 17 Ago 2020 17:25

Pra quem não entendeu, algo do tipo:

@ 2, 0 PROMPT Campo[ 1 ]
@ 2, 0 PROMPT Campo[ 2 ]
@ 2, 0 PROMPT Campo[ 3 ]
MENU TO nOpcCampo
@ 4, 0 PROMPT TIpo[ 1 ]
@ 4, 0 PROMPT Tipo[ 2 ]
@ 4, 0 PROMPT Tipo[ 3 ]
MENU TO nOpcTipo


Isso vai deixar só a opção escolhida em destaque, e vai permitir alterar pelas setas.
Acaba até deixando a tela mais limpa.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 17 Ago 2020 17:36

Olhem aí um teste rápido, como ficou mais limpo:

      wOpen( 5, 0, 20, 80, "Filter" )
      FOR EACH oElement IN ::acFilterConfig
         @ 7, 1 PROMPT Pad( oElement[ FIELD_NAME ], 20 )
      NEXT
      MENU TO nOpcField
      FOR EACH oElement IN ::FilterOptions
         @ 9, 1 PROMPT Pad( oElement, 20 )
      NEXT
      MENU TO nOpcCompare
      @ 11, 1 GET ::acFilterConfig[ nOpcField, FIELD_COMPARE ]
      @ 12, 1 GET ::acFilterConfig[ nOpcField, FIELD_RANGEFROM ]
      @ 13, 1 GET ::acFilterConfig[ nOpcField, FIELD_RANGETO ]
      READ
      wClose()


filtro1.png
filtro1.png (9.34 KiB) Visualizado 2469 vezes


Nem dá pra perceber o PROMPT/array, porque é tudo numa mesma posição.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 18 Ago 2020 16:38

To apanhando um pouco pra alterar, mas tá relativamente mais fácil que antes.

Sério, não é um bicho do outro mundo.

Agora tenho duas listas:

Campos: contendo nome, .T. ou .F. se é pra aparecer, e um valor zerado

Filtros: só poderia ser isso: nome do campo, tipo de comparação (igual, intervalo, etc), e dois valores porque pode precisar de um ou dois (em intervalo precisa de 2 valores)

Exemplo: codigo de cliente de 1 a 10

o Filtro vai ter
"CODIGO", 8, 1, 10
8 = FILTRO_RANGE = filtro por intervalo

Então, para todo e qualquer filtro, basta uma lista igual a essa: campo, tipo de filtro, intervalode, intervaloate

A lista pode ter elementos infinitos: codigo 1 a 10, nome "A" a "B", etc.

Relativamente simples.

E a origem pra criar esse filtro, é a outra lista que contém os campos, e qual o valor zerado/default de cada um.

primeira lista: codigo, nome, endereco, provavelmente com os default 0, Space(30) e Space(30)

segunda lista: conforme for selecionando um desses, vai aumentando

CODIGO, INTERVALO, 1, 10
NOME, CONTENDO, "JOSE", ""
NOME, CONTENDO, "QUINTAS", ""

e por aí vai.
Relativamente simples, mas em array.

É um achoice/tbrowse com os filtros já criados

É um achoice/tbrowse com a lista de campos - esse é o primeiro elemento de um filtro

É um achoice/tbrowse com a lista de tipos de filtro - esse é o segundo elemento do filtro

É o get de um ou dois valores, que serão usados para comparação de igual, maior, menor, intervalo, etc.
esses são os outros dois elementos do filtro, que começam com valores zerados.

Pensando em uma coisa de cada vez, fica mais simples.
A complicação é em trabalhar com esses arrays, e principalmente passando parâmetros.
Usando achoice(), acabei precisando de variável PRIVATE pra facilitar.

Poderíamos amadurecer essa idéia de filtros universais....
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 18 Ago 2020 16:42

os elementos do array dos campos

#define FIELD_NAME       1
#define FIELD_SELECTED   2
#define FIELD_EMPTYVALUE 3


os elementos do array de filtros

#define FILTER_FIELD     1
#define FILTER_COMPARE   2
#define FILTER_RANGEFROM 3
#define FILTER_RANGETO   4


os tipos de comparação que coloquei

#define COMPARE_NO_FILTER          1 //
#define COMPARE_EQUAL              2 // =
#define COMPARE_GREATHER_OR_EQUAL  3 // >=
#define COMPARE_LESS_OR_EQUAL      4 // <=
#define COMPARE_GREATHER           5 // >
#define COMPARE_LESS               6 // <
#define COMPARE_NOT_EQUAL          7 // !=
#define COMPARE_RANGE              8 // >= rangefrom .AND. <= rangeto
#define COMPARE_HAS_TEXT           9 // text $ field
#define COMPARE_NOT_HAS_TEXT      10 // ! text $ field
#define COMPARE_BEGIN_WITH_TEXT   11 // field = text*
#define COMPARE_IN_TEXT           12 // field $ text
#define COMPARE_NOT_IN_TEXT       13 // ! field $ text
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 18 Ago 2020 16:51

Aproveitando:

A montagem do filtro depois pode ser pra DBF ou MySQL do mesmo jeito, criando uma string.

cFiltroSQL := "CODIGO >= 1 AND CODIGO <= 10"
cFiltroSQL += " AND NOME LIKE '%JOSE%'"

cFiltroDBF := "CODIGO >= 1 AND CODIGO <= 10"
cFiltroDBF += " AND 'JOSE' $ NOME"

conexao:Execute( "SELECT * FROM CLIENTES WHERE " + cFIltroSQL )

SET FILTER TO &( cFiltroDBF )


Detalhe importante no filtro em DBF:
Como está usando campo/conteúdo, NÃO DEPENTE DE VARIÁVEIS.
Esse é um problema comum que temos ao usar variáveis local/private/etc. que complica tudo, mas assim não tem problema.

Pois é... ao usar SQL... vemos certas coisas que fazíamos em DBF que eram problema.

Eu já disse por aqui:
A gente pode tirar idéia de onde menos se espera.
Isso de montar o comando SQL, dá uma idéia de fazer o mesmo com DBF, pra não ficar dependente de nada, ou até com o próprio SQL.

No final de tudo, seja qual for a seleção, o filtro é uma simples string.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

MediaMonkey / Aplicativos

Mensagempor JoséQuintas » 18 Ago 2020 16:57

Mesmo assim, em DBF criei uma opção adicional:

METHOD Filter() Class FilterClass

   LOCAL oElement, lReturn := .T., xValue

   FOR EACH oElement IN ::aFilterList
      xValue := FieldGet( FieldPos( oElement[ FIELD_NAME ] ) )
      DO CASE
      CASE oElement[ FILTER_COMPARE ] == COMPARE_NO_FILTER
      CASE oElement[ FILTER_COMPARE ] == COMPARE_EQUAL ;             lReturn := ( xValue == oElement[ FILTER_RANGEFROM ] )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_GREATHER_OR_EQUAL ; lReturn := ( xValue >= oElement[ FILTER_RANGEFROM ] )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_LESS_OR_EQUAL ;     lReturn := ( xValue <= oElement[ FILTER_RANGEFROM ] )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_GREATHER ;          lReturn := ( xValue >  oElement[ FILTER_RANGEFROM ] )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_LESS ;              lReturn := ( xValue <  oElement[ FILTER_RANGEFROM ] )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_NOT_EQUAL ;         lReturn := ( xValue != oElement[ FILTER_RANGEFROM ] )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_RANGE ;             lReturn := ( xValue >= oElement[ FILTER_RANGEFROM ] .AND. xValue <= oElement[ FILTER_RANGETO ] )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_HAS_TEXT ;          lReturn := ( Trim( oElement[ FILTER_RANGEFROM ] ) $ xValue )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_NOT_HAS_TEXT ;      lReturn := ( ! Trim( oElement[ FILTER_RANGEFROM ] ) $ xValue )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_BEGIN_WITH_TEXT ;   lReturn := ( Substr( xValue, 1, Len( Trim( oElement[ FILTER_RANGEFROM ] ) ) ) == Trim( oElement[ FILTER_RANGEFROM ] ) )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_IN_TEXT;            lReturn := ( xValue $ oElement[ FILTER_RANGEFROM ] )
      CASE oElement[ FILTER_COMPARE ] == COMPARE_NOT_IN_TEXT;        lReturn := ( ! xValue $ oElement[ FILTER_RANGEFROM ] )
      ENDCASE
      IF ! lReturn
         EXIT
      ENDIF
   NEXT

   RETURN lReturn


Opção 1:
SET FILTER TO oFiltro:Filter()


Opção 2:
DO WHILE ! Eof()
   Inkey()
   IF ! oFiltro:Filter()
      SKIP
      LOOP
   ENDIF
   SKIP
ENDDO


A segunda opção é interessante, pra quando o usuário clicar não aparecer "programa não está respondendo"

Parece complicado mas não é, é só lembrar do array:
campo, tipo de comparação, de/até

   FOR EACH oElement IN ::aFilterList
      xValue := FieldGet( FieldPos( oElement[ FIELD_NAME ] ) )


Vai percorrer a lista de filtros, pegando o campo referência
Se por acaso o tipo de filtro é um intervalo

      CASE oElement[ FILTER_COMPARE ] == COMPARE_RANGE


o que fazemos num intervalo? testamos o intervalo

lReturn := ( xValue >= oElement[ FILTER_RANGEFROM ] .AND. xValue <= oElement[ FILTER_RANGETO ] )


As duas "variáveis", os elementos 3 e 4, que pra facilitar usei o #define.
Poderia ser FILTRO_INTERVALO, FILTRO_DE, FILTRO_ATE, é que pra deixar disponível, deixei em inglês.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18014
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Próximo



Retornar para Interface com Clientes

Quem está online

Usuários vendo este fórum: Nenhum usuário registrado online e 3 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
cron
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro