Jump to content
JohnLM

Is there a way to create a photo capture toobar?

Recommended Posts

I use ms powerpoint to hold and store all my screenshots of various things throughout the day using my main laptop. I especially do this for items I purchase on Amazon and Ebay. 

 

However, on my tablet I cannot do this since I don't have MS Office on it. 

 

So now, I would like to create a rolling image bar that holds/shows all my screenshots made on the tablet and then save them all in one file, like a project.  I want to do something very similar to what powerpoint does, but nothing fancy.  Just a vertical toolbar that holds/shows all images I made.  

 

Is there a component that can help me halfway through this project idea, or can I build something close to what I want to do with the tools/components already built into D11/D12 ?

 

In my vision of such a tool, I have the following: 


1. a panel/toolbar 
2. an timage
3. button to capture the screenshot(s)
4. add/create a new timage in the toolbar every time I take a screenshot (get from cliboard, etc) 
5. scroll up/down inside the toolbar of images that I took thus far 
6. a main timage that shows the screenshot I take
7. and if I click on any of the images in the toolbar, that image will show on the main timage

8. save and load buttons

 

All this in the above steps are basically what I do in ms powerpoint. 

 

1856138356_ImageListEx_Screenshot2024-01-22184422.thumb.png.fc1319281684824c1b0dfd387e3eadd5.png

 

Edited by JohnLM

Share this post


Link to post

Microsoft OneNote is a decent clipping / note taking application if you are already used to Office applications. It is free to download and use with some premium features requiring a Microsoft 365 subscription. 

Share this post


Link to post

Using a TImage for each image will probably consume far to many resources if you have a fair amount of images - or large ones.

 

I would just use a TImageList, a TPaintBox and a TScrollBar:

Store a thumbnail of the images in the imagelist.

Use the scrollbar to control which image(s) to show.

Draw the currently visible image(s) from the imagelist to the paintbox.

  • Like 1

Share this post


Link to post

The images would be coming from the clipboard and would be in the same size dimensions.  For instance, when I am screenshotting Amazon or Ebay, I will take the whole screen, including the bottom statusbar/date/time area for proof of date and time. 

 

The saving part would come after I've finished the screenshot session(s). I would have to figure out how to combine all the images into one, or save them in a zip and Load the zip back into the toolbar list. I haven't quite figured those parts as yet. There are plenty of zip resources to google up. 

 

Not that anyone has brought this up but.. I've never worked with ImageList's. And last I remembered, the images have to be no larger than 32x32 dimensions.  And, I can't just paste from the clipboard into it.  I would have to reduce the size of the clipboard images down to 32x32, save them individually and then load them into the ImageList. So, the ImageList component in Delphi is out of the question. 

 

I am looking in Delphi 12 to see if there are any new image type components. Then I google whatever info I can find on how to use them. 

Share this post


Link to post

Progress. . . 

 

I have made some progress in this project.  I can now: 

 

1. dynamically create a new Image inside a Scrollbox -- I had lots of trouble with this.  At first I was using TPaintbox but border/image would disappear when moving window around.  Now, I am using a TImage instead. It works. 

 

2. and add a border around it - I had trouble figuring that out. also added border around main image, im1. 

 

3. add text to it (showing the component name, i.e., (im1, im2, ... im10 and so on) -- had trouble with aligning text in each image. 

 

4. I can also scroll up/down through the imagelist with the wheelmouse. 

 

796506878_0201_screenshot-progress01-ImageListEx_d12_vcl_w10_v02.thumb.png.aff400486cf8e5c51b6f8127d1e54224.png

 

Next steps:   

 

1. is to get the screenshots into the main image and the image list inside the scrollbox.

 

2.  possibly add a global hot-key -- Using the clipboard I can assign the image to the main image and then pass that on to the *new* image, as if I press the [add] button, but through code.  I am considering adding a global hot-key to this part of the process..., when I screenshot the window or whole desktop screen, add it to the main image and imagelist. 

 

3. when I click on one of the images in the imagelist, to somehow have that image give the illusion of setfocus or something.  I haven't quiet figure on a solution yet. Maybe make the border around the image thicker.  But at the moment, I could not figure that out -- if anyone know how, please explain, thanks. 

 

4. to add a save-all to save all the images into one file. I have not figure that out yet either.  One idea is to use a Zip archive.  But another could be to save all the images into one stream, and then Load the images from the stream back into the imagelist. 

 

The one thing I regret in this topic is the subject title. I should have said, imagelist. Oh well. 

 

Edited by JohnLM

Share this post


Link to post

Point 3. - one option is to use multiple images and display them according to the event

Share this post


Link to post

@Stano - re Point 3:  I have not figured out how to set an event to the TImages yet. I'm having trouble with it. I believe I have to assign an Event to the image each time I dynamically create one. 

 

If I click on IM_2 for instance, nothing happens since there is no event because these images are created dynamically at runtime and I set the .Parent to the Scrollbox. I am still researching this portion.  But once I figure out how, then I can scroll up/down this custom imagelist and mouse-select on the image and that image will get shown on the main image on the left side. 

 

re the Event, or fake wrapper event..

 

What I have tried so far is this: 

 

1. create a very small button, i.e., [:] -- I gave the button .name, btn, and the .caption as '[:]' to make it small and not as noticeable.  

    (If I can't figure out how to write an event to dynamically created TImages, then this button will be hidden later on when it's finally working.)

 

2. in the button's properties, I added an .onClick event

 

3. I write some code in the .onClick event and added code to sound a Beep (for testing purposes, to see which image in the custom imagelist I have clicked on). 

 

Here is some code snippet thus far.  Everything works: (adding images and scrolling up/down in the image list) but the event is not, which is the Button's event at the moment. 

 

var
  Form1: TForm1;
  cnt: integer = 0;
  StepCntr: integer = -105;
  posse: integer = 0;
  im: timage;

implementation

{$R *.dfm}

// add a TImage to the imagelist inside the TScrollbox
// evey time [add] button is clicked, a new TImage is dynamically created and added to the imagelist
// 
procedure TForm1.btnAddClick(Sender: TObject);
begin
  // Note: im (the TImage) var is before the Implementation area.

  // dynamically create single TImage, and assign its .Parent to Scrollbox
  // and assign an .onclick event via a hidden [:] button.
  //
  // use that button's even code (below) to test which .Tag indicates which TImage
  // is clicked on.
  //
  im := timage.Create(self);
  im.Parent := sb1;
  im.OnClick := btn.OnClick;

  // intialize the TImage and calc its placement within the Scrollbox.
  //
  // keep track of the .Tag so we can use that as the indicator for which
  // TImage is clicked on in the imagelist area.
  //
  // The var cnt (or index, is a counter) to hold each TImage as ID (stored in the .Tag propery) so
  // that we can use that in the [:] button's logic to determin which TImage
  // was clicked and call the routine to show *that* image to the main image.
  //
  // the var StepCntr is to calc the image placement. 
  // 
  // And, for the portion of the project, I am writing via .Textout the image
  // name onto the image, so that I can keep track of what I am calling, etc.
  //
  inc(cnt);
  im.Tag:=cnt; // assign it an index no.
  inc(StepCntr, 105+3);
  im.Name   := 'IM_'+intTostr(cnt);  // assign im a name, i.e., IM_1, IM_2, ... IM_10
  im.top    := StepCntr+3;
  im.Left   := 3;
  im.Width  := 105;
  im.Height := 105;
  im.Canvas.TextOut(30, 40, 'IM_'+inttostr(cnt));

  // create border around image in custom imagelist.
  // 
  im.Canvas.Brush.Style := bsClear;
  im.Canvas.Pen.Color   := clBlue;
  im.Canvas.Rectangle(im.ClientRect);
end;

procedure TForm1.btnClick(Sender: TObject);
begin
  // a fake but crude wrapper event to test weather clicking an individual
  // image in the imagelist is working.
  // 
  case im.tag of
    1: begin end;
    2: beep;      // we clicked on IM_2, so produce a audible tone
    3: begin end;
  end;
end;

 

Edited by JohnLM
edited comments

Share this post


Link to post

TVirtualImageList has only three events

  1. OnChange
  2. OnDraw
  3. OnGetBitmap

Unfortunately, neither is suitable for your needs. I don't know if Helper can be applied. Let the knowledgeable comment.

Share this post


Link to post

re building an custom event, or crude wrapper event. . . 

 

I have an idea that might work but it requires me to add an additional parameter to an event for the TButton, recall I gave it the name, 'btn'. 

 

Normally, the .onclick event looks like this: 

 

procedure TForm1.btnClick(Sender: TObject);
begin
end;

To get my idea to possibly work, I will need to add an additional parameter to this, thus making it now look like this: 

 

procedure TForm1.btnClick(Sender: TObject; _tag: integer);
begin
end;

Then, I will write the following code:

 

procedure TForm1.btnClick(Sender: TObject; _tag: integer);
begin
  with TImage(Form1.FindComponent('IM_' + inttostr(_tag))) do begin
    beep;
    // show the imagelist's image that was clicked on, in the main image. 
    image1.picture.assign( TImage(Form1.FindComponent('IM_' + inttostr(_tag))) );
  end;
end

...as a test to see if it does what I am hoping it will do, which is, beep and show the larger image for the main image when a given timage is clicked on in the custom imagelist area. 

 

Thus, the TButton, btn's event will activate, beep and show a larger image for the main image.

 

Again, I know nothing about events and how to create or modify them--unless someone shows me how.  Otherwise, this project will be on hold for a very long time since I have to figure this all out. But if/when I do, I will update this topic. 

 

 

Edited by JohnLM

Share this post


Link to post
22 minutes ago, JohnLM said:

Thus, the TButton, btn's event will activate, beep and show a larger image for the main image.

 

Again, I know nothing about events and how to create or modify them--unless someone shows me how.  Otherwise, this project will be on hold for a very long time since I have to figure this all out. But if/when I do, I will update this topic. 

 

Delphi is strongly typed language you cannot modify the signature of an event. In order to find out which button was clicked you should the sender parameter of onClick:

 

procedure TForm1.btnClick(Sender: TObject);

var

  c : TComponent;
begin

  if Sender is TButton then // <--- the name of the class of the button
  begin

     c:=Self.FindComponent('IM_'+TButton(Sender).Tag.ToString) ;

........

You should never use Form1 inside a method of the TForm1 that's a bad design you're locking the implementation to that one reference instead you can write Self.FindCompoent or leave out self and write FindComponent.

Please try not to use With it's an evil language contruct that has no place in modern code.

 

Edited by Lajos Juhász
c: was converted to smiley.....
  • Thanks 1

Share this post


Link to post

Maybe this will help you:

procedure TForm1.btnClick(Sender: TObject);
begin    
//  if not (Sender is not TImage) then Exit; or
  if Sender is TImage then
  begin   
    var Im := TImage(Sender);
    
    case Im.tag of
      1: begin end;
      2: beep;      // we clicked on IM_2, so produce a audible tone
      3: begin end;
    end;  
  end; 
end;

 

  • Thanks 1

Share this post


Link to post

@Lajos Juhász -- your solution works (thanks) as long as I modify the code as follows:

 

procedure TForm1.btnClick(Sender: TObject);
var
  c: TComponent;
begin
  // -- Lajos 
  c := FindComponent('IM_'+TButton(Sender).Tag.ToString);
  eb1.Text := c.Tag.ToString; // show the tag id (the image clicked)
end;

 

Share this post


Link to post

@Stano -- and your solution works, thanks. 

 

procedure TForm1.btnClick(Sender: TObject);
begin
  if Sender is TImage then begin
    var Im := TImage(Sender);
    eb1.Text := im.tag.ToString;
    case Im.tag of
      1: begin end;
      2: beep;      // IM_2 was clicked, so produce a audible tone
      3: begin end;
    end;
  end;
end;

 

Share this post


Link to post

Thank you to Lajos and Stano for your solutions.  Very appreciated!  I learned something new.  I just wish there was a way to show the progress(s) in action so that you and others can visualize the app in action. 

Share this post


Link to post

If it works for you, then the next step is. 

  1. Change the procedure line TForm1.btnClick(Sender: TObject); to ImageClick(Sender: TObject);
  2. Destroy the button on the form.

Good luck to you.

Share this post


Link to post

@Stano -- it took me a moment, but I got what you meant and took care of it, thanks. 

 

Oh, and I figured out how to make the border around the images thicker, using: image1.Canvas.Pen.Width:=5;

 

 

Share this post


Link to post
15 minutes ago, JohnLM said:

@Stano -- it took me a moment, but I got what you meant and took care of it, thanks. 

I'm glad. 
Now that procedure needs to be placed in the right place within the form. The challenge is to hide it as much as possible from the environment.

Edited by Stano

Share this post


Link to post

Well, I added to the Public section.  I made sure that it was still working (the process), and then I removed that TButton, btn.  I was going to hide the button if I was still going to use it. But now that I am no longer using it, I don't have to hide it.

 

Public
  procedure ImageClick(Sender: TObject);

 

Edited by JohnLM

Share this post


Link to post

I wrote that you should hide the procedure as much as possible. And you put it on display for the world to see:classic_biggrin: You're supposed to proceed from the top down
 

  strict private  
    FSeasonSelect: TSeasonSelect;
  private
  strict protected   
  protected
  public
    property SeasonSelect: TSeasonSelect read FSeasonSelect write FSeasonSelect;

 

Share this post


Link to post
On 1/22/2024 at 10:47 AM, JohnLM said:

I especially do this for items I purchase on Amazon and Ebay. 

Just an idea.

If this is a Chrome page use  https://www.printfriendly.com/

to convert all HTML pages to PDF.

I have an addon for Chrome which I use all the time

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×