In an Edit control, how to show translucent text that disappears when new text is entered? - delphi-7

I made the following code but something does not work.
unit Unit9;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, ADODB, Grids, DBGrids, ExtCtrls;
type
TForm9 = class(TForm)
edt1: TEdit;
procedure FormCreate(Sender: TObject);
end;
var
Form9: TForm9;
const
EM_SETCUEBANNER = $1501;
implementation
uses
Unit2;
{$R *.dfm}
procedure TForm9.FormCreate(Sender: TObject);
var
Banner: String;
buf: array [0..$ff] of Char;
begin
Banner := UTF8Encode('Введите логин');
Utf8ToUnicode(PWideChar(#buf), PAnsiChar(Banner), Length(Banner));
SendMessage(edt1.Handle, EM_SETCUEBANNER, 0, Integer(#buf));
end;
end.
For example, as on some websites, an edit control displays "Login" until something is written.

Related

True free heap not what it should be after ShellExecute

I have a simple Application that reads data from an .ini file into a record, and then does a ShellExecute. However, when I run it in debug mode,it tells me that the True free heap isn't what it should be:
"True heap size: 688128, True free heap: 688016, Should be: 688128"
This only happens if I actually run the ShellExecute (however even if I don't run the ShellExecute, I get a True free heap of 688016, but no complaint that it should be 688128), so I wonder if I either need to free the PChar() conversion (which shouldn't be the case from all that I've read), or the handle returned by ShellExecute (though CloseHandle(ShellHandle); doesn't change the message), or if it's intended behavior?
The IniSettings.SetupCommand in question is an .msi file that triggers a UAC prompt, but I really just want to make this a Fire & Forget thing since my Lazarus app doesn't care what it launches.
For reference, here's my whole Unit. I'm using Lazarus 1.6.2, FPC 3.0.0, i386-win32, and I'm targeting Windows only with this. My Debug Settings are at the very bottom, after the code.
unit MainUnit;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls,
Graphics, Dialogs, StdCtrls, IniFiles, Windows;
type
{ IniSettings }
TAutorunIniSettings = record
AutorunTitle: AnsiString;
SetupCommand: AnsiString;
end;
{ TMainForm }
TMainForm = class(TForm)
btnSetup: TButton;
lblTitle: TLabel;
procedure btnSetupClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ private declarations }
IniSettings: TAutorunIniSettings;
public
{ public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.lfm}
{ TMainForm }
procedure TMainForm.FormCreate(Sender: TObject);
var
AutorunIni: TIniFile;
begin
try
AutorunIni := TIniFile.Create('Autorun.ini');
IniSettings.AutorunTitle := AutorunIni.ReadString('Autorun', 'Title', 'Autorun');
IniSettings.SetupCommand := AutorunIni.ReadString('Autorun', 'Setup', '');
self.Caption := IniSettings.AutorunTitle;
finally
if(AutorunIni <> nil) then AutorunIni.Free;
end;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
end;
procedure TMainForm.btnSetupClick(Sender: TObject);
begin
ShellExecute(0, 'open', PChar(IniSettings.SetupCommand), nil, nil, SW_SHOWNORMAL);
end;
end.

Loading an array of records back into a program from a file?

I am creating a program that moves through an array of records and save these student records to a file.
However I now wish to reload the data (StudentName,Class,Grade) back into the array and subsequently display them in a list box on another form.
I have tried a few methods but with no success.
This is the code that wrote the file:
unit NewStudent;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
ExtCtrls, studentdata;
{ TFormNewStudent }
Type
TFormNewStudent = class(TForm)
Button1: TButton;
ButtonAddStudent: TButton;
Button3: TButton;
ComboBoxPredictedGrade: TComboBox;
EditClass: TEdit;
EditName: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure ButtonAddStudentClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
Type
TPupil = Record
Name:String[30];
ClassGroup:String;
ComboBoxPredictedGrade:Integer;
end;
var
FormNewStudent: TFormNewStudent;
StudentRecArray : Array[1..30] of TPupil;
StudentNo:integer;
studentFile:TextFile;
implementation
{$R *.lfm}
{ TFormNewStudent }
procedure TFormNewStudent.Button1Click(Sender: TObject);
begin
FormStudentData.visible:=true;
FormNewStudent.visible:=false;
end;
procedure TFormNewStudent.Button3Click(Sender: TObject);
begin
FormStudentData.visible:=False;
FormNewStudent.visible:=True;
end;
procedure TFormNewStudent.ButtonAddStudentClick(Sender: TObject);
var
newStudent:string;
Begin
assignfile(studentFile,'G:\ExamGen\studentfile.txt');
StudentRecArray[StudentNo].Name:=EditName.text;
StudentRecArray[StudentNo].ClassGroup:=EditClass.text;
StudentRecArray[StudentNo].ComboBoxPredictedGrade:=ComboBoxPredictedGrade.ItemIndex;
append(studentFile);
newStudent:=(StudentRecArray[StudentNo].Name)+','+(StudentRecArray[StudentNo].ClassGroup)+','+(IntToStr(StudentRecArray[StudentNo].ComboBoxPredictedGrade));
writeln(studentFile,newStudent);
closefile(StudentFile);
StudentNo := StudentNo + 1;
end;
procedure TFormNewStudent.FormCreate(Sender: TObject);
begin
ComboBoxPredictedGrade.Items.Add('A');
ComboBoxPredictedGrade.Items.Add('B');
ComboBoxPredictedGrade.Items.Add('C');
ComboBoxPredictedGrade.Items.Add('D');
ComboBoxPredictedGrade.Items.Add('E');
ComboBoxPredictedGrade.Items.Add('U');
end;
end.
ScreenShot 1: StudentFile
ScreenShot 2: AddStudent Form
Answer given by Zamrony P. Juhara is correct, but your approach here may be not the most convenient. You define record which contains information about each student, then you write procedures to write this record to file and another one to read it. If you'll eventually change format of your record, you'll have to rewrite this code also. There are better ways, in my opinion.
You can define record containing only simplest members, like Ken White suggested:
TPupil = Record
Name:String[30];
ClassGroup:String[20]; //some convenient value
ComboBoxPredictedGrade:Integer;
end;
Such a record have fixed size and contains all needed information in itself (version with ClassGroup:String actually stores pointer to another area in memory where your string is), and then you can save and load it extremely easy:
var
myFile : File of TPupil;
procedure TFormNewStudent.ButtonAddStudentClick(Sender: TObject);
Begin
assignfile(studentFile,'G:\ExamGen\studentfile.txt');
StudentRecArray[StudentNo].Name:=EditName.text;
StudentRecArray[StudentNo].ClassGroup:=EditClass.text;
StudentRecArray[StudentNo].ComboBoxPredictedGrade:=ComboBoxPredictedGrade.ItemIndex;
append(studentFile);
Write(studentFile,StudentRecArray[StudentNo]); //THAT'S IT!
closefile(StudentFile);
inc(StudentNo);
end;
procedure TFormNewStudent.ReadFromFile;
begin
AssignFile(myFile,'G:\ExamGen\studentfile.txt');
Reset(studentFile);
StudentNo:=1;
while not Eof(studentFile) do begin
Read(studentFile,StudentRecArray[i]);
inc(StudentNo);
end;
end;
There is little drawback: file is not so readable as it was before, because Integer is saved exactly as 4-byte value, not its decimal representation.
There is much more interesting possibilities if you move from record to class, in that case you can use streaming system in a way as IDE saves forms to disc, in .dfm or .lfm files, so you'll be able to automatically save complex ierarchies of objects and load them back.
var
myFile : TextFile;
text : string;
lines : TStringList;
i : integer;
...
lines := TStringList.Create();
AssignFile(studentFile,'G:\ExamGen\studentfile.txt');
Reset(studentFile);
i:=1;
while not Eof(studentFile) do
begin
ReadLn(studentFile, text);
lines.CommaText := text;
studentRecArray[i].Name := lines[0];
studentRecArray[i].ClassGroup := lines[1];
studentRecArray[i].ComboBoxPredictedGrade := StrToInt(lines[2]);
inc(i);
end;
CloseFile(studentFile);
lines.Free();

Lazarus - Mac OSX Debugging Error

I used to use Delphi 7 on my PC, but now that I bought a MacBook (Mid 2012 - OSX Mountain Lion), I wanted to continue programming in Pascal and have a similar Interface. Lazarus seems to deliver most of the things I wanted, but it seems to run into a lot of errors, when compiling even the simplest applications! To test it, I made a simple "Russian Roulette" application, just for fun, but the program just freezes, when launched or even when compiled inside Lazarus.
When launching it from command line, It shows me the following error:
TCarbonButton.SetFocus Error: SetKeyboardFocus failed with result -30585
I don't think my coding is the problem, but I guess I should include it:
unit RussianRouletteUnit;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
Buttons, ExtCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Kugeln: TLabeledEdit;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
Number: Integer;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
if Random(StrToInt(Kugeln.Text))+1 = 1 then
begin
Button1.SetFocus;
Memo1.Color := clred;
Memo1.Text := 'BOOM';
Memo1.Lines.Add('HEADSHOT');
end;
end;
initialization
randomize;
end.
I hope you guys can help me out, any help is apprechiated :D

Pasting multiple lines into a TEdit

With respect to a TEdit component, would it be possible for the component to handle a multi-line paste from the Windows Clipboard by converting line breaks to spaces?
In other words, if the following data was on the Windows Clipboard:
Hello
world
!
...and the user placed their cursor in a TEdit then pressed CTRL+V, would it be possible to have the TEdit display the input as:
Hello world !
You'd need to subclass the TEdit using an interposer class, and add a handler for the WM_PASTE message:
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, adsdata, adsfunc, adstable;
type
TEdit= class(StdCtrls.TEdit)
procedure WMPaste(var Msg: TWMPaste); message WM_PASTE;
end;
type
TForm3 = class(TForm)
AdsTable1: TAdsTable;
Edit1: TEdit;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
uses
Clipbrd;
{ TEdit }
procedure TEdit.WMPaste(var Msg: TWMPaste);
var
TempTxt: string;
begin
TempTxt := Clipboard.AsText;
TempTxt := StringReplace(TempTxt, #13#10, #32, [rfReplaceAll]);
Text := TempTxt;
end;
end.

Why do I get multiple windows messages of same kind?

I'm trying to respond to some windows and application messages, but I get them multiple times.
For example, I write the following code to show a message box when the date of system is changed using WM_TIMECHANGE. WMTimeChange is executed more than once, and I see multiples (most times two or three) messageboxes one behind another. Maybe, I am missing something?
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
protected
procedure WMTimeChange(var Msg: TMessage) ; message WM_TIMECHANGE;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
procedure TForm1.WMTimeChange(var Msg: TMessage);
begin
showmessage('Date/Time has changed!');
end;
end.
Testing in Windows XP.
EDIT: Just to clarify, my intention is understand WHY that happen and not how to get around the multiple calls. Anyway, if an answer to that is not possible, I will probably accept one answer to the later.
EDIT2: Removed Delphi Tag as it seems not a Delphi issue.
Your code is correct. It sounds like that Windows is sending the WM_TIMECHANGE message several times.
So you can just add a small time-hysteresis comparison to let your message be triggered only once per a 1% of day, i.e. more or less 15 minutes:
type
TForm1 = class(TForm)
protected
FWMTimeChangeTimeStamp: TDateTime;
procedure WMTimeChange(var Msg: TMessage) ; message WM_TIMECHANGE;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
procedure TForm1.WMTimeChange(var Msg: TMessage);
begin
if Now-FWMTimeChangeTimeStamp>0.01 then
begin
showmessage('Date/Time has changed!');
FWMTimeChangeTimeStamp := Now;
end;
end;
This is kind of what I've used in my case to be resilient to this behavior. But as said in comments, will only work if the user take time to answer the application. So, Arnaud Bounchez is a better approach to general use. Only don't forget to initialize the FWMTimeChangeStamp to something that is different from current computer clock.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
protected
procedure WMTimeChange(var Msg: TMessage) ; message WM_TIMECHANGE;
private
isTimeChangeEventShowing: Boolean;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
isTimeChangeEventShowing := false
end;
procedure TForm1.WMTimeChange(var Msg: TMessage);
begin
if not isTimeChangeEventShowing then
begin
isTimeChangeEventShowing := true;
showmessage('Date/Time has changed!');
isTimeChangeEventShowing := false;
end;
end;
end.

Resources