|
Post by Chris Iverson on Jan 2, 2019 23:49:43 GMT -5
Oops, my last edit got ninja'd. See the last part of my previous post.
|
|
|
Post by metro on Jan 3, 2019 0:02:30 GMT -5
Thanks Chris, I was using "n" for the index array initially and changed to r because of the over use of n in multiple spots I played with the indexing as I said but it was late and I may not have been concentrating good job finding it appreciate the help
EDIT
I'll have to dig deeper your change fixes the display (ie no blank line) but when I select a row then click "edit" the row selected is out one index position. so for now I will leave the blank line till I understand whats going on
|
|
|
Post by Chris Iverson on Jan 3, 2019 1:05:19 GMT -5
That one's easy, too.
YOUR array is one-indexed.
All Win32 internal arrays, including the one that it maintains the listview with, are zero-indexed. (Note that your own indexes are not passed into the control's internal array; the addRow sub just tells the control there's new data to include.)
When you ask the Win32 control what item is selected, it returns it's own array index number, which is zero-indexed.
You need to add one to the iItem value returned to match your array, or you need to build your array zero-indexed in the first place. (If you do choose to zero-index YOUR array, that then means you have off-by-one problems with the LB SQL DLL, which handles it's row counts one-indexed, as well as returning duplicate results if you go above/below row count.)
As you can probably guess, off-by-one errors are one of the most common headaches for programmers, especially when moving across different programming languages with different semantics. The semantics of C(especially the way for loops and array definitions work), which the Win32 API is written with(and for, really), lend themselves to being zero-indexed by default. LB's own semantics lend it towards being one-indexed. You can do either in both languages, but you'll need to do more off-by-one correction work to handle it.
|
|
|
Post by metro on Jan 3, 2019 2:21:37 GMT -5
Thanks Chris, I believe it has sunk in, so I now have one based indexes and have changed the [editrow] line print RecFound$(LVITEM.iItem.struct+1)' watch for saving edited data to select the LVITEM.iItem.struct+1 (index) which i'm guessing is plus 1 because I load the rows in reverse I just have to remember if I save back to the listview to allow for that offset or I just save changes back to the DB and re-load the listview. I'm glad there's no limit on dumb questions here, I've learnt a lot on this forum. once again invaluable help....appreciate it
PS changes made to original posted code
|
|
|
Post by Chris Iverson on Jan 3, 2019 2:47:50 GMT -5
which i'm guessing is plus 1 because I load the rows in reverse Not quite. It's because the Windows API numbers it's arrays starting at zero, whereas a lot of LB users(yourself included) number your arrays starting at one. That's what zero/one-indexing means. If the Win32 API(actually, C code) creates an array that can old 10 items, the items are numbered 0-9, and the first item is index #0. int a[10]; //Create array of 10 items a[0] = 1; //Set first index's value to 1 a[9] = 10; //Set last index's value to 10 In LB code, creating an array of 10 items creates an array numbered from 1-10. The first item is index #1. (This isn't the full truth of LB's arrays, but we'll leave off even more confusing details for now.) dim a(10) 'Create array of 10 items a(1) = 1 'Set first index's value to 1 a(10) = 10 'Set last index's value to 10 Because of this, if you're moving data between the two interfaces, you need to bump the index +/- 1 to make sure they match up. Otherwise, you'll either start your data too early, or too late. Here's an example table of an 10-item array filled with the numbers 1-10, in both C and LB. Index | Win32 API/C Array | LB Array | 0 | 1 |
| 1 | 2 | 1 | 2 | 3 | 2 | 3 | 4 | 3 | 4 | 5 | 4 | 5 | 6 | 5 | 6 | 7 | 6 | 7 | 8 | 7 | 8 | 9 | 8 | 9 | 10 | 9 | 10 |
| 10 |
|
|
|
Post by Rod on Jan 3, 2019 3:31:06 GMT -5
Our habit of starting arrays from number 1 is driven by how Liberty listboxes and comboboxes work. Here index 0 is reserved and the first entry is numbered 1 not 0. 0 is actually used to return "not found" or to set the selected item to "nothing".
So as a Liberty coder I often build matching arrays starting from 1. I just ignore the fact that there is actually an array element 0. So for n = 1 to 10 instead of for n = 0 to 9 Liberty helps by dimming 11 elements when you ask for 10. You get array positions 0 to 10 (eleven elements) but only use 1 to 10 (ten elements).
Using API creates a zero based index, unlike Liberty, so everything can be zero based, mixing one and zero just over complicates does it not.
|
|
|
Post by metro on Jan 3, 2019 4:10:27 GMT -5
certainly a trap for the uninitiated Rod It's amazing how many times you can look at things and not see the problem that's why its invaluable posting here, great help ...no judgement
|
|
|
Post by meerkat on Jan 4, 2019 8:00:32 GMT -5
metro, Thanks for your help. I like the look, but it sure seems like a lot of trouble just to do dynamic interfaces. I'm going to wait for LB5. Posed to have a grid. If it can be created dynamically then we may have a easier solution. Hopefully we can create dynamic buttons, check boxes etc in the grid.. We will see?
Like you, I don't have a lot of time lately. Just bought a 16 unit apartment and am busy improving and maintaining it. Dan..
|
|
|
Post by metro on Jan 4, 2019 9:34:28 GMT -5
glad to see one of the Vegas trips finally paid off hope ya got a new shirt too
|
|
|
Post by metro on Jan 11, 2019 10:03:44 GMT -5
We got sidetracked on this thread but rather than start a new I thought I'd post some code I've played with to give me an editable array of API created textboxes....maybe useful for someone to expand on. some credit goes to Cundo and RNBW for the start focus is set to the first textbox initially then you can tab to the next tb. making changes to data if required.
'=================================================== ' CREATE TEXTBOX GRID CreateTextboxAPI_Grid_5.bas ' USING WINDOWS API '=================================================== ' modified from LB Newsletter API Corner ' with corrections by Cundo LB Conforum 19 July 2016 ' Further modifications by RNBW 21 July 2016 ' Some Mods by metro Jan 2019 '=================================================== dim newdat$(1000) Fname$="cowNumber , recogn , followNum , also , date , milkingTime , milkAmount , milkmeterNumber" nomainwin
line$(1)="106,Krokus,9,250,6-12-20018,18,15.2,1" line$(2)="88,Krokus,17,250,6-12-20018,18,6.8,1" line$(3)="68,Krokus,25,250,6-12-20018,18,8.6,1" line$(4)="91,Krokus,33,250,6-12-20018,18,8.4,1" line$(5)="67,Krokus,41,250,6-12-20018,19,17.0,1" line$(6)="62,Krokus,49,250,6-12-20018,19,8.0,1"
'LOAD INFO for a = 1 to 6 for q= 1 to 8 Ldat$(a,q)=WORD$(line$(a),q,",") next next
numFields=8 numRecs=6
MENU #1, "&File","&Read", [readIt],_ "E&xit", [quit]
[WindowSetup] WindowWidth = 840 : WindowHeight = 600 UpperLeftX = INT((DisplayWidth-WindowWidth)/2) UpperLeftY = INT((DisplayHeight-WindowHeight)/2) ' ------------------------------------------------- ListBox #1.lb1, newdat$(), [selectlist], 40, 190, 645, 150 button #1.btn1 ," Save Data ",[button1Click], UL, 40, 350, 75, 25 OPEN "API Textbox Grid" FOR dialog AS #1 PRINT #1, "trapclose [quit]" #1.lb1,"Font Courier_New 10 BOLD " #1.lb1,"hide"
Global Style, Style1
startH = 40: startV = 40: hRow = 20 : width = 80 DIM hT(numRecs,numFields) FOR row = 1 to numRecs FOR col = 1 to numFields ' Set up the style for the Textboxes Style = _WS_CHILDWINDOW OR _WS_BORDER OR _WS_VISIBLE OR _WS_TABSTOP'_ES_RIGHT 'OR _ES_NUMBER hPos = startH + (col-1)*width vPos = startV + (row-1) * hRow hT(row,col) = CreateTextbox(hwnd(#1),hPos,vPos,width+1,hRow+1,Style) NEXT col NEXT row
'FILL GRID FOR row = 1 to numRecs FOR col = 1 to numFields Print SetText$(hT(row,col), Ldat$(row,col)) NEXT col NEXT row
call SetFocus hT(1,1)
WAIT
[quit] CLOSE #1: END
[readIt] handle = GetFocus() txt$ = GetWindowText$( handle ) NOTICE txt$ WAIT
[button1Click]
FOR row = 1 to numRecs FOR col = 1 to numFields NewLine$( row,col)=GetWindowText$( hT(row,col)) ' print NewLine$(row,col) newdat$(row)=newdat$(row)+","+NewLine$(row,col) ' newdat$(row)= AFTER$(newdat$(row),",") NEXT col NEXT row for z= 1 to numRecs newdat$(z)= AFTER$(newdat$(z),",") next
#1.lb1,"show" #1.lb1,"reload" z=1 redim newdat$(1000) Wait [selectlist]
WAIT
'-------------------------------------------- ' SUBs and FUNCTIONs '--------------------------------------------
' Get the focus in the Texbox Function GetFocus() CALLDLL #user32, "GetFocus",_ GetFocus AS uLONG END Function
' Set the focus in the Texbox SUB SetFocus hWnd CALLDLL #user32, "SetFocus",_ hWnd AS uLONG,_ result AS LONG END SUB
'Get the text entered into the Textbox FUNCTION GetWindowText$(hWnd) total = GetWindowTextLength(hWnd) Title$ = SPACE$(total) + CHR$(0): l= LEN(Title$)
CALLDLL #user32, "GetWindowTextA",_ hWnd AS uLONG,_ Title$ AS PTR,_ l AS LONG,_ result AS LONG GetWindowText$ = TRIM$(Title$) END FUNCTION
'Get the length of the text entered into Textbox FUNCTION GetWindowTextLength(hW) CALLDLL #user32, "GetWindowTextLengthA",_ hW AS uLONG,_ GetWindowTextLength AS LONG END FUNCTION
' Function to create Textbox FUNCTION CreateTextbox(hW, x, y, w, h, Style) Style = _WS_CHILDWINDOW OR _WS_BORDER _ OR _WS_VISIBLE hInst = GetWindowLong(hW, _GWL_HINSTANCE)
CALLDLL #user32, "CreateWindowExA",_ 0 AS LONG,_ "EDIT" AS PTR,_ "" AS PTR,_ Style AS LONG,_ x AS LONG,_ y AS LONG,_ w AS LONG,_ h AS LONG,_ hW AS uLONG,_ 0 AS LONG,_ hInst AS LONG,_ 0 AS LONG,_ CreateTextbox AS uLONG END FUNCTION
FUNCTION GetWindowLong(hW, type) CALLDLL #user32, "GetWindowLongA", _ hW AS uLONG,_ type AS LONG,_ GetWindowLong AS LONG END FUNCTION
function SetText$(hWnd , caption$) calldll #user32, "SendMessageA",_ hWnd as ulong,_ _WM_SETTEXT as long,_ 0 as long,_ caption$ as PTR,_ result as long end function
Sub SendMessageLong hWnd,msg,wParam,lParam CallDLL #user32, "SendMessageA",_ hWnd As uLong, _ msg As Long,_ wParam As Long,_ lParam As Long,_ re As Long end sub
|
|
|
Post by meerkat on Jan 13, 2019 15:39:23 GMT -5
Thanks metro. Ya.. lost my shirt in Los Vegas. Now I'll probably lose everything else with the apartment..
I still need to put buttons, dropdowns, radio buttons, links, text, textarea, photos etc in the grid. Else all I can do is edit stuff in it. It also has to be dynamic so it's possible to lay it out with variables and position boxes via program control. I've come to a dead end. Unless someone has a way to do this, i'll wait for LB5 to see if it's still a problem.
Dan
|
|
|
Post by metro on Jan 14, 2019 7:27:37 GMT -5
Just maybe Carl has a solution close at hand.. you could stick with RunBasic if RB1.02 is around the corner.
|
|
|
Post by meerkat on Feb 24, 2019 12:01:56 GMT -5
Just maybe Carl has a solution close at hand.. you could stick with RunBasic if RB1.02 is around the corner. Thanks metro, I did a quick try maintaining a SQLite database with a grid. It's a simple test where I display the rows of a table in a grid with the option to do add, change, or delete. I tried but couldn't figure out how to put buttons in the grad, or how to display data that can't be changed. This is my first try, and basically I'm not sure I've done it correctly. If you can show me how to display without changes, insert photos and buttons into the grid, and also insert a grid into a grid. If not I think I'll wait for V1.0.2 of Run Basic. Any help will be appreciated... Thanks Dan... ' ------------------------------------ ' LB5 sqlite file maint with grid ' ------------------------------------
sqliteconnect #mem, ":memory:" mem$ = "CREATE TABLE tblA ( tblANum integer(5), tblADescr VARCHAR(10), tblACount integer(5))" #mem execute(mem$) print "Table A Created"
for i = 1 to 100 #mem execute("INSERT INTO tblA VALUES (";i;",'tblA_";right$("000"+str$(i),3);"',";i*10;")") next i print "Insert 100 random records complete" #mem execute("CREATE UNIQUE INDEX tblA_num ON tblA(tblANum)") print "Index Created"
mem$ = "SELECT max(length(tblANum)) as w1, max(length(tblADescr)) as w2, max(length(tblACount)) as w3 FROM tblA" ' find widths of columns for grid setup #mem execute(mem$) #row = #mem #nextrow() w1 = #row w1() * 12 w2 = #row w2() * 12 w3 = #row w3() * 12 w3 = 120 print "Column widths are:";w1,w2,w3
mem$ = "SELECT * FROM tblA LIMIT 20" #mem execute(mem$) rows = #mem ROWCOUNT() 'Get the number of rows
col = 6 row = 20 dim a$(col, row) grid #w.grid, a$(), [clicked], 10, 10, 600, 300 'create a grid widget
print "Rows:";rows for i = 0 to rows -1 #row = #mem #nextrow() tblANum = #row tblANum() tblADescr$ = #row tblADescr$() tblACount = #row tblACount() a$(0,i) = "[ADD]" a$(1,i) = "[CHG]" a$(2,i) = "[DEL]" a$(3,i) = str$(tblANum) a$(4,i) = tblADescr$ a$(5,i) = str$(tblACount) print tblANum;chr$(9);tblADescr$;chr$(9);tblACount next i
' ------------------------------------ ' show record data in grid with ' Add, Chg, or Del ' ------------------------------------ open "Grid Test" for window as #w ' open the grid #w.grid columnnames("ADD","CHG","DEL","Num","----Description----","Count") 'label the colums #w.grid columnwidths(50,50,50,w1,w2,w3) 'set sizes for columns #w.grid rownames("Table A","Record","Maintenance") 'label the rows #w.grid rowlabelwidth(60) 'set sizes for rows '#w.grid selectxy(2, 2) 'cause col 3, row 3 to be selected
wait
[clicked] xy$ = #w.grid cellxy$() 'column,row clicked x = val(word$(xy$,1," ")) y = val(word$(xy$,2," ")) print "clicked: xy";xy$;" x:";x;" y:";y acd$ = #w.grid value$() print "cell contents: ";acd$ 'contents of cell clicked if acd$ = "[ADD]" then goto [addLike] ' add like this record if acd$ = "[CHG]" then goto [chg] if acd$ = "[DEL]" then goto [del] wait [addLike] [chg] [del] print "Doing ";acd$
#w.grid selectxy(4, y) 'cause col 4, row y to be selected tblANum$ = #w.grid value$() 'print contents of selected cell
' ---------------------------------------------- ' Detail maintenance grid ' ---------------------------------------------- dim a1$(1, 3) mem$ = "SELECT * FROM tblA WHERE tblANum = ";tblANum$ #mem execute(mem$) #row = #mem #nextrow() tblANum = #row tblANum() a1$(0,1) = #row tblANum$() tblADescr$ = #row tblADescr$() a1$(0,2) = #row tblADescr$() tblACount = #row tblACount() a1$(0,3) = #row tblACount$()
print acd$;" ";tblANum;" ";tblADescr$;" ";tblACount a1$(0,0) = acd$ a1$(1,0) = "[Exit]" grid #w1.grid, a1$(), [clicked1], 10, 10, 300, 300
open "Maintenance" for window as #w1 grid #w1, a1$(), [clicked1], 10, 10, 100, 300 'create a grid widget #w1.grid columnnames("Maintenance") 'label the colums #w1.grid columnwidths(100) 'set sizes for columns #w1.grid rownames("","Num","Descr","Count") 'label the rows #w1.grid rowlabelwidth(60) 'set sizes for rows
wait [clicked1] xy$ = #w1.grid cellxy$() 'column,row clicked x = val(word$(xy$,1," ")) y = val(word$(xy$,2," ")) print "clicked: xy";xy$;" x:";x;" y:";y val$ = #w1.grid value$()
acd1$ = #w1.grid value$() print "cell contents: ";acd$ 'contents of cell clicked if acd1$ = acd$ then goto [doMaint] 'add like this record if acd$ = "[Exit]" then close #w1 wait end if [doMaint] print "Do ";acd$ close #w1 wait
[eoj] print "** End of Update**" #mem disconnect() end
|
|
|
Post by metro on Feb 25, 2019 7:24:15 GMT -5
Hmm, Dan, your code throws an error for me under Linux , I'll try and solve why that is. I think we need some input from Carl or any of the other talents in the pool here as to whether what you are trying to achieve is doable in LB. You have certainly mastered runbasic and its a shame Carl doesn't have the time to resolve the locking issues you have been experiencing with Sqlite and Runbasic. I certainly do not have the skill set to find a solution, crikey I'm just short of 64 it could take me till I'm 78 to gain half of you ability.
|
|
|
Post by meerkat on Feb 25, 2019 8:12:54 GMT -5
Ya Right! If I had a clue, I'd still have my shirt after my Las Vegas trip. From now on I'll simply skip the trip and send them a check, stay home hand have a brew, and save everyone a lot of time.
Actually the code is usable as is but not very polished. It just needs some more cell features like; - multi line text editing - display only cells - ability to place buttons - images - ability to open multiple grids in a window. Now it makes a new window. - fonts by cell - links
Maybe I should use it for what it was intended and not use it as a form. It's basically set up to act like a spread sheet. Maybe there is something in LB5, haven't found yet. If it's like LB4 most of the windows are static and you have to hard code the locations. Maybe I don't know yet, but if LB5 has variables on the x,y locations, and you can dynamically create them with the program, that solves a lot of stuff.
BTW - if you try to set the font (#w.grid "font areal 14") it locks up LB5 and you have to kill it with the task manager.
Hope things are good down under. Have a gday ... Dan
|
|