TRzPageControl: Dynamic images on the tabs or their positions to use elsewhere

Home Forums Konopka Signature VCL Controls (formerly Raize Components) TRzPageControl: Dynamic images on the tabs or their positions to use elsewhere

Viewing 4 reply threads
  • Author
    Posts
    • #2417
      Patrick Marten
      Participant

        Greetings,

        I’m looking for a way to display “dynamic” images on the tabs of a TRzPageControl. By dynamic images I mean images with dynamic text set at runtime. The goal is to display a count of certain data for each tab.

        First I found an article where someone exported each image from the imagelist assigned to the PageControl as bitmap and used bitmap.canvas.textout to draw a text on that image and then replaced the old image in the imagelist with the new one. This worked to some extent, but not in the way I would like it to be. The text was always white, although I set it to black as in the article. It also was always bold and looked somehow stretched or whatever – not usable in the end.

        Then I wanted to give the DevExpress’ UI Adorner badgets a try. It’s much easier to create such a badge and it looks fine, but they need to be positioned manually and for this I need the position and the size of each tab – not the client area of each tab, but the tab itself.

        I’ve tried to use TRzPageControl.OnPaintTabBackground event. The ARect parameter seems to provide the info I need, but once I do something here, the page control – or rather the tab area – looks broken. No idea why. I don’t change anything on the tabs or pagecontrol. I just access ATabIndex and ARect to determine the the text to be displayed and the position of the badge.

        I also call

        ACanvas.FillRect(ARect);
        Handled := True;

        at the end, but it’s more or less the same without those two lines or without the first one.

        Then I wanted to try to store the data from ARect in a private variable for each tab and use those elsewhere outside of the TRzPageControl.OnPaintTabBackground event, but the event is firing “too late”.

        Is there a way to access the position / size info of the tabs at runtime regardless of the said event at the timeI choose, i.e. after everything has been drawed?

        Or maybe is there another way to accomplish what I need, that I didn’t think of?

         

        Best regards,

        Patrick

      • #2421
        Ray Konopka
        Keymaster

          Hi Patrick,
          I’m not entirely sure what you are trying to accomplish. The first thing that comes to mind is why not just use the built in support for displaying images on each tab? That is, drop a TImageList onto the form and then populate the image list with the images you want to display. You can dynamically add images to an image list at runtime if necessary. Then assign the image list instance to the TRzPageControl.Images property. Then for each TRzTabSheet, you can set the ImageIndex property to display the image. There are other Image**** properties that can be used to control the position of the image as well.

          Ray

        • #2422
          Patrick Marten
          Participant

            Hi Ray,

            as I said, I’m looking for a way to display images with dynamic text set at runtime.

            For instance a main record has several subrecords related to it. When I select that main record (its details are on a TRzTabSheet), I would like to inform the user, that there are X sub records stored for that main record.

            The count of the sub records per main record can be different. One has 5, one has none, one has 20 etc.

            The easiest would be to just set the tab caption to something like “sub records: X”, but I would like to make it more eye catching by using tab images. I am aware of the possibilities you have described, but the problem is the varying number of sub records to display on the image. I would have to add one image for each possible number of sub records, which doesn’t make sense, because there is no limit.

            So I was looking for a way to either “paint” the number as text onto an image that just serves as background, so to speak = combination of an image and a dynamic text on it. This didn’t work properly as described above, so I wanted to use DevExpress UI Adorner badges to display those images, but in order to position them correctly on the TRzTabSheets, I need appropriate position and size of each tab. The only way to access that info seems to be the TRzPageControl.OnPaintTabBackground event, but once I put some code there, to obtain the number of sub records to display and to position the badges, the painting seems to be interrupted and the tabs look “ugly” or “not finished”, although I only read the info of ARect without to change anything PageControl / TabSheet related.

            If I just store the info of ARect in a private variable in the TRzPageControl.OnPaintTabBackground event, the painting is not affected, it seems, but the problem here is, that all my code to position the  badges is executed before that event and the only way to get it to work is to execute a TTimer instead of calling my code directly, which executes my code with some delay.

            That’s why I was wondering, if it’s possible to access the same data as in ARect in the TRzPageControl.OnPaintTabBackground outside of this event. Or alternatively if there is a better way to paint a text onto the image of a TabSheet.

          • #2449
            Ray Konopka
            Keymaster

              Hi,
              Instead of trying to adorn the display of the tab with a separate image, what about changing the image that is referenced by the image list. For example, I created a new test project by dropping a TRzPageControl onto the main form. I then added 3 tab sheets. I then dropped a TImageList component onto the form. I then set the RzPageControl1.Images property to ImageList1. I then added an image to the image list. And next, I set the ImageIndex for the first tab so that the image in the image list was visible on the tab.
              Next, I dropped a TRzButton on the form and created an OnClick event handler:

              procedure TForm2.RzButton1Click(Sender: TObject);
              var
                B: TBitmap;
                R: TRect;
              begin
                R := Rect( 0, 0, 16, 16 );
                B := TBitmap.Create;
                B.Width := 16;
                B.Height := 16;
                B.Canvas.Brush.Color := clRed;
                B.Canvas.Pen.Color := clWhite;
                B.Canvas.Pen.Width := 1;
                B.Canvas.Rectangle( R );
                B.Canvas.Font.Color := clWhite;
                B.Canvas.Brush.Style := bsClear;
                B.Canvas.TextRect( R, 2, 2, '23' );
                ImageList1.Replace( 0, B, nil );
              end;

              The event handler creates a new image dynamically and then replaces the image in the image list. So, when you click on the button, the image for the first tab shows 23 in an image.
              Ray

            • #2468
              Patrick Marten
              Participant

                Hi Ray,

                thank you for the example. As I said in my initial post, that’s something I’ve tried first – well, it’s similar. This approach is somewhat limited.

                In my attempt I had a round image with a transparent background and some gradient in the ImageList (one that is being used in other places of the application). I then was “exporting” the bitmap, then using it’s canvas to draw the text and thenreplacing the image in the ImageList with the new one.

                This worked to some extent, but not in the way I would like it to be. The text was always white, although I set it to black as in the article. It also was always bold and looked somehow stretched or whatever and the transparency was gone – not usable in the end.

                Plus this also affects the height of the tab / tab sheet, while UI adorner don’t.

                Using your example, I would “lose” the look of the original image as well, but that aside, I can’t draw a rounded rect for some reason. Modified code:

                procedure TForm2.RzButton1Click(Sender: TObject);
                var
                  B: TBitmap;
                  R: TRect;
                  S: string;
                begin
                  R := Rect( 0, 0, 16, 16 );
                  B := TBitmap.Create;
                  B.Width := 16;
                  B.Height := 16;
                  B.Canvas.Brush.Color := clRed;
                  B.Canvas.Pen.Color := clWhite;
                  B.Canvas.Pen.Width := 1;
                  //B.Canvas.Rectangle( R );
                  B.Canvas.RoundRect( R, 8, 8 );
                  B.Canvas.Font.Color := clWhite;
                  B.Canvas.Brush.Style := bsClear;
                  S := '23';  
                  //B.Canvas.TextRect( R, 2, 2, '23' );
                  B.Canvas.TextRect( R, S, [tfCenter] );
                  ImageList1.Replace( 0, B, nil );
                end;
                
                

                With B.Canvas.RoundRect( R, 8, 8 ); only, there is no image visible. Only if I do both lines:
                B.Canvas.Rectangle( R );
                B.Canvas.RoundRect( R, 8, 8 );
                I see the image again, but with the first one (rectangle) being in the background of the second one. Tried different values for the radius and also Ellipse instead of RoundRect.

                Couldn’t find an explanation on the internet.

            Viewing 4 reply threads
            • You must be logged in to reply to this topic.