Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Glenn9999's Code Sharing 3

Status
Not open for further replies.

Glenn9999

Programmer
Jun 19, 2004
2,312
US
I'm sharing some things that really don't have a cohesive topic and are so short I feel bad in posting them as individual FAQs.
They are little things that I've tried over the years or "proof of concepts" for certain things I have in more "production-oriented" code or even answers to questions previously asked here. There was a question, as well, of how much of this constitutes as "useful". It seemed the best idea from some advice I got from another person here was to just post it, make FAQ(s) out of what is interesting (to minimize what shows up in the FAQ section/reduce the admin's workload, etc), and see what happens.

Putting Notepad in a Panel
Code:
var
  procid: DWord;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Execute_Program('Notepad.exe', '', procid, false);  // this is a function that I have that simply runs a program.
  procid := Windows.FindWindow('Notepad', nil);
  Windows.SetParent(procid, Panel1.Handle);
  PostMessage(procid, WM_SYSCOMMAND, SC_MAXIMIZE, 0); // maximize the window.
end;

A bitmap as a form background
Code:
var
  mybitmap: TBitmap;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyBitMap := TBitMap.Create;
  MyBitMap.LoadFromFile('QUADRILL.BMP');
  Form1.Brush.Bitmap := MyBitMap;  // sets the bmp to be the background of the form.
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  MyBitMap.Free;
end;

Compare two TBitmaps
Code:
function GetPixelSize(informat: TPixelFormat): Extended;
  // returns proper byte size for input
  begin
    case informat of
      pf16bit: Result := 2;
      pf24bit: Result := 3;
      pf8bit: Result := 1;
      pf1bit: Result := 1/8;
      pf4bit: Result := 1/2;
      pf32bit: Result := 4;
    else
      Result := 0;
    end;
  end;

function myBitmapsAreSame(Bitmap1, Bitmap2: TBitmap): Boolean;
var
  i: integer;
  RowSize: integer;
begin
  Result := false;
  if (Bitmap1.Width = Bitmap2.Width) and
     (Bitmap1.Height = Bitmap2.Height) and
     (Bitmap1.PixelFormat = Bitmap2.PixelFormat) then
    begin
      RowSize := trunc(Bitmap1.Width*GetPixelSize(Bitmap1.PixelFormat));
      for i := (Bitmap1.Height-1) downto 0 do
        begin
          Result := CompareMem(Bitmap1.ScanLine[i], Bitmap2.ScanLine[i], RowSize);
          if Result = false then exit;
        end;
    end;
end;

Callback function Example - DLL
Code:
library mydll;
   uses sysutils;
  type
    cbproc = function(num1, num2: integer): integer;

  procedure domath(var invar: integer; mycallback: cbproc);
    begin
      invar := invar * 3;
      invar := mycallback(invar, 2);
    end;

  exports
    domath  index 1;
  end.

Callback function Example - Main Program, also shows dynamic DLL load
Code:
{$APPTYPE CONSOLE}
program main; uses windows;
type
  cbproc = function(num1, num2: integer): integer;
  dmproc = procedure(var invar: integer; mycallback: cbproc);
var
  libhandle: DWord;
  dllproc: dmproc;
  invar: integer;

function add_two_numbers(num1, num2: integer): integer;
  begin
    Result := Num1 + Num2;
  end;

begin
  write('Input invar: ');
  readln(invar);
  writeln;
  writeln('DLL function multiplies by three.');
  writeln('Callback function as called from DLL adds two.');
  writeln;
  libhandle := LoadLibrary('MYDLL.DLL');
  if libhandle <> 0 then
    begin
      @DLLProc := GetProcAddress(libhandle, 'domath');
      if @DLLProc <> nil then
        dllproc(invar, @add_two_numbers);
      FreeLibrary(libhandle);
    end;
  writeln('Invar is now: ', invar);
  readln;
end.


Sort CheckListBox based on what is checked (true first)
Code:
procedure TForm1.SortButtonClick(Sender: TObject);
var
  i, j: integer;
begin
  i := 0;
  while (i < CheckListBox1.Items.Count-1) do
    begin
      if CheckListBox1.Checked[i] = true then
        inc(i)
      else
        break;
    end;
  j := i;
  while (j <= CheckListBox1.Items.Count-1) do
    begin
      if CheckListBox1.Checked[j] = true then
        begin
          CheckListBox1.Items.Exchange(j, i);
          CheckListBox1.Checked[i] := true;
          CheckListBox1.Checked[j] := false;
          inc(i);
        end;
      inc(j);
    end;
end;

TColor explained in code.
Code changes a panel color based on the values of three scroll bars. Shows how TColor can be manipulated.
Code:
  TForm1 = class(TForm)
    Panel1: TPanel;
    sbRed: TScrollBar;
    sbGreen: TScrollBar;
    sbBlue: TScrollBar;
...
  end;

 color_type = (ctRed, ctGreen, ctBlue);

procedure TForm1.FormShow(Sender: TObject);
begin
  Label1.Caption := 'TColor = $' + IntToHex(Integer(Panel1.Color), 8);
end;

function SetColorChange(incolor: TColor; position: integer; color: color_type): TColor;
type
  marray = array[0..3] of byte;
begin
  Marray(incolor)[Integer(color)] := position;
  Result := incolor;
end;

procedure TForm1.sbRedChange(Sender: TObject);
begin
  Panel1.Color := SetColorChange(Panel1.Color, sbRed.Position, ctRed);
  Label1.Caption := 'TColor = $' + IntToHex(Integer(Panel1.Color), 8);
end;

procedure TForm1.sbGreenChange(Sender: TObject);
begin
  Panel1.Color := SetColorChange(Panel1.Color, sbGreen.Position, ctGreen);
  Label1.Caption := 'TColor = $' + IntToHex(Integer(Panel1.Color), 8);
end;

procedure TForm1.sbBlueChange(Sender: TObject);
begin
  Panel1.Color := SetColorChange(Panel1.Color, sbBlue.Position, ctBlue);
  Label1.Caption := 'TColor = $' + IntToHex(Integer(Panel1.Color), 8);
end;

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Get TCanvas for a Window Handle
The intent is to come up with one procedure which can draw on any window handle. Works for the test scenario given,
as well as some screen saver code I did.
Code:
procedure drawform(Win_handle: THandle; fill_color: Tcolor);
  { single procedure to draw on any window handle passed }
  var
    MyCanvas: TCanvas;
    WinRect: TRect;
  begin
    GetClientRect(Win_Handle, WinRect);
    MyCanvas := TCanvas.Create;
    MyCanvas.Handle := GetDC(Win_handle);
    try
      MyCanvas.Brush.Color := fill_color;
      MyCanvas.FillRect(Rect(WinRect.Left,WinRect.Top,WinRect.Right, WinRect.Bottom));
    finally
      ReleaseDC(win_Handle,MyCanvas.Handle);
      MyCanvas.Free;
    end;
  end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  DrawForm(Panel1.Handle, clBlue);
  sleep(1000);
  DrawForm(Panel1.Handle, clRed);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DrawForm(Form1.Handle, clGreen);
  sleep(1000);
  DrawForm(Form1.Handle, clYellow);
end;

Delete all files and folders for path given
Code:
 procedure m_deltree(filepath: TFileName);
    var
      tfileinfo: TSearchRec;
      r: TFileName;
      retcode: longint;
      atribute: word;
    begin
      r := filepath + '\*.*';
      retcode := FindFirst(r, faAnyFile, tfileinfo);
      while retcode = 0 do
        begin
          if (tfileinfo.attr and faDirectory = faDirectory) then
            begin
              if (tfileinfo.name <> '.') and (tfileinfo.name <> '..') then
                 m_deltree(filepath + '\' + tfileinfo.name)
            end
          else
            begin
              atribute := 0;
              FileSetAttr(filepath + '\' + tfileinfo.name, atribute);
              SysUtils.DeleteFile(filepath + '\' + tfileinfo.name);
            end;
          retcode := FindNext(tfileinfo);
        end;
      SysUtils.FindClose(tfileinfo);
      atribute := FaDirectory;
      FileSetAttr(filepath, atribute);
      RemoveDir(filepath);
    end;

Get Icon out of EXE file
(also scales 32x32 icon to 16x16 icon)
Code:
function GetHomeDirectory: string;
  var
    outstr: string;
  begin
    Outstr := ExtractFilePath(Paramstr(0));
    Result := OutStr;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  IconRes: TIcon;
  DrawRect: TRect;
  BitMapRes1, BitmapRes2: TBitmap;
begin
  if OpenDialog1.Execute then
    begin
      // create graphics resources
      IconRes := TICon.Create;
      BitMapRes1 := TBitMap.Create;
      BitMapRes2 := TBitMap.Create;
      try
        // extract icon
        IconRes.Handle := ExtractIcon(HInstance, PChar(OpenDialog1.FileName), 0);

        // set canvas to draw the original icon
        BitMapRes1.Width := 32;
        BitMapRes1.Height := 32;
        BitMapRes1.Canvas.Draw(0, 0, IconRes);

        // now copy icon to new resource, smaller
        BitMapRes2.Width := 16;
        BitMapRes2.Height := 16;
        DrawRect.Top := 0;
        DrawRect.Left := 0;
        DrawRect.Bottom := 16;
        DrawRect.Right := 16;

        // redraw icon resource, resizing
        BitMapRes2.Canvas.StretchDraw(DrawRect, BitMapRes1);
        // save file
        BitMapRes2.SaveToFile(GetHomeDirectory + '\test01.bmp');
        MessageDlg('Icon extracted.', mtInformation, [mbOK], 0);
      finally
      // free resources
        BitMapRes1.Free;
        BitMapRes2.Free;
        IconRes.Free;
      end;
    end;
end;

Load INI file hierarchially into TreeView
Code:
procedure TForm1.Button1Click(Sender: TObject);
var
  tnode1, tnode2: TTreeNode;
  insect, insectvalues: TStrings;
  iniobj: TInifile;
  i, j: integer;
begin
  if OpenDialog1.Execute then
  begin
  iniobj := TiniFile.Create(OpenDialog1.Filename);
  TreeView1.Items.BeginUpdate;
  TreeView1.Items.Clear;
  insect := TStringList.Create;
  insectvalues:= TStringList.Create;

  insect.Clear;
  iniobj.ReadSections(insect);
  for i := 0 to (insect.Count - 1) do
    begin
      TNode1 := Treeview1.Items.Add(nil, insect.Strings[i]);
      insectvalues.Clear;
      iniobj.ReadSectionValues(insect.Strings[i], insectvalues);
      if InsectValues.Count > 0 then
        for j := 0 to (insectvalues.count - 1) do
          TNode2 := TreeView1.Items.AddChild(TNode1, insectvalues.Strings[j]);
    end;
  TreeView1.Items.EndUpdate;
  iniobj.free;
  insect.free;
  insectvalues.free;
  end;
end;

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
(This is the last of the "small code snippets" I have onhand.)

Keypress handling
This code uses a form key press event to enable input into a label caption. I used this to give a different
look to a project I was working on
Code:
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
const
  bksp = #8;
  enter = #13;
var
  slength: integer;
begin
  slength := length(label1.caption);
  case key of
    bksp: label1.caption := copy(label1.caption, 1, slength-1);
    enter: messagedlg('Enter Pressed', mtInformation, [mbOK], 0);
  else
    if slength < 26 then
      case key of
        'a'..'z': label1.caption := label1.caption + upcase(key);
        'A'..'Z': label1.caption := label1.caption + key;
      else
        windows.beep(10000, 1000);
      end
    else
       windows.beep(10000, 1000);
  end;
  slength := length(label1.caption);
  label2.caption := IntToStr(slength);
end;

CSV into ListView
I don't know if this is the best way, but a good demo on ListView vsreport
Code:
procedure TForm1.AddListView(x, y: integer; ListItem: TListItem; instr: string);
  var
    NewColumn: TListColumn;
  begin
    if x = 0 then
      begin
        NewColumn := Listview1.Columns.Add;
        NewColumn.Caption := instr;
      end
    else
      begin
        if y = 0 then
          ListItem.Caption := instr
        else
          ListItem.Subitems.Add(instr);
      end;
  end;

procedure TForm1.split_string(x: integer; instr: string);
  var
    partstr: string;
    reststr: string;
    y: integer;
    ListItem: TListItem;
  begin
    reststr := instr;
    y := 0;
    if x <> 0 then
      ListItem := ListView1.Items.Add;
    while Pos('",', reststr) <> 0 do
      begin
        partstr := Copy(reststr, 2, Pos('",', reststr)-2);
        AddListView(x, y, ListItem, partstr);
        inc(y);
        reststr := Copy(reststr, Length(PartStr) + 4, Length(reststr));
      end;
    partstr := Copy(reststr, 2, Length(reststr) - 2);
    AddListView(x, y, ListItem, partstr);
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  infile: TextFile;
  instr: string;
  x: integer;
begin
  if OpenDialog1.Execute then
    begin
      ListView1.ViewStyle := vsReport;
      AssignFile(infile, OpenDialog1.Filename);
      reset(infile);
      x := 0;
      while not eof(infile) do
        begin
          readln(infile, instr);
          split_string(x, instr);
          inc(x);
        end;
      closefile(infile);
      MessageDlg('CSV file loaded.', mtInformation, [mbOK], 0);
    end;
end;

Print a text file out of a memo with paging/margins
Code:
procedure TForm1.PrintButtonClick(Sender: TObject);
var
  i, j: integer;
  linesize: integer;
  textsize: integer;
  pagesize: integer;
  hmargin, vmargin: integer;
begin
  if PrintDialog1.Execute then begin
    Printer.Title := 'Sample Text File Printer';
    Printer.Canvas.Font := Memo1.Font;
    pagesize := Printer.PageHeight;
    for j := 1 to Printer.Copies do
      begin
        Printer.BeginDoc;
        hmargin := GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSX) -
                   GetDeviceCaps(Printer.Canvas.Handle, PHYSICALOFFSETX);
        vmargin := GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSY) -
                   GetDeviceCaps(Printer.Canvas.Handle, PHYSICALOFFSETY);
        StatusLabel.Caption := 'Printing Page ' + IntToStr(Printer.PageNumber);
        linesize := vmargin;
        for i := 0 to Memo1.Lines.Count-1 do
          begin
            textsize := Printer.Canvas.TextHeight(Memo1.Lines.Strings[i]);
            if linesize+textsize+vmargin >= pagesize then
              begin
                Printer.NewPage;
                StatusLabel.Caption := 'Printing Page ' + IntToStr(Printer.PageNumber);
                linesize := vmargin;
              end;
            Printer.Canvas.TextOut(hmargin, linesize, Memo1.Lines.Strings[i]);
            inc(linesize, textsize);
          end;
        Printer.EndDoc;
      end;
    StatusLabel.Caption := 'File Printed.';
  end;
end;

Make a splash screen
Be sure in the main code that you create the splash form last and do something like this.
Code:
begin
  Application.Initialize;
  Application.ShowMainForm := false;
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TfrmSplash, frmSplash);
  Application.Run;
end.

Then make sure there's a TImage and a TTimer on the splash screen form.
Code:
procedure TfrmSplash.FormCreate(Sender: TObject);
// doing all the stuff programmatically, most of this can be done in VCL
// forms designer as well
begin
  Image1.Picture.LoadFromFile('circuit-31.bmp'); // this image is 380x220
  // position Image1 correctly & make sure loading screens, labels can be seen
  Image1.Top := 0;
  Image1.Left := 0;
  Image1.Transparent := false;
  // blow up and stretch image to twice size
  Image1.Width := Image1.Picture.Width * 2;
  Image1.Height := Image1.Picture.Height * 2;
  Image1.Stretch := true;
  // set form size to image size
  FrmSplash.Width := Image1.Width;
  FrmSplash.Height := Image1.Height;
  // set some form properties to befit the splash screen
  FrmSplash.BorderStyle := bsNone; // bsToolWindow is good if you want to see the form
  FrmSplash.FormStyle := fsStayOnTop;
  FrmSplash.Position := poScreenCenter;
  FrmSplash.Show;
end;

procedure TfrmSplash.Timer1Timer(Sender: TObject);
begin
  FrmSplash.Close;
  Form1.Show;
end;

Process Listing
Uses tlhelp32.
Code:
procedure ProcessListan;
var
    lstHandle: THandle;
    EntryProc: TProcessEntry32;
begin
  lstHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if lstHandle <> INVALID_HANDLE_VALUE then
    begin
     EntryProc.dwSize:=SizeOf(EntryProc);
     if Process32First(lstHandle, EntryProc) then begin
        Repeat
          writeln(EntryProc.th32ProcessID, '':10, EntryProc.szExeFile);
        Until Not Process32Next(lstHandle, EntryProc);
        CloseHandle(lstHandle);
     end;
  end;
end;

Some window manipulations
This code does various things to the form window.
Code:
procedure TForm1.Button1Click(Sender: TObject);
// removes the icon and option buttons.  Done this way to test doing this with another language that didn't support it
var
  MyWnd: HWnd;
  mySysMenu: DWord;
  Style: Dword;
begin
  { get handle for my window }
  MyWnd := GetForegroundWindow;
  mySysMenu := GetSystemMenu(myWnd, false);
  Memo1.Lines.Clear;
  Memo1.Lines.Add('MyWnd: ' + IntToStr(myWnd));
  Memo1.Lines.Add('Handle: ' + IntToStr(Form1.Handle));
  Memo1.Lines.Add('Menu Handle: ' + IntToStr(mySysMenu));
  Style := GetWindowLong(myWnd, GWL_STYLE);
  Style := Style xor WS_SYSMENU;
  SetWindowLong(myWnd, GWL_STYLE, Style);
  DrawMenubar(myWnd);
  Application.ProcessMessages;
end;

procedure TForm1.HideTitlebar;
// completely hides the title bar
var
  Style: Longint;
begin
  if BorderStyle = bsNone then Exit;
  Style := GetWindowLong(Handle, GWL_STYLE);
  if (Style and WS_CAPTION) = WS_CAPTION then
  begin
    case BorderStyle of
      bsSingle,
      bsSizeable: SetWindowLong(Handle, GWL_STYLE, Style and
          (not (WS_CAPTION)) or WS_BORDER);
      bsDialog: SetWindowLong(Handle, GWL_STYLE, Style and
          (not (WS_CAPTION)) or DS_MODALFRAME or WS_DLGFRAME);
    end;
    Height := Height - GetSystemMetrics(SM_CYCAPTION);
    Refresh;
  end;
end;

procedure TForm1.ShowTitlebar;
// shows the title bar.  Undoes "HideTitleBar"
var
  Style: Longint;
begin
  if BorderStyle = bsNone then Exit;
  Style := GetWindowLong(Handle, GWL_STYLE);
  if (Style and WS_CAPTION) <> WS_CAPTION then
  begin
    case BorderStyle of
      bsSingle,
      bsSizeable: SetWindowLong(Handle, GWL_STYLE, Style or WS_CAPTION or
          WS_BORDER);
      bsDialog: SetWindowLong(Handle, GWL_STYLE,
          Style or WS_CAPTION or DS_MODALFRAME or WS_DLGFRAME);
    end;
    Height := Height + GetSystemMetrics(SM_CYCAPTION);
    Refresh;
  end;
end;

procedure TForm1.Button5Click(Sender: TObject);
// disables the close button.  Some other options specified below which will work here too.
var
  mySysMenu: DWord;
begin
{ Const SC_SIZE As Int32 = &HF000
  Const SC_MOVE As Int32 = &HF010
  Const SC_MINIMIZE As Int32 = &HF020
  Const SC_MAXIMIZE As Int32 = &HF030
  Const SC_CLOSE As Int32 = &HF060
  Const SC_RESTORE As Int32 = &HF120
  Const MF_BYCOMMAND As Int32 = &H0
  Const MF_SEPARATOR As Int32 = &H800 }

  mySysMenu := GetSystemMenu(Form1.Handle, false);
  EnableMenuItem(mySysMenu, SC_CLOSE, MF_DISABLED);
  DrawMenuBar(Form1.Handle);
end;

procedure TForm1.Button6Click(Sender: TObject);
// enables the close button.
var
  mySysMenu: DWord;                              
begin
  mySysMenu := GetSystemMenu(Form1.Handle, false);
  EnableMenuItem(mySysMenu, SC_CLOSE, MF_ENABLED);
  DrawMenuBar(Form1.Handle);
end;

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Wow, thanks for sharing. The 3rd one looks a little familiar... That's some really nice stuff you got there, I'm sure anyone can make use out of it.

JD Solutions
 
I couldn't help but to notice your splash screen example. That may be fine in some cases, but remember, one of the purposes of a splash screen is to have something to show while the application is busy loading - thus appearing responsive.

With that being said, there is a way to create and show a form before the main form is even created...

1 - Create a new custom form, and remove from application's auto-create.
2 - Put this code into your application's unit:

Code:
program ApplicationUpdater;

uses
  Forms,
  uUpdateMain in 'uUpdateMain.pas' {frmMain},
  UpdateCommon in 'UpdateCommon.pas',
  uSplash in 'uSplash.pas' {frmSplash};

{$R *.res}

var
  Spl: TfrmSplash;

begin
  Application.Initialize;
  Spl:= TfrmSplash.Create(nil);  //Don't use CreateForm, but create it traditionally
  try
    Spl.Show;  //Show the form and bring it to the front
    Spl.BringToFront;
    Application.ProcessMessages;  //Forcefully show
    Application.CreateForm(TfrmMain, frmMain);
  finally
    Spl.Free;  //Hide and free before the application starts
  end;
  Application.Run; 
end.


JD Solutions
 
The splash screen you mentioned above is ideal for simply showing something to make your program look cool on startup. However, the example I just posted is meant for when your program may take a while to load and needs to show something in the mean-time. Once everything's loaded and ready to go, the splash screen is hidden right before the main form shows.

JD Solutions
 
The only down-side to the method I posted actually is that you can't post back to it - meaning good luck trying to post the loading status or anything from the main form to the splash form... I've tried and failed, but there must be a way...

JD Solutions
 
The only down-side to the method I posted actually is that you can't post back to it - meaning good luck trying to post the loading status or anything from the main form to the splash form... I've tried and failed, but there must be a way...

that's why I create my splash form from the FormCreate event of my startup form.

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
The question is how to efficiently and appropriately hide the main form? And when I tried to create the splash screen during the FormCreate event, it tries to treat the splash screen as the main form. It's sloppy the way I have it now, and the splash screen is also a login screen as well, so if the login fails and it closes, you still see the main screen flash for a second.

JD Solutions
 
easy,

set your main form visible property to false and add this to your DPR source:

Application.ShowMainForm:=False;

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top