Importing gambas components into your projects (guide)

Post

Posted
Rating:
#1 (In Topic #579)
Guru
BruceSteers is in the usergroup ‘Guru’
Importing Gambas components/classes
A rough guide/example

We've all been in the situation where we are using a gambas component but it does not quite do what you want it to.

One option in this case is to get on the gambas developers mailing list and ask if they could add the feature. and who knows it might be a good idea and they may add it. but then it only exists in the new development version of gambas and no other.

But it also might not be possible, maybe the component you want to change is used by gambas itself and the developers do not wish to modify it. Maybe they just do not want the change as they do not see it to be worthwhile.

Do not fear though, for MANY gambas components and functions there is another way for us.
Quite a number of gambas components are written in gambas and made in such a way that it may be fairly easy to import the function or component into your own project and then you can modify the code to your hearts content.

There are a variety of advantages to doing this.
<LIST>
  • <LI>
  • Modify / Append / Upgrade / Trim / Whatever you want the the component.</LI>
    <LI>
  • All modifications to the imported component are always with your program on any gambas version.</LI>
    <LI>
  • Newer components with upgrades and fixes will work on older gambas (may require a little code adjustment for backward compatibilty)</LI>
</LIST>

There are a variety of Disadvantages to doing this.
<LIST>
  • <LI>
  • New upgrades fixes on the original gambas component will not happen to yours, you will have to upgrade manually.</LI>
    <LI>
  • Changes in gambas could affect your app.
     For example modifying gambas settings files with a modified gb.settings,
    You could import the gb.settings component and use it to save/load setting in your own app without any issue, but if you import gb.setting to modify settings files saved by gambas itself then that format may change at some point making your app not work on them.</LI>
</LIST>


I will give a quick guide here on how to import 2 types of things.
Firstly a whole component, I will import the gb.settings component code then remove the default one via the project settings.
Secondly a class from a component, I will extract the Message.class from gb.gui.base but keep gb.gui.base in our project yet have a custom Message() command.

First.
A whole component

The gb.settings component.

The other day on the gambas dev mailing list someone wanted the Settings.class to be able to handle comment lines they had in a VB ini file.
The Settings.class allows for a single comment line on the first line of the settings file by adding an argument when creating a new settings class.

Code (gambas)

  1.  
  2.   Dim mySettings As Settings
  3.   mySettings = New Settings(Settings.Path, "This is my 1st line title")
  4.  
  5.  

Benoit was VERY clear about the Settings.class though that it is used internally by gambas and he is not willing to make any solid changes to it to make it work on ini files, and also how it saves data is subject to change at any time. it Currently saves a file a lot like an ini file but it is just a coincidence.  this means that if you have made an app that uses Settings.class to process ini files then at sometime it could stop working as the gambas Settings files format could change, Another good reason to import the class into your program as then it will not change.

So..  How to import the component / classes.
<LIST>
  • <LI>
  • Step 1: Get the latest gambas source code from Gambas / gambas · GitLab.</LI>
    <LI>
  • Step 2: In your projects .src/ folder Create a folder called "Settings" (the folder name can be anything)</LI>
    <LI>
  • Step 3: navigate to the gambas source folder comp/src/gb.settings/.src and copy 2 files Settings.class and _Settings_Keys.class into the Newly created MyProject/.src/Settings/ folder (the main.module file is a test file we don't need).</LI>
    <LI>
  • Step 4: If your project is already using the gambas gb.settings component then remove it from the project Properties page components list.</LI>
</LIST>

And that's it.  Now you are not using Gambas built in gb.settings component but have your own version with your project that you are free to manipulate and edit as you please to suit your needs.

Here is a project with the edited Settings class I did for the above mentioned conversation,..
(attachment removed)

It works the same as you would normally use Settings but has a few extra features..
<LIST>
  • <LI>
  • The top line comment is not only settable at creation with the above mentioned method now, you can use Settings.Title = "my comment" at anytime to set the comment line or CurrentComment = Settings.Title to get it.</LI>
    <LI>
  • SetSlotTitle(Slot As String, Title As String) , A new command that will set a comment below the slot line of any existing [Slot]</LI>
    <LI>
  • GetSlotComment(Slot As String) As String , this will read the comment line of a named slot.</LI>
    <LI>
  • SetTitleIfChanges(Title As String) , This sets the main top comment but does not trigger the settings to save. it is only saved if any other settings change and get saved.</LI>
</LIST>
If those are not the modifications you require then follow the above process and make the changes you need.

As simple as that for a complete component import.




Next.
Now Importing just a function/class

The Message() function from gb.gui.base

Right here's my scenario .
I want in my app the Message() function to support more then 3 buttons for easier multiple choice questioning and i also want more images to choose from. Sigh,  I better ask the gambas team if they can ma….  wait , hang on……

i could DIY this..

The Message() function unlike the gb.settings component is a bit more tricky because it's a small function/class inside a much larger component that i want to keep gb.gui.base.
So what we will have to do is import Just the Message.class and it's related files but we will have to rename it otherwise it will conflict with gb.gui.base Message()

For this implication I will rename it to Choice() as it's reason is more choices.

So..  How to import the function / classes.
<LIST>
  • <LI>
  • Step 1: Get the latest gambas source code from Gambas / gambas · GitLab.</LI>
    <LI>
  • Step 2: In my projects .src/ folder i Create a folder called "Message" (the folder name can be anything)</LI>
    <LI>
  • Step 3: Message is a part of the gb.gui.base component so navigate to the source folder comp/src/gb.gui.base/.src/Message and copy all 3 files into my Newly created MyProject/.src/Message/ folder</LI>
    <LI>
  • Step 4: Rename the Message.class file Choice.class</LI>
    <LI>
  • Step 5: Copy the Message folder from the gb.gui.base/ folder into your main project folder. these have the images that display.</LI>
    <LI>
  • Step 6: Replace the text in the 2 lines in FMessage.class that refer to the folder "./gb.gui.base/message" with "./message"</LI>
</LIST>

Now you have your own version of the Message() command called Choice()
At present it works identical to Message with things like Choice.warning() Choice.Error()

Here is a version I modified with a test app…
(attachment removed)

It works the same as you would normally use Message but has a few extra features..
<LIST>
  • <LI>
  • ALL types of Message can have as many buttons as you want.</LI>
    <LI>
  • Buttons are passed as a string array Ie. iValue = Choice("Choose a Number", ["1", "2", "3", "4, "5"])</LI>
    <LI>
  • New property AutoResize with ALL commands, sets auto-resize on all the buttons so they all fit their text, without it ALL buttons are the size of the largest text.</LI>
    <LI>
  • New property SeperateCancel with ALL command puts a Spring between the cancel button and the rest (cancel is always the right hand button)</LI>
    <LI>
  • New command Choice.Custom(sMessage As String, Optional Buttons As String[], Optional Type As String = "question", Optional SeparateCancel As Boolean, Optional (AutoResize) As Boolean) As Integer</LI>
    <LI>
  • The "Type" argument of Choice.Custom gets the stock image by name. ANY stock image name can be used. default to 'info' if image is not found.</LI>
    <LI>
  • The test app included with the project lets you edit the settings to test the look.</LI>
</LIST>

Example Usage…
iVal = Choice.Question("Select a number",  ["1", "2", "3", "4, "5", "Cancel"], True, True)  ' buttons match text size and there is a space between cancel button and the others

iVal = Choice.Error("Error, How many times do you want to panic?",  ["1", "2", "3", "4, "5", "Cancel"])  ' buttons evenly spaces and all the same size as the Cancel button

iVal = Choice.Custom("Select a help page",  ["1", "2", "3", "4, "5", "Cancel"], "help",,True)  ' buttons evenly spaces and all fit their text and the help stock icon is used for the image.

(attachment removed)

Again this may not be what you require so get the generic Message and make your own modifications you do need :)

I have just shown the way.  ;)

There are no documents for the attached files, read the code and work it out ;)

Hope that may help some of you :)
Wishing well
Bruce
Online now: No Back to the top

Post

Posted
Rating:
#2
Guru
BruceSteers is in the usergroup ‘Guru’
Additional…

Another method for creating your own custom objects is with Inheritance.

You can make a new class file and use the Inherits keyword to make it inherit all the properties of another object.

Consider the following class file…..
The file name is myGrid.class
After adding this file to my .src/ directory and compiling i will get a different gridview object available in the IDE called myGrid
It copies all the properties from the GridView object but has 4 additional features.

myGrid1.SetColumns(string[])  ; sets the column count and text for each header
eg.  myGrid1.SetColumns(["column 1", "column 2", "column 3"]) sets Column.count to 3 and fills the header texts

myGrid1.MoveRowUp(optional row as integer)  ; moves the currently selected or supplied row number up 1
myGrid1.MoveRowDown(optional row as integer)  ; moves the currently selected or supplied row number down 1

Plus the Sort() event is automatically enabled and sorts using the columns set in Columns.Sort.

Things to note…
Setting the _Similar Const to "GridView" allows the IDE to change an existing GridView into a myGrid using the "Change into" option

Setting _DrawWith Const to "GridView" tells the IDE how to show the control  (it displays it just like a gridview)

I was able to intercept the _RaiseSort() event and utilize it myself but some objects are not so easy to grab the events.
you will have to play and discover what can be used.

All the best
Bruce

Code (gambas)

  1.  
  2. ' Gambas class file
  3.  
  4.  
  5. Public Const _Similar As String = "GridView"
  6. Public Const _DrawWith As String = "GridView"
  7.  
  8. '' Move currently selected row (or supplied Row number) up 1
  9. Public Sub MoveRowUp(Optional (Row) As Integer = -1) As Boolean
  10.  
  11.   If (Not Me.Rows.Count) Or If (Row = 0) Then Return
  12.   If (Me.Row <= 0 And Row = -1) Then Return
  13.  
  14.   Dim iPos As Integer = IIf(Row = -1, Me.Row, Com.Bounds(Row, 0, Me.Rows.Max))
  15.   Dim sData As String
  16.   For c As Integer = 0 To Me.Columns.Max
  17.  
  18.     sData = Me[iPos, c].Text
  19.     Me[iPos, c].Text = Me[iPos - 1, c].Text
  20.     Me[iPos - 1, c].Text = sData
  21.     Me.Rows[iPos - 1].Selected = True
  22.  
  23.   Next
  24.  
  25.  End
  26.  
  27.  
  28.  
  29. '' Move currently selected row (or supplied Row number) down 1
  30. Public Sub MoveRowDown(Optional (Row) As Integer = -1) As Boolean
  31.  
  32.   If (Not Me.Rows.Count) Or If (Row = Me.Rows.Count - 1) Then Return
  33.   If (Me.Row = Me.Rows.Count - 1 And Row = -1) Then Return
  34.  
  35.   Dim iPos As Integer = IIf(Row = -1, Me.Row, Row)
  36.   Dim sData As String
  37.   For c As Integer = 0 To Me.Columns.Max
  38.  
  39.     sData = Me[iPos, c].Text
  40.     Me[iPos, c].Text = Me[iPos + 1, c].Text
  41.     Me[iPos + 1, c].Text = sData
  42.     Me.Rows[iPos + 1].Selected = True
  43.   Next
  44.  
  45.  End
  46.  
  47. '' Sets column count and header texts from the given array.
  48. '' Eg. SetColumns(["Column 1", "Column 2", "Column 3"])
  49. Public Sub SetColumns(sTexts As String[])
  50.  
  51.   Me.Columns.Count = sTexts.Count
  52.  
  53.   For c As Integer = 0 To sTexts.Max
  54.     Me.Columns[c].Text = sTexts[c]
  55.   Next
  56.  
  57.  
  58.  
  59. Public Sub _RaiseSort()
  60.  
  61.   If Me.Rows.Count = 0 Then Return
  62.  
  63.   Dim Values, ValueSorted As New String[], SelectList As New Integer[]
  64.   Dim Nx, iNx As Integer, sel As String
  65.  
  66.   If Me.Row >= 0 Then sel = Me[Me.Row, Me.Columns.Sort].Text
  67.  
  68.   For Nx = 0 To Me.Rows.Max
  69.      Values.Add(Me[Nx, Me.Columns.Sort].Text)
  70.      SelectList.Add(Me.Rows[Nx].Selected)
  71.   Next
  72.  
  73.   ValueSorted = Values.Copy()
  74.   ValueSorted.Sort(IIf(Me.Columns.Ascending, gb.Ascent Or gb.IgnoreCase, gb.Descent Or gb.IgnoreCase))
  75.  
  76.   For Nx = 0 To ValueSorted.Max
  77.     For iNx = 0 To Me.Columns.Max
  78.       Swap Me[Nx, iNx].Text, Me[Values.Find(ValueSorted[Nx], 0, Nx), iNx].Text
  79.     Next
  80.  
  81.     Values.Clear()
  82.     For iNx = 0 To Me.Rows.Max
  83.         Values.Add(Me[iNx, Me.Columns.Sort].Text)
  84.     Next
  85.   Next
  86.  
  87.   If sel <> "" Then
  88.     For iNx = 0 To Me.Rows.Max
  89.       If sel = Me[iNx, Me.Columns.Sort].Text Then
  90.         Me.Rows[iNx].Selected = True
  91.         Break
  92.       Endif
  93.     Next
  94.  
  95.   Me.Refresh()
  96.  
  97.  
  98.   Raise Sort ' raise the sort event in the parent class in case you want to detect it there.
  99.  
  100.  
  101.  
Online now: No Back to the top
1 guest and 0 members have just viewed this.