XBrowse edicción en celda multilinea

Post Reply
User avatar
Sebastián Almirón
Posts: 170
Joined: Mon Dec 12, 2005 9:56 am
Location: Moralzarzal - Spain

XBrowse edicción en celda multilinea

Post by Sebastián Almirón »

Hola,
Estoy haciendo un XBrowse que en la segunda columna tiene que admitir varias líneas por celda porque se pueden escribir hasta 250 caracteres.

Es sobre un array y la segunda posición del array tiene 250 caracteres, pero a la hora de escribir permite escribir cualquier cantidad de caracteres, hasta que le das Intro y entonces solo almacena los primeros 250 caracteres.

He probado con oBrwgest:acols[2]:cEditPicture := replicate('X',250) . Pero entonces al escribir no salta automáticamente de linea al llegar el cursor a la derecha de la celda y hay que introducir el texto en una unica línea aunque luego de dar intro ya salga bien.

Es decir, de que manera puedo hacer que salte de linea mientras se escribe y a la vez que no pueda escribir más de 250 caracteres.

Saludos

Code: Select all | Expand

 REDEFINE Xbrowse oBrwgest ARRAY alingest;
                              COLUMNS 1, 2, 3, 4;
                              COLSIZES 58,710,58,140;
                              HEADERS 'Contacto','MNEMO DE GESTION','Aplazado','Usuario'; //Contacto es una fecha
                              ID 103 OF oDlg  LINES CELL FASTEDIT
                              
oBrwgest:lVScroll := .T. AEval( oBrwgest:aCols, {|o| o:nEditType := EDIT_GET} ) oBrwgest:nDataLines := 3 oBrwgest:bonchanges := {|| lcambiado := .t.} oBrwgest:lautoappend := .t.
User avatar
karinha
Posts: 8720
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil
Contact:

Re: XBrowse edicción en celda multilinea

Post by karinha »

¿Estableciste:

Code: Select all | Expand

   oBrw:lFastEdit := .t.

?

Saludos.

João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: XBrowse edicción en celda multilinea

Post by Antonio Linares »

Estimado Sebastian,

Aqui tienes un ejemplo funcionando:

Code: Select all | Expand

// xbrml250.prg
// Verifies XBrowse multi-line cell edit with a hard 250-character limit.
//
// Why picture fails for multi-line:
//   cEditPicture forces TGet (single line) instead of TMultiGet.
// Correct approach:
//   nDataLines >= 2 + no picture  -> TMultiGet (auto word-wrap)
//   bOnPreEdit -> RTrim + LimitText( 250 )
//
// IMPORTANT:
//   If the array cell is already PadR(..., 250) / Space(250), Len() is already
//   250. LimitText(250) then blocks every keystroke because the control is full
//   (and TMultiGet does NOT SelectAll like TGet). Always RTrim before LimitText.

#include "FiveWin.ch"
#include "XBrowse.ch"

#define MAX_MNEMO  250

//----------------------------------------------------------------------------//

function Main()

   local oWnd, oBar, oBrw, oMsg
   local aData := SampleData()
   local cInfo := ""

   DEFINE WINDOW oWnd TITLE "XBrowse multi-line + LimitText(250)" ;
      FROM 1, 1 TO 28, 100

   DEFINE BUTTONBAR oBar OF oWnd SIZE 70, 22

   DEFINE BUTTON OF oBar PROMPT "Check" ;
      TOOLTIP "Show Len() of current MNEMO cell" ;
      ACTION ShowLen( oBrw )

   DEFINE BUTTON OF oBar PROMPT "Fill 250" ;
      TOOLTIP "Put exactly 250 real chars (no trailing pad)" ;
      ACTION FillMnemo( oBrw, aData, MAX_MNEMO, .F. )

   DEFINE BUTTON OF oBar PROMPT "Pad 250" ;
      TOOLTIP "PadR to 250 spaces ÔÇö shows the classic 'cannot type' bug if you drop RTrim" ;
      ACTION FillMnemo( oBrw, aData, 0, .T. )

   DEFINE BUTTON OF oBar PROMPT "Help" ;
      ACTION MsgInfo( ;
         "1. Click MNEMO and type ÔÇö text wraps at the cell edge (soft wrap)." + CRLF + ;
         "2. You cannot type/paste more than 250 characters." + CRLF + ;
         "3. ENTER          = end cell edit (save)." + CRLF + ;
         "4. Ctrl+ENTER or Shift+ENTER = one real line break." + CRLF + ;
         "5. ESC            = cancel edit." + CRLF + ;
         "6. 'Check' shows Len() of stored value." + CRLF + CRLF + ;
         "Soft wrap is only visual. Real newlines need Ctrl/Shift+ENTER.", ;
         "How to test" )

   @ 4.5, 0.5 XBROWSE oBrw OF oWnd ;
      ARRAY aData ;
      COLUMNS 1, 2, 3, 4 ;
      COLSIZES 80, 480, 70, 100 ;
      HEADERS "Contacto", "MNEMO DE GESTION", "Aplazado", "Usuario" ;
      LINES CELL FASTEDIT ;
      SIZE 700, 340 PIXEL

   oWnd:oClient = oBrw
   oBrw:lVScroll    := .T.
   oBrw:nDataLines  := 3
   oBrw:lAutoAppend := .T.

   AEval( oBrw:aCols, {| o | o:nEditType := EDIT_GET } )

   // Column 2: multi-line + max 250 chars
   // Leave cEditPicture empty so XBrowse creates TMultiGet
   oBrw:aCols[ 2 ]:bOnPreEdit := {| oCol | LimitMnemoEdit( oCol ) }

   // Keep stored value at most 250; optional PadR if you need fixed length
   oBrw:aCols[ 2 ]:bOnPostEdit := {| oCol, xVal, nKey | ;
      If( nKey != VK_ESCAPE .and. xVal != nil, ;
         oCol:Value := Left( xVal, MAX_MNEMO ), ) }

   oBrw:bOnChange := {|| ;
      cInfo := "Row " + LTrim( Str( oBrw:nArrayAt ) ) + ;
         "  |  Len = " + LTrim( Str( Len( oBrw:aRow[ 2 ] ) ) ) + ;
         "  RTrim = " + LTrim( Str( Len( RTrim( oBrw:aRow[ 2 ] ) ) ) ) + ;
         " / " + LTrim( Str( MAX_MNEMO ) ), ;
      If( oMsg != nil, oMsg:SetText( cInfo ), ) }

   oBrw:CreateFromCode()

   DEFINE MSGBAR oMsg PROMPT "Edit MNEMO: wrap + max 250 (RTrim before LimitText)" OF oWnd

   ACTIVATE WINDOW oWnd ;
      ON INIT ( oBrw:SetFocus(), oBrw:GoTop() )

return nil

//----------------------------------------------------------------------------//
// Called when the in-cell editor is ready (after TMultiGet is created).

static function LimitMnemoEdit( oCol )

   local oGet  := oCol:oEditGet
   local bOrig
   local c

   if oGet == nil
      return nil
   endif

   // Must free trailing spaces BEFORE LimitText, or Len is already 250
   // and the user cannot type a single character.
   if oGet:IsKindOf( "TMULTIGET" )
      c := RTrim( oGet:cText )
      oGet:cText := c
      oGet:LimitText( MAX_MNEMO )
      oGet:SetPos( Len( c ) )   // caret at end

  // XBrowse: plain ENTER ends edit (EditGetkeyDown).
  // Ctrl+ENTER / Shift+ENTER must NOT end edit and must insert ONE newline.
  // Do NOT call Replace(CRLF): the multiline EDIT already inserts a line
  // break via WM_CHAR (ES_WANTRETURN). Doing both produces two breaks.
  bOrig := oGet:bKeyDown
  oGet:bKeyDown := {| nKey | ;
     If( nKey == VK_RETURN .and. ;
        ( GetKeyState( VK_CONTROL ) .or. GetKeyState( VK_SHIFT ) ), ;
        nil, ;  // keep editing; let TMultiGet insert a single newline
        If( bOrig != nil, Eval( bOrig, nKey ), nil ) ) }

   elseif oGet:IsKindOf( "TGET" )
      oGet:LimitText( MAX_MNEMO )
   endif

return nil

//----------------------------------------------------------------------------//

static function SampleData()

   local a := {}

   // Store only real text (no PadR to 250). Pad only if your backend needs it,
   // and always RTrim in bOnPreEdit before LimitText.
   AAdd( a, { Date(), "Short note", .F., "ANA" } )
   AAdd( a, { Date() - 1, ;
      "This cell already holds a longer text so you can see multi-line display " + ;
      "with nDataLines = 3. Click to edit: typing wraps at the cell edge and " + ;
      "cannot exceed 250 characters thanks to LimitText in bOnPreEdit.", ;
      .T., "PEPE" } )
   AAdd( a, { Date() - 3, "", .F., "LUIS" } )
   // Row that mimics a fixed-length field (250 spaces / padded) ÔÇö still editable
   AAdd( a, { Date() - 5, PadR( "Padded field", MAX_MNEMO ), .F., "TEST" } )

return a

//----------------------------------------------------------------------------//

static function ShowLen( oBrw )

   local cText, nLen, nAt

   if oBrw:nLen < 1
      MsgInfo( "Browse is empty" )
      return nil
   endif

   nAt   := oBrw:nArrayAt
   cText := cValToChar( oBrw:aRow[ 2 ] )
   nLen  := Len( cText )

   MsgInfo( ;
      "Row: " + LTrim( Str( nAt ) ) + CRLF + ;
      "Len( MNEMO )       = " + LTrim( Str( nLen ) ) + CRLF + ;
      "Len( RTrim(MNEMO)) = " + LTrim( Str( Len( RTrim( cText ) ) ) ) + CRLF + CRLF + ;
      "First 80 chars:" + CRLF + Left( cText, 80 ), ;
      "Stored length" )

return nil

//----------------------------------------------------------------------------//

static function FillMnemo( oBrw, aData, nLen, lPadOnly )

   local c

   DEFAULT lPadOnly := .F.

   if oBrw:nLen < 1
      return nil
   endif

   if lPadOnly
      c := PadR( "Padded to 250", MAX_MNEMO )
   else
      c := Replicate( "X", nLen )
   endif

   aData[ oBrw:nArrayAt, 2 ] := c
   oBrw:RefreshCurrent()
   MsgInfo( "Assigned Len=" + LTrim( Str( Len( c ) ) ) + ;
      "  RTrim=" + LTrim( Str( Len( RTrim( c ) ) ) ) + CRLF + ;
      "Click the cell and type ÔÇö should accept input up to 250.", ;
      "Fill MNEMO" )

return nil

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Sebastián Almirón
Posts: 170
Joined: Mon Dec 12, 2005 9:56 am
Location: Moralzarzal - Spain

Re: XBrowse edicción en celda multilinea

Post by Sebastián Almirón »

Perfecto Antonio, funciona muy bien.
Lo del codebloq bOnPreEdit no lo conocía.
Muchas gracias.

Post Reply