Jump to content

David Schwartz

Members
  • Content Count

    1237
  • Joined

  • Last visited

  • Days Won

    25

Everything posted by David Schwartz

  1. David Schwartz

    form data store component ?

    Sorry, I don't see what this is bringing to the party. I'm already opening the files and loading them into a stringlist. That's easy. What I want is to have the data actually embedded in the EXE somehow so I don't have to copy the text files around. Yes, I can put them all into a single zip file, but I still have to copy that zip file around with the EXE. It's the same problem as with DLLs. These are just some files containing text data saved from listboxes. And yes, I know I can declare them as resource strings. But that means when I update them (in another program) then I have to save them to disk as txt files and then go through a process of copying and pasting the data into the files with the resource strings. Either that or I need to write some code to take the contents of the list boxes and save them into .pas files that declare them as resource strings. That's certainly a solution, but I'd rather just be able drag and drop the txt files (or paste a filename) into a component on a form in the IDE and have them saved on the form for access at run-time.
  2. David Schwartz

    DL a file from the web

    I'm looking for code, not a lecture. 🙂
  3. David Schwartz

    DL a file from the web

    That is, it's not dependent on anything else being installed than what the platform comes with. However, an open-source lib installed into Delphi is OK. The thing is, most libs are based on low-level system calls, like Wininet, right? Anyway, your code is 162 lines.
  4. David Schwartz

    DL a file from the web

    assumes Chrome is installed. And if it's set to "Ask user for destination" (as mine is) then it will keep popping up for each file, right? What if you want it to go to a specific folder -- as in, the program has no way of knowing where Chrome is set to download the files to?
  5. David Schwartz

    Converting C++ API Post Request into Delphi Code

    Thanks for pointing this out.
  6. David Schwartz

    Getters & Settters??

    Unless you have a flawless crystal ball that sees very far into the future and all of the ways the class might be used, you have no way to predict which, if any, of the state variables you're adding to your class might change over time. By using a property to expose all of these state variables, you allow the class to evolve without impacting existing clients of the class in any way. Using properties is more of an on-going "best practice" as far as I'm concerned, that's simply rooted in years of having to deal with the consequences of NOT using them in large projects. It's the same reason people use #define for constants in C rather than the values themselves. They're read-only, but you can change them in one place without impacting all of the code. In fact, this is one thing I find totally insane about CSS -- you cannot define symbolic constants for anything, and so if you want to change a property of a common thing, you have to edit the value of that property everywhere! Properties in Delphi take it another step by allowing you to simply refer to the variable name itself if you don't need to do anything with it, or refer to a proc or func that can do pretty much anything with it. This is particularly handy in situations where you want to use Property Injection after a object has been created. Every assignment can have a setter that sets a flag saying whether a required parameter was set. Then if you try using a method and a required parameter has NOT been set, it's easy to raise an exception that uses very little overhead in that determination. Thinking about these things becomes second nature after a while, and it's great to have a practice to follow that makes it easy to change your mind about things later on.
  7. David Schwartz

    Getters & Settters??

    If there's anything you take away from this discussion, it should be that understanding Properties (with their getter and setter methods) is helpful, but when you get into discussions involving passing data in and out of Forms, it usually turns into something more akin to a religious debate. There are lots of common practices that apply to interacting with classes, starting with the basic principles of "objects" which are: encapsulation, inheritance, and polymorphism. The whole point of classes is twofold: (1) model behavior; and (2) maintain state. In most GUI-based apps, a form's behavior is going to vary with how it's used: maybe to simply display a message; get an input value; display and/or edit some data; and more complex forms that combine several of these. However, there are several ways to get and set the state (field values) inside of that form class. Worse, the way people employ these methods is very inconsistent, which can be observed by looking at a lot of different code written by may different people. Properties are properties, and Dalija did a great job explaining them. The "why" part wasn't really addressed: it's because properties afford the programmer some latitude in terms of 'encapsulation'. For instance, you put 'i' and 's' in front of some property names to clue the programmer into how they're used (handy if you're not using an IDE that already ensures the types match up). The point here is, right now you might have implemented those as one type that makes sense today; but in a month or a year down the road, it might make sense to change those types or where the values are stored. And that's where Getters come in -- they enforce the promise that the property is whatever type you say it is, regardless of how it occurs inside the class. So an integer could change to a string, or vice versa, because of some other change. If you accessed that variable directly by name, and its type changed, that could have incredibly wide-ranging repercussions on the rest of the application. But by using a property that says CustomerNum (with or without an 'i' in front) is always an Integer, you don't have to worry about whether the underlying variable changes to a string or a field in some other record or object -- references to CustomerNum will always refer to an integer. Even if you replace it with a DB query. As for Setters, they have a totally different set of uses that can be equally important. Their main use is to ensure the integrity of the internal state of the object. If the state of a given variable can only have three distinct values, you'd use a Setter to make sure it isn't assigned something else, which can cause problems for the behavior of the entire object later on. So the Setter can act as a sort of "door bouncer" to keep disreputable characters out of the club, so to speak. That's the "why" part in a nutshell. Here's where we get into what's behind the religious debate part... In Delphi, a "form" is a TForm which is a class derived from something in the VCL that's intended to act as a container for visual components -- hence VCL = Visual Component Library. When you create a 'class' in Delphi, it inherits from TObject and it's pretty much a blank slate. You get to define what's in it and how its clients are supposed to use it. When you create a 'form' in Delphi, it's actually a TForm, a class in itself, and it's FAR from a blank slate. It's part of a complex inheritance tree and it acts as a container for VCL components that depend on things present in the TForm inheritancy hierarchy. This imposes a bunch of fixed rules as well as guidelines to follow, some of which are required and some optional. How you get data into and out of a form should be guided by how you do that with any other class. However, in practice, people tend to not follow those rules very much. And you can tell from all of the back-and-forth between different folks here that some hold rather strong opinions about what to do and not do. I did a presentation for CodeRage 9 where I discussed this very topic in some detail, entitled "Have You Embraced Your Inner Software Plumber Yet?" The essence of this presentation is that getting data in and out of forms is more aligned with the whole domain of Dependency Injection than anything else. Unfortunately, when people hear that term, they tend to think of Unit Testing, not managing the lifetime of forms in their apps, including Dephi's forms. There are three types of DI for classes: (1) constructor injection; (2) property injection; and (3) setter/getter injection. People have described all of these earlier in the thread. Neither of them is "best", although some are better for certain situations and needs than others. Complicating things, the data they represent can be input only, output only, and bi-directional. So the DI part needs to account for this dynamic as well. (FYI: a DI framework / Service Locator lets you save and lookup different instances of things is a totally different and unrelated discussion. It would have been nice if the original developers built Delphi's form management on top of a DI framework, as that would have codified how to get data in and out of forms consistently, but ... they didn't go that way. I've seen it done in large applications, and it simplifies the hell out of things because the way you interface with every form is the same. It's quite refreshing to see!) And in my talk, I don't even address the situation where the form is interacting with a database maintained implicitly in another unit than the one that's dealing with it. This is the situation where you say, "Open this form to edit the current record in some DB based on whatever the user is doing right now." It's extremely common, and takes very little effort on your part because the form is simply mirroring both data and state being managed by some database components that probably live on a Data Module elsewhere. You just call Create and ShowModal and everything else is handled automatically. A guy named Mark Seemann has written a lot on this topic; he has a blog, has written some books, and gives talks on the subject. He has written a book, Dependency Injection for .NET that's quite popular, and while the code is focused on .NET, the principles apply equally well to Dephi. He seems to have co-authored a newer version of it recently that I haven't seen but is probably worth checking out. There's also the book Dependency Injection in Delphi by Nick Hodges. You can use Mark's book to learn the principles and Nick's book to see a lot of the examples in Delphi. I don't think Nick intended that, but it just shows how universal these patterns are. (It looks like all of Nick's books are on sale at Amazon right now.)
  8. David Schwartz

    best way to display a list of panels?

    I need something like a TListView but each Item is a fixed-height panel with other components on it. Each one is the same structurally, but with different values. (The same way that list items are all strings, but with different values.) It's one column wide and can have zero to a dozen or two "rows". I need it to behave like a typical List View would. I have a list of panels, and I added a helper function to the base panel to let me add the list to it, and it works fine (more or less). But I've got a splitter and the base panel sits on the top; when it resizes (to make the base panel bigger), items that are initially created "below the horizon" get reordered when the panel exposes them and I don't know why. I need the resizing to not reorder things! Something else does reordering. (FWIW, the splitter and panels are both Raize components: TRzSplitter and TRzPanel.) I guess I have two options: one is when the splitter stops (or the panel stops getting resized), clear the base panel and re-display the list of subpanels on the it. If I could freeze the base panel so nothing updates until you stop adjusting the splitter, that would be really nice, as it causes a lot of screen flickering. Is there a good way to do that? Or maybe just add subpanels incrementally, so you see a gap expand until it's large enough for another subpanel which is then displayed. Or when shrinking the panel, then subpanels disappear when there's not enough height for a full one. The other option would be to find a better control to use. There are several kinds of new panels that do things along this line, but it's unclear which might be best. Suggestions are welcome. (TFlowPanel, TGridPanel, TRelativePanel, TStackPanel, TCardPanel. And let's not forget TScrollBox!) Jedi has a TJvItemsPanel and TJvComponentPanel. Also, having a scrollbar would be handy if there are just too many to display no matter what. What's the best way to solve this?
  9. David Schwartz

    JSON superobject question

    I'm playing with SuperObject for the first time and the example refers to paths but there's something (a lot) that's unclear to me. (It could use more examples.) { "success": true, "data": { "voices_list": [ { "Engine": "neural", "VoiceId": "ai2-Stacy", "VoiceGender": "Female", "VoiceWebname": "Stacy", "Country": "US", "Language": "en-US", "LanguageName": "English, US", "VoiceEffects": [ ] }, { "Engine": "neural", "VoiceId": "ai1-Matthew", "VoiceGender": "Male", "VoiceWebname": "Matthew", "Country": "US", "Language": "en-US", "LanguageName": "English, US", "VoiceEffects": [ "news" ] }, {...} ], "count": 50 } } This JSON response packet has two items: success and data. data has two items: voices_list and count The VoiceEffects is mostly empty, but sometimes has one or more items in it. I basically want to create an object from this Initially, I'm trying to figure out how to get the count in voices_list. There should be two ways: 1) should be via data.count, but all I ever get is zero 2) I'd think there's a way to ask for how many elements are in the voices_list array, which should be 50 in this case, but I can't figure out how to get that count. obj := SO(RESTResponse1.Content); obj.AsObject.S['success'] --> true but obj.AsObject.I['data.count'] --> 0 (zero) What am I missing?
  10. David Schwartz

    JSON superobject question

    BINGO! The example shows ['xx.yy'] but that doesn't work, and using obj.O[___].I[___] didnt' occur to me This works: resp.success := obj.AsObject.S['success']; resp.count := obj.O['data'].I['count']; // because this element happens to exist resp.count := obj.O['data'].O['voices_list'].AsArray.Length; // this queries the array directly
  11. David Schwartz

    Function with 2 return values ?

    You can override the counter method to disable it, right?
  12. David Schwartz

    Function with 2 return values ?

    I guess I'm not clear what you're referring to. What good are Interfaces if you don't inherit from them? You cannot define any data fields in them.
  13. David Schwartz

    Function with 2 return values ?

    We do. They're called 'abstract' classes. They've been around for quite a while now. Similar semantics as C++ but the compiler isn't as strict. https://docwiki.embarcadero.com/RADStudio/Sydney/en/Classes_and_Objects_(Delphi)
  14. Here's some pseudo-code that needs to be executed when you visit a particular URL: case TodaysName of 'mon': ShowPage(1); 'tue': ShowPage(2); . . . 'fri': ShowPage(5); end; ShowPage loads a list of either HTML files or URLs, then sends that page out to the browser. I want to implement this in TMS WebCore, and the app sits at the URL in question. I'm looking at a situation where the pages use a different template for each day. Someone will edit the template for each day eg, on Sunday) and save it; when the URL is viewed in the browser it will display that day's template as edited previously. The users might create the pages using an HTML page / web editor, or maybe create them in, say, Wordpres, or any number of similar options. Is it sufficient to load up the entire HTML file and send it out to the browser? Or will the header need to be doctored in some way? I suppose I could also write an app that would let the user edit the pages and save their most relevant details somewhere. I know this isn't specific to WebCore, but may be a fairly common problem with many kinds of services.
  15. David Schwartz

    How to display one of several web pages at one URL

    Thanks, I'm looking for a general solution. It's not for me, but for others.
  16. David Schwartz

    Function with 2 return values ?

    Either you're going to keep adding parameters to the method's signature, or you're going to have to collect them into an object. Take your pick. Mark Seemann calls these Parameter Objects or Façade Services. They typically start out as a collection of fields passed around as related parameters, but usually end up taking on a life of their own and become Façade Services. And ... if you set up an interface that the class implements, then this won't be a problem.
  17. David Schwartz

    Function with 2 return values ?

    I think the safest way is to have two 'out' parameters with a Boolean return value that indicates they're both valid. If you have a bunch, then you should return them in a class instance as the RESULT of the function call.
  18. David Schwartz

    Converting C++ API Post Request into Delphi Code

    This looks like the same question that Randell Carpenter posted in the Cross Platform section. Have you searched Google for curl examples in Delphi? Here's one: This might be useful: https://github.com/Mercury13/curl4delphi Here's another example: http://thundaxsoftware.blogspot.com/2015/12/sending-rest-api-messages-with-delphi.html
  19. David Schwartz

    C to Delphi pascal

    You don't need curl for this. RESTRequest and RESTResponse should be fine. The example above is similar to what you'd need.
  20. David Schwartz

    How to display one of several web pages at one URL

    WebCore is obviously overkill for this. I'm thinking PHP is probably better. It's running on somebody's hosting account to allow them to sequence through pages over time and manage the sequencing separately from the pages themselves. Most are using Wordpress. midnight Monday -> show page-1 midnight Wednesday -> show page-2 midnight Friday -> show page-3 midnight Saturday -> show page-4 midnight Sunday -> show page-5 With no other pages, then page-5 will always show after that. All will appear at the same URL / home page. The pages can be edited on a Wordpress site installed in a folder that they can get to easily. The page names can be long strings of random characters so they can't be easily guessed. Perhaps that schedule can be done inside of WP as well by filling in a form and then the script can read it from the WP DB. (Just thinking out loud here...)
  21. David Schwartz

    How to display one of several web pages at one URL

    That's what I'm asking about... If I have a script in the document root that loads up a little table that has a filename or URL plus a timestamp of when that page should be displayed, can I simply load the page from a file or the URL and simply send it to the browser without worrying about anything else? For example, if I put a Wordpress site in a folder beneath the document root, then let the user access that to create the pages. The little table used by the script above it would simply need to find the URL to request from the WP site based on the current time vs. times in the list, and then load it up and send it to the browser. The whole purpose of this is to have a mechanism separate from the platform to manage time-based displays of specific pages, which is not something that Wordpress or any other platform I know of does easily. The guy who created this whole model has it implemented on InfusionSoft / Keap and hired one of their consultants to build the whole site for him. The page sequencing is fairly trivial, but there's no Wordpress plugin I've found that does that. It's sort of antithetical for how most websites work. (Typically, you post a page and the site displays it. There's no notion of "sequencing over time" for the same page URL. In fact, it's quite counter-intuitive. But for this application, it's required.) Analogy: you go into a resturant and they have a daily special that's different each day. A web site works by having a different room you'd go into for that special. But you only want it open on the day that special is being offered. Which means you'd need seven different rooms to handle daily specials each day of the week. That's silly. You just list them by day and you order the "Daily Special". The kitchen can't fix the other ones if you were to ask. That's like a URL in this case -- same URL, different thing served up based on the day. Websites don't work that way.
  22. EUR and USD are almost equal right now. I was paid $32k back in 1982. Current salaries are around $100k, and even really cheap Delphi devs are $70k. Full stack web devs are up to $150k. Delphi is a "full-stack" tool, but nobody seems to regard it as such. 🙂
  23. David Schwartz

    How to display one of several web pages at one URL

    Well, I'm concerned about the "page editor" and dependencies that may be in the HEAD section that may need to be changed. I use "page editor" loosely because it could be just about anything, and could also be done in Wordpress to create the requisite pages. What I want to create is a generic tool that doesn't care what's used to create the pages. What it does is looks at the current date and time and then determines which page to display. I was thinking the page would need to be loaded and partially parsed so the header can be tweaked, but upon further thought, that's probably not necessary. Can I just load a file or URL and send it to the browser as-is?
  24. David Schwartz

    Parse Json again, complicated

    If you create a class for this, then there's a method that can theoretically create an instance of it and fill it from a chunk of JSON data: var data_obj := TJson.JsonToObject<TMyObj>( req.Response ); In this case, the JSON data would go into a class TMyObj, which is the type returned in data_obj. I've used it for simple objects, but I'm not sure how it would handle lists and arrays. BTW, that JSON has an error in it -- a dangling comma
  25. I'm building an app that uses a REST API. The API itself is rather simple. There are a dozen optional parameters that you can send to a few of the endpoints as 'xyz=<boolean>' where <boolean> is a string of either 'true' or 'false', along with a few parameters that take one of a few strings or a number. I created a unit with API-related methods in it and it's called from the main form when needed. That much is working with default parameter settings. Now I want to add a simple way to let the user select API options and have them passed to the API unit without the API unit knowing anything about the UI, and without requiring a ton of arguments on one setter method or a ton of properties to set every possible parameter. (These are all inputs to the API calls; the output is a JSON packet.) The app right now is a VCL app, and it may change. I have created a Page Control with several tabs that have checkboxes on them with an explanation next to each one that says what it's for. I made the caption on the checkboxes the same as the name of the API setting, like 'xyz' above, with the thought that I could use it somehow in the settings if I collect the components into an array. The challenge is that you need to clear parameters before each API call, and add a few locally (URL, login name and pwd) that are buried in the API unit. (I suppose they could be moved into the Main unit if it helps.) So when I call the API method, it calls an internal method to clear the Parameters, adds the URL, login and pwd params, and its at THIS POINT where I need to add the OTHER params selected by the user on the UI side. Then I call RESTRequest.Execute and wait for the response. I can think of several different ways to do this, all of which are fairly convoluted and inelegant. Even if I just have a bunch of setters that need to be called, I'd need to pass in a callback method that's called to add them to the list of parameters at exactly the right point. All of the examples I can find tend to be very simplistic, mixing the UI and the API calls in the same unit; I'm trying to keep them separate, but SOMETHING needs to be used to get the values from the UI elements and either save them for later, or inject them directly as parameters into the POST call at the point where it's being created. This would seem like it would be a fairly consistent pattern when you have an app with a UI and one or more units with API-specific logic in them, and you don't want to have the API units having to know anything about what's in the UI, yet it needs to include the values of settings made in the UI at a place in the logic flow that's quite inconvenient for the API's client to access. I'm curious if anybody here has come up with a clean and fairly simple solution to this problem that they'd care to share?
×