lazarus - TMemo text property - textbox

I am using a TMemo box intead of a TEdit box simply because of the multi-line ability.
I was guessing and I used the .Text property to assign a value at run-time. But then I realised that there was no Text property at design time. Rather I found the Lines property.
I checked this page: http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tmemo.html for more info.
I found out that there is no Text property but only a Lines property in that documentation.
Is my use of .Text correct or is it a problem using this?
Here's my code:
if dlgSave.Execute Then
begin
txtSaveName.Text := dlgSave.FileName;
end;
txtSaveName : TMemo
dlgSave : TSaveDialog
Thanks for any inputs.

Lines is a TStrings, a class that is basically a wrapper for an array of strings.
Text is a simple property that when read concatenates the strings together (with lineseparators between them), and when assigned too parses the single string into multiple strings.
I wouldn't worry too much about it, just think twice before using it for huge strings (think hundreds of MBs and bigger), since all the copying done by this highlevel functionality will eat quite some memory.
Another (minor) reason not to use it is if you want reading and writing to be binary the same. Assume you have a text with mixed line endings and you assign it to text and read it back, then the mixed lineendings will be uniform now.

Related

What is the meaning of a pipe "|" in Delphi 7?

As the title says, I would like to know what is the meaning of the pipe (or tube) "|" in a Delphi code. See that screenshot :
I know the meaning of "*" which is a wild card for one or more characters, but I can't find what means "|".
Thanks
This is a question that can be answered by reading the documentation. It can be found here:
Vcl.Dialogs.TOpenDialog.Filter
To create file masks in program code, assign a value to the Filter
property that consists of a description and a mask separated by a
vertical bar (pipe) character. Do not include spaces around the
vertical bar. For example,
OpenDialog1.Filter := 'Text files (*.txt)|*.TXT';
Multiple filters should be separated by vertical bars. For example,
OpenDialog1.Filter := 'Text files (*.txt)|*.TXT|Pascal files (*.pas)|*.PAS';
To include multiple masks in a single filter, separate the masks with
semicolons. This works both in the Object Inspector and in program
code. For example,
OpenDialog1.Filter := 'Pascal files|*.PAS;*.DPK;*.DPR';
You might like to absorb the hints found here (How can I search for Delphi documentation?) in order to help you in the future.
In Delphi, the | character is often used as separator in certain string properties to differentiate between:
The description and the mask of a file filter, as used in TOpenDialog.Filter.
The short part, the long part and the image index of a hint text, as used in all Hint properties.
The pipe separates the filter expression (on the right) from the caption the user will see (on the left). If you want to apply more than one filter, just append it, also separated by pipes.
For TOpenDialog this is just a syntax to specify in one line of Filter both:
friendly type name (here: Regles de chaurfage)
file extension related to the type (here .fuz)
This is not language operator. This is just some kind of convention TOpenDialog is using.
Multiple filters should be separated by vertical bars.
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Dialogs_TOpenDialog_Filter.html

How to get a single Arabic letter in a string with its Unicode transformation value in DELPHI?

Considering this Arabic word(جبل) made of 3 letters .
-the first letter is جـ,
-name is (ǧīm),
-its Unicode value is FE9F when its in the beginning,
-its basic value is 062C and
-its isolated value is FE9D but the last two values return the same shape drawing ج .
Now, Whenever I try to get it as a single character -trying many different ways-, Delphi returns the basic Unicode value.
well,that makes sense,but what happens to the char with transformation? It is a single char too..Looks like it takes the transformed value only when it is within a string, but where? how to extract it?When and which process decides these values?
Again the MAIN QUESTION:
How can I get the Arabic letter or its Unicode value as it is within a string?
just for information: Unlike English which has tow cases for its letters(Capital and Small), Arabic has four cases(Isolated, Beginning,Middle And End) with different rules as well.
I'm not sure I understand the question. If you want to know how to write U+FE9F in Delphi source code, in a modern Unicode version of Delphi. Do that simply like so:
Char($FE9F)
If you want to read individual characters from جبل then do it like this:
const
MyWord = 'جبل';
var
c: Char;
....
c := MyWord[1];//this is U+062C
Note that the code above is fine for your particular word because each code point can be encoded with a single UTF-16 WideChar character element. If the code point required multiple elements, then it would be best to transform to UTF-32 for code point level processing.
Now, let's look at the string that you included in the question. I downloaded this question using wget and the file that came down the wires was UTF-8 encoded. I used Notepad++ to convert to UTF16-LE and then picked out the three UTF-16 characters of your string. They are:
U+062C
U+0628
U+0644
You stated:
The first letter is جـ, name is (ǧīm), its Unicode value is U+FE9F.
But that is simply incorrect. As can be seen from the above, the actual character you posted was U+062C. So the reason why your attempts to read the first character yield U+062C is that U+062C really is the first character of your string.
The bottom line is that nothing in your Delphi code is transforming your character. When you do:
S[1] := Char($FE9F);
the compiler performs a simple two byte copy. There is no context aware transformation that occurs. And likewise when reading S[1].
Let's look at how these characters are displayed, using this simple code on a VCL forms application that contains a memo control:
Memo1.Clear;
Memo1.Lines.Add(StringOfChar(Char($FE9F), 2));
Memo1.Lines.Add(StringOfChar(Char($062C), 2));
The output looks like this:
As you can see, the rendering layer knows what to do with a U+062C character that appears at the beginning of the string.
Shaping of Arabic characters for presentation in Windows is served by the Uniscribe services (USP10.dll).
UniScribe
You may find the following blog post useful:
Roozbeh's Programming Blog
I don't think you can do it using string/char related methods. But using pchar, maybe can you access the memory and read the Pword values directly
EDIT: After discussing with David, I think that you will always get the basic/isolated value of the letter. The fact that begin or end glyph is used, is probably just handled by the display framework of the OS

Using .AsString or .Text?

I have just seen a bit of code (D5) where they used...
aStr:=tblAcct.FieldByName('Name').Text;
It seems to work fine but I have always used...
aStr:=tblAcct.FieldByName('Name').AsString;
I have used both when loading a TMemo and again there seems no difference.
aMemo.Lines.Text:=tblAcct.FieldByName('History').Text;
aMemo.Lines.Text:=tblAcct.FieldByName('History').AsString;
Is there a reason why I should use one over the other?
If so, which one?
Actually for TMemo, I usually use...
aMemo.Lines.Assign(tblAcct.FieldByName('History'))
which seems to work fine too.
Thanks
The Text property is meant to be used to obtain the textual representation of a field being edited in a DataAware control, in contrast with the DisplayText property that gives you a string to represent the value to the user (it may contain punctuation or other decoration to the plain value).
Contains the string to display in a data-aware control when the field is in edit mode
A typical example is a TFloatField with the Currency property set to True. The DisplayText gives you a string with the number containing commas (if needed), the decimal separator and a currency symbol. The Text property gives you a string without commas or currency symbol.
begin
MyFloatField.Currency := True;
MyFloatField.AsFloat := 1234.56;
A := MyFloatField.Text; //'1234.56'
B := MyFloatField.DisplayText; //'$1,234.56', depends on your locale
end;
Both above properties can be customized writing a OnGetText event handler where you can write custom logic to convert the value to a string representation. The DisplayText parameter indicates if the wanted string is meant to represent the value for edit or not.
On the other hand, the AsString property uses a more plain conversion between the base data type and string. Each TField descendant implements the virtual GetAsString method using functions from the RTL to perform that representation. Following the TFloatField example, this class calls FloatToStr() for that purpose.
All this said, the answer to your question is: AsString returns the same string as the Text property if there's no OnGetText event handler, but it may be different if there's a event handler or a non-standard TField descendant.
I can't tell what is more appropriate for you, because it depends on what's the intended use for the returned value, but if you're using it to display the values to the user in the UI (as your code example), I advise you to use the DisplayText property.
AsString contains field's value as string.
Text contains the string to display in a data-aware control when the field is in edit mode.
So in your case I think you should use AsString.

Are Delphi strings immutable?

As far as I know, strings are immutable in Delphi. I kind of understand that means if you do:
string1 := 'Hello';
string1 := string1 + " World";
first string is destroyed and you get a reference to a new string "Hello World".
But what happens if you have the same string in different places around your code?
I have a string hash assigned for identifying several variables, so for example a "change" is identified by a hash value of the properties of that change. That way it's easy for me to check to "changes" for equality.
Now, each hash is computed separately (not all the properties are taken into account so that to separate instances can be equal even if they differ on some values).
The question is, how does Delphi handles those strings? If I compute to separate hashes to the same 10 byte length string, what do I get? Two memory blocks of 10 bytes or two references to the same memory block?
Clarification: A change is composed by some properties read from the database and is generated by an individual thread. The TChange class has a GetHash method that computes a hash based on some of the values (but not all) resulting on a string. Now, other threads receive the Change and have to compare it to previously processed changes so that they don't process the same (logical) change. Hence the hash and, as they have separate instances, two different strings are computed. I'm trying to determine if it'd be a real improvement to change from string to something like a 128 bit hash or it'll be just wasting my time.
Edit: Version of Delphi is Delphi 7.0
Delphi strings are copy on write. If you modify a string (without using pointer tricks or similar techniques to fool the compiler), no other references to the same string will be affected.
Delphi strings are not interned. If you create the same string from two separate sections of code, they will not share the same backing store - the same data will be stored twice.
Delphi strings are not immutable (try: string1[2] := 'a') but they are reference-counted and copy-on-write.
The consequences for your hashes are not clear, you'll have to detail how they are stored etc.
But a hash should only depend on the contents of a string, not on how it is stored. That makes the whole question mute. Unless you can explain it better.
As others have said, Delphi strings are not generally immutable. Here are a few references on strings in Delphi.
http://blog.marcocantu.com/blog/delphi_super_duper_strings.html
http://conferences.codegear.com/he/article/32120
http://www.codexterity.com/delphistrings.htm
The Delphi version may be important to know. The good old Delphi BCL handles strings as copy-on-write, which basically means that a new instance is created when something in the string is changed. So yes, they are more or less immutable.

Delphi - Problem With Set String and PAnsiChar and Other Strings not Displaying

I was getting advice from Rob Kennedy and one of his suggestions that greatly increased the speed of an app I was working on was to use SetString and then load it into the VCL component that displayed it.
I'm using Delphi 2009 so now that PChar is Unicode,
SetString(OutputString, PChar(Output), OutputLength.Value);
edtString.Text := edtString.Text + OutputString;
Works and I changed it to PChar myself but since the data being moved isn't always Unicode in fact its usually ShortString Data.... so onto what he actually gave me to use:
SetString(OutputString, PAnsiChar(Output), OutputLength.Value);
edtString.Text := edtString.Text + OutputString;
Nothing shows up but I check in the debugger and the text that normally appeared the way I did it building 1 char at a time in the past was in the variable.
Oddly enough this is not the first time I ran into this tonight. Because I was trying to come up with another way, I took part of his advice and instead of building into a VCL's TCaption I built it into a string variable and then copied it, but when I send it over nothing's displayed. Once again in the debugger the variable that the data is built in... has the data.
for I := 0 to OutputLength.Value - 1 do
begin
OutputString := OutputString + Char(OutputData^[I]);
end;
edtString.Text := OutputString;
The above does not work but the old slow way of doing it worked just fine....
for I := 0 to OutputLength.Value - 1 do
begin
edtString.Text := edtString.Text + Char(OutputData^[I]);
end;
I tried making the variable a ShortString, String and TCaption and nothing is displayed. What I also find interesting is while I build my hex data from the same array into a richedit it's very fast while doing it inside an edit for the text data is very very slow. Which is why I haven't bothered trying to change the code for the richedit as it works superfast as it is.
Edit to add - I think I sorta found the problem but I have no solution. If I edit the value in the debugger to remove anything that can't be displayed (which by the old method used to just not display... not fail) then what I have left is displayed. So if it's just a matter of getting rid of bytes that were turned to characters that are garbage how can I fix that?
I basically have incoming raw data from a SCSI device that's being displayed hex-editor style. My original slow style of adding one char at a time successfully displayed strings and Unicode strings that did not have Unicode-specific characters in them. The faster methods even if working won't display ShortStrings one way and the other way wont display UnicodeStrings that aren't using non 0-255 characters. I really like and could use the speed boost but if it means sacrificing the ability to read the string... then what's the point in the app?
EDIT3 - Alright now that I've figured out that 0-31 is control char and 32 and up is valid I think I'm gonna make an attempt to filter char and replace those not valid with a . which is something I was planning on doing later to emulate hex editor style.
If there are any other suggestions I'd be glad to hear about them but otherwise I think I can craft a solution that's faster than the original and does what I need it to at the same time.
Some comments:
Your question is very unclear. What exactly do you want to do?
Your question reads terrible, please check your text with a spelling checker.
The question you are referring to is this one: Delphi accessing data from dynamic array that is populated from an untyped pointer
Please give a complete code sample of your function like you did in your previous question, I want to know if you implemented Rob Kennedy's suggestion or the code you gave yourself in a following answer (let's hope not :) )
As far a I understand your question: You're sending a query to your SCSI device and you get an array of bytes back which you store in the variable OutputData. After that you want to show your data to the user. So your real question is: How to show an array of bytes to the user?
Login as the same user and don't create an account for every new question. That way we can track your question history an can find out what you mean by 'getting advice'.
Some assumptions and suggestions if I'm right about the true meaning of your question:
Showing your data as a hex string won't give any problems
Showing your data in a normal Memo field gives you problems, although a Delphi string can contain any character, including 0 bytes, displaying them will give you problems. A TMemo for example will show your data till the first 0 byte. What you have to do (and you gave the answer yourself), is replacing non viewable characters with a dummy. After that you can show your data in a TMemo. Actually all hex viewers do the same, characters that cannot be printed will be shown as a dot.
I used PAnsiChar in my example for a reason. It looked like OutputLength was being measured in bytes, not characters, so I made sure to use a type whose length is always measured in bytes. You'll also notice that I showed the declaration of OutputString as an AnsiString.
Since the edit control stored Unicode, though, there will be a conversion between AnsiString and UnicodeString. That will take the system's current code page into account, but that's probably not what you want. You might want to declare the variable as a RawByteString instead. That won't have any code page associated with it, so there won't be any unexpected conversions.
Don't use strings for storing binary data. If you're building what amounts to a hex editor, then you're working with binary data. It's important to remember that. Even if your binary data happens to consist mostly of bytes that can be interpreted as text, you can't treat the data as text or you'll run into exactly the problems you're seeing — characters that don't appear as expected. If you get a bunch of bytes from your SCSI device, then store them in an array of bytes, not characters.
In hex editors, you'll notice that they always show the hexadecimal values of the bytes. They might show those bytes interpreted as characters, but that's secondary, and they generally only show the bytes that can represent ASCII characters; they don't try to get too fancy with the basic display. The good hex editors will offer to display the data interpreted as wide characters, too. This aids in debugging because the user can look at the same data in multiple ways. But they're just views of the data. They're not actually changing the binary contents of the data.
When you filter out non viewable characters...You'll probably need to decide what to do with a couple of them like #9(Tab), #10(LF), #11(Verticle Tab), #12(FF-or New Page),#13(CR)

Resources