Browsing - generaly
--------------------------------------------------------------------------------
I have build some array and I wanted to display inside a window browse using TCColumn to add the individual column.
ADD COLUMN TO oBrow ARRAY ELEM 1
ADD COLUMN TO oBrow ARRAY ELEM 2
ADD COLUMN TO oBrow ARRAY ELEM 3
ADD COLUMN TO oBrow ARRAY ELEM 4
ADD COLUMN TO oBrow ARRAY ELEM 5
This work fine. But what happen is... my array consist to 15 element so I have try with a shortcut by doing this
FOR n := 1 TO 15
ADD COLUMN TO oBrow ARRAY ELEM n
NEXT n
This do not work!
After some checking, I found that the header file TcBrowse.ch for TCColumn, it is using a code block to pass in the data block. Which mean that the <n> is physically passed in without assigning any value. When it reaches the browse, only the last element is browse through the cell. I have also try this.
FOR n := 1 TO 15
bBlock := &( "{ | | oBrw:aArray[ oBrw:nAt,"+Str(n)+" ] }" )
oBrw:AddColumn( TCColumn():New( "Header", bBlock ))
NEXT n
This doesn't work either! It gives me a syntax error at block definition . I have also checked the bBlock code. It cannot eval a class into a code block. Can anyone help! Because if I hard code it, when there is any changes in the number of element and I have maintain the code again.
Try :
FOR n := 1 TO 15
ADD COLUMN TO oBrow ARRAY ELEM &n
NEXT n
If that doesn't work, look at your PPO file (compile with /p) and use the method call instead of the command and it should work no probs.
First, your method would not work with number. only work with string.Secondly, I do not think you understand my problem. When you issue the command below, all the code block will look like this:
FOR nSize := 1 TO Len( aSize )
oBrow:AddColumn( TCColumn():New( IF(.F., OemToAnsi( cTitle ), cTitle ) ;
{|x| IF(Pcount()>0, oBrow:aArray[oBrow:nAt, nSize] :=x, oBrow:aArray[oBrow:nAt, nSize])} ))
NEXT nSize
The problem is oBrow:aArray[ oBrow:nAt, nSize ] is in a code block. It is going to stay that way until it is eval. By that time nSize is the last number, so when you eval all the code block, the data will be showing thelast element only. nSize is the problem! Only if we can physically change nSize into the content before putting it into the code block, only can this problem be resolved. Otherwise there are no other method. Even if I change the nSize into string and use the <&>, the problem will still exist because the code block still store &nSize which refer to the same variable after the FOR..NEXT loop.
Try this one:
FOR nSize := 1 TO Len( aSize )
oBrow:AddColumn( TCColumn():New( IF(.F., ;
OemToAnsi( cTitle ), cTitle ) {|x| IF(Pcount()>0, oBrow:aArray[oBrow:nAt, &(nSize) ] :=x, ;
oBrow:aArray[oBrow:nAt, &(nSize) ])} ))
NEXT nSize
You need to use the detached locals technique, because nSize is called from ithin a code block, the value of nSize at run time will be Len(aSize) + 1 for all columns, certanly not what you wanted to. So you need a function to create that code block inside your For..Next loop:
FOR nSize := 1 TO Len( aSize )
oBrow:AddColumn( TCColumn():New( IF(.F., OemToAnsi( cTitle ), cTitle ) ;
YourCol( oBrow, nSize ) )
NEXT nSize
STATIC Function YourCol( oBrow, nSize )
RETURN {|x| If(Pcount()>0, oBrow:aArray[oBrow:nAt, nSize] :=x, oBrow:aArray[oBrow:nAt, nSize])} ))
This way nSize will retain its value (1, 2, 3, etc) for each column from your array. This is the only way to solve this problem in a For..Next loop to avoid coding each column separately.
Try this:
FOR n := 1 TO 15
MyAddColumn(oBrow,n)
NEXT n
PROCEDURE MyAddColumn(oBrow,n)
ADD COLUMN TO oBrow ARRAY ELEM n
RETURN
I've not tried it... but it should work.
I have been using this code, partly from old clipper, since four years and works fine: oLbx is a browse object, with redefine from resources or similar titulos: Array with the column titles anchos: Array with column sizes
aDatHist: Multidimensional array with the data for the columns. Each subarray has the a lenght of titulos or anchos
oLbx:SetArray( aDatHist )
FOR i=1 TO LEN(Titulos)
oLbx:AddColumn( TCColumn():New( Titulos[i], ABrowseBlock(oLbx:aArray,i,oLbx);
,,,, "LEFT", anchos[i], .F., .T.,,,, .F. ) )
NEXT i
This is the function you need:
FUNCTION ABrowseBlock(a, x, oLbUsr)
RETURN ( {|p| IF(PCOUNT() == 0, a[oLbUsr:nAt, x], a[oLbUsr:nAt, x] := p)} )
It really works
You have to use a "detached local." This means that n must be in its own codeblock then it will stay in scope. I don't have an example handy--check in your Clipper documentation for a description of "detached local."
Thank you very much. I have got it working already. The idea is the same by moving the code block outside the For..Next loop.
--------------------------------------------------------------------------------
I use wbrowse and REDEFINE LISTBOX ... from a DBF. Now I want to put bitmap "Tick" or "Blank" in first column instead of "Y" or "N" . How do I do that ? I use v1.95
Very easy:
a) load your two bitmaps in a handler variable:
hBmp1 := LoadBitmap(GetResources(),"name_of_ the_bitmap")
hBmp2 := LoadBitmap(GetResources(),"name_of_the_other_bitmap")
b) and in the fields clause use the handler number instead of the field name:
REDEFINE LISTBOX.... FIELDS dbf->field, dbf->field2, IIF(deleted(),hBmp1,hBmp2),dbf->field3......
--------------------------------------------------------------------------------
Is it possible to use a Combobox as a field of a TWbrowse if so how ?
If you mean when you edit the cells of the browse with lEditCol() - yes. Just have a look in WBrowse.prg in FW\SOURCE\CLASSES. In metod lEditCol.
Check the wdbu source code when you edit a logical field wdbu display a combobox to choose .T. or .F.
--------------------------------------------------------------------------------
Anyone know how to overcome error "1513/Operation too complex: " when building a bLine for wbrowse? The line I am tring to compile is 1007 characters long and have 35 fields. bLine:=&("{|| {"+ cLine + "} }")
Not perfect, but you could do it like this as a last resort :
bLine:=&("{|| {MyBrwLine()} }")
FUNCTION MyBrwLine()
RETURN {Field1, Field2, Field3.... Field35}
--------------------------------------------------------------------------------
Please look at the .JPG: ( WIN3.JPG ) The Browse is outside of control's edge. WHY? What's the problem in my code? The Control is a LISTBOX with the follow mark check:
-Notify
-Integral height
-Multi column
-Scroll bar always
The Objet in y code is a TWBrowse. What happen?
The LISTBOX REDEFINE is:
* Browse
REDEFINE LISTBOX OLBX FIELDS OEMTOANSI(DATO1->LETRA),OEMTOANSI(DATO1->NOMBRE),;
OEMTOANSI(DATO1->TELF),OEMTOANSI(MEMOLINE(DATO1->DATO,80,1)) ;
FIELDSIZES 50,280,280,280 ;
HEADERS 'Letra','Nombres','Telefonos','Datos Adicionales' ON DBLCLICK DATTELF(OLBX,.F.) ID 413 OF ODLG
I have the same problem on some browses. Im using Visual Studio to create 16bit dlls...what are you using? Ive noticed that you can fool the listbox sometimes by setting the data widths...it is a trial and error thing. I would certainly be interested in a solution to this.
I use Borland Workshop. Yes, I try to change the data width settings. I'll try with several values. I will write here, about this, ok?
How do you create your browse control in Borland RW. To me it looks like you are using another style of control and may be this is the problem. I create a browse by clicking on the little key on the bottom of the tools then typing TWBrowse, then OK, then for the style of the new control in the properties dialog :
0 | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL |WS_TABSTOP
Only the first three parameters are coming by default. The rest is up to you. I have never had your problem.
Are you shure, the field sizes are OK? They seams too big for me. Try to reduce.
You must select customer control when add a new control( not ListBox ) to dialog and Class name is TWBrowse.
Seems to me that your mixing two different concepts. Actually it isn't your fault. The problems is the way the TWBrowse class is mapped into a command using the keyword LISTBOX. This tends to be confused with the Windows API ListBox - two different things. Make sure you're defining your browse as a Custom Control (ie the icon with the Key in the toolbar) and that you define it as "TWBrowse" - not as a standard ListBox. I'm sure that's your problem.
--------------------------------------------------------------------------------
Still Now, I am using the clipper. So, I will try and learn for Fivewin. But, I have a problem Dos to Windows programing. Becasue, always I used the DBedit function of Clipper. So, I have a lot of problem to modified the our program. If you have a DBedit function of windows, Pls. inform me! I will purchse the function.
I can't see where is the problem. Fivewin has 2-3 ways to use a file browse on window....tcbrowse,twbrowse,listboxes.... and too many ways to edit the data.....you can edit them in the browse or you can call another window/dialog to do the modification... i find the convertions from dos to windows veeery veeery easy. :} Fivewin has everything u want about browse/edit....
dbEdit is obsolete even in plain old Clipper. Maybe the easiest way before digging into TWBrowse or TCBrowse classes, give a look at FiveWin's Browse() function. You won't be able to do fancy things but since you have the source code to it, you can learn from it.
--------------------------------------------------------------------------------
I have a generic function to all my browses wich work with lCellStyle (very nice!!). I only have two kinds of columns: those only to show and those to show and edit. In the method bkeydown I call to my function tbrKey to trap the keys and do things with them. If you type inside a column that is only to show a dialog appear to search in that column. If you type inside a column that lets you edit, then in that cell start a get. The problem is that the character that start this get is missing. How I can start with this character and include it on the get? Keyboard() is no good solution because it generated GPFs.
Try something like
POSTMESSAGE( oGet:hWnd, WM_CHAR, nKey )
--------------------------------------------------------------------------------
I want to blink some items on a browse. any idea?... i can imagine a way with bitmaps and a timer to change them but i guess is a very stupid way.... I have a window with a browse i browse a database file with my network users. online or not. now i have a form and i send messages from local user to another my system check with timer if the user has a message(s) waiting .... if yes i want to blink an item on the browse beside the userid column, so the user can see that he has a message waiting. now... the column can be a set of bitmaps who can change quickly so i have a blink effect, or a text blinking item....
Did something similar for a Message bar item, you have to use a timer and repaint the cells once black once white etc. This give the appearance of blinking.
--------------------------------------------------------------------------------
I have a big problem for me. How can i create a action if i click on the headerfield of a browse like changing the index information of the field etc
Use the ACTION clause of the LISTBOX FIELDS command.
Do this :
oYour_Brw:aActions := {{|| Action_Col_1()}, {||
Action_Col_2()},......And_So_On.....}
--------------------------------------------------------------------------------
I have a browse in a windows with buttons: The F9 button do this sentence:
order(case(indexord(),1,1,3,3,2,2,4,4,5,5,6,6,7,7,1))
then the browse refresh and change the order but the cell lost the focus (look at the grey color): How I can get the focus on the cell again?.
Did you tried to ( order(case(indexord(),1,1,3,3,2,2,4,4,5,5,6,6,7,7,1)) , yourBrw:Setfocus() )?
--------------------------------------------------------------------------------
a) i have a tcbrowse i am on 5th item on the browse (somewhere on the midle of my browse on the screen).now i refresh the browse with .t. my browse goes to the current record but this record goes to the top of my browse.... how can i refresh the browse with out lost the browse position? (if i delete the records i must go to the next or prev record..)
b) how can i disable the horizontal scroll bar on a browse that i create from source code? ( i try everything i can imagine... )
Play around with setting ::oBrowse:nRowPos manually
--------------------------------------------------------------------------------
When doing a right-click on an element in the table, the cursorline isn't set to the line I clicked on. How can I do this ?
Do this :
oYour_Browse:bRClicked : = { |nRow, nCol, nFlags|
oYour_Brwse:LButtonDown(nRow, nCol, nFlags) }
which will change the highlited row to the new position when you click on the browse with the right mouse button .
--------------------------------------------------------------------------------
As I make to magnify the height of the lines in one listbox (tbrowser). Very obliged for the attention.
You can't increase the height of the line of a list box and keep the size of the font without changes in the FW C source code. If you increase the size of the font, the height of the lines of the list box will increase automatically.
--------------------------------------------------------------------------------
Is there a way to lock a column from being resized in the wbrowse class?
Just set ::lMChange to FALSE (this is also valid for TCBrowse)
Not for the whole browse just for a single column?
I think that can only be achieved with TCBrowse class, not with TWBrowse class since it isn't column based. To make it work under TCBrowse, when a column is frozen, it won't be allowed to be resized. Since you can only freeze columns from left to right, only contiguous columns could be flagged so as to avoid resizing. Check out TCBrowse:MouseMove().
--------------------------------------------------------------------------------
Is there any way to speed up the Vscroll bar on a wbrowse when the DBF size is big (30,000 records) ? It is too slow when dragging the scollbar cursor up and down.
Yes! You have to modify TWBrowse class - Method VScroll. Substitute
::Skip( nLParam - ::oVScroll:GetPos() )
with
( ::cAlias ) -> ( CmxKeyGoTo( nLParam ) )
or the xxxKeyGoto() function provided by your RDD.
TWBROWSE is a general CLASS to work with DBF(s) , ARRAYS, Objects and is not posible to put a special code for manage CDX o NTX RDD(s) I thing that is better solution to use a codeblock with the best operation to jump over desired records like
::bJump = {|cAlias,nRecno|(cAlias ) -> ( CmxKeyGoTo( nRecno ) )}
and in the VSCROLL METHOD
EVAL(::bJump,::cAlias,nLParam)
Since Windows treats the 'thumbpos' of the veritcal scroll as an integer, you will always have problems once your database exceeds 32,367 records. You should consider
oBrw:blogiclen:= { || min( 32000,lastrec() ) }
when defining your browse, or consider changing the scrllbar class to accomodate large data files.
--------------------------------------------------------------------------------
How to size a browse to just fit in a dialog without using a resource in a DLL. I already try GetCoors(), GetClientRect(), GetWndRect() and oWnd:CoorsUpdate()
? oWnd:nTop
? oWnd:nBottom
? oWnd:nLeft
? oWnd:nRight
from EMG, but the browse does not fit. It oversize the dialog.
Can you be more specific about your problem. It seams to me now, you have the same problem I as have. My question is: do you create browse from RESOURCE (.RC or .DLL) or you put it on the dialog with @ y,x commands? It is important. If I don't use resources, I can fit browse without problem, but if I use resources, then there are problems, browse doesn't fit always in the dialog! The difference arise when I change the system settings related to the font sizes! (Setup-display-settings-font size).
Try:
FUNC zAdjDialog( oDlg, oWndMain )
* Function..: Ajust and position Dialog in size of window parent
* Parameters: oDlg - your dialog
* oWinMain - window parent
LOCAL nMsgHeight:= 0
IF oWndMain:oMsgbar # NIL
nMsgHeight:= oWndMain:oMsgBar:Height()
ENDI
oDlg:SetSize( ;
oWndMain:GetCliRect():nRight - ABS( oWndMain:GetCliRect():nLeft ), ;
oWndMain:GetCliRect():nBottom - ABS( oWndMain:GetCliRect():nTop ) +
nMsgHeight ;
)
oDlg:Move( oWndMain:nBottom - oWndMain:GetCliRect():nBottom - nMsgHeight ,0 )
RETU NIL
FUNC zAdjControl( oCtrl, oWinDlg, nTop )
* Function..: Adjust control in window/dialog
* Parameters: oCtrl - your control
* oWinDlg - window/dialog parent
* nTop - Top of control
LOCAL nMsgHeight:= 0
IF EMPTY( nTop )
IF EMPTY( nTop:= ABS( oCtrl:nTop ) )
nTop:= 0
ENDI
ENDI
IF oWinDlg:oMsgbar # NIL
nMsgHeight:= oWinDlg:oMsgBar:Height()
ENDI
/*
oCtrl:SetSize( ;
oWinDlg:GetCliRect():nRight - ABS( oWinDlg:GetCliRect():nLeft ), ;
oWinDlg:GetCliRect():nBottom - nTop - nMsgHeight ;
)
*/
oCtrl:SetSize( ;
oWinDlg:GetCliRect():nRight - ABS( oCtrl:nLeft ), ;
oWinDlg:GetCliRect():nBottom - nTop - nMsgHeight ;
)
RETU NIL
Maybe you should consider DIALOG metrics (borders, title-bar, etc.) and subtract them from total size.
--------------------------------------------------------------------------------
Can anyone provide a sample piece of code for finding a record in a browse.
At the moment I have a browse displaying customers in account order , when the user hits the find button , the index is changed and a get is placed below the browse for the user to type in the customers name , as each letter is typed the browse moves to the required record - but if the user makes a mistake and uses backspace the whole search messes up. Anyone got a better solution.
// sample of present code
REDEFINE GET oClient VAR cClient ID EditFndClnt UPDATE picture '@!' color(GETCOL)
oClient:bKeyDown := {|nKey|cClient+= chr(nKey),oBrowDlg:Update(),FndClnt(oCust,cClient,oLbx),;
oClient:SetPos(len(alltrim(cClient))),oClient:SetFocus()}
oClient:bLostFocus := {||oClient:Hide(),cClient := " ",oClient:SetPos(0),;
oClient:Refresh(),oCust:SetIndex('ACCNO'),oCust:seek(str(oCust:accno,5)),;
lExit := TRUE,oBrowDlg:end()}
static function FndClnt(oCust,cClient,oLbx)
oCust:seek(cClient)
oLbx:Refresh()
return(nil)
Try adapting the function attached.
/* DbSearch() performs an incremental search on a character field in a database indexed on that field and visualized with TWBrowse or TCBrowse. After one second since the last keystroke, the seek is restarted.
Example:
REDEFINE LISTBOX oBrw FIELDS .........
oBrw:bKeyChar := { | nKey | IF( DbSearch(nKey,oBrw), oBrw:Refresh(),) }
Note: You must define two public or static vars as follows:
PUBLIC cArgume := "", nSeconds := SECONDS() */
FUNCTION DbSearch(nKey,oBrw)
LOCAL cKey := UPPER( chr(nKey) ),;
nRecno := RECNO(),;
nLapso := SECONDS() - nSeconds,;
cArgAnt
cArgume := IF(nLapso > 1 .OR. nLapso < 0,"",cArgume)
cArgAnt := cArgume
cArgume += cKey
IF !DBSEEK(cArgume)
cArgume := cArgAnt
DBGOTO(nRecno)
nSeconds := SECONDS()
RETURN .F.
END
IF !(RECNO() = nRecno)
oBrw:UpStable()
nSeconds := SECONDS()
RETURN .T.
END
nSeconds := SECONDS()
RETURN .F.
Have you tried my TSearch class? You can get a copy at my FiveWin page at:
http://ourworld.compuserve.com/homepage ... rogram.htm It is a popup search box with dynamic searching as you described, but the backspace works too. I call it from a buttonbar button on a browse. I think there is some example code in the zip file.
--------------------------------------------------------------------------------
I have written a few (small but stable) Clipper 5.2e for DOS applications for various clients (I run a small Networking Company inSouth Africa). I have been approached by one of my my larger clients to write an application for them but the main criteria is that is runs under Windows 98. I have downloaded the demo version of Fivewin and would like to purchase the latest version and use this for my application. Before I do this, however, I need to know that I will be able produce the results (as I have never written any application for windows).
I therefore have been testing the samples etc. and tried to write an extremely simple bit of code just to scroll through a database (see below) but I am getting strange results and I'm not sure why.
In the code below the idea is to click on the '>>Next' and '<<Previous' buttons and display the two test fields. In DOS this would be a breeze but for some reason (in this example) each time I click on either '>>Next' or '<<Previous' the programs seems to keep a history of the records previously used and each time one of the buttons is pressed it seems as though my application displays each previosuly viewed record in quick succession and then stops at the correct record and displays it (it is definately scrolling through the database as I can see my HDD light flickering as I click on the aforementioned buttons). Is this a windows anomaly or do I just not understand the concept of using dialog boxes and button bars etc. Obviously the more records you view the longer it takes to print the results as it appears to start at the first results displayed and sroll through each previously displayed record before displaying the correct information. I have noticed, however, that it does not start at the first record in the database but at the first window displayed ie. if you are at the beginning of the file INVOICE.DBF and press the '<<Previous' button say 20 times and then the '>>Next' button it will quickly display the first record in the database 20 times and then display the next (and correct) record.
Try this:
@ 5,1 BUTTON '&<<Previous' OF ODLG SIZE 80, 23 ACTION ( DBSKIP( -1 ), ODLG:Update() )
@ 5,20 BUTTON 'Next&>>' OF ODLG SIZE 80, 23 ACTION ( DBSKIP(), ODLG:Update() )
@ 7,20 BUTTON 'En&d' OF ODLG SIZE 80, 23 ACTION EXIT()
@ 2,1 SAY 'Invoice Number ' + STRZERO(INVOICE->IVREF) UPDATE
@ 3,1 SAY 'Invoice Remark ' + INVOICE->IVDBREM UPDATE
Take a look at the \samples directory. You'll find several small examples about almost everything that you can do with Fivewin. That will speed up your learning curve.
I tried your code and it works perfectly fine for me. You may be interested in my "Introduction to FiveWin" article located on my web site (see below).
http://ourworld.compuserve.com/homepages/jbott
You should look into a resource editor. Borland's Workshop is very used by the FW community. It allows you to draw very nice screens including buttons, icons ... You will only have to REDEFINE the buttons, and the actions to be performed. FW is an excellent tool for clipper programmers.
--------------------------------------------------------------------------------
I need a Filtered Browse better than the LISTBOX with the clause SELECT (so slow).
You can use a conditional index or the Tdbf class with the setscope() method.
use class tcbrowse and use method
bGoTop
bGoBottom
bSkip
not very fast, but resolve problem. you see example ( BRWSIP.PRG )
BETTER SOLUTION WOULD BE THAT ONE THAN TO CREATE A TEMPORARY INDEX .
(alias())->( dbClearIndex() )
INDEX ON EspNtx ;
TO cNomeNtx ;
FOR cCondFor
IF USE COMIX3 try this
cKey := "0001"
PlanPazi->( cmxClrScope( 0 ) )
PlanPazi->( cmxClrScope( 1 ) )
*
PlanPazi->( cmxSetScope( 0, cKey ) )
PlanPazi->( cmxSetScope( 1, cKey ) )
PlanPazi->( dbGoTop() )
while PlanPazi->( ! eof() )
*
PlanPazi->( dbskip() )
ENDIF
--------------------------------------------------------------------------------
Question (Probably posted many times) In table view, my numbers are proportionally and not nicely ailing. I need to set a global font for doing it, but How ? The Ng's are not clear for me (use negative number ?) Please, post the syntax.
Courier is not a proportional font. Try this.
DEFINE FONT oFont NAME "Courier" SIZE -0,10
If you are referring to TWBrowse, try setting oBrw:aJustify. It's an array containing a series of logical values, one for each column. True value means right alignment (good for numbers).
--------------------------------------------------------------------------------
When adding a record to a browse, the browse repositions so that the new record is the only one displayed. Does anyone have some hints on having the record added to the bottom of the existing list without scrolling all other items out of view.
Try this
GoLastIn()
oBrw:UpStable()
oBrw:ResetBarPos()
oBrw:SetFocus()
oBrw:Refresh()
FUNCTION GoLastIn
LOCAL nLastRecno:=0,cOldOrder:=( cAlias )->( OrdName() )
( cAlias )->( DBSETORDER( 0 ) )
( cAlias )->( DBGOBOTTOM() )
nLastRecno:=( cAlias )->( RECNO() )
( cAlias )->( ORDSETFOCUS( cOldOrder ) )
( cAlias )->( DBGOTO( nLastRecno ) )
RETURN nLastRecno
I sending a BrwBottom() Function Which is your want
Function BrwBottom( oBrw )
local nSkipped
local nLines := oBrw:nRowCount()
local n
local bChange := oBrw:bChange
oBrw:bChange := NIL
oBrw:goBottom()
oBrw:lHitBottom = .t.
oBrw:lHitTop = .f.
Eval( oBrw:bGoBottom )
nSkipped = oBrw:Skip( -( nLines - 1 ) )
oBrw:nRowPos = 1 - nSkipped
oBrw:GetDC()
for n = 1 to -nSkipped
oBrw:DrawLine( n )
oBrw:Skip( 1 )
next
oBrw:DrawSelect()
oBrw:ReleaseDC()
if oBrw:oVScroll != nil
oBrw:oVScroll:GoBottom()
endif
oBrw:bChange := bChange
if oBrw:bChange != nil
Eval( oBrw:bChange )
endif
Return nil
--------------------------------------------------------------------------------
Anyone have a way to browse an array on resource bitmaps. i can't seem to get it at all <ok so i'm stupid>
Here is somewhat of an answer. To load the resource bitmaps:
aadd(aBmp, loadBitmap( getResources(), "CUSTOMER"))
Then use a standard listbox with an array. If the data isn't character, listbox automatically recognizes it as a bitmap.
--------------------------------------------------------------------------------
Hi for all ! I have a problem with Dialog and Browse coordinates .Here is the source code
local oBut
local oDlg
local nHorRes := GetSysMetric( 0 )
local nVerRes := GetSysMetric( 1 )
// Dialog window with coordnates .
DEFINE DIALOG oDlg FROM 0, 0 to nVerRes - 100, ;
nHorRes - 50 PIXEL TITLE 'Browse dialog'
// Here I want to create column browse with less cooordinates
@ 0, 0 COLUMN BROWSE oBrw ALIAS GO SIZE oDlg:nRight - 10, ;
oDlg:nBottom - 50, nRow PIXEL OF oDlg
ADD COLUMN TO BROWSE oBrw DATA ... HEADER ...
etc..
// At the bottom of dialog window I want to put some buttons .
@ oDlg:nBottom - 25, 10 BUTTON oBut PROMPT ' ... ' ;
SIZE 80, 12 PIXEL OF oDlg ACTION but_push1()
etc..
My problem is that Browse coordinates don't appears trully . I can't understandant in which way I can operate with Dialog widow and Browse control sizes . The sizes nVerRes and nHorRes work OK and Dialog window I create for size which I want . But the controls objects in Dialog box like Browse , Buttons and etc . did not understand oDlg:nTop ,oDlg:nBottom or etc. I will be thankfull for any help .
Try using oBrw:Move( etc. ) in ACTIVATE DIALOG's ON INIT clause.
Do the following and it will work well
a) Create all your controls without worrying about position and size in your window definition ie.
@ 0, 0 control ::oControl1 .......................... SIZE 0, 0 PIXEL
Use the pixel clause for all controls
b) Add a bDlgInit as follows: oDlg:bDlgInit := {|| ::PositionDlgControls()}
METHOD PositionDlgControls
::oControl1:Move(10, 10, 60, 18) // Top, Left, Width, Height
::oControl3:Move(32, 10, 60, 18)
::oControl4:Move(32, 10, 60, 18)
::oControl5:Move(32, 10, 60, 18)
::oControl6:Move(32, 10, 60, 18)
etc etc etc etc
return nil
This works very well as all your positionaing and sizing for all controls is done in one place, making it much easier to do You must NOT size and position your controls before the init of the dialog, other wise the coordinates are all weird and will confuse the hell out of you
--------------------------------------------------------------------------------
The code below doesn´t work because when bskip is called after a couple of times the VAR Linha is NIL causing the error. Can someone help me solving this problem ? Code :
LOCAL nRegistos, Linha := 1
Nregistos := RegistosPara(mbrowse)
mbrowse:bgotop := { || DBGOTO(Nregistos[Linha := 1] ) }
mbrowse:bobottom := { || DBGOTO(Nregistos[Linha := LEN(Nregistos) ] ) }
mbrowse:bskip := { |nanda| ChavePara(nanda, Nregistos, @Linha) }
FUNCTION Chavepara(nanda,nregistos,linha)
LOCAL nandou
nandou :=0
* movimento dentro de gama aceitavel
IF Linha + nanda < 1
* passei topo do bloco !
nanda := - Linha + 1
ELSEIF linha + nanda > LEN(Nregistos)
* passei o fim do bloco !
nanda := LEN(Nregistos) - Linha
ENDIF
Linha += nanda
nandou := nanda
if nregistos[linha] > 0
DBGOTO(Nregistos[Linha] )
endif
RETURN(nandou)
>mbrowse:bobottom := { || DBGOTO(Nregistos[Linha := > LEN(Nregistos) ] ) }
Isn't this supposed to be "bGoBottom"?
That´s right but but in the program that is correct. What I pretend to know is that if this is in fact a valid code just like it is in standard clipper. When buiding the array of records and display it the 1st time everything works weel, but when I move the browse cursor it immediatly gives an error. I´ve found out that the VAR Linha in the block
mbrowse:bskip := { |nanda| ChavePara(nanda, Nregistos, @Linha) }
is becoming NIL but I can´t find why. I can´t see where in this code the value is changed to NIL. Maybe you could give a clue.
I don't understand your using Linha:= as an array postion. This will return .T. or .F. not a number.
>>mbrowse:bgotop := { || DBGOTO(Nregistos[Linha := 1] ) }
If you want to go to the first record and set Linha to 1, then I would do it like this:
mbrowse:bgotop := { || (Linha:=1, DBGOTO(Nregistos[Linha] ) ) }
> > mbrowse:bgotop := { || DBGOTO(Nregistos[Linha := 1] ) }
> If you want to go to the first record and set Linha to 1, then I would do it
> like this:
> mbrowse:bgotop := { || (Linha:=1, DBGOTO(Nregistos[Linha] ) ) }
The two expressions are semantically equivalent.
--------------------------------------------------------------------------------
I would like to shift the position of an item in wbrowse with drag & drop. Up to now I have used an indexed field with the row-number. I mark the line which I want to transfer with the left button, then I click the right mouse-button to select the line. Afterwards I again mark the space where I want to insert the line with the left mouse-button, and finish the change with a right click. But I think this is not the usual procedure. So I tried with
oLbx:bLClicked
oLbx:bLButtonUp.
But bLButtonUp is only sending back the row in pixel. Can someone tell me how I know how to find the record-number of the line?
This might help, get text row from pixel row
METHOD nClickRow ( pnPixRow ) CLASS qBrowser
/*
return browse row matching pixel row
*/
return nWRow( ::oBrw:hWnd, ::oBrw:hDC, pnPixRow, If( ::oBrw:oFont != nil, ::oBrw:oFont:hFont, 0 ) )
--------------------------------------------------------------------------------
WBrowse. How to make headers active ? Meaning, if I click a header then something can be executed (Mostly used for index order related to that column)
oBrowse:aActions:={ {|oBrw,nRow,nCol|MsgInfo("You pressed the 1st column")},;
{|oBrw,nRow,nCol|MsgInfo("You pressed the 2nd column")}}
Thanks for the hints. Yes it goes now. Any chance we put a bitmap on the headers ?
Take a look into CanalFive Grid, quite powerful and amazing way to make your data look sharp !!!! check at:
http://canalfive...com
--------------------------------------------------------------------------------
do you think that it is a bug or my fault?
odbf:=tdatabase():new()
obrw:=twbrowse...
if i put a scop on a dbf and if there is no record matching the scop then my wbrowse is empty, so all is ok (so the scop is "working") but if i add a record, then delete it my wbrowse show me the deleted record NOT Normal!! if i add a new record then the wbrowse show the new record (and no more the deleted one) any idea?
It is normal - after you delete the record - do a DBSkip(0) on the work area. The reason you still see the deleted record is because you have not moved from that record yet...
i see the deleted record even if i close the dialog and return after in it
I suppose SET DELETED is on?
yes sure!
the proof is that if there are two records matching the scop one record not deleted and one record deleted the only record that i see in the browse in the not deleted the strange thing is if the only record matching the scope is a deleted record, then it appears in the browse
--------------------------------------------------------------------------------
Is there any way to create relation on browse with arrays? for example i have 2 arrays with this records
Array(a) Array(b)
{"Test1",100,200} {"Test1",1000,2000}
{"Test2",200,200} {"Test2",50,100}
i want to create relation with items Array(a)/First Item & Array(b)/First Item ...
b:nAt:=ascan(a[a:nAt,1],b) ???
--------------------------------------------------------------------------------
I tried to replace TWBROWSE in an app I'm working on with TSBROWSE. When compiling, I get: treeview.ch (14) "Fatal C3048 Preprocessor table overflow". It works fine using TWBROWSE.
My includes are ordered as follows:
include fivewin.ch
include tsbrowse.ch
include treeview.ch
include font.ch
Any idea what to try other than reducing number of includes, which can't be done with the current form being displayed.
Whoops, I meant TCBROWSE, not TWBROWSE.
Try by including the folowing lines at the begining of your program:
#define _DDE_CH // if you don't use DDE in your program
#define _VIDEO_CH // if you don't use VIDEO in your program
#define _TREE_CH // if you don't use TREE in your program
#define _ODBC_CH // if you don't use ODBC in your program
#define _OBJECTS_CH
#include "FiveWin.ch"
We have the same problem. We compile the module with Clipper 5.2e and linked it with other modules compiled with Clipper 5.3b. It worked fine But with "#define" thing, we completely compiled our modules with 5.3b.
What causes these? Is there any other way? (like for example i'm using all those objects)
Guess you're using Clipper 5.3. Either copy fivewin.ch and comment out some of the rarely used #includes at the top:
#include "Folder.ch"
#include "Tree.ch"
#include "Print.ch"
#include "DLL.ch"
#include "ODBC.ch"
#include "DDE.ch"
#include "Video.ch"
or add stuff like the following BEFORE #includeING fivewin.ch
#define _FOLDER_CH
#define _TREE_CH
and so forth.
Can you move some sections of code into separate PRGs? Like the tree for instance?
Alternately, you could move the tree into a separate file, preprocess it and put it back (and thus be able to remove the ch include).
I think if you can free up more RAM it would also help.
This is a single module from the others that handles user/group security system, and I'm using a tree to select from. Guess with a little work I could break it into another module. What do you mean on preprocessing it in another file and then putting it back.... I don't quite understand what you mean exactly. I'm willing to try anything to make it work.....
The ch files are used to translate a lot of the Clipper and Fivewin syntax to other more arcane functions and OOP calls. So, for instance all your tree syntax is translated into class syntax. You can get the preprocessor output by compiling with Clipper using the /P parameter.
clipper myapp /p
The output file will be the same name as the PRG but with a PPO extension.
Now if you have a stable section of code, like the tree, you can copy out the tree section from the PRG and paste it into a temp PRG file, preprocess it, then copy it back into the original PRG (I would leave the original code in but comment it out). Now you can also comment out the #include "tree.ch" since this code has already been preprocessed.
This is not an elegant solution. If you need to change the code in the preprocessed section, you have to go through all this all over again. The
better solution is to move sections of code into other modules.
I don't know how you do things, but I have seen entire large applications written in 1 or 2 PRGs. This is when you are going to really get into
trouble with preprocessor overflows. My applications are more likely to be 50 PRGs. I program in OOP syntax which promotes the use of smaller PRGs. OOP also makes it is also easier to break your code down into smaller modules since you can pass entire objects around (containing lots of code).
Ok, I understand what your telling me now..... I'll look into that solution to see if I can break my prg down a little more. I do as you on breaking my code into modules. I typically have a module for each type of action in my prg and use a lot generic functions to handle actions used across many modules. I haven't used a lot of OOP for each module, though I know I should. This module is rather large because it does a lot, but I think I can break it down some.
Once you start using OOP you will quickly wonder how you ever did without it. There is an article on basic OOP on my website (see URL below).
To get you started thinking about it, imagine having a class for each business object somthing like this:
class TCustomer from TData
method new
method add
method edit
method browse
endclass
TData is my enhanced database class. After creating the above you can just do:
define button of oBar... action TCustomer():new():browse()
to get a child window browser. On that window you can have add, edit, delete buttons:
define button of oBar action ::add()
define button of oBar action ::edit()
define button of oBar action ::delete()
So simple!
And you can pass the entire object around:
oCustomer := TCustomer():new()
whatever(oCustomer)
Then within the whatever() function you can call oCustomer:edit() or oCustomer:print(). You'll love it.
Thanks for the reply Manuel and Luis. I knew that was one thing to do, but in my old age it slipped my memory. What little is left. <G>
--------------------------------------------------------------------------------
Hi FW users ! I want to make use possibilities of TcBrowse Seek and etc methods . But in FW\samples directory I did not found any sample with this . I'll be thankfull , if you can send me any sample how to exhaust oBrw:Seek , oBrw:ResetSeek and etc methods . And another question is about TcBrowse aActions data . How to make codeblocks for TcBrowse columns and then how to use them ?
Did you look at TestTcbr.prg? It shows quite clearly how to use the seek feature inside TCBrowse.
I'm searching how to select some rows with mouse or Shift+arrows or Ctrl+push in TcBrowse class . As I saw in ListBox class this
possibility is , but in TWbrowse and TcBrowse - no . Maybe is another solution to do this ? May thanks for ant advice ! With best regards !
Here is a message from my archives telling how to do this:
I tried it with arrays... And it works !!!
Then, I thought, if I can do it with arrays, I should be able to do it with a file in a TWBrowse. I did it !!!
By adding a new field to my database, I update that field when I select the record. When the field is updated, I also created a oLbx:Pane(IIF field = .T., RGB(red), RGB(blue))... Works even better... I can now go to the database and process all records with this field at .T.
--------------------------------------------------------------------------------
I'm using oLBX:bChange := { || ShoInvRec() } to display some data in the dialog box that is associated with the current record in the browse.
I know it is evaluating this function for every record in the database. As I scroll down the list, I can see the associated data scrolling
through until it reaches the current record.
My question is how can I control the scope so that it evaluates only the current record? Or, can I incorporate the function in oLBX:bLine?
I do this
redefine get oG1 var cName id ........
redefine listbox oLbs fields DBF1->number, ....... on change SeekAnyData( )
function SeekAnyData( ) // Seek the key number into MyFile and display it in oG1
MyFile->(Dbseek(DBF->Number))
cName = MyFile->Name
oG1:Refresh()
return( Nil)
In only my third week of using Fivewin, I'm still Jimmy source code not Jimmy resource editor, but I think I follow what you are saying.
> redefine get oG1 var cName id ........
First define a Get object with the data I want to display.
redefine listbox oLbs fields DBF1->number, ....... on change SeekAnyData( )
Second, use the ON CHANGE clause to call the function.
> function SeekAnyData( ) // Seek the key number into MyFile and display it
> in oG1
> MyFile->(Dbseek(DBF->Number))
> cName = MyFile->Name
> oG1:Refresh()
> return( Nil)
Finally seek the key for the record, reinitialize the GET vars and then refresh the oGET.
I see what you're saying but why do we seek at all? I thought we were already positioned on the appropiate record.
I followed your suggestion, but my oGET:Refresh() doesn't seem to be working. I posted a new message with more detail.
Thanks in advance for any suggestions.
Try this:
redefine get ....... of oDlg UPDATE ......
Change oGet:Refresh( ) to oGet:Update( ) or oDlg:Update( )
--------------------------------------------------------------------------------
I can't seem to get my GETs to be repainted as I scroll through my dbf. here's what I'm doing:
// first I load my memvars from the database
LoadVars()
// then I do my GETs
@row,col get oGET VAR mITEMCODE pict ... of oWND
... more gets ....
// then I do my LBX
@row,col listbox oLBX ...
// to repaint the GETs, I use:
oLBX:bChange := {|| LoadGets() , oGET:Refresh() }
I'm certain that LoadGets() is initializing my memvars properly, but oGET:Refresh() doesn't seem to be working for me. I'm sure I must be leaving something out.
I use this in my code.
1. put your get object in an array
aObj := { oGet1, oGet2, oGet3 ... }
on your bChange,
oLbx:bChange := { || DoRefresh(aObj) }
2. create a function with parameter to hold aObj.
function DoRefresh(aObj)
local i
for i = 1 to len(aObj)
aObj[i]:Refresh()
next
return nil
... or if you want more complex, use oGet:VarPut() to update the object b4 refreshing the obj.
--------------------------------------------------------------------------------
I have a listbox (Wbrowse), i want to drag a line to an other line. Swap between line 3 and line 5.
I begin the drag on line 3 and drop on line 5. The start line is found with oLbx:nRowPos, but how can i identify the drop
line ?? I have the var nRow but is in pixel, or how can i convert the nRow in nRowPos ?
Use NWROW() function (look inside WBROWSE.PRG for a how to use sample).
--------------------------------------------------------------------------------
I have an array wich is filled from a dbf off 9 fields depending on the configuration wich can be changed the record amount is 14. The stucture of the browse MUST be downwards the fieldget( 1....9 ) and as column the records.
i create a dialog and then the column browse and here is the problem.
@ 1, 2 COLUMN BROWSE .....
oBrw:SetArray( .............
Then i want to do something like this :
For n := 1 To Len( aArray )
ADD COLUMN TO oBrw ARRAY ELEM n
Next n
This doesn't work
is there a method to work around this problem ?
Remember the array you will be browsing has to be a nested array, not a simpleone.
That is it must be like this
{ { field1, field2, fieldN } ,;
{ field1, field2, fieldN }... }
In which each subarray is the "record" to be browsed.
If you array is like this:
{ field1, field2, fieldN }
That's why nothing is browsed.
Your correct Luis, but the array is correct while when i define :
ADD COLUMN ARRAY ELEM 1
ADD COLUMN ARRAY ELEM 2
.................
this works but i don't know how many cols there are since it is config dependable so i thought
For n := 1 To Len( aArray )
ADD COLUMN ARRAY ELEM n
Next
should do the trick but it won't
Thanks anyway for the responce
your trouble seems to come from the 'detached local'-problem. Please have a look to the following source. May be it helps.
STATIC gaStatArr := {;
{ "Line 1", 12345.67, 123 },;
{ "Line 2", 12345.67, 123 },;
{ "Line 3", 12345.67, 123 },;
{ "Line 4", 12345.67, 123 } ;
}
...
...
...
LOCAL aHeader := { "Header 1", "Header 2", "Header3" }
LOCAL aSize := { 20, 20, 40 }
LOCAL aPict := { "@!", "@E 999.99", "999" }
...
...
...
REDEFINE COLUMN BROWSE oBrow ID 40 OF oDlg
...
oBrow:SetArray( gaStatArr )
...
...
for n := 1 to len( aHeader )
oBrow:AddColumn( TCColumn():New( aHeader[ n ], MakeBlock( n, oBrow ), aPict[ n ],,, If( !.T., "LEFT", Upper( "RIGHT" ) ), aSize[ n ],
.F., .F.,,,, .F. ) )
next
...
...
...
STATIC FUNCTION MakeBlock( n, oBrw )
RETURN ( { | x | if( pcount() > 0, oBrw:aArray[ oBrw:nAt ][ n ] := x, oBrw:aArray[oBrw:nAt ][ n ] ) } )
Should've thought of that... Detlef hit the nail right in the head. You need to use detached locals to solve your problem.
Thanx Luis and Detlef for the responce, i tested it yesterday and it works like a charm
), Now i got it working like i wanted but the most important question remains why do we need to use detached locals for it why cant we do it like the first thought of mine in a loop.
Because the loop counter got a fixed value at the end of the loop. Such value is the FOR statement upper limit plus one.
You should get yourself hold of Rick Spence's "Clipper 5.2 Power Programmer's Guide" if you want more insight on Detached Locals and other Clipper's stuff. (Enrico's explanations is just fine)
--------------------------------------------------------------------------------
In Tcbrowse.ch there are an " #translate VALID ...... " defined. Help needed please!
If this, the valid-clause of an GET or a DIALOG are not ok when the clause are in the form:
....VALID if(xy=z,.T.,.F.) or ...VALID if(xy->(dbseek(z)),.T.,(msginfo("Not OK"),.F.))
In this case, there are both results of the if() evaluated! If I disable this directive, all is OK.
I don't understand what you mean exactly
1- What version of tcbrowse are you using (ie if it's FW original, from which version; if it's the one I changed, what date is it from)?
2.- Can you post the whole line where you are using the VALID clause since the snippet isn't at all clear, because it seems you're using the VALID keyword twice
In any case the first valid should be simplified just as
VALID ( xy == z ) // the if() is redundant
Guenther refers to a #xtranslate statement in TCBrowse.ch which comes from original FiveWin version since 1.9.5 ( or prior versions, I don't know ).
Inclusive the class you modified, comes with that statement, and more, TSBrowse also preserves it.
I actually haven't ever used such command. I left it there for compatibility.
I now realize what he meant.
I've never used it ever either, but certainly seems to be not very useful and quite obnoxious.
--------------------------------------------------------------------------------
When I use the for to clause in a browse, the record pointer is always on the first record of the scope. I want to open such a browse but the last record should have focus.
did you try "GO BOTTOM" before opening the browse?
Try:
ACTIVATE DIALOG oDlg CENTERED ;
ON INIT ( oBrw:nLen := 1, oBrw:GoBottom() ) ;
ON PAINT ( oBrw:SetFocus() ) ;
Ok, I've just tried and that works fine
--------------------------------------------------------------------------------
This change was brought on by a funny, which has now bugged me long enough.
When moving your mouse around the browse, it changes to a left-right cursor when you are on top of a column boundary. If your last column is defined narrow enough, it would do this somewhere inside the last column.
I've changed the mousemove method inside wbrowse to counter this behaviour.
METHOD MouseMove( nRow, nCol, nKeyFlags ) CLASS TWBrowse
local nColPos := 0
local aColSizes := ::GetColSizes()
if ::lDrag
return Super:MouseMove( nRow, nCol, nKeyFlags )
endif
if ::lCaptured
CursorWE()
::VertLine( nCol )
return 0
endif
if ::lMChange .and. AScan( aColSizes,;
{ | nColumn | nColPos += nColumn,;
nCol >= nColPos - 1 .and. ;
nCol <= nColPos + 1 }, ::nColPos,Len(aColSizes) - 1 ) != 0
CursorWE()
else
Super:MouseMove( nRow, nCol, nKeyFlags )
endif
return 0
--------------------------------------------------------------------------------
TwBrowse Release Candidate I (beta) Harbour compatible available from:
http://www.dbwide.com.ar
There is no source or no documentation with it. How should you expect us to test it?
WHY another browser? What is better in this browser?
Patrick, is the same browser, but 100% compatible with Harbour. In few days, Hernán will put in its Page, the Final version.
--------------------------------------------------------------------------------
I use several 'redefine brose ....' and more or less by accident I found some strange things.
e.g. I had a browse which enabled about 40 lines, while at that time the databse only has about 15 records. Things like pageup/down (and similar went weird, if I clicked on the place of an empry row, a row (identical to another) would appear. And so on.
All this went away the moment I changed the height (in the resource) of the browse and increased the number of records.
is there some rule that a browse may not have more than X lines?
Not at all. It may have as many rows as needed.
Do you have deleted records ? If so, please remember that you have to set <oBrw>:bLogicLen to return the proper amount of
records (without the deletes ones).
> Do you have deleted records ?
it is in a test situation, it happens often that there are even more deleted than actual records. It would explain, that at a fresh start (only adding) all is fine.
>> set <oBrw>:bLogicLen
Also if all I do is " redefine browse obrw ....." and no special clauses whatsoever?
--------------------------------------------------------------------------------
I have a question that I tried many way to keep a numeric value right in TWBrowse or TListbox but it didn't work. I need like PADL(n,w,d) function or Str(n,w,d) function. Thanks in advance for any help,
In TWBrowse, set the aJustify elements for the numerics to True, like so:
oBrow:aJustify := { .F., .F., .T., .F., .T. }
Those cells will now appear right-justified.
I use "align right" for that.
--------------------------------------------------------------------------------
I try to use 2 TBrowse object and 2 alias from 1 file. I use cmxsetscope() for query database. When I click on left browse but right browse do not query correctly.
Example:
Clipper 5.2e, FW 2.0d
index expression is GROUP+CODE
GROUP CODE NAME GROUP
CODE NAME
'M ' 'CAR' 'CAR name'
'CAR' 'TOY' 'Toyota'
'M ' 'PEN' 'PEN brand'
'CAR' 'HON' 'Honda'
'PEN' 'CRO' 'Cross'
'PEN' 'PAR' 'Parker'
Procedure ConMCode()
local oDlg, oBrw1, oBrw2, oBtn, oSay
OPENFILE('CCRCODE','SUB')
OPENFILE('CCRCODE','MAN')
MAN->(cmxSetScope(0,'M '))
MAN->(cmxSetScope(1,'M '+chr(122)))
DEFINE DIALOG oDlg RESOURCE 'CONMCODE'
REDEFINE LISTBOX oBrw1 FIELDS MAN->cod_code, MAN->cod_desc ;
HEADERS 'Code', 'Description' ;
FIELDSIZES 50, 180 ;
UPDATE ;
ID 101 ;
ON DBLCLICK EditMan(.F.,oBrw1)
ON CHANGE oBrw2:UpStable() ;
SUB->(cmxSetScope(0,MAN->COD_CODE))
SUB->(cmxSetScope(1,MAN->COD_CODE+chr(122)))
REDEFINE LISTBOX oBrw2 FIELDS SUB->cod_code, SUB->cod_desc ;
HEADERS 'Code', 'Description' ;
FIELDSIZES 50, 180 ;
UPDATE ;
ID 102 ;
ON DBLCLICK EditSub(.F.,oBrw2)
ACTIVATE DIALOG oDlg
Thanks in advance for your help,
The call to cmxSetScope() has to bee done inside the ON CHANGE clause
DEFINE DIALOG oDlg RESOURCE 'CONMCODE'
REDEFINE LISTBOX oBrw1 FIELDS MAN->cod_code, MAN->cod_desc ;
HEADERS 'Code', 'Description' ;
FIELDSIZES 50, 180 ;
UPDATE ;
ID 101 ;
ON DBLCLICK EditMan(.F.,oBrw1)
ON CHANGE ( SUB->(cmxSetScope(0,MAN->COD_CODE))
SUB->(cmxSetScope(1,MAN->COD_CODE+chr(122)) ) )
....
Activate Dialog oDlg On Init Eval( oBrw1:bChange )
I try to use this but it's still not work.
REDEFINE LISTBOX oBrw1 FIELDS MAN->cod_code, MAN->cod_desc ;
HEADERS 'Code', 'Description' ;
FIELDSIZES 50, 180 ;
UPDATE ;
ID 101 ;
ON DBLCLICK EditMan(.F.,oBrw1) ;
ON CHANGE ( SUB->(cmxSetScope(0,MAN->COD_CODE)) , ;
SUB->(cmxSetScope(1,MAN->COD_CODE+chr(122)) ) )
Does the second browse have a index on the COD_CODE field?
The second browse use the same index file.
Database CCRCODE.DBF
Index file CCRCODE.NTX
Expression COD_TYPE+COD_CODE
Field name Type Width
COD_TYPE C 3
COD_CODE C 3
COD_DESC C 30
The first browse key is 'M '+COD_CODE
The second browse key is COD_TYPE+COD_CODE * the COD_TYPE will relation to COD_CODE in first browse
I don't think cmxSetScope() works with the NTX RDD.
I'm sorry the index file is CCRCODE.CDX
--------------------------------------------------------------------------------
I use Clipper 5.2e / FW2.0d / Comix / Blinker 4.10. I tried to browse 2 databases that has relation but it doesn't work. Pls see my sample below, I don't know what I do wrong. Thanks in advance for any idea,
#include 'FiveWin.ch'
#include 'set.ch'
#include 'cmx52.ch'
Static oDlg, oBrw1, oBrw2
*------------------*
Procedure Main
SET RESOURCES TO "BWCC.DLL"
SET RESOURCES TO "FWDBG.DLL"
SET RESOURCES TO "TEST2.DLL"
DBUSEAREA(.T.,,'CCRTRN','TRN',.T.)
TRN->(OrdSetFoCus(1))
MsgInfo(OrdKey())
MsgInfo(OrdName())
DBUSEAREA(.T.,,'CCRTBL','TBL',.T.)
TBL->(OrdSetFoCus(2))
MsgInfo(OrdKey())
MsgInfo(OrdName())
TBL->(cmxSetScope(0,'O'))
TBL->(cmxSetScope(1,'O'+chr(126)))
DEFINE DIALOG oDlg RESOURCE "TESTBRW"
REDEFINE LISTBOX oBrw1 FIELDS TBL->TBL_RMNO, TBL->TBL_LAST ;
FIELDSIZES 60, 150 ;
HEADERS 'ROOM' , 'NAME' ;
ID 101 ;
OF oDlg
oBrw1:bChange := { || oBrw_Con( oBrw1, oBrw2 ) }
REDEFINE LISTBOX oBrw2 FIELDS TRN->TRN_TRNO,
STR(TRN->TRN_UNIT*TRN->TRN_QTTY) ;
FIELDSIZES 60, 100 ;
HEADERS 'TRN#' , 'AMOUNT' ;
ID 102 ;
OF oDlg
ACTIVATE DIALOG oDlg ON INIT Eval( oBrw1:bChange )
TBL->(DBCLOSEAREA())
TRN->(DBCLOSEAREA())
RETURN
*-----------------*
Function oBrw_Con( oBrw1 , oBrw2 )
Select TRN
TRN->(DBseek(TBL->TBL_INTNO))
* oBrw2:SetFilter( 'TRN->TRN_INTNO' , TBL->TBL_INTNO , TBL->TBL_INTNO )
TRN->(cmxSetScope(0,TBL->TBL_INTNO))
TRN->(cmxSetScope(1,TBL->TBL_INTNO))
oBrw2:UpStable()
oBrw2:Refresh()
Select TBL
TBL->(DbGoTop())
oBrw1:SetFocus()
return nil
Put a "SELECT TRN" before the REDEFINE for oBrw2, or specify the alias as in oBrw2:alias := "TRN"
SELECT TRN
REDEFINE LISTBOX oBrw2 FIELDS TRN->TRN_TRNO,
...
...
SELECT TBL
oBrw2:alias is going to be TBL because that was the active table when the listbox was defined.
Thanks a lot, I've got it and work nice.. : >
--------------------------------------------------------------------------------
Suppose I wish to browse a file. Not so much allow modifications. Just browse it. Any suggestions on the best way to do so.
I'm not sure this is "best", but TWBrowse is certainly "easy":
redefine listbox fields alias "Customer" id 101 of oDlg
--------------------------------------------------------------------------------
I have a browse (redefine .... browse ....) and I would prefer it to have no scrollbars (neither hor. nor vertical). Using MS Visual Dev to generate the resource and have already set there to use no scrollbars. Yet they appear.
I managed to eliminate one with obj:
lNoHScroll:=.T., alas there appears to be no obj:lnoVscroll.
Who knows how to fully eliminate them?
Try:
oBrowse:oHScroll:setRange( 0,0 )
oBrowse:oHScroll := nil
oBrowse:oVScroll:setRange( 0,0 )
oBrowse:oVScroll := nil
Tried both, no success. I also liiked into tcbrowse.prg but could not find a data field suggesting to be useble.
> Ps. Op ons laatste gesprek kom ik binnenkort terug, het was wat hectisch de
> laatste tijd !!
Okay no hurry, I completely overhauled my app since that time. Several independent browses into a dialog, sending SMS messages, 'intelligent' buttons, etc.
I use twBrowse() and the suggested statements works for me !
Maybe a :refresh() ?
FW2.3b + Clipper 5.3 + Blinker 6.0
That is the same as a listbox? Bit difficult in my case then, the browse is supposed to show entries from a database and putting that in an array would be a very tedious thing.
> That is the same as a listbox?
Yes.
>Bit difficult in my case then, the browse is
> supposed to show entries from a database and putting that in an array would
> be a very tedious thing.
You can use arrays but you can also use databases. I do most of my database browses using TWBrowse which is defined as either @ 0,0 LISTBOX... or REDEFINE LISTBOX... Listbox doesn't have all the capabilities of TCBrowse, but often you don't need them.
I haven't used MS Visual Dev, but I know that in Workshop you must define a custom control as TWBrowse instead of using the standard "listbox" that Workshop has or you will have strange problems like you are experiencing.
Also in workshop you can disable the scrolling by editing the style. You take out these. WS_VSCROLL | WS_HSCROLL.
I changed it to a "Listbox" (I discovered that there were 2 helpitem on listbox, one for use as regular and one for use with a dbf). But the
scrollbar remains. Although (as far as I can see) the problem (scrolling going haywire) has disappeared, and I wanted to eliminate the bar as a
workaround.
>>> custom control as TWBrowse instead of using the standard "listbox" that
In MSDev I can define a customer control, but then I get a runtime error.
--------------------------------------------------------------------------------
I have an empty database with a character field len 20, and a browse to show that field in a dialog with a buttonbar. The first button in the bar, it's used to diaplay a dialog to add a record with data entered by the user. Now, the problem is that when i add the first record in the database, the browse doesn't show it after the refresh, but if i close and open the dialog with the browse again, it shows it normally. The curious thing is that when i add a register and there are other records in the database, there isn't any problem. I am using oBrw:Refresh() and i tried oBrw:UpStable and oBrw:BugUp() too, and any combination of those methods to refresh the browse after i add the record, but it doesn't help. This problem happens with arrays and databases, and it doesn't matter how many items or the size of each one. What can it be?
Note: i don't want to use tsbrowse's autoappend functionality, because i must do it with the buttonbar.
Check your alias...
define browse... alias cAlias
=> cAlias must be your database alias name
--------------------------------------------------------------------------------
In a browse I can (in the column statement) define an "order indxname" which defines the actual index to use when the columnheader is double clicked.
This is nice, however I want (when the column header is clicked) to have the control.
Question is, "Is there a way to define an action when a certain column header is (double) clicked?"
I had the same necessity; for this reason I modified for my personal use the tcbrowse and tccolumn classes.
I attach them here, just to show you how I did. Search for ::bHeadclick inside both classes. I don't expect you can compile and use this code, probably it calls more functions from my personal library or other pieces of code. But you should to get some idea about how to do.
Since The NG do not allow me to send whole code inside one zip, search two zip files in following messages
TCC.ZIP TCB1.ZIP
I will check them out, although I remember that in 1.9x there was a default
codeblcok which could be changed for such purposes.
--------------------------------------------------------------------------------