views:

184

answers:

3

i used to this on a form and create it like 10 times, that was ok, until i tried to pass this number, it started eating system resources, is there anyway i could create a component like this? it for a Simulator project, 8bits needed to indicate the value of the register in binary

alt text

any help, comments, ideas are really appreciated. ty.

+1  A: 

You have these options, in order of difficulty:

  1. Create a frame, and reuse it
  2. Create a compound control (using maybe a panel, labels and checkboxes). Each control will handle its own keyboard/mouse interaction.
  3. Create a whole new control - all elements are drawn using the proper APIs and all keyboard/mouse interaction is handled by the control code.
ldsandon
If resource usage is an issue, then only option 3 will be any help.
Rob Kennedy
@Rob Kennedy: And I just implemented option 3.
Andreas Rejbrand
+16  A: 

I was slightly bored, and I wanted to play with my new Delphi XE, so I've made a component for you. It should work in older Delphi's just fine.

BitEdit demo app

You can download it here: BitEditSample.zip

How does it work?

  • It inherits from customcontrol, so you can focus the component.
  • It contains an array of labels and checkboxes.
  • The bit number is stored in the "tag" property of each checkbox
  • Each checkbox gets an onchange handler that reads the tag, to see which bit needs to be manipulated.

How to use it

  • It has a property "value". If you change it, the checkboxes will update.
  • If you click the checkboxes, the value will change.
  • Set the property "caption" to change the text that says "Register X:"
  • You can create an "onchange" event handler, so that when the value changes (because of a mouseclick for example), you'll be notified.

The zipfile contains a component, a package, and a sample application (including a compiled exe, so you can try it out quickly).

unit BitEdit;

interface

uses
  SysUtils, Classes, Controls, StdCtrls, ExtCtrls;

type
  TBitEdit = class(TCustomControl)
  private
    FValue         : Byte; // store the byte value internally
    FBitLabels     : Array[0..7] of TLabel; // the 7 6 5 4 3 2 1 0 labels
    FBitCheckboxes : Array[0..7] of TCheckBox;
    FCaptionLabel  : TLabel;
    FOnChange      : TNotifyEvent;
    function GetValue: byte;
    procedure SetValue(const aValue: byte);
    procedure SetCaption(const aValue: TCaption);
    procedure SetOnChange(const aValue: TNotifyEvent);
    function GetCaption: TCaption;
    { Private declarations }
  protected
    { Protected declarations }
    procedure DoBitCheckboxClick(Sender:TObject);
    procedure UpdateGUI;
    procedure DoOnChange;
  public
    constructor Create(AOwner: TComponent); override;
    { Public declarations }
  published
    property Value:byte read GetValue write SetValue;
    property Caption:TCaption read GetCaption write SetCaption;
    property OnChange:TNotifyEvent read FOnChange write SetOnChange;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TBitEdit]);
end;

{ TBitEdit }

constructor TBitEdit.Create(AOwner: TComponent);
var
  I:Integer;
begin
  inherited;
  Width := 193;
  Height := 33;

  FCaptionLabel := TLabel.Create(self);
  FCaptionLabel.Left := 0;
  FCaptionLabel.Top  := 10;
  FCaptionLabel.Caption := 'Register X :';
  FCaptionLabel.Width := 60;
  FCaptionLabel.Parent := self;
  FCaptionLabel.Show;


  for I := 0 to 7 do
  begin
    FBitCheckboxes[I] := TCheckBox.Create(self);
    FBitCheckboxes[I].Parent := self;
    FBitCheckboxes[I].Left   := 5 + FCaptionLabel.Width + (16 * I);
    FBitCheckboxes[I].Top    := 14;
    FBitCheckboxes[I].Caption := '';
    FBitCheckboxes[I].Tag  := 7-I;
    FBitCheckboxes[I].Hint := 'bit ' + IntToStr(FBitCheckboxes[I].Tag);
    FBitCheckboxes[I].OnClick := DoBitCheckboxClick;
  end;

  for I := 0 to 7 do
  begin
    FBitLabels[I] := TLabel.Create(Self);
    FBitLabels[I].Parent := self;
    FBitLabels[I].Left   := 8 + FCaptionLabel.Width + (16 * I);
    FBitLabels[I].Top    := 0;
    FBitLabels[I].Caption := '';
    FBitLabels[I].Tag  := 7-I;
    FBitLabels[I].Hint := 'bit ' + IntToStr(FBitLabels[I].Tag);
    FBitLabels[I].Caption := IntToStr(FBitLabels[I].Tag);
    FBitLabels[I].OnClick := DoBitCheckboxClick;
  end;


end;

procedure TBitEdit.DoBitCheckboxClick(Sender: TObject);
var
  LCheckbox:TCheckbox;
  FOldValue:Byte;
begin
  if not (Sender is TCheckBox) then
    Exit;

  FOldValue := FValue;
  LCheckbox := Sender as TCheckbox;
  FValue := FValue XOR (1 shl LCheckbox.Tag);

  if FOldValue <> FValue then
    DoOnChange;
end;

procedure TBitEdit.DoOnChange;
begin
  if Assigned(FOnChange) then
    FOnChange(Self);
end;

function TBitEdit.GetCaption: TCaption;
begin
  Result := FCaptionLabel.Caption;
end;

function TBitEdit.GetValue: byte;
begin
  Result := FValue;
end;

procedure TBitEdit.SetCaption(const aValue: TCaption);
begin
  FCaptionLabel.Caption := aValue;
end;

procedure TBitEdit.SetOnChange(const aValue: TNotifyEvent);
begin
  FOnChange := aValue;
end;

procedure TBitEdit.SetValue(const aValue: byte);
begin
  if aValue=FValue then
    Exit;

  FValue := aValue;
  DoOnChange;
  UpdateGUI;
end;

procedure TBitEdit.UpdateGUI;
var
  I:Integer;
begin
  for I := 0 to 7 do
    FBitCheckboxes[I].Checked := FValue shr FBitCheckboxes[I].Tag mod 2 = 1;
end;

end.

Resources

I guess the problem that the OP was facing is a feedback loop, where two event handlers call each other.

Other resources don't seem to increase in an unusual way when using more bit editors. I've tested it with an application with many instances of the bit edit component:

Many

             [MANY]      |     [1]
-------------------------+--------------
#Handles                 |   
User       :   314       |          35
GDI        :    57       |          57
System     :   385       |         385
#Memory                  |
Physical   : 8264K       |       7740K
Virtual    : 3500K       |       3482K
#CPU                     | 
Kernel time: 0:00:00.468 |  0:00:00.125
User time  : 0:00:00.109 |  0:00:00.062 
Wouter van Nifterick
So, how's resource usage when there are 10 or more of these controls? *That's* what prompted the question. Does this answer do anything about it?
Rob Kennedy
@Rob: true, true. I've added an extra paragraph about resources.
Wouter van Nifterick
@Wouter: the next time you're *slightly bored*, I'd love to throw some work at you (at the same rate you've used here offcourse).
Lieven
OMG!!!!!!!!! man, ur AMAZING xD, thanks alot, like 10,000 Times :Du saved my day
killercode
+9  A: 
Andreas Rejbrand
Slightly bored?
Sertac Akyuz
@Sertac: Also, I love to build GUIs and dig into Windows API, so it was also a good training exercise.
Andreas Rejbrand
@Andreas - Yep, it figures.. I recall your highly disputed answer about 3rd party components. :)
Sertac Akyuz
its amazing man, small thing, TabStop property not working correctly, u can still use it on the Checkboxesthanks alot, now i got some code to read :D and use :D, and some ppl to credit :D
killercode
with CheckboxRect[i] do begin Top := ((Height - (CheckboxHeight)) div 2) + ((CheckboxHeight + VerticalSpacing) div 2);i think this line will align the caption in the middle of the Checkboxes and Title, but i dunno if this is the best method or not
killercode
@killercode: Yes, I just though it looked better if the numbers were above the label and checkboxes, that share the same line. But you can do as you like.
Andreas Rejbrand
ok, tycan u check the TabStop thing? tab stop is not working for the control when its set to false correctly, but when u click on any check box, it works for the checkboxes no matter whathttp://www.pixhost.org/show/1550/4147431_imge.png (Windows XP)
killercode
@killercode: Now the control will not get focus when clicked if TabStop is false.
Andreas Rejbrand
THANKS ALOT XD XD XD XDMAN, YOU RULE :D
killercode
im deeply sorry, can u tell me how can i add a panel control to it to be abel to display the hex value?, ive been trying to since yesterday and i got totally lost
killercode
killercode, you should really start to accept answers if you find them useful - that's how StackOverflow should work. And it's a way to say thank you to the one who helped you best.
ldsandon
@killercode: Now I added this feature. Set `ShowHex` to true. You might also want to change the `HexPrefix` (for instance, to '0x').
Andreas Rejbrand
ooooooooh, so thats how stackoverflow works, sorry, i didnt know, so all i have to do is to Click that Tick icon under the answer right?
killercode
im sorry, i didnt wanna abuse u anymore, but i cant seem to be abel to do it, im new to the world of API and stuff, here is y i asked the first time for a TPanel control, so i can do this and i wont have to ask u to redesign it, sorry :(, http://www.pixhost.org/show/1423/4154060_look.png, im sure u can see the diffrence, the ones on the left are aligned since its a fixed size TPanel and it looks good, i can understand if u dont wanna do it, i know that its my fault and mine only, thanks for everything :), ill keep trying
killercode
@killercode: OK, now I see what you mean. I have updated the component. To align the controls, set `AutoLabelWidth` to false, and then set `ManualLabelWidth` to the width you want to reserve for the labels. If you just set the same `ManualLabelWidth` of all controls, they will align just fine.
Andreas Rejbrand
@killercode: Now I also added the property `LabelAlignment`, so you can choose if you want to left och right align your label column.
Andreas Rejbrand
hmmmmm, lets say its not perfect.....ITS HEL* MORE THAN PERFECT, THANKS ALOT MAN, i hope there was anything i can do for u incharge :)thanks again, u saved my whole world this time
killercode