Solved

Flickerless coloured text

Posted on 1997-08-30
5
223 Views
Last Modified: 2010-05-18
I want to display a text (Tlabel) and part of letters must have one colour (e.g. blue) and part must have
another colour (e.g. red).

Example:
Situation 1: all letters are red
Situation 2: the leftmost letter is blue, the rest is red
Situation 3: the 2 most left letters are blue, the rest is red
Situation 4: all letters are blue.

About 20 times every second a letter must change its colour, WITHOUT any flickering.
So far, I have tried the following with and without
REPAINT, REDRAW.

I tried using 2 labels (the left label initially empty,
and then growing with 1 letter at the time, while the
second label initially is full, and looses 1 letter at
the time): FLICKERING occurs.

I tried using 1 label with a shape over it, colouring
the letters. The shape initially has a width of zero,
and grows the width of a letters every time:
FLICKERING occurs.

I tried using 1 label with up to ten shapes colouring the
letters (initially all shapes have a width of zero,
and then grow in turn with 1,2,3,4,..or 10 letters width): FLICKERING occurs).


Due to the target of the program: I can't use Canvas.Paint
or at least I rather wouldn't want to do this, because
the label can be anywhere on the screen, and be moved
around at runtime.

I'm totally out of idears.
0
Comment
Question by:Willem083097
  • 3
5 Comments
 
LVL 2

Accepted Solution

by:
icampbe1 earned 200 total points
ID: 1343080
I guess that the best approach would be to set csOpaque in the ControlStyle property.  You can further explore the use of invalidate on changes.  Finally, you can process the WM_ERASEBKGND message and return a non zero (although I'm not sure that descendants of TGraphicControl get that message).  

I believe that setting csOpaquw will do it though.  Hope this helps.

Ian C.

PS:  I think I will write a little component this afternoon to play with the idea.  If it works... its yours.

0
 
LVL 2

Expert Comment

by:icampbe1
ID: 1343081
Ok, ignnore my previous comment.  here is a lable that I named TStateLabel (you can change its state ).  It is a TLabel with two new properties:  HiliteColor and HiliteState.

Hilite color is default Blue but you can change it with this property.
The default text color is Red, but you can change that (Font.Color).
The HiliteState property has the following values:
 hsNone - No hilited characters
 hsOne - the first character
 hsTwo - the first two characters
 hsAll - all hilited.

Just install it on your palette and drop it on your form.  You can set the properties in the IDE or from your program.  I assume that you will mostly want to change the HiliteState property.

NO FLICKER!!!

If I had your E-Mail I would send it that way... Oh well, here it is.

UNIT StateLabel;

INTERFACE

USES
 Windows, Messages, Classes, Controls, Graphics, StdCtrls;

TYPE
  THiliteState = ( hsNone, hsOne, hsTwo, hsAll );

  TStateLabel = CLASS( TLabel )
  PRIVATE
    FHiliteState: THiliteState;
    FHiliteFont:  TFont;
    PROCEDURE SetHiliteColor( AValue: TCOlor );
    FUNCTION  GetHiliteColor: TColor;
    PROCEDURE SetHiliteState( AValue: THiliteState );
    PROCEDURE CMFontChanged( VAR Message: TMessage ); Message CM_FONTCHANGED;
  PROTECTED
    PROCEDURE Paint;  Override;
  PUBLIC
    CONSTRUCTOR Create( AOwner: TComponent );  Override;
    DESTRUCTOR Destroy;  Override;
  PUBLISHED
    PROPERTY HiliteColor: TColor  read GetHiliteColor write SetHiliteColor;
    PROPERTY HiliteState: THiliteState  read FHiliteState write SetHiliteState;
  END;

PROCEDURE Register;


IMPLEMENTATION


CONSTRUCTOR TStateLabel.Create( AOwner: TComponent );
BEGIN
   Inherited Create( AOwner );
   FHiliteFont := TFont.Create;
   FHiliteFont.Assign(Font);
   FHiliteFont.Color := clBlue;

   Font.Color := clRed;
   FHiliteState := hsNone;
END;

DESTRUCTOR TStateLabel.Destroy;
BEGIN
   FHiliteFont.Free;
   Inherited Destroy;
END;

FUNCTION TStateLabel.GetHiliteColor: TColor;
BEGIN
   Result := FHiliteFont.Color;
END;

PROCEDURE TStateLabel.SetHiliteColor( AValue: TCOlor );
BEGIN
   IF FHiliteFont.Color <> AValue THEN BEGIN
      FHiliteFont.Color := AValue;
      Invalidate;
      END;
END;

PROCEDURE TStateLabel.CMFontChanged( VAR Message: TMessage );
VAR Temp: TColor;
BEGIN
   Inherited;
   Temp := FHiliteFont.Color;
   FHiliteFont.Assign(Font);
   FHiliteFont.Color := Temp;
   Invalidate;
END;

PROCEDURE TStateLabel.SetHiliteState( AValue: THiliteState );
BEGIN
   IF FHiliteState <> AValue THEN BEGIN
      FHiliteState := AValue;
      Invalidate;
      END;
END;

PROCEDURE TStateLabel.Paint;
VAR
  Rect: TRect;
  DrawStyle: Integer;
  Text: String;
BEGIN
   Inherited Paint;
   Text := GetLabelText;
   IF FHiliteState <> hsNone THEN
      WITH Canvas DO BEGIN
         Brush.Style := bsClear;
         Rect := ClientRect;
         DrawStyle := DT_EXPANDTABS;
         IF WordWrap THEN DrawStyle := DrawStyle OR DT_WORDBREAK;
         CASE Alignment OF
           taLeftJustify:  DrawStyle := DrawStyle OR DT_LEFT;
           taRightJustify: DrawStyle := DrawStyle OR DT_RIGHT;
           taCenter:       DrawStyle := DrawStyle OR DT_CENTER;
           END;
         IF Layout <> tlTop THEN BEGIN
            DrawText(Handle,PChar(Text),Length(Text), Rect, DrawStyle OR DT_CALCRECT);
            IF Layout = tlBottom THEN
               OffsetRect( Rect, 0, Height-Rect.Bottom )
            ELSE
               OffsetRect( Rect, 0, (Height-Rect.Bottom) DIV 2 );
            END;
         CASE FHiliteState OF
           hsOne:  Text := Copy( Text, 1, 1 );
           hsTwo:  Text := Copy( Text, 1, 2 );
           END;
         Canvas.Font := FHiliteFont;
         DrawText( Canvas.Handle, PChar(Text), Length(Text), Rect, DrawStyle );
         END;
END;


PROCEDURE Register;
BEGIN
  RegisterComponents('Samples', [TStateLabel]);
END;

end.


Have fun  :)

Ian C.
0
 
LVL 2

Expert Comment

by:icampbe1
ID: 1343082
Hi again,

I did a little cleanup on the label.  It now works exactly as it should (including alignments of left, right, center, and enabled etc).  My E-Mail is iancamp@interlog.com, send me a note with your E-Mail address, and I mail it to you instead of posting it.  I've tested it thoroughly and it works just fine.

Ian C.

0
 

Author Comment

by:Willem083097
ID: 1343083
Superb! There are no other words to describe the fast answer
of Ian Campbel.

Using both Delphi 2.0 and since shortly Delphi 3.0, his component
gave a compiler error: stupid me: I was running it under
Delphi 2.0. By the time I found out the reason, Ian had already
send me an email including a 2.0 version.

Thanks a lot Ian!. Excellent answer!.
I will use your component as soon as I figure out how I
can use a integerparameter for setting the number of letters
to be coloured in stead of a predefined hsOne, hsTwo state-
definition (which is not very useful of course when
I want to change the colour of the 134th letter).

BTW: I already discovered that a (loosy) alternative approach is
to use a transparent Tlabel for every letter with a
caption ' x ' where x = the letter. Precalc the width of
solely the x and start the following letter there, minus
the leading space (necessary because e.g. the f and j can
share the same x-coordinates)
Before changing the color, the original width must be retained because the width of e.g. an f in Arial 100 points is wrongly returned when measered on another (invisible) label.
This is both fast and not flickering. It is also not
a very good approach.

Willem
0
 

Expert Comment

by:Shakil
ID: 3332612
If u could write a code to color 134th Char only.

Shakil
0

Featured Post

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

776 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