Jump to content

Leaderboard


Popular Content

Showing most liked content since 12/17/2017 in all areas

  1. 4 points
    lennart

    Database Examples

    Sorry for the delay we are working non-stop on the next update, so its hectic! First, let me explain a bit where we are, so we can pick the right storage mechanism: The past months we have focused solely on the visual aspect of the RTL. We had to start somewhere and since the visual aspect is what most people care about first, that seemed like the best place. So as you have no doubt seen, we have gone through the RTL with a fine tooth comb, removing things that didnt work, rewriting controls from scratch and testing each part to make sure that everything works. But that is just 1/3 of the path we are on. We are now moving into the non-visual aspects of the RTL. Here we have things like databases, non-visual controls (TComponent in Delphi and Lazarus), filesystems and ultimately node.js - which by nature is UI less and runs on the server (or the shell). We have also brushed up Phonegap and removed the wrongs we found there. The Phonegap API has not stood still and have evolved, so it was due for an overhaul. So that is a quick "status". We are completing 1/3 of the planned system, which covers the visual aspects. DB typically falls under "non-visual", with bindings back to visual later. DB for browsers, what is what? Modern browsers actually have 3 DB engines built into them: WebSQL IndexDB Microsoft Access (*) (*) Only supported by Microsoft and relies on COM (so not for mobile). It must be mentioned that WebSQL, which is the only really good option here, has been deprecated. But it wont vanish tomorrow. The W3C (world wide web consortium) is a bit like the vatican; they move in decades and code will linger in the codebase for ages before it changes. So I wouldnt worry too much about using WebSQL. Secondly, there are shim's for everything these days. A "shim" is a JS re-implementation of something. What a shim does is check if a feature is supported, and if it's not then the shim installs itself and delivers the missing functionality. In other words, you can safely use websql and just download a shim if suddenly google or firefox lacks it. Here is a nice shim for websql: https://github.com/agershun/WebSQLShim Then there is IndexDB. This is a no-sql database and is designed to store JS structures (or objects) in a typical name-value pair style. I think JS people like this a lot since they can easily stuff raw JS objects into it, using a string key. And while it does have its uses, its not a table/row/column solutions. And finally there is access. Which is a pure Microsoft solution, only runs in Edge or Internet Explorer and requires the onslaught of COM. This might have changed in the later versions of edge but either way - this is Microsoft only. So I doubt that is interesting. Thinking outside the box, Smart approach Facing this typical JavaScript mess (sorry but it's true, the browser wars were not kind to JS) I decided we needed to become independent. Browsers change all the time and JS have little standards to speak of compared to Delphi, C# or C++; So coming from Delphi JS will be hell to work with unless you do a long and serious study. Our role is in many ways to "tame" JS and force it to behave inside object pascal's rules. So we needed some structure, something that only change when we allow it! So that people can write programs without being afraid that it will vanish in six months. So we created two solutions: TW3Dataset for simple, single table work SQLite compiled from C to JavaScript Note: Some bugs sadly crept into TW3Dataset, but these have been fixed. So the next update will remedy the situation profoundly. The second option, SQLite, is awesome. It is a pure, 1:1 compile from the original C code, so it contains everything WebSQL has "and then some". The reason it havent been wrapped more rigidly is because it's destined to become a part of our "DataSnap" like API later. Like mentioned above we are on a journey here, and we have to deal with things in the right order. So each DB engine will be isolated in a "driver" like class and then register with a common API. That way people can use classes like TDatabase, TQuery, TStatement and similar high-level components to access any database they like. IndexDB is the oddball in all of this, so we might write a shim/proxy to leverage that. Picking an engine OK, with a situation rapport out of the way, lets pick a database. Our options are thus: WebSQL SQLite TW3Dataset Since TW3Dataset needs the update, I have excluded that. SQLite is awesome but could perhaps need more solid wrappers. So for this I will use WebSQL since that has more clearly defined classes. Picking a storage point Browsers only have cache storage. This is basically a sandboxed file that is saved in the cache folder. Under phonegap this is likewise sandboxed and stored in the "yourname.app/cache" folder if im not mistaken (not sure about that one, please check the Phonegap docs if you need the absolute path). But you dont need a path to load or save into the cache. The browser maps your data into the file-region automatically. Also worth mentioning: When you run in the browser you have a limit of 10-15 megabytes (depends on the browser) for cache storage. When you link the project with Phonegap this limit goes away and you have the same storage rights as native applications. So you dont need to worry about running out of space if you plan to link with phonegap. For pure browser work, you are not expected to make huge databases - but rather cache info before shipping that to a server. A bit like what you would use TClientDataset for under Delphi. But ok, let's use normal cache storage for now. WebSQL is excellent because this will store itself automatically! You dont need to do anything in particular to load or save it. It all boils down to you creating or dropping the database. DB example Right! So fire up Smart and create a new visual project. Our first business is to create the database object and I typically put that into the application class. That way it can be accessed by any form in the program. A nice helper function is also good to have. Here is how it looks so far: unit Unit1; interface uses Pseudo.CreateForms, System.Types, SmartCL.System, SmartCL.Components, SmartCL.Forms, SmartCL.Application, SmartCL.DbSql, Form1; type TApplication = class(TW3CustomApplication) private FDatabase: TW3WebSQLDatabase; public procedure ApplicationStarting; override; published Property Database: TW3WebSQLDatabase read FDatabase; end; // global easy-access function to DB layer function Datastore: TW3WebSQLDatabase; implementation function Datastore: TW3WebSQLDatabase; begin Result := TApplication(Application).database; end; procedure TApplication.ApplicationStarting; begin //setup database engine FDatabase:=TW3WebSQLDatabase.Create; FDatabase.DBName:={$I 'app:name'}; FDatabase.DBDescription:='Database for ' + {$I 'app:name'}; FDatabase.DBSize:=(1024 * 1024) * 4; inherited; end; end. This creates a websql database that can hold 4 megabytes of data. Which in browser terms is huge (I mean, you are not doing your taxes here are you). Then there is the main form and actually making something happen. So drop a TW3Button on the form and set the title to "Create Database". We then need some code to create a table and insert some records. For brewity here is the whole code for Form1: unit Form1; interface uses System.Types, System.Types.Convert, System.Objects, System.Time, SmartCL.System, SmartCL.Time, SmartCL.Graphics, SmartCL.Components, SmartCL.FileUtils, SmartCL.Forms, SmartCL.Fonts, SmartCL.Theme, SmartCL.Borders, SmartCL.Application, SmartCL.DbSql, SmartCL.Controls.Button; type TForm1 = class(TW3Form) procedure W3Button1Click(Sender: TObject); private {$I 'Form1:intf'} protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; end; implementation { TForm1 } uses unit1; procedure TForm1.W3Button1Click(Sender: TObject); var Transaction: TW3WebSQLCustomTransaction; begin // activate database try if not Datastore.Active then Datastore.Active := True; except on e: exception do begin writeln("Failed to activate database: "); writeln(e.message); exit; end; end; // Get new write transaction if Datastore.GetWriteTransaction(Transaction) then begin // Create our table try Transaction.Execute("create table if not exists customers (id integer primary key asc, name string);",[]); finally if Transaction.LastFailed then WriteLn(Transaction.LastError); Transaction.Free; end; end else raise Exception.Create('Failed to create write transaction error'); // Get new write transaction if Datastore.GetWriteTransaction(Transaction) then begin try // Populate the table with some records for var x := 1 to 10 do begin var MyData := 'John Doe #' + x.ToString(); Transaction.Execute("insert into customers (name) values (?);",[MyData]); end; finally if Transaction.LastFailed then WriteLn(Transaction.LastError); Transaction.Free; end; end else raise Exception.Create('Failed to create write transaction error'); // Get a new read transaction if DataStore.GetReadTransaction(Transaction) then begin // Setup the OnSuccess event handler. Transaction.OnSuccess := procedure (Sender: TObject) begin var Reader := TW3WebSQLReadTransaction(Sender); if Reader.Dataset <> nil then begin var Dataset := Reader.Dataset; for var x := 0 to Dataset.rows.Length - 1 do begin var Row := Dataset.rows.item(x); WriteLn(Row['name']); end; end; // All done, kill the transaction Reader.free; end; // Setup the OnFailed event handler TransAction.OnFailed := procedure (Sender: TObject) begin var Reader := TW3WebSQLReadTransaction(Sender); writelnF("Read transaction failed: %s", [reader.LastError]); // Kill the transaction Reader.free; end; // OK lets execute the SQL Query! try Transaction.Execute("select * from customers;",[]); finally if Transaction.LastFailed then WriteLn(Transaction.LastError); end; end; end; procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} end; procedure TForm1.Resize; begin inherited; end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end. Now you are going to notice something -- namely that the database is persistent (!) So if you run this example 10 times, it will actually create 10 new records every time. The key here is the SQL that creates the database: Transaction.Execute("create table if not exists customers (id integer primary key asc, name string);",[]); This basically says "Create this database UNLESS it already exists". Manual storage with SQLite I am bit pressed for time right now. I will be away from the office for about a month pending surgery. I will be busy with forum duty etc. as much as I can, but sadly a secondary example with SQLite will have to wait a little. But I hope this one has given you an easy path to store things in the cache. Also remember: You can look at the data using the Browser Devtools I will do an article on SQLite when time allows
  2. 3 points
    jarto

    New Alpha update

    New update available: 2.9.9.102 In this one I've fixed some bugs in TW3ListBox and TW3CheckListBox. @IElite Have a look at the TW3CheckListBox source to see how you can control the creation of TW3ListBoxItemData. I also added TW3ListBox.Selected[Index] so that you can easily toggle selected on/off for items.
  3. 3 points
    jarto

    New Alpha update

    After a long break, a new update is available: 2.9.9.97 IDE: - Added support for search paths - Updated SynEdit - Bug fixes - ACE (TW3AceEditor) added to the Component Palette RTL: - New units: - System.Collections - System.StorageDevice - Marjor improvements to TW3Dataset, TW3DatasetFilter and WebSQL - Bug fixes and improvements to TextParser - Bug fixes to WebFonts support - Moved TCriticalSection to System.Types - Improvements to TW3ListBox and TW3CheckListBox: - Support for SelectedIndex and automatic change of style background for selected items - Support for MultiSelect - Possibility to override creation of TW3ListBoxItemData - Allows use of own classes and properties - Allows overriding SetSelected to control what styling changes should be made when items are selected Bug fixes to many demos
  4. 2 points
    IElite

    FYI - TLayout - Beginner

    You can also use the devices dimensions to calculate your control's size. e.g. below, I create the layout height based on 1/4 the size of the ClientHeight procedure TForm1.Resize; begin inherited; if Handle <> nil then fLayout:= Layout.Bottom(Layout.Height(ClientHeight Div 4).Margins(10), fPanel); if Assigned(fLayout) then begin fLayout.Resize(self); end; end;
  5. 1 point
    EWB

    Smart Test Framework

    Hey, here is the SMS test framework fixed! Projct download: ProjTester
  6. 1 point
    jarto

    Overriding TW3ListBoxItemData style

    And when you have a pretty short list like this, but with complicated items, it's a good idea to set W3Listbox1.RecycleControls := False;
  7. 1 point
    jarto

    Overriding TW3ListBoxItemData style

    Found the problem in your CSS. Try this: .XListBoxItemSelectedStyle{ background-color: #000000; color: #FFFFFF } .XListBoxItemStyle{ color: #000000; background-color: #FFFFFF
  8. 1 point
    Czar

    New Alpha update

    exciting to see the update. smartcl.pas needs // Implementation of storage-device "Browser:" //SmartCL.StorageDevice.Browser, as SmartCL.StorageDevice.Browser, file doesn't exist
  9. 1 point
    lynkfs@gmail.com

    SQLite Loadfromstream

    This code snippet saves a SQLite database to local storage and reloads it again. All goes fine up till the end (LoadFromStream) but leaves the db in an inactive state Any suggestions ? var MyStream : TStringStream; MyStream := TStringStream.Create; db.SaveToStream(MyStream,true); var textdata3 := MyStream.DataString; //save textdata3 to local storage var LocalStorage2 := TW3LocalStorage.Create; LocalStorage2.Open('sqlite'); LocalStorage2.SetKeyStr('stream',textdata3); LocalStorage2.Close; //read textdata3 from local storage LocalStorage2.Open('sqlite'); textdata3 := LocalStorage2.GetKeyStr('stream','unknown'); LocalStorage2.Close; MyStream.DataString := textdata3; db.LoadFromStream(MyStream); //all good up to here writeln(db.active); //false
  10. 1 point
    lennart

    back(s)lash

    Strange, no idea how you get the $ postfixing there (which means its a managed variable or object, it has nothing to do with obfuscation -- it just means smart handles the life-cycle of that variable or entity). Are you using inline variables to hold this or properly defined variables? There is a subtle but huge difference. But as EWB points out, you need to build it up like you would any array. And I would add some functions for each record to simplify managing them. Like "AddParam(bla bla bla)" and stuff like that. Just a quick test i did now to see what this was about: JC = record id : integer; external 'id'; name : string; external 'name'; age : integer; external 'age'; end; JB = record field1 : string; params : Array of JC; end; JA = record fields : array of JB; end; Then i just wrote some code in a button onClick handler: procedure Form1.W3Button1OnClick(Sender: TObject) var head: JA; row : JB; begin row.field1 := 'first'; head.fields.add(row); asm @raw = JSON.stringify(@head); end; showmessage(raw); end; The code above, when it reaches the showmessage call, produces clean JSON. No postfixing. The postfix is added to all Smart "managed" variables, but records should be excluded from that. But (!) JavaScript work by references, so seem to me you managed to fall between two chairs and when you assigned values to the data, JS produces references to the values rather than the values itself (a bit like pointers can behave under COM Delphi coding). Here is the result I got: {"fields":[{"field1":"first"}]} Now, mapping to existing data, which i presume you are doing (?), where you have a wad of JSON you load in, parse to an object structure -- and then i presume you want a ready to go array structure from that? Well, i did something similar in the memory-filesystem unit if you look there, but as a general rule i read in the data into a variant, then typecast and traverse that, copying over the data i need. Then just null the variant to get the GC to clean up. I also have a node.js websocket server that sends info as JSON on my network, and designed the structures to be simple and easy to transport. Using a typical envelope record to make identification easy, then attaching the actual message as base64 inside: type TNetworkPacket = record Identifier: string; //GUID ClientId: string; //GUID envelopeId: string; //ID of the contained type envelope: string; // Contained type, base64 encoded end; // Then i can do simple lookups for the handler when i get a package // Locate a handler for this JSON packet var handler := __dispatch[envelopeid]; // Did we support this message? Ok, dispatch if assigned(handler) then handler(Socket, Packet.Envelope):
  11. 1 point
    Dennis07

    c++

    Because the initialization section is called only after the variables get initialized.
  12. 1 point
    EWB

    c++

    Pre-increment: 1. Let's say you want to buy a very expensive apple for $2 2. Your mam gives you $1 3. You ask your dad and he decides to give you $1 dollar too 4. You buy the apple 5. Total money received: $2 Post-increment: 1. You want the same apple for $2 2. Mam gives you $1 3. You ask dad, but dad will only give you a dollar when you bring something back for him from the shop 4. You go to the shop but can't buy the apple, and bring something back for your dad 5. Total money received: $2 In javascript world: var i = 0; [ i++, i, ++i, i, i--, i, --i, i ]; //----> [0, 1, 2, 2, 2, 1, 0, 0] In smart pascal world: AFAIK, smart don't have the equivalent i++ post increment operator, inc(i) will emit --i the trick to mimic i++ and i-- var j := 0; var postInc := lambda(): integer; j += 1; result := j - 1; end; var postDec := lambda(): integer; j -= 1; result := j + 1; end; [ postInc, j, Inc(j), j, postDec, j, Dec(j), j] ; //----> [0, 1, 2, 2, 2, 1, 0, 0]
  13. 1 point
    Dennis07

    c++

    Initialization with 0 / '' / 0.0 / nil is implicite in Smart Pascal Why so complicated? function PostInc(var i: integer); begin Result := i; inc(i); end;
  14. 1 point
    Igor Savkic

    back(s)lash

    > stringifying this (asm @textdata = JSON.stringify(@data); where @data refers to JA) gives what I was after. > Except that all fieldnames in the result-string have a '$1' appended ({"field1$1"). No idea why that happens or how to avoid that. I would bet on obfuscation mechanism, try declaring all your fields with property: JB = record property field1: string; property params: Array of JC; end;
  15. 1 point
    EWB

    Black Screen of Death

    Just place DebugBreak somewhere in your code, and it will act like a breakpoint. You need to have Chrome Developer Tools open for this to work (hit F12). If you have Developer Tools open, an extra bit of awesomeness is that you can click and hold the Refresh button to clear the cache. I step through Code using chrome directly not using the internal SMS integrated debugger! procedure TForm1.Button1Click(Sender: TObject); begin DebugBreak; console.log('Button1 clicked'); end; My SMS integrated debugger is disabled.
  16. 1 point
    lennart

    RemObject JSON FileUpload

    That looks like Delphi code? Second snippet there? You have to look at the Smart classes and the RO imported classes and method-names. If you look at the generated code after importing a RODL file, you will notice: (* This codegen depends on RemObjectsSDK.js: file must be in "SmartMobileStudio\Libraries\" folder * Usage: * var channel := TROHTTPClientChannel.Create("http://localhost:8099/JSON"); * var msg := TROJSONMessage.Create(); * var service := TNewService.Create(channel, msg); * service.Sum(1, 2, * procedure(aResult: Integer) * begin * ShowMessage('Result = ' + IntToStr(aResult) ); * end, * ROErrorCallback); *) Note: in the above imported RODL file, the remote service is just called "NewService". You have to import the RODL file for your service stack. Also make sure that you have a JSON channel on your native server. You might want to look at our classes for dealing with memory and binary data, like System.Memory.Buffer. System.Memory.Allocation etc. since they will simplify working with raw data. The unit System.Types.Convert is also very important, it has a class called TDataType that allows you to encode between instrinsic types, memory and byte-arrays.
  17. 1 point
    You can load and save to normal streams, then push that into the cache (for example). The filesystem has been there for some time, but we have deprecated it since it only comes into play with phonegap really. Uploading and catching files is done easier using standard html5 methods. But we have a baseclass and cache filesystem implementation, and will soon have node and phonegap wrapped too -- then loading and saving to real devices will be very simple. We have to finish the visual parts of SMS first before we dig into the non visual. But look at the storage units! It is very simple to base64 encode a stream and save it to the cache
  18. 1 point
    rdevine

    LevelDB in replace of localstorage?

    This looks interesting - https://github.com/google/lovefield Cheers, Bob
  19. 1 point
    EWB

    Async keyword

    While converting some EWB routines to Smart we came across with the async keyword used in EWB. EWB supports asynchronous procedure/function calls using the special async keyword. Asynchronous calls allow the developer to queue a procedure/function call in the browser so that it is run as part of the message queue processing for the main UI thread in the browser. Asynchronous calls are available only at runtime. To make an asynchronous procedure/function call, simply preface the call with the async keyword. For example: procedure TForm1.Button1Click(Sender: TObject); begin async CreatePanel(0); end; this will queue up a call to the CreatePanel procedure so that it will run in the next round of message processing in the browser. Because the compiler will emit a closure for this call, the value of any local variables or parameters will be properly captured, even if the parent method that is calling the function/procedure has finished executing. How Asynchronous Calls Are Executed Because asynchronous calls are added to the message queue for the main UI thread in the browser, they are executed in a first-in, first-out (FIFO) manner. This means that there may be a delay between when the asynchronous call is made and when the call is actually executed. Also, asynchronous calls in EWB are emitted by the compiler as Javascript closures. Closures are functions that are dynamically created and capture the entire run-time scope of their parent execution context. Whenever a closure is actually executed, it will do so using the same scope that was present when the closure was created. Closures are ideal for asynchronous calls, because they need to capture the state of all variables and parameters so that they are available when the call is actually executed. Mixing Synchronous/Asynchronous Calls Because the main UI thread in the browser is used for executing all code, any synchronous code will execute before any asynchronous calls that are queued in the message queue. This is important to understand because it determines how you should combine synchronous and asynchronous calls to achieve the desired outcome.For example, suppose that you want to create a large number of panels in a container, and want to show a progress dialog while the panels are created. To do this, you would normally do something like this: procedure TForm1.CreatePanels; var I: Integer; begin for I:=1 to 100 do TW3Panel.Create(Self); end; procedure TForm1.Button1Click(Sender: TObject); begin ShowProgress('Creating panels...'); CreatePanels; HideProgress; end; However, if you were to execute the above code in the browser, you will see that the panels are created, but the progress dialog will never show. This is because the UI updates for the ShowProgress call will not be executed until any other currently-executing code has completed. In this case, this is the CreatePanels and HideProgress calls, so the ShowProgress UI updates will get merged with the HideProgress UI updates, and the progress dialog will never get shown (or will be shown/hidden so fast that you won't see it). procedure TForm1.CreatePanels; var I: Integer; begin for I:=1 to 100 do TW3Panel.Create(Self); end; procedure TForm1.Button1Click(Sender: TObject); begin ShowProgress('Creating panels...'); CreatePanels; HideProgress; end; The key to fixing this problem is to allow the UI to update incrementally while we create the panels, and we'll use asynchronous calls to do so: procedure TForm1.CreatePanel(I: Integer); begin TW3Panel.Create(Self); Inc(I); if (I < 100) then async CreatePanel(I) else async HideProgress; end; procedure TForm1.Button1Click(Sender: TObject); begin ShowProgress('Creating panels...'); async CreatePanel(0); end; We don't want to use an asynchronous call to ShowProgress because we want it to be executed immediately so that it is the first UI update to occur. However, we do want to queue each CreatePanel call and the HideProgress call because doing so will force them to execute in-order after any UI updates from the ShowProgress call, as well as allow the UI to update during each panel creation. I will try to mimic the example using SmartMobileStudio: procedure TForm1.CreatePanels; var I: Integer; begin for I:=1 to 100 do TW3Panel.Create(Self); end; procedure TForm1.CreatePanel(I: Integer); begin TW3Panel.Create(Self); Inc(I); if (I < 100) then //async CreatePanel(I) TW3Dispatch.Execute(lambda() CreatePanel(I) end, 0) else //async HideProgress; TW3Dispatch.Execute(lambda() HideProgress() end, 0); end; procedure TForm1.W3Button1Click(Sender: TObject); begin ShowProgress('Creating panels...'); TW3Dispatch.Execute(lambda() // Execute first CreatePanels; TW3Dispatch.Execute(lambda() // Execute 2nd HideProgress(); end, 0) end, 0) end; procedure TForm1.W3Button2Click(Sender: TObject); begin ShowProgress('Creating panels...'); //async CreatePanel(0); TW3Dispatch.Execute(lambda() CreatePanel(0); end, 0); end; The async keyword in SMS providing better abstraction is very welcomed. async openDB(); async saveDB();
  20. 1 point
    The SQLLite engine we ship is compiled to JS from C. So i would just Base64 encode the data and stuff it in the cache. For mobile apps (phonegap) you should work directly with the filesystem, and honestly I would use WebSQL (which is just a wrapper around SQLite inside webkit/moz). Later when we have the node.js DB framework you can write a small server to deal with data storage, and just use SQLite to cache up changes that are uploaded to the server when it connects.
  21. 1 point
    IElite

    FYI - TLayout - Beginner

    FYI - TLayout - Beginner - Layouts on Multiple Forms Note: Be sure to set the Layout object = nil when the form deactivates Code on GitHub
  22. 1 point
    IElite

    FYI - TLayout - Beginner

    FYI - TLayout - Beginner - Multiple Layouts Code on GitHub
  23. 1 point
    IElite

    FYI - TLayout - Intermediate

    This is a continuation of examples on how to use the TLayout object. I will be using tags (e.g. layout, tlayout, intermediate) so that you can find them easily enough in the future. Please be sure to read the Articles by @gabr42 http://smartmobilestudio.com/documentation/layout-manager as well as visit the beginner thread FYI - TLayout - Intermediate - How to layout a control with nested controls on the form Note: This example shows how to layout controls onto another control on the form Profile Landscape Code on GitHub
  24. 1 point
    IElite

    FYI - TLayout - Intermediate

    FYI - TLayout - Intermediate - Device orientation change Note: How to layout controls based on device orientation Profile Landscape Code on GitHub
  25. 1 point
    IElite

    FYI - TLayout - Beginner

    FYI - TLayout - Beginner - HTML Layout Code on GitHub
  26. 1 point
    IElite

    FYI - TLayout - Beginner

    FYI - TLayout - Beginner - How to place multiple controls on the form in Left Bar & Right Bar positions unit Form1; interface uses SmartCL.System, SmartCL.Graphics, SmartCL.Components, SmartCL.Forms, SmartCL.Fonts, SmartCL.Borders, SmartCL.Application, SmartCL.Layout, SmartCL.Controls.Panel; type TForm1 = class(TW3Form) private {$I 'Form1:intf'} fLayout: TLayout; fLeftBar: TW3Panel; fRightBar: TW3Panel; protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; end; implementation { TForm1 } procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} fLeftBar:= TW3Panel.create(self); fRightBar:= TW3Panel.create(self); fLayout:= Layout.Client(Layout.Margins(10), [Layout.Left(Layout.Width(100), fLeftBar), Layout.Right(Layout.Width(100), fRightBar)] ); end; procedure TForm1.Resize; begin inherited; if Assigned(fLayout) then begin fLayout.Resize(self); end; end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end.
  27. 1 point
    IElite

    Snipplets

    Maybe You can also create a forum thread for sharing snipplets?
  28. 1 point
    SMS is perfect capable for a business app, but it is less fancy to show it but moreover it is not easy to create a business demo (what kind of demo, what should it do?) I made 2 blog post a long time ago, maybe you can look at these to get you started: http://andremussche.blogspot.nl/2012/06/remobjects-integration-in-smart-mobile.html http://andremussche.blogspot.nl/2012/06/remobjects-integration-in-smart-mobile_21.html In short, SMS can generate client side classes for RemObjects services, the same as it is done by Remobjects itself in the Delphi IDE. So it is 100% RO code , so you can use it the same way as you did in Delphi (but some things work a little different in javascript) About data abstract: RO does not provide a (good) generator for DA tables and schemas, but you can use the plain javascript code in an ASM section in SMS. By using variants you can access the tables and colums by name, but you don't have the type safety and code completion as you have with the fully generated RemObjects code (that's the way I did not like DA). And example of an ASM section in a blog post of RO themselves (btw, with RO, not DA, before I made the generator) http://blogs.remobjects.com/blogs/valeriyg/2012/05/30/p4377 So with SMS you can use the same functions and functionality of both RO and DA, with no need to change your server side! It is just another client . About the GUI: you can use the default controls and designer of the SMS IDE, but you can also use jQuery and plain html with a html5 component set like KendoUI.
  29. 0 points
    IElite

    Database Examples

    I guess not!
×