0

I would like to declare a TBitmap Globally.

I tried as follows:

Locally within a method, this works fine

std::auto_ptr<Graphics::TBitmap> RenderGraphic(new Graphics::TBitmap());

OR

Graphics::TBitmap * RenderGraphic = new Graphics::TBitmap;

So to declare it globally I tried this in the header file

Graphics::TBitmap *RenderGraphic;

And this in the constructor

__fastcall TShipGraphic::TShipGraphic(TComponent* Owner)
: TForm(Owner)

{

  Graphics::TBitmap * RenderGraphic = new Graphics::TBitmap;

}

Which compiles fine but when running, throws an access violation exception at the first occurrence of

      RenderGraphic->Canvas->Pen->Color = clBlack;

Please advise, tks in advance.

The reference source I was using is C++ Builder Graphics Introduction

which suggested the declaration in the constructor

BarryK
  • 11
  • 5
  • 1
    In the constructor you are declaring and initializing a local variable and not the global variable `RenderGraphic` – Kerem Nov 12 '18 at 12:39
  • Global to what? You got more than one Forms? using `Graphics::TBitmap * RenderGraphic = new Graphics::TBitmap;` in main form cpp somwhere at the top usually works but ... if you are accessing it from different forms it might get duplicated unless you use `static`. Much safer is to have it as a member and share its pointer when ever you need to. The access violation is usually at the start when you are accessing things not yet initialized. We need to know more about architecture of your app ... Hope you are not using threads ... – Spektre Nov 13 '18 at 04:38
  • @Spektra In this instance global across all methods within ONE form. – BarryK Nov 13 '18 at 06:42
  • I placed Graphics::TBitmap * RenderGraphic = new Graphics::TBitmap; near the top of the .cpp, outside of the Constructor, or any other method, and now don't get Access Violation errors, however all my RenderGraphic->Canvas-> statements, like MoveTo, LineTo, Polygon appear to do nothing as no bitmap is drawn to the canvas, when using Canvas->Draw(10, 10, RenderGraphic); and when saving to a .bmp file, the file size is zero. Perhaps this is a different question. – BarryK Nov 13 '18 at 07:06
  • Ok I have worked the bitmap size was probably zero hence nothing appeared. I established this being to draw over an existing bitmap loaded from file. Rendergraphic->SetSize sorts out this problem. But in order to draw transparently over what is already on the form canvas, I still need to first load a bitmap, albeit a plain white one. RenderGraphic->Transparent = true, has no effect unless a bitmap has been loaded from file. Any advise here? – BarryK Nov 13 '18 at 12:50
  • @Spektre, I also don't know where to delete RenderGraphic; . If I do it in the FormClose event, then when using the form again, I will get an Access Violation. – BarryK Nov 13 '18 at 12:51
  • @BarryK if you use `std::auto_ptr` (or `std::unique_ptr` in C++11 and later), you don't need to worry about deleting it at all. But, if you don't use a smart pointer, then use the Form's destructor (not its `OnClose` event) – Remy Lebeau Nov 13 '18 at 20:21
  • @BarryK in order to work with transparency you need to set the transparent color before using Draw ... – Spektre Nov 13 '18 at 22:16
  • @BarryK what I usually do is to have the bmp as a member of main form, create on its constructor , delete in `OnDestroy` , set size in `OnResize` ... You can pass pointer to your bmp to whatever form you got or even use `Application->Tag` for it. Also you can simply check if the bitmap pointer is not `NULL` before its use to avoid access violations ... But as we have no info about your app architecture we can only guess ... hence no usable answers yet. – Spektre Nov 14 '18 at 06:32
  • Many thanks @Spektre, you have in fact answered **all** my questions. I was wanting to `delete` it to clear it, but as answered on another thread, that was not necessary or particularly clever. I am now clearing it with a white `FillRect` and deleting it in the `OnDestroy` event and will look into the smart pointers in future. – BarryK Nov 14 '18 at 08:06
  • @BarryK OKi btw if you want also fast direct Pixel access on the bitmap take a look at: [#4 GDI Bitmap](https://stackoverflow.com/a/21699076/2521214) and look for the `ScanLine[]` usage... – Spektre Nov 14 '18 at 08:57

1 Answers1

0

You need to implement a singleton. Consider read-only case (bitmap is created once, no setter function).

In MyGraphics.h define accessor function

#include <vcl.h>
TBitmap* GetRenderGraphic();

Implementation in MyGraphics.cpp

static std::unique_ptr<TBitmap> renderGraphic(new TBitmap());

TBitmap* GetRenderGraphic()
{
    return renderGraphic.get();
}

Use it (required including of MyGraphics.h)

GetRenderGraphic()->Canvas->Pen->Color = clBlack;
serge
  • 992
  • 5
  • 8
  • Many Thanks @serge . I did as suggested, however I get a linker error [ilink32 Error] Error: Unresolved external 'TShipGraphic::GetRenderGraphic()' referenced from E:\!STAB PROGRAM\BARRACUDA 2018E - SG CODE\BARRACUDA 2018E2\WIN32\DEBUG\OSSSHIPGRAPHIC.OBJ [ilink32 Error] Error: Unable to perform link – BarryK Nov 12 '18 at 13:43
  • `TShipGraphic::GetRenderGraphic()` seems to be not implemented or the implementation is not included in the project. It should be marked as `static` also as you use class method to access static member. – serge Nov 12 '18 at 14:15