Jump to content


uniGUI Subscriber
  • Posts

  • Joined

  • Last visited

  • Days Won


Ron last won the day on June 12 2021

Ron had the most liked content!

Profile Information

  • Gender
  • Location

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

Ron's Achievements

Advanced Member

Advanced Member (4/4)



  1. It is working fine with Indy POP3, got over 8000 characters in one message while testing against Google Mail. //Message: TListView component set at vsReport procedure TmainForm.ReadEmails; var IDmessage: TIdMessage; i: Integer; begin try with POP3 do begin AutoLogin := False; Host := 'pop.gmail.com'; Username := '******@gmail.com'; Password := '*******'; Port := 995; IOHandler := IOHandlerTLS; UseTLS := utUseImplicitTLS; end; with IOHandlerTLS do begin Destination := 'pop.gmail.com:995'; Host := 'pop.gmail.com'; Port := 995; DefaultPort := 0; SSLOptions.Method:=sslvTLSv1_2; end; POP3.Connect; POP3.Login; try Messages.Clear; IDmessage := TIdMessage.Create(nil); try //for i := 1 to POP3.CheckMessages do for i := 1 to 10 do begin IDmessage.Clear; POP3.Retrieve(i, IDmessage); Messages.Items.Add; Messages.Items[i - 1].Caption:=DateToStr(IDmessage.Date); Messages.Items[i - 1].SubItems.Add(IDmessage.From.Address); Messages.Items[i - 1].SubItems.Add(IDmessage.Subject); Messages.Items[i - 1].SubItems.Add(IDMessage.Body.Text); end; finally FreeAndNil(IDmessage); end; finally POP3.Disconnect; end; except on e : Exception do ShowMessage('error=' + e.Message); end; end;
  2. The code I presented does not change the HTMLFrame size, but only the canvas size. It makes the canvas fill the HTMLFrame, as the frame resizes. The code makes sure your canvas is always filling the frame. If you want to know the size of the canvas, you can get it from canvas.height and canvas.width, through an ajax call.
  3. Of course you can add an href tag for identification, but that is not necessary as you have the ability to identify the link through the ajax call using a parameter, as in the example. As you have to use a parameter anyway, you might as well use the parameter itself as the identifier, rather than using the href and then passing the href as a parameter, if you understand what I mean. Keep it simple. You will probably generate the html code automatically, so you can do this the way you like. Regarding your issue with the memo, you need to attach a test project for us to be able to analyze what happens.
  4. It is very easy to generate an Ajax call from an Anchor element, by using the onclick event: <a onclick="ajaxRequest(MainForm.HTMLFrame, ['linkclicked'], { link: 'test'});">A link</a> In the MainForm you respond to the call, and open whichever form you wish: procedure TMainForm.HTMLFrameAjaxEvent(Sender: TComponent; EventName: string; Params: TUniStrings); begin if sameText(eventname,'linkclicked') then begin showMessage('Link clicked: '+Params.Values['link']); end; end; A test project is attached. ajaxtest.zip
  5. This is the code I use in the HTMLFrame called daycalFrame on MainForm, where I want the canvas to fill the whole frame, making sure redrawing is done on each resize: <canvas id="daycal"> <script type="text/javascript"> var canvas = $('#daycal')[0]; var ctx = canvas.getContext("2d"); window.addEventListener('resize', resizeCanvas, true); function resizeCanvas() { canvas.width = MainForm.daycalFrame.getWidth(); canvas.height = MainForm.daycalFrame.getHeight(); drawStuff(); } </script>
  6. Ron

    vcl forms

    Hi Vishwak, I am not aware of any such free project, unfortunately...
  7. If you are only talking about input, there should be no problem if you use insert queries only. Because then you are not opening any tables, but only executing queries. If you need to display a lot of data after all the input has been saved, you can join many tables in a query. I only use queries, never any table dataset components, and I only use live queries with small tables. Better to write the SQL yourself, and select/insert/update only what you need if you need speed.
  8. You can only run protocol commands that the browser is able to interpret, like http/s: and ftp:, or desktop protocol handlers like mailto: and tel: as mentioned above, providing the handlers are set up. This means you can also do a CORS call to a local web server, which then starts a program on the local machine. Cross-Origin Resource Sharing (CORS) is a standard that allows server to relax the same-origin policy. This is used to explicitly allow some cross-origin requests while rejecting others. The webserver has to be installed on the local computer, of course, and configured to respond to the call. You can use Indy HTTP Server to create this webserver.
  9. You could automatically log in the user and take him to the last form, if you could identify him and have saved his state. You would need public IP, local IP and a unique cookie set at last login.
  10. Those are just dummy variables, and you only need the port set if you are not using port 80, which it then defaults to over http.
  11. I have tried that, but as the fields rearrange with smaller window width, the height of the containing panel is not automatically adjusted to fit the fields. To get variable field width, I have this arrangement: 1. A panel - CPanel - with layout "border", with maxheight and minheight, which acts as a container for the next panel 2. A panel - FPanel - with layout "auto", with maxwidth, minwidth, maxheight and minheight 3. A fieldcontainer with layout "column", with maxwidth and minwidth But the height of the containing panels are not adjusted. Here is the code, and I am trying to create everything at runtime, and it starts with createForm, which calls setupPanel, which calls createPanel, which calls createFC (fieldcontainer), which calls the fields creation methods. Not sure if this is really possible, but I am not giving up easily. function TUniMainModule.createPanel(aowner, aparent:TUniPanel;aHeight:integer;title, subtitle:string):TUniPanel; var sTitle, lTitle:string; cPanel, FPanel:TUniPanel; heightStr, heightStr2, chStr:string; begin CPanel:= TUniPanel.Create(aowner); with CPanel do begin parent:=aparent; name:= 'panCPanel'+getUniqueID; color:=$00EFEFEF; borderStyle:=ubsNone; layout:='border'; titleVisible:=false; layoutConfig.Width:='100%'; layoutConfig.Margin:='0 0 0 0'; JSInterface.JSConfig('minHeight', [200]); JSInterface.JSConfig('maxHeight', [370]); end; sTitle:=title; lTItle:='<b>'+title+'</b><br>'+subtitle; heightStr:=inttostr(aHeight); heightStr2:=inttostr(aHeight+1); chStr:=inttostr(81); FPanel:= TUniPanel.Create(aowner); with FPanel do begin parent:=CPanel; name:= 'panFPanel'+getUniqueID; borderStyle:=ubsNone; layout:='auto'; layoutAttribs.Align:='top'; layoutConfig.Margin:='7 10 9 15'; color:=clWhite; collapsible:=true; collapsed:=false; title:=sTitle; titleVisible:=true; layoutConfig.Region:='center'; JSInterface.JSConfig('minWidth', [445]); JSInterface.JSConfig('maxWidth', [990]); JSInterface.JSConfig('minHeight', [200]); JSInterface.JSConfig('maxHeight', [370]); JSInterface.JSConfig('animCollapse', [250]); with clientEvents.UniEvents do begin values['afterCreate']:='function afterCreate(sender){sender.addCls("FPanel");sender.addCls("FPanelT");sender.addCls("shadowPanel");sender.addBodyCls("FBodyPanel")}'; values['beforeInit']:='function beforeInit(sender, config){config.defaults={margin:"0px 15px 0px"}}'; end; with clientEvents.ExtEvents do begin values['mouseover']:='function mouseover(sender, eOpts){sender.addCls("effectPanel2");}'; values['mouseout']:='function mouseout(sender, eOpts){sender.removeCls("effectPanel2");}'; values['collapse']:='function collapse(p, eOpts){'+FPanel.JSName+'.setTitle("'+lTitle+'");'+CPanel.JSName+'.setHeight('+chStr+',{duration:5,easing:"easeIn"});'+FPanel.JSName+'.removeCls("FPanelT");'+ FPanel.JSName+'.addCls("FPanelTC")+'+aparent.JSName+'.updateLayout();}'; values['beforeexpand']:='function beforeexpand(p, eOpts){var c='+CPanel.JSName+';c.setHeight('+heightStr2+');c.expand();'+aparent.JSName+'.updateLayout();}'; values['expand']:='function expand(p, eOpts){'+FPanel.JSName+'.removeCls("FPanelTC");'+FPanel.JSName+'.addCls("FPanelT");'+FPanel.JSName+'.setTitle("'+sTitle+'");var c='+ CPanel.JSName+';c.setHeight('+heightStr+');c.expand();'+aparent.JSName+'.updateLayout();}'; end; JSInterface.JSConfig('titleCollapse', [True]); end; result:=FPanel; end; function TUniMainModule.createFC(owner, aParent:TUniPanel; aHeight:integer):TUniFieldContainer; var fc:TUniFieldContainer; begin fc:=TUniFieldContainer.Create(owner); with fc do begin parent:=aParent; name:='fc'+getUniqueID; //title:=''; //width:=900; fieldLabel:=''; layout:='column'; //layout:='form'; //layout:='fit'; height:=aHeight; layoutConfig.Margin:='10 75 0 25'; layoutConfig.width:='100%'; //JSInterface.JSConfig('labelAlign', [top]); //JSInterface.JSConfig('minWidth', [205]); //JSInterface.JSConfig('maxWidth', [410]); JSInterface.JSConfig('minWidth', [425]); JSInterface.JSConfig('maxWidth', [950]); end; result:=fc; end; procedure TUniMainModule.createForm(aOwner, aParent:TUniPanel;formID:integer); var tPan:TUniPanel; fc:TUniFieldContainer; queryComp, sqlParam, formSQL, aTitle, fLabel:string; queryID, fMaxLength, fWidth, fieldID, fTYpe, aHeight, panID:integer; dbQuery:TMySQLQuery; function getFormQuery(s:string):TMySQLQuery; var i:integer; begin for i:=0 to componentCount-1 do if (Components[i] is TMySQLQuery) and sameText(uppercase(Components[i].Name), uppercase(s)) then result:=Components[i] as TMySQLQuery; end; begin createSpacer(aOwner, aParent); //formID determines form setup //select * from forms where id=:form_id; with formQuery do begin paramByName('form_ID').AsInteger:=formID; open; if not (recordCount=0) then begin formSQL:=fieldByName('sql').AsString; sqlParam:=fieldByName('parameter').AsString; queryComp:=fieldByName('querycomp').AsString; end; close; end; //get correct query parameter ID from formID case formID of 1: queryID:=customerID; end; //get correct query from form setup table dbQuery:=getFormQuery(queryComp); with dbQuery do begin sql.Text:=formSQL; paramByName(sqlParam).AsInteger:=queryID; open; end; //loop through panels table //select * from panels where form_id=:form_id order by id; with panelsQuery do begin paramByName('form_ID').AsInteger:=formID; open; if not (recordCount=0) then begin while not eof do begin aTitle:=fieldByName('title').AsString; aHeight:=fieldByName('height').AsInteger; panID:=fieldByName('id').AsInteger; setupPanel(aOwner, aParent, dbQuery, formID, panID, aHeight, aTitle,'subtitle'); Next; end; end else begin //Log error close; exit; end; close; end; createSpacer(aOwner, aParent); end; procedure TUniMainModule.setupPanel(aowner, aparent:TUniPanel;query:TMySQLQuery;formID, panID, aHeight:integer;title, subtitle:string); var tPan:TUniPanel; fc, fc1, fc2:TUniFieldContainer; dSource, fName, fLabel:string; fMaxLength, fWidth, fieldID, fTYpe:integer; ds:TDataSource; containerID:integer; function getDS(q:TMySQLQuery):TDataSource; var i:integer; begin for i:=0 to componentCount-1 do if (Components[i] is TDataSource) and ((Components[i] as TDataSource).Dataset=q) then result:=Components[i] as TDataSource; end; begin tPan:=createPanel(aOwner, aParent, aHeight, Title,'subtitle'); //create fieldcontainer - local variable as this has to be unique for each panel... fc1:=createFC(aOwner, tPan, aHeight); //fc2:=createFC(aOwner, tPan, aHeight); //loop through fields connected to selected panel //select * from fields where form_ID=:formId order by panel_id, id; with fieldDataQuery do begin if active then close; paramByName('form_ID').AsInteger:=formID; paramByName('panel_ID').AsInteger:=panID; open; if not (recordCount=0) then begin while not eof do begin fType:=fieldByName('fTYpe').AsInteger; fieldID:=fieldByName('id').AsInteger; fLabel:=fieldByName('label').AsString; fWidth:=fieldByName('width').AsInteger; fMaxLength:=fieldByName('maxlength').AsInteger; fName:=fieldByName('fieldname').AsString; containerID:=fieldByName('container').AsInteger; {case containerID of 1: fc:=fc1; 2: fc:=fc2; end; } ds:=GetDS(query); case fTYpe of 1: createCB(fc1, ds, fName, fLabel, fWidth); 2: createEdit(fc1, ds, fName, fLabel, fWidth, fMaxLength); end; Next; end; end else begin //Log error close; exit; end; close; end; end; In addition there are functions for creating the fields: procedure TUniMainModule.createEdit(aParent:TUniFieldContainer;aDataSource: TDataSource; fName:string; aLabel:string;aWidth, aMaxlength:integer); var ed:TUniDBEdit; begin ed:=TUniDBEdit.Create(aParent.owner); with ed do begin name:='ed'+getUniqueID; parent:=aParent; text:='Kaj Ronny Nilsen'; fieldLabel:=aLabel; datafield:=fName; dataSource:=aDataSource; width:=aWidth; maxLength:=aMaxLength; font.Size:=11; tag:=0; borderStyle:=ubsSingle; layoutConfig.Margin:='10 20 0 0'; layoutConfig.ColumnWidth:=0.45; fieldLabelSeparator:=''; fieldLabelAlign:=laTop; fieldLabelFont.Color:=clDkGray; with clientEvents.UniEvents do begin values['afterCreate']:='function afterCreate(sender){sender.addCls("SPEdit");}'; end; end; end; procedure TUniMainModule.createCB(aParent:TUniFieldContainer;aDataSource: TDataSource; fName:string; aCaption:string;aWidth:integer); var cb:TUniDBCheckBox; begin cb:=TUniDBCheckBox.Create(aParent.owner); with cb do begin name:='cb'+getUniqueID; parent:=aParent; tag:=1; caption:=aCaption; datafield:=fName; dataSource:=aDataSource; width:=aWidth; font.Size:=11; layoutConfig.Margin:='10 20 0 0'; layoutConfig.ColumnWidth:=0.45; end; end;
  12. I want fields to be in two columns at a window width greater than a certain width, and then only a single column when the window is smaller than this certain width. How to do this? I guess that I cannot use two containers, as in the first image, but if I use only one container, how to make it overflow to a second column when the container is too small for the fields? PS: Unfortunately I was unable to upload images.
  13. It is all based on ExtJS, where you can find the documentation: https://docs.sencha.com/extjs/7.0.0/modern/Ext.SegmentedButton.html#cfg-margin Granted, ExtJS is a bit complex...
  14. I have found a compromise: if I reload the application about 3 seconds after the deploy file is swallowed up by the HyperServer, then I will catch the new version in most of the cases: procedure TMainForm.checkTimerTimer(Sender: TObject); begin if fileExists('c:\antirust\timebok\deploy\timebok.dep') then begin UniMainModule.log('Fast Reloading application after 3000ms delay...'); sleep(3000); showToast('Fast Reloading application - time: '+TimeToStr(now)); uniSession.AddJS('document.location.reload();'); end; end; From the log: 3:00:20 PM Deploy file discovered 3:00:32 PM Deploy file moved after 11 secs. - reloading application 3:00:32 PM Application startup - version: 3:00:43 PM Deploy file discovered 3:00:54 PM Deploy file moved after 11 secs. - reloading application 3:00:55 PM Application startup - version: 3:01:02 PM Deploy file discovered 3:01:04 PM Deploy file moved after 2 secs. - reloading application 3:01:05 PM Application startup - version: 3:01:19 PM Deploy file discovered 3:01:29 PM Deploy file moved after 9 secs. - reloading application 3:01:29 PM Application startup - version: 3:01:50 PM Deploy file discovered 3:01:51 PM Deploy file moved after 0 secs. - reloading application 3:01:51 PM Application startup - version: 3:02:03 PM Deploy file discovered 3:02:13 PM Deploy file moved after 10 secs. - reloading application 3:02:14 PM Application startup - version: 3:02:32 PM Deploy file discovered 3:02:36 PM Deploy file moved after 3 secs. - reloading application 3:02:36 PM Application startup - version: 3:02:45 PM Deploy file discovered 3:02:46 PM Deploy file moved after 0 secs. - reloading application 3:02:46 PM Application startup - version: 3:02:54 PM Deploy file discovered 3:02:58 PM Deploy file moved after 3 secs. - reloading application 3:02:58 PM Application startup - version: 3:04:27 PM Deploy file discovered 3:04:32 PM Deploy file moved after 5 secs. - reloading application 3:09:06 PM Application startup - version: ... 3:17:35 PM Fast Reloading application after 1000ms delay... 3:17:37 PM Application startup - version: 3:17:58 PM Fast Reloading application after 2000ms delay... 3:18:01 PM Application startup - version: 3:18:18 PM Fast Reloading application after 2000ms delay... 3:18:20 PM Fast Reloading application after 2000ms delay... 3:18:21 PM Application startup - version: 3:18:36 PM Fast Reloading application after 2000ms delay... 3:18:38 PM Fast Reloading application after 2000ms delay... 3:18:39 PM Application startup - version: 3:18:40 PM Fast Reloading application after 2000ms delay... 3:18:40 PM Fast Reloading application after 3000ms delay... 3:18:44 PM Application startup - version: 3:19:13 PM Fast Reloading application after 3000ms delay... 3:19:17 PM Application startup - version: 3:19:33 PM Fast Reloading application after 3000ms delay... 3:19:36 PM Fast Reloading application after 3000ms delay... 3:19:40 PM Application startup - version: 3:19:40 PM Application startup - version: 3:19:47 PM Fast Reloading application after 3000ms delay... 3:19:51 PM Application startup - version:
  15. For development, I am using a special setup, trying to reduce time from compilation to browser refresh without any issues. For this I have to use HyperServer, due to is ability to automatically reload a new application file, from the deploy folder. So I run a webserver on my development PC, apache 2.2, and I have a post-compile event in Delphi which copies the EXE file to the \deploy folder, renaming it to *.dep. I have a timer in the mainForm which discovers that the HyperServer has loaded the new application file: procedure TMainForm.reloadTimerTimer(Sender: TObject); begin with uniMainModule do if newFileDate<>fileDate then begin reloadTimer.Enabled:=false; showToast('Reloading application...'); uniSession.AddJS('document.location.reload();'); end; end; This works fine, and it runs this newFileDate function in the MainModule: function TUniMainModule.newFileDate:TDateTime; var fileDateInt:Integer; begin fileDateInt := fileAge('c:\antirust\timebok\timebok.exe'); if fileDateInt > -1 then result:=fileDateToDateTime(fileDateInt); end; Of course this function is also run at MainModule startup: procedure TUniMainModule.UniGUIMainModuleCreate(Sender: TObject); begin fileDate:=newFileDate; end; The MainForm timer runs at 500ms intervals, so this all works fine, as you can see in the screenshot. But - there is of course another timer running in the HyperServer, and I wonder how I can reduce its interval? It seems like the HyperServer timer runs at 10 secs interval, and I would like to lower it to about 1 second. Then I can reduce the time from compile to browser reload, to about 3 seconds - maybe.
  • Create New...