Board index » cppbuilder » How to draw onto standard controls like TMemo?

How to draw onto standard controls like TMemo?

Is there a way to draw onto some standard control like the TMemo?
For example if I'd like to create a custom control derived from
TMemo and would like to draw a custom border? What would I do? I
would disable the default TMemo border and draw an alternate one.
But how do I draw onto the control?

Thanks in advance,
Jim.

 

Re:How to draw onto standard controls like TMemo?


Use a MESSAGE_MAP to intercept WM_PAINT messages, and associate a
TControlCanvas to the TMemo for the actual painting.

Gambit

Quote
"Jim Steele" <j...@codeland.org> wrote in message

news:Xns9114994F74063JimAtCodeLand@207.105.83.65...
Quote
> Is there a way to draw onto some standard control like the TMemo?

Re:How to draw onto standard controls like TMemo?


Hi Remy,

thanks for your quick answer. First off sorry for posting this
into the wrong newsgroups. I should have posted this message
in .vcl.writing.

There is still another small problem I have. I now assigned a
TControlCanvas (equals to getting the DC for a handle, right?)
for my TMemo descendant within its constructor. I intercepted
the WM_PAINT message and I draw an black rectangle somewhere
on the control.

This results in heavy flickering and in high system load.
That high that the BCB component panel turns grey until it
receives another paint message. When I try to compile an
application using the new component BCB hangs (because of
the high system load?).

The flickering is surely a result of the default WM_PAINT
handler that is called afterwards (so I could intercept the
WM_ERASEBKGND), but I have no clue why it produces such a
high workload.

Thanks in advance,
Jim.

Quote
> "Remy Lebeau" wrote:

> Use a MESSAGE_MAP to intercept WM_PAINT messages, and associate a
> TControlCanvas to the TMemo for the actual painting.

> Gambit

Re:How to draw onto standard controls like TMemo?


Quote
"Jim Steele" <j...@codeland.org> wrote in message

news:Xns9114E61D53FD9JimAtCodeLand@207.105.83.65...

Quote
> thanks for your quick answer. First off sorry for posting this
> into the wrong newsgroups. I should have posted this message
> in .vcl.writing.

Yes, that would be a better place if you're writting a component

Quote
> The flickering is surely a result of the default WM_PAINT
> handler that is called afterwards (so I could intercept the
> WM_ERASEBKGND), but I have no clue why it produces such a
> high workload.

Can't answer that without a sample of your code that causes the problem.

Gambit

Re:How to draw onto standard controls like TMemo?


"Remy Lebeau" <gambi...@gte.net> wrote in <3b97e4fe$1_1@dnews>:

Quote

>"Jim Steele" <j...@codeland.org> wrote in message
>news:Xns9114E61D53FD9JimAtCodeLand@207.105.83.65...

>> The flickering is surely a result of the default WM_PAINT
>> handler that is called afterwards (so I could intercept the
>> WM_ERASEBKGND), but I have no clue why it produces such a
>> high workload.

>Can't answer that without a sample of your code that causes the problem.

Here's some code:

In header file:

class PACKAGE TMyMemo : public TMemo
{
protected:
    ...
    TControlCanvas *FCanvas;
    ...
    virtual void __fastcall WndProc(Messages::TMessage &Message);
    ...

public:
    __fastcall  TMyMemo(TComponent *Owner);
    __fastcall ~TMyMemo();
    ...

...

Quote
};

In source file:

// ctor
__fastcall TMyMemo::TMyMemo(TComponent *Owner)
    : TMemo(Owner)
{
    // not used at the moment
    // ControlStyle = ControlStyle << csOpaque;

    // somehow this does not work
    ControlStyle = ControlStyle << csAcceptsControls;

    // create control canvas
    FCanvas          = new TControlCanvas;
    FCanvas->Control = this;

Quote
}

// dtor
__fastcall TMyMemo::~TMyMemo()
{
    if (FCanvas != NULL) delete FCanvas;

Quote
}

// overridden window proc
void __fastcall TMyMemo::WndProc(Messages::TMessage &Message)
{
    switch (Message.Msg)
    {
        case WM_PAINT:
            if (FCanvas) {
                FCanvas->Pen->Color = clBlack;
                FCanvas->Rectangle(10,10,100,100);
            }
            break;

        default:
            TMemo::WndProc(Message);
    }

Quote
}

That's all.

Thanks,
Jim.

Re:How to draw onto standard controls like TMemo?


Hi Jim,

I think I know what your intentions might be.  To draw a background image or
watermark in a memo field etc.  I tried doing that except I had a problem
with the caret.  Everytime it blinked, it would cause a redraw, and hence
your heavy flickering that you experience.  This is the high workload.

Problem you are experiencing at design time is related to this I believe,
and you need to check for csDesigning state for the component and ONLY draw
the rectangle at run-time.

Hope that helps,

Brent

The fact that I

Re:How to draw onto standard controls like TMemo?


"Brent" <b.kni...@NOSPAM.mcauley.acu.edu.au> wrote in <3b97f7a8_2@dnews>:

Hi Brent,

thanks for the hint. It really helped. The disadvantage is
that it is no more wysiwyg editing within the IDE :-)

Quote
> Everytime it blinked, it would cause a redraw.

Mmm, _my_ control does not redraw at all when the caret blinks.
But whenever I enter some text in the memo it disturbs the rect
that I have drawn. Same with bitmaps, etc. - I tried to Invalid
ate() the control every time the user changes it, presses a key,
and/or uses the mouse to do something. That worked, but it is
surely _not_ a nice solution.

Something else: I've seen code for a transparent memo. What do you
think about the idea to use a TCustomPanel as base class for my
custom memo and to dynamically create a transparent TMemo within my
control's c'tor? If my brain isn't totally screwed yet it should be
possible then to draw to the TCustomPanel's canvas without having
problems with the memo itself. But it would take some more memory ...

Thanks,
Jim.

Re:How to draw onto standard controls like TMemo?


First thing you're missing is that you have to return 0 to let Windows know
that you processed the WM_PAINT message, otherwise it'll end up going to the
default handler and being processed a second time.  That might be why it's
flickering.

Second, now that I experiment with your code, I see WM_PAINT is not a good
message to intercept, unless you're willing to draw the text itself as well,
that that can get pretty involved.  WM_ERASEBKGND is better.  However, I
notice that by setting BorderStyle = bsNone, the text is drawn starting at
(0, 0), and it's drawn with a solid background that I can't get rid of, thus
the sections of the border that the text is over will be lost.  I'm sure
that's not the effect you're looking for.  Also, I notice that when clicking
on the memo, then onto the form, the text in the memo gets painted over
completely.

I see you mentioned you have code for a transparent Memo.  Your idea for
that is certainly an option.

Gambit

Quote
"Jim Steele" <j...@codeland.org> wrote in message

news:Xns9114EDE4A1BA2JimAtCodeLand@207.105.83.65...

Quote
> Here's some code:

<snip>

Re:How to draw onto standard controls like TMemo?


Quote
>First thing you're missing is that you have to return 0
>to let Windows know that you processed the WM_PAINT message

Ahh, okay.

Quote
>drawn starting at (0, 0), and it's drawn with a solid
>background that I can't get rid of,

Right. It seems to me that the control window is
recreated with new window params.

Quote
>I see you mentioned you have code for a transparent Memo.
>Your idea for that is certainly an option.

Okay, I'll try. It is just Delphi code, but I think
I'm able to port it ;-)

If you're interested here is the URL to the code I mentioned:

http://www.efg2.com/Lab/Library/UseNet/2000/1129a.txt

Thanks,
Jim.

Re:How to draw onto standard controls like TMemo?


Quote

>> Okay, I'll try. It is just Delphi code, but I think
>> I'm able to port it ;-)

I ported it and it flickers terribly :\

However I tried to change my component a bit and base it on
a TCustomPanel. The TMemo that is displayed inside the panel
is created dynamically within the constructor. Now BCB keeps
telling "Component '' has no parent". I created the memo as
follows (in constructor):

FMemo = new TMemo(this); // 'this' = TCustomPanel
FMemo->Left = 0;
FMemo->Top = 0;
FMemo->Right = Width - 1;
FMemo->Bottom = Height - 1;
FMemo->Visible = true;
...

Referring to the TMemo in a TCustomPanel container:
Is there a way to publish the TMemo's properties as properties
of the new component? At the moment I'd have to access - for
example - MyMemo1->Memo->Lines->Strings[0] and I'd like to
change this to MyMemo1->Lines->Strings[0]. Do I have to re-
publish each property?

My questions might sound extremely stupid, but though I hope
asking is still okay ;-) Please tell me if I overstep the point
at which it is difficult to stand pain :-)

Thanks,
Jim.

Re:How to draw onto standard controls like TMemo?


Hi Jim,

The Transparent Memo sounds really cool.  Do you still have or know where
the code is?  I have an idea of how to create a transparent control (maybe)
and I might do that later in the year.

Using transparent controls certainly sounds better than what I tried to do
once.  Place images (TPaintBox etc) ontop of a TMemo.  Didn't work to well.

Cheers,

Brent

Re:How to draw onto standard controls like TMemo?


Hi Jim,

The Parent is where the component is going to be placed.  Without a parent,
the component does not know where it is supposed to go.

FMemo = new TMemo(this); // 'this' = TCustomPanel

signifies that this (TCustomPanel) owns the Memo control.  It will be
responsible for destroying the Memo when the Panel is deleted.

HTH,

Brent

Re:How to draw onto standard controls like TMemo?


"Brent" <b.kni...@NOSPAM.mcauley.acu.edu.au> wrote in <3b982dcd_1@dnews>:

Quote
>The Parent is where the component is going to be placed. Without a
>parent, the component does not know where it is supposed to go.

Yes, i know. But why do I get this error message
when I properly write:

FMemo = new TMemo(this); // 'this' = TCustomPanel

Quote
>signifies that this (TCustomPanel) owns the Memo control.

Yes. So there should be no problem then, normally.

Thanks,
Jim.

Re:How to draw onto standard controls like TMemo?


"Brent" <b.kni...@NOSPAM.mcauley.acu.edu.au> wrote in <3b982dcd_1@dnews>:

Oh, sorry. I think I misunderstood. Okay, I set the
'Parent' and it works fine now. Thanks!!

Jim.

Re:How to draw onto standard controls like TMemo?


Because you *forgot* to set the Parent, that's what Brent was trying to tell
you

    FMemo->Parent = this;

Gambit

Quote
"Jim Steele" <j...@codeland.org> wrote in message

news:Xns91153426730B0JimAtCodeLand@207.105.83.65...
Quote
> Yes, i know. But why do I get this error message
> when I properly write:

> FMemo = new TMemo(this); // 'this' = TCustomPanel

Other Threads