Solved

Editable ListBox

Posted on 2011-09-10
8
391 Views
Last Modified: 2012-05-12
I have a code that allows me to edit in ListBox (actually it temporary paces EditBox in front of ListBox) and I would like to have the same "edit" efect on newly added ListBox item. Click on Add button should add new item and place EditBox in front of it.
I'm new to programming and open for any alternatives.
I use Delphi 7.
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
const
  UM_DESTROYCONTROL = WM_USER +333;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    procedure ListBox1DblClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    procedure eDone(Sender: TObject);
    procedure eMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure eKeyPress(Sender: TObject; var Key: Char);
    procedure UmDestroyControl(Var msg: TMessage);
      message UM_DESTROYCONTROL;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//==============================================================================
procedure TForm1.ListBox1DblClick(Sender: TObject);
var
  edt: TEdit;
  rect: TRect;
  lbox: TListbox;
begin
  lbox := (sender as TListbox);
  if lbox.ItemIndex < 0 then exit;
  edt:= TEdit.Create(self);
  edt.BorderStyle:= bsNone;
  rect:= lbox.ItemRect( lbox.itemindex );
  rect.topleft := lbox.ClientToScreen( rect.topleft );
  rect.BottomRight := lbox.clienttoscreen( rect.bottomright );
  rect.topleft := ScreenToClient( rect.topleft );
  rect.BottomRight := screenToClient( rect.bottomright );
  edt.text := lbox.Items[lbox.itemindex];
  edt.setbounds( rect.left+2, rect.top, lbox.clientwidth-2, rect.bottom-rect.top);
  edt.OnExit := eDone;
  edt.OnMouseDown:= eMouseDown;
  edt.OnKeyPress:= eKeyPress;
  edt.Parent := Self;
  SetCapturecontrol( edt );
  edt.SetFocus;
end;
//==============================================================================
procedure TForm1.eDone(Sender: TObject);
var
  dlgBtn: Integer;
begin
  if (Sender as TEdit).Text = '' then begin
    ListBox1.Items.Delete(ListBox1.itemindex);
    PostMessage( handle, UM_DESTROYCONTROL, 0, Integer(Sender));
  end else begin
    ListBox1.Items[ ListBox1.itemindex ] := (Sender as TEdit).Text;
    PostMessage(Handle, UM_DESTROYCONTROL, 0, Integer(Sender));
  end;
end;
//==============================================================================
procedure TForm1.eMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if not PtInrect( (Sender as TControl).ClientRect, Point(X,y) ) then eDone(Sender);
end;
//==============================================================================
procedure TForm1.eKeyPress(Sender: TObject; var Key: Char);
begin
  if Key = #13 then eDone(Sender);
end;
//==============================================================================
procedure TForm1.UmDestroyControl(var msg: TMessage);
begin
  TObject(msg.lparam).Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListBox1.Items.Add('sampleText');
  ListBox1.TopIndex := ListBox1.Items.Count-1;
end;

end.

Open in new window

0
Comment
Question by:3axap
  • 4
  • 2
  • 2
8 Comments
 
LVL 25

Accepted Solution

by:
epasquier earned 500 total points
ID: 36517364
put a list box, a TEdit and a button.
set the TEdit BorderStyle = bsNone

Add an onCreate event for the form to calculate some key values (max elements, drawing offsets)
Add Edit's events :
- onExit : will hide the edit box
- onChange : will update the corresponding listbox item value

Create a new function : ListBoxEdit , parameter i:integer (index of the item to edit). It will :
a) make sure that item is visible and selected
b) put the edit visible and on top of that item, precisely, so that the user can't tell the difference except that it's editable, and of course give it focus

then add a button events to add an item and call the edit function

You're done !
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    ListBox: TListBox;
    Edit: TEdit;
    Button: TButton;
    procedure ButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure EditExit(Sender: TObject);
    procedure EditChange(Sender: TObject);
  private
    { Déclarations privées }
    LbDrawOffset,NbItemsMax:Integer;

    procedure ListBoxEdit(i:integer);
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
Var
 R:TRect;
begin
 // Get maximum of items visible in listbox
 R:=ListBox.ItemRect(0);
 LbDrawOffset:=ListBox.Width-R.Right; // Usualy 4 pixels
 NbItemsMax:=(ListBox.Height-LbDrawOffset) Div ListBox.ItemHeight;
// ListBox.Height:=NbItemsMax*ListBox.ItemHeight+LbDrawOffset; // make the listbox the exact height of NbItemsMax elements
 LbDrawOffset:=LbDrawOffset Div 2;
end;

procedure TForm1.EditExit(Sender: TObject);
begin
 Edit.Visible:=False;
end;

procedure TForm1.EditChange(Sender: TObject);
begin
 ListBox.Items[Edit.Tag]:=Edit.Text;
end;

procedure TForm1.ListBoxEdit(i:integer);
Var
 R:TRect;
begin
 if i>=NbItemsMax then ListBox.TopIndex:=i-NbItemsMax+1;
 ListBox.ItemIndex:=i;
 R:=ListBox.ItemRect(i);
 With Edit do
  begin
   Tag:=i; // Set Edit.Tag to the currently edited index
   Top:=ListBox.Top+R.Top+LbDrawOffset;
   Left:=ListBox.Left+R.Left+LbDrawOffset+2; // add 1 to make both lb text and edit text at the same place
   Width:=R.Right-R.Left-2;
   Height:=R.Bottom-R.Top;
   Text:=ListBox.Items[i];
   Visible:=True;
   SetFocus;
  end;
end;

procedure TForm1.ButtonClick(Sender: TObject);
begin
 ListBoxEdit(ListBox.Items.Add('New')); // Add item, get its index and call edit mode for this item index
end;

end.


// DFM 
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 337
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object ListBox: TListBox
    Left = 8
    Top = 39
    Width = 121
    Height = 81
    ItemHeight = 13
    TabOrder = 0
  end
  object Edit: TEdit
    Left = 144
    Top = 47
    Width = 121
    Height = 13
    BorderStyle = bsNone
    Ctl3D = False
    ParentCtl3D = False
    TabOrder = 1
    Text = 'Edit'
    Visible = False
    OnChange = EditChange
    OnExit = EditExit
  end
  object Button: TButton
    Left = 8
    Top = 8
    Width = 75
    Height = 25
    Caption = 'Button'
    TabOrder = 2
    OnClick = ButtonClick
  end
end

Open in new window

0
 
LVL 36

Expert Comment

by:Geert Gruwez
ID: 36518105
just use a treeview with only top level items
far easier, just set editing = true in options

why make life so difficult ?
0
 
LVL 25

Expert Comment

by:epasquier
ID: 36518298
because it's fun :o)

And maybe also because a TListBox will not have the same look as a TListView, when you select a line in a list box all the line is properly selected, but in the treeview only the text of the node is. I find that not so pretty in some situations
0
 
LVL 25

Expert Comment

by:epasquier
ID: 36518307
besides, I could have made it less complex by putting some constants instead of evaluating the offsets and such.

You only need the EditExit, EditChange, and a simpler ListBoxEdit function to make this work. But for educational purpose I felt necessary to do it right

Of course, Geert, you are right that most of the time it's better to find alternate and quicker solutions to a need, even if that means loose a few unnecessary functionalities. In that way, your solution is effective
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 36

Expert Comment

by:Geert Gruwez
ID: 36518656
epasquier,
looks like you have found some spare time again
0
 

Author Comment

by:3axap
ID: 36518757
I've chosen ListBox because of how it looks (especially with skin I use).
pasquier thank you so much for such complete solution.
0
 

Author Closing Comment

by:3axap
ID: 36518760
I've chosen ListBox because of how it looks (especially with skin I use).
epasquier thank you so much for such complete solution.
0
 
LVL 25

Expert Comment

by:epasquier
ID: 36519031
> looks like you have found some spare time again
yes and no. That one was an easy one, It took me 5 minutes

3axap : thanks, and you got it right the 1st time : pasquier is my name
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now