-
Content Count
2684 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
Delphi 12 IDE, auto-formatter mutilates generics
Remy Lebeau replied to A.M. Hoornweg's topic in Delphi IDE and APIs
Ah! Stupid me, that joke went right over my head, I didn't even notice the 13 🤯 -
Create a new instance of a generic class
Remy Lebeau replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
Where is System._CreateClass defined? I cannot find it in any RTL source file, and when I do a test creating a class instance from a metaclass, there is no such function call. -
Create a new instance of a generic class
Remy Lebeau replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
Even if you could get this to compile, you need to make the constructor virtual in order to call a derived constructor from a base metaclass type. -
But you didn't explain earlier WHY you need to preserve the HDC, only that you want to use it across "two tasks", without any example or explanation of what those tasks actually are. And, as Delija already mentioned, you can simply Lock the TBitmap's Canvas to prevent the VCL from releasing the HDC automatically. Just make sure you Unlock it before you resize or free the TBitmap, and re-Lock it again after resizing. That makes no sense. If you are using the TBitmap's HDC for both functions, then there is no need to wait for a paint event to draw the string onto the TBitmap. Since you are not drawing the string onto a display HDC directly, there is no need to wait for a paint event. You can just draw onto the TBitmap whenever you want, since it is all just in-memory data. If you want to draw the TBitmap onto a display Canvas so the user can see the image, that certainly needs to be done in a paint event, but that does not mean you have to draw onto the TBitmap itself in the paint event. And in fact, you shouldn't do it that way. Prepare the TBitmap image ahead of time, and then just draw the TBitmap as-is whenever a paint event occurs, and then invalidate the display window whenever the TBitmap image changes so a new paint event can display the updated image. And this way, you don't even need the TBitmap's HDC to be persistent over time, you only need it when you are updating your image. For example: type TTextPanel = class(...) private procedure BmpChanged(Sender: TObject); procedure UpdateData; protected procedure Paint; override; procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end; constructor TTextPanel.Create(AOwner: TComponent); begin inherited Create(AOwner); FBmp := TBitmap.Create; FBmp.OnChange := BmpChanged; end; destructor TTextPanel.Destroy; begin FBmp.Free; inherited Destroy; end; procedure TTextPanel.BmpChanged(Sender: TObject); begin Invalidate; end; procedure TTextPanel.Paint; begin inherited Paint; ... Canvas.Draw(0, 0, FBmp); ... end; procedure TTextPanel.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); begin inherited SetBounds(ALeft, ATop, AWidth, AHeight); FBmp.SetSize(Width, Height); UpdateData; end; procedure TTextPanel.UpdateData; begin // update FBmp image as needed... end; I think you are making this task harder than it really needs to be. If you think I'm wrong, feel free to provide an example demonstrating exactly what you are trying to accomplish.
-
Then there is no point in calling getdbrecord() in the OnCreate event, since it will always fail to find a matching record. As it should be, since the user hasn't been allowed to type in a name yet! Then you need to perform a SELECT query without a WHERE clause. And then after you have called FDQuery1.Open(), you can call FQuery1.First() before reading the field values. type TfrmDino = class(TForm) ... private procedure displaydbrecord; public procedure get1stdbrecord; procedure searchdbrecord(const AName: string); end; procedure TfrmDino.FormCreate(Sender: TObject); begin WindowState := wsMaximized; get1stdbrecord; end; procedure TfrmDino.btnSearchClick(Sender: TObject); begin searchdbrecord(edtSearch.Text); end; procedure TfrmDino.displaydbrecord; var sName: String; img1: string; ... begin sName := FDQuery1.FieldByName('name').AsString; edtRecno.Text := FDQuery1.FieldByName('record').AsString; edtName.Text := sName; ... img1 := sName + '.jpg'; ... end; procedure TfrmDino.get1stdbrecord; begin FDQuery1.SQL.Text := 'SELECT record,name,meaning,pronounce,period,maingroup,size,lived,diet,factfile FROM dino'; FDQuery1.Open; FDQuery1.First; displaydbrecord; end; procedure TfrmDino.searchdbrecord(const AName: string); begin FDQuery1.SQL.Text := 'SELECT record,name,meaning,pronounce,period,maingroup,size,lived,diet,factfile FROM dino Where name = :PName'; FDQuery1.ParamByName('PName').AsString := AName; FDQuery1.Open; displaydbrecord; //edtSearch.Clear; end; Did you read the documentation yet? https://docwiki.embarcadero.com/RADStudio/en/Navigating_and_Manipulating_Records Even if you hook up the TDBNavigator to your DataSource, you don't have your UI hooked up to the Navigator, so of course nothing happens when you click the buttons. You would have to either use the TDBNavigator's events to re-query your records every time a button is clicked, or you should change your UI to use TDBEdit components and let them update themselfes automatically when the DataSource is navigated.
-
Why are you creating an HDC to begin with? TBitmap already has its own HDC that it manages for you. Just draw on your TBitmap whenever you need to. What are you trying to accomplish exactly by managing your own HDC manually? You don't need that 2nd step. You can't. Resizing a bitmap will destroy its old data. But TBitmap will handle copying the old data into the new memory for you. You would have had to do that yourself with a manual HDC, so better to just let TBitmap do it for you.
-
Simply set the TPageControl's ActivePage property back to Tab1, eg: procedure TfrmDino.getdbrecord; var ... begin ... PLTabSheet.ActivePage := TabSheet1; end;
-
OK, first problem... what do you see in the following snippet? (ignoring the unused img variables here) You are calling getdbrecord() in the Form's OnCreate event! What value does edtSearch hold when the Form is first created, BEFORE the user has a chance to type anything into it? Is it blank? Does it have a default value? We don't know, but I'm guessing it is not a valid record name. OK, next problem... see anything wrong with the following snippet? The sName variable is BLANK when you use its value to assign the img1 and img2 variables! Not that it really matters here, since you are not actually using those img variables for anything useful to begin with, but it is still something to be aware of so you don't make this same mistake again in the future. Lastly, just on a side note, in the following code snippet... You should be checking that TFDQuery.Open() actually found a matching record before you access the Field values. If TFDQuery.Open() does not find a match, the TFDQuery.Bof and TFDQuery.Eof properties will both be true, eg: ... FDQuery1.SQL.Text := '...'; ... FDQuery1.Open; if FDQuery1.Bof and FDQuery1.Eof then begin // no matching record found, do something... end else begin // place field data into tedit controls... end; Now, let's put all of that together... procedure TfrmDino.BitBtn1Click(Sender: TObject); begin Close; end; procedure TfrmDino.btnSearchClick(Sender: TObject); begin getdbrecord; end; procedure TfrmDino.FormCreate(Sender: TObject); begin WindowState := wsMaximized; //getdbrecord; end; procedure TfrmDino.getdbrecord; var sName: String; imgPath: String; img1: String; //img2: String; begin sName := edtSearch.Text; FDQuery1.SQL.Text := 'SELECT record,name,meaning,pronounce,period,maingroup,size,lived,diet,factfile FROM dino Where name = :PName'; FDQuery1.ParamByName('PName').AsString := sName; FDQuery1.Open; if FDQuery1.Bof and FDQuery1.Eof then begin ShowMessage('Name not found'); Exit; end; //place data into edtName edtRecno.Text := FDQuery1.FieldByName('record').AsString; edtName.Text := FDQuery1.FieldByName('name').AsString; edtMeaning.Text := FDQuery1.FieldByName('meaning').AsString; edtPronounciation.Text := FDQuery1.FieldByName('pronounce').AsString; edtPeriod.Text := FDQuery1.FieldByName('period').AsString; edtMainGroup.Text := FDQuery1.FieldByName('maingroup').AsString; edtSize.Text := FDQuery1.FieldByName('size').AsString; edtLived.Text := FDQuery1.FieldByName('lived').AsString; edtDiet.Text := FDQuery1.FieldByName('diet').AsString; memFactfile.Text := FDQuery1.FieldByName('factfile').AsString; //displayimages imgPath := 'D:\Delphi_11_Community\MyProjects\Dinobase\dino_images\'; img1 := sName + '.jpg'; //img2 := sName + '_size.jpg'; dinoImage.Picture.LoadFromFile(imgPath + img1); //edtSearch.Clear; end;
-
The only LoadFromFile() code you have shown us so far is in the form's OnCreate event before the SQL query is performed. Please show your updated code that calls it after the SQL query is performed. That is just a copy/paste of the example code I gave you originally. What does your REAL code look like? Did you put a breakpoint on imagePath, or show it in a ShowMessage(), or anything to verify it is holding the correct path before you then pass it to LoadFromFile()? No, it doesn't.
-
'group' is a reserved keyword in SQL. To use a reserved keyword in an object name, like a column field, you have to surround the name with square brackets, eg: FDQuery1.SQL.Text := 'SELECT record,name,meaning,pronounce,[group],period,size,lived,diet,factfile FROM dino Where name = :PName';
-
Delphi 12 IDE, auto-formatter mutilates generics
Remy Lebeau replied to A.M. Hoornweg's topic in Delphi IDE and APIs
Please don't spread fake news. There is no such version. It is explicitly mentioned, in a roundabout way: Modeling is deprecated, and the current code formatter depends on it, so the formatter is also deprecated. -
It is raw RGB, use whatever values you want for the R, G, B channels. The code you showed is not using a dark brown, it's more like a red-ish brown. RGB(80,47,15) is actually #502F0F in paint programs (not to be confused with the '#xxxx' character constant notation in Pascal!). It is not. Completely different RGBs. TColor(#575) is decimal 575 is hex $23F (use any calculator to verify that), and TColor($0000023F) is R=63($3F) G=2($02) B=0($00). RGB(80,47,15) would be TColor($0F2F50). If you want to set that in code, you can use the actual RGB() function: edtLived.Font.Color := TColor(RGB(80,47,15)); BTW, you may want to have a look at the TControl.ParentFont property. Instead of setting the Font.Color on every control individually, you can set it once on their parent instead, and then have the controls inherit it via ParentFont.
-
Yes. You can enter a custom color value directly into the property editor, you just have to use decimal notation (drop the #) or hex notation, ie use '575' or '$23F' (without the quotes). Even in your code, don't use '#' for color values. '#' is used to specify a Char constant, and a character is not a color. Use TColor(575) or TColor($23F) in code, or more expressive TColor(RGB(63, 2, 0)) or TColor(RGB($3F, $2, $0)). It is highlighted because that TEdit has the input focus at the time. Simply put the focus somewhere else, such as the Form itself. Also, make sure the Form's ActiveControl property is not set at design-time (or, set it to the UI control you actually want to have the focus initially).
-
Where are you calling TfrmDino.getdbrecord() from? It is not in the code you have shown. You can't activate the query before you have configured it. Sounds like you hadn't defined the SQL for it yet before trying to use it. All of that setup stuff you are doing in the Form's OnCreate event should be done using the Object Inspector at design-time instead. Start with this: https://docwiki.embarcadero.com/RADStudio/en/FireDAC
-
Obviously, you need to adjust the code for your particular setup, which you did not provide ANY details about, so I could only give you a GENERAL solution. What kind of database are you are trying to access? What component(s) are you are using to access that database? My example was meant to represent whatever Query component you are actually using on your Form, such as a TQuery, TFDQuery, etc. Use whatever the actual component name really is. Not a String variable. Have you read Delphi's documentation on working with Databases? There are whole books on this subject.
-
Yes, I see the same issue happen, the top of the Recent menu is WAY off screen:
-
There should be no difference between setting up a query at design-time vs runtime. So, what are you REALLY having trouble with, exactly? Can you show the actual code that you are having trouble with? All you need is something like this: Query.SQL.Text := 'SELECT Name, OtherFieldsAsNeeded from dino where Name = :PName'; Query.ParamByName('PName').AsString := sName; Query.Open; edtName.Text := Query.FieldByName('Name').AsString;
-
No, I was actually referring to the compiler's Library and Browsing Paths, the debugger's Source Path, etc. There are multiple search paths in a project, make sure none of them are referring to Indy's source folder during compiling. You don't want the compiler finding Indy's source code if you want to use the pre-installed version. You said you re-installed the IDE and transferred over old projects. Do you have the same problem if you start a new project fresh? What IDE version were the old projects written in? It is generally a good idea to create a new project in the new IDE and then add your existing source files to the new project as needed, rather than just open an old project in the new IDE.
-
Is there more to the error message? I would think it would tell you WHY it can't compile the unit. In any case, it sounds like the project is trying to recompile Indy from its source code. Does the project refer to Indy's source code folder directly? It shouldn't, so if it does then remove that folder from the project's search directories. The project should only be using the pre-installed unit/package binaries that were already compiled for the IDE.
-
Assigning custom colors to properties via code at runtime is trivial, as shown earlier. But if you want to choose custom colors at design-time, that is possible but not trivial, as you have to write your own custom property editor and register it for TColor, overriding the default property editor. See webcolors and custom colors in Delphi's Object Inspector colorpicker at design-time Custom colors in Delphi 7
-
Profile - currently no entry Delphi 12
Remy Lebeau replied to Brian Evans's topic in Community Management
There is now. -
It has been added. Oddly, it is listed as just "Delphi 12" instead of as "Delphi 12 Athens".
-
Delphi 12: Install Packages inconsistency?
Remy Lebeau replied to PeterPanettone's topic in Delphi IDE and APIs
Sure, but I shouldn't really have to go to that much trouble in the first place just to get basic behavior. -
And RandomFrom()
-
RandomRange() has been around since Delphi 6.