Page 1 of 2
Linear Programmer looking for a clue
Posted: Sat Feb 05, 2022 3:22 am
by glennj.0158
Hi all -- I''m an embarrassed old fart. Began programming in the '60s and worked with linear languages like Fortran and COBOL with a little C and several more obscure languages thrown in. While I understand the conceptual basis for event-driven programming I have zero experience.
I'm looking for a resource which will answer questions like "I have the form and supporting code so what do I do to make it run?" There is clearly a user conceptual error involved because the program compiles, flashes a window, and vanishes into the night.
Files are another area where I don't even know what I don't know. I'm used to a language with some sort of record structure associated with file read/write operations. Copying a structure containing strings and/or lists cannot be as simple as getting the size of the structure and writing that many bytes to disk. Even if that worked reading it back would not correctly allocate the memory. I think I have to write the strings individually and loop through arrays and lists. A proper meta-structure will let me do this but it seems more complex than necessary.
Any pointers or suggested reading material appreciated.
Regards
Glenn
Re: Linear Programmer looking for a clue
Posted: Sat Feb 05, 2022 8:50 am
by Bitblazer
Welcome to Purebasic.
glennj.0158 wrote: Sat Feb 05, 2022 3:22 am
Hi all -- I''m an embarrassed old fart. Began programming in the '60s and worked with linear languages like Fortran and COBOL with a little C and several more obscure languages thrown in. While I understand the conceptual basis for event-driven programming I have zero experience.
I'm looking for a resource which will answer questions like "I have the form and supporting code so what do I do to make it run?" There is clearly a user conceptual error involved because the program compiles, flashes a window, and vanishes into the night.
The crucial concept difference is the windows event loop. I suggest you start following the
Purebasic survival guide or
Kale's PureBasic book and use the
PureBasic online documentation as additional help.
If you have any questions while doing that, you can best join the PureBasic
Discord chat.
glennj.0158 wrote: Sat Feb 05, 2022 3:22 amFiles are another area where I don't even know what I don't know. I'm used to a language with some sort of record structure associated with file read/write operations. Copying a structure containing strings and/or lists cannot be as simple as getting the size of the structure and writing that many bytes to disk.
You can actually do that with PureBasic.
glennj.0158 wrote: Sat Feb 05, 2022 3:22 amEven if that worked reading it back would not correctly allocate the memory. I think I have to write the strings individually and loop through arrays and lists. A proper meta-structure will let me do this but it seems more complex than necessary.
You could just use a
database to handle all the lowlevel stuff for you.
For example - the basic problem with strings is the question of length. In 2022 you additionally have to consider that every single character is likely 2 bytes in length (unicode) and not just one byte (ascii). But what (and how!) you save and restore data, depends on yourself. Either way, the fundamental problem is the size. Here is the
PureBasic File function documentation. Another crucial element of PureBasic are
structures. Some people store strings by a fixed length and for short strings, simply waste some disk space and limit long strings to a certain maximum size, others store strings fully dynamic by writing a header in front of any dynamic field, that contains the following length. Nowadays most people don't even use these basic methods of writing data and structures by hand anymore and instead use databases and let the
database do the lowlevel handling.
With PureBasic you can do all of the approaches. Start learning the language by doing it the old way "as usual" and later use databases like the new kids who use a full blown multi-megabyte relational database to store a 8 byte fixed size username
I suggest that you install
discord and join the purebasic chat and start reading a lot. PureBasic as procedural language will soon feel like good old times because the conceptual hurdle of object oriented languages is not needed.
Re: Linear Programmer looking for a clue
Posted: Sat Feb 05, 2022 11:06 am
by infratec
for structures to disk ...
the simplest way is to convert the structure to a JSON string and write this to the file.
Youn can read it in again and import the JSON string to the structure.
look at the help for
Code: Select all
InsertJSONStructure()
ExtractJSONStructure()
SaveJSON()
LoadJSON()
https://www.purebasic.fr/english/viewto ... 85#p552485
With additional crypting:
https://www.purebasic.fr/english/viewto ... 30#p548630
Re: Linear Programmer looking for a clue
Posted: Sat Feb 05, 2022 2:53 pm
by glennj.0158
Thank you both (and others who may follow) for the assist. I did find and am already reading the survival guide and will pick up and read the other references. I will have to look at the JSON as this looks like a workable short-term solution but I agree that using a DBMS to pick up the slack is a better long term solution. I'm currently using Access, Oracle and some lesser known platforms in other contexts.
The push to get back into programming came from my wife's quilting hobby. Cutting and putting together the quilt can require a lot of not-difficult-but-tedious calculation and planning. Found I enjoy the problem solving aspect a lot and learning a new language and approach is just a different kind of (sometimes frustrating) problem.
Regards
Glenn
Re: Linear Programmer looking for a clue
Posted: Sat Feb 05, 2022 3:14 pm
by glennj.0158
I've downloaded Discord but it looks like I need an invite to the PB community server.
Glennj.0158 is my Discord handle
Regards
Glenn
Re: Linear Programmer looking for a clue
Posted: Sat Feb 05, 2022 3:17 pm
by infratec
The easiest database for such a 'single' case is ... sqlite.
Re: Linear Programmer looking for a clue
Posted: Sat Feb 05, 2022 4:54 pm
by mk-soft
The best way is via databases (SQLite, etc).
But you can also use your own file format and structures where the strings have a fixed size.
Just like you wrote your own databases back then.
Example (Had too much time)
Update 2
Code: Select all
;-TOP
; Comment : Own DataBase with static structure
; Author : mk-soft
; Version : v1.01.2
; Create : 05.02.2022
DeclareModule MyData
Structure udtRecord
Delete.w ; Base flag is mark as delete. Always first entry (2 Bytes)
; User Data
ID.q ; Quad Own ID (8 Bytes)
Name.s{20} ; Static Unicode String (40 Bytes)
Age.l ; Long (4 Bytes)
EndStructure
Declare OpenData(Filename.s)
Declare CloseData(DataID)
Declare CompressData(DataID)
Declare CountRecord(DataID)
Declare ReadRecord(DataID, RecID, *Record.udtRecord, All = #True)
Declare WriteRecord(DataID, RecID, *Record.udtRecord)
Declare DeleteRecord(DataID, RecID, State = #True)
EndDeclareModule
Module MyData
EnableExplicit
; Base for all record types
Macro cntRecord()
(Lof(DataID) / SizeOf(udtRecord))
EndMacro
; ----
Procedure OpenData(Filename.s) ; Result: Database ID
Protected DataID
DataID = OpenFile(#PB_Any, Filename, #PB_File_SharedRead | #PB_File_SharedWrite)
ProcedureReturn DataID
EndProcedure
Procedure CloseData(DataID)
If IsFile(DataID)
CloseFile(DataID)
EndIf
EndProcedure
Procedure CompressData(DataID) ; Result: Count of delete records
Protected readOffset.q, writeOffset, rec, cnt, delete
Protected *record.udtRecord
cnt = cntRecord() - 1
*record = AllocateStructure(udtRecord)
For rec = 0 To cnt
readOffset = rec * SizeOf(udtRecord)
FileSeek(DataID, readOffset)
ReadData(DataID, *record, SizeOf(udtRecord))
If *record\Delete = #True
delete + 1
EndIf
If *record\Delete = #False
FileSeek(DataID, writeOffset)
WriteData(DataID, *record, SizeOf(udtRecord))
writeOffset + SizeOf(udtRecord)
EndIf
Next
FreeStructure(*record)
If delete
FileSeek(DataID, writeOffset)
TruncateFile(DataID)
EndIf
ProcedureReturn delete
EndProcedure
; ----
Procedure CountRecord(DataID) ; Result: Count of records
ProcedureReturn cntRecord()
EndProcedure
; ----
Procedure ReadRecord(DataID, RecID, *Record.udtRecord, All = #True) ; Result: Bool record read
Protected OffRecord.q, cnt
If Not *Record
ProcedureReturn #False
EndIf
If Not IsFile(DataID)
ProcedureReturn #False
EndIf
If RecID < 1 Or RecID > cntRecord()
ProcedureReturn #False
EndIf
OffRecord = (RecID - 1) * SizeOf(udtRecord)
FileSeek(DataID, OffRecord, #PB_Absolute)
; Mark as delete ?
If Not All
If ReadWord(DataID) = #True
ProcedureReturn #False
EndIf
EndIf
; Read record
FileSeek(DataID, OffRecord, #PB_Absolute)
cnt = ReadData(DataID, *Record, SizeOf(udtRecord))
If cnt <> SizeOf(udtRecord)
ProcedureReturn #False
Else
ProcedureReturn #True
EndIf
EndProcedure
Procedure WriteRecord(DataID, RecID, *Record.udtRecord) ; Result: Bool record write
Protected OffRecord.q, cnt, new
If Not *Record
ProcedureReturn #False
EndIf
If Not IsFile(DataID)
ProcedureReturn #False
EndIf
If RecID < 0 Or RecID > cntRecord()
ProcedureReturn #False
EndIf
If RecID = 0
OffRecord = Lof(DataID)
new = #True
Else
OffRecord = (RecID - 1) * SizeOf(udtRecord)
EndIf
FileSeek(DataID, OffRecord, #PB_Absolute)
cnt = WriteData(DataID, *Record, SizeOf(udtRecord))
If cnt <> SizeOf(udtRecord)
ProcedureReturn #False
Else
ProcedureReturn #True
EndIf
EndProcedure
Procedure DeleteRecord(DataID, RecID, State = #True) ; Result: Bool state changed
Protected OffRecord.q, cnt, *Record.udtRecord
If Not IsFile(DataID)
ProcedureReturn #False
EndIf
If RecID < 1 Or RecID > cntRecord()
ProcedureReturn #False
EndIf
OffRecord = (RecID - 1) * SizeOf(udtRecord)
FileSeek(DataID, OffRecord, #PB_Absolute)
If WriteWord(DataID, State)
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
EndModule
;- Example
CompilerIf #PB_Compiler_IsMainFile
Global Record.MyData::udtRecord
Global file.s, base, cnt, rec
file = GetHomeDirectory() + "MyDataBase.dat"
DeleteFile(file)
base = MyData::OpenData(file)
If base
; Add records
Record\Name = "Tom"
Record\Age = 8
MyData::WriteRecord(base, 0, @Record)
Record\Name = "Jerry"
Record\Age = 6
MyData::WriteRecord(base, 0, @Record)
Record\Name = "Michael"
Record\Age = 65
MyData::WriteRecord(base, 0, @Record)
For cnt = 1 To 100
Record\Name = "Number " + cnt
Record\Age = Random(100, 1)
MyData::WriteRecord(base, 0, @Record)
Next
; Delete age over 50
cnt = MyData::CountRecord(base)
For rec = 1 To cnt
If MyData::ReadRecord(base, rec, @Record)
If Record\Age > 50
MyData::DeleteRecord(base, rec)
EndIf
EndIf
Next
; Output record
cnt = MyData::CountRecord(base)
Debug "Count = " + cnt
For rec = 1 To cnt
If MyData::ReadRecord(base, rec, @Record)
Debug "RecID " + rec + ": Mark delete = " + Record\Delete + " : Name = " + Record\Name + " / Age = " + Record\Age
EndIf
Next
Debug "Compress " + file
cnt = MyData::CompressData(base)
Debug "- " + cnt + " records deleted"
; Output record
cnt = MyData::CountRecord(base)
Debug "Count = " + cnt
For rec = 1 To cnt
MyData::ReadRecord(base, rec, @Record)
Debug "RecID " + rec + ": Mark delete = " + Record\Delete + " : Name = " + Record\Name + " / Age = " + Record\Age
Next
Else
Debug "Error: Open " + file
EndIf
CompilerEndIf
Re: Linear Programmer looking for a clue
Posted: Sat Feb 05, 2022 5:43 pm
by Bitblazer
glennj.0158 wrote: Sat Feb 05, 2022 3:14 pm
I've downloaded Discord but it looks like I need an invite to the PB community server.
Glennj.0158 is my Discord handle
Regards
Glenn
PureBasic Discord chat
Re: Linear Programmer looking for a clue
Posted: Sat Feb 05, 2022 6:38 pm
by glennj.0158
Thank you Bitblazer for the invite.
Re: Linear Programmer looking for a clue
Posted: Sat Feb 05, 2022 6:43 pm
by glennj.0158
Thanks mk-soft, a much more involved response than expected!
I've just gotten onto GitHub to get the SQLite tools. I agree this is the best long-term solution.
If the quilting utilities actually become ready for prime time I will post them there.
Until/unless I migrate you get credit for the read/write scheme.
-Regards
Glenn
Field order on a form -- how to fix what the IDE gave
Posted: Tue Feb 08, 2022 3:39 am
by glennj.0158
OK - I have a new burning question.
I used the IDE to create a simple form with 6 fields and two buttons. The fields 1-5 run down the left margin, field 6 is to the right of 5 and the buttons are on the bottom.
I expected the progression to be F1 - F2 - ... F5 - F6 - B1 -B2 and back to F1
i Get F1 - F2 - f4 - F3 - B1 - B2 - F6 - F5 and back to F1
I suspect this has something to do with field Creation order rather than screen geometry. Can I fix this without deleting and creating the form.
Regards
Glenn
Re: Linear Programmer looking for a clue
Posted: Tue Feb 08, 2022 4:36 am
by skywalk
Post the code created by the form editor.
You will find it is just lines of text you can edit without manipulating graphically on a screen.
I never use a form editor cause I hate wasting time clicking and dragging and clicking inside so many input fields.
Cut and paste and search and replace are your friend.
Re: Field order on a form -- how to fix what the IDE gave
Posted: Tue Feb 08, 2022 7:45 am
by Marc56us
glennj.0158 wrote: Tue Feb 08, 2022 3:39 am
I used the IDE to create a simple form with 6 fields and two buttons. The fields 1-5 run down the left margin, field 6 is to the right of 5 and the buttons are on the bottom.
I expected the progression to be F1 - F2 - ... F5 - F6 - B1 -B2 and back to F1
i Get F1 - F2 - f4 - F3 - B1 - B2 - F6 - F5 and back to F1
I suspect this has something to do with field Creation order rather than screen geometry. Can I fix this without deleting and creating the form.
Yes,
There is no "tab-order" field. Moving from gadget to gadget is set by order in creation.

You can edit source of form (From > Switch code / Design View) and change order of lines.
If you do not work with project, F5 launch form preview and you can verify order.
(Do not change anything else in code mode (except strings or numeric values))
I use the FD all the time, even for small applications. It saves a lot of time by taking care of the laborious part of coding (ie: anchoring gadgets in different places and resizing them automatically, creating menus, including image codes in memory, pre-filling lists, etc). For everything it can't do (popup, toolbar with 24x24 icons and multiple status bars), you can add it afterwards in the application code

Re: Linear Programmer looking for a clue
Posted: Tue Feb 08, 2022 9:38 am
by mk-soft
I also use FormDesigner a lot. But under Preferences -> Form make the following setting
- New gadgets use #PB_Any by default (off)
- Generate event procedures (off)
With constants for the windows and gadgets I find better.
Even if the FormDesigner works well. I do not like the event management so and write this rather myself Or use with many gadgets also my EventDesigner V3 to create the creation of all necessary procedures and event management (see signature)
Re: Linear Programmer looking for a clue
Posted: Tue Feb 08, 2022 4:15 pm
by netmaestro
I don't recommend that new PB coders start with the form designer. The form you're making sounds relatively straightforward so it won't take much work to put a few gadgets on it with straight coding. This way you'll rapidly come to understand the workings of the event loop and my personal favorite, event binding. An event loop in one of my projects will often be no more than:
Code: Select all
Repeat : Event = WaitWindowEvent() : Until Quit
with all events bound to their individual procedures. You'll make a few mistakes, count on it. But if you follow this path you'll find that corrections to your malfunctioning code are available on the forum within minutes. Lots of us monitor Coding Questions routinely and are always glad to show the way. (There is even a bit of lighthearted competition for being first with an answer! You've gotta watch CQ like a hawk to beat RASHAD, that's for sure.)
In this way you'll come to learn the important things and understand them before letting a tool do them for you. Anyway, that's just one man's opinion.