Sunday, May 14, 2006

Transparent Splash Screen

Transparent Splash Screen As a Modeless Dialog[1]

We would like the splash screen window automatically disappear e.g. after five seconds period. It would be good if an impatient user could close it by a click in the client area.
Moreover it is interesting for the splash screen to be transparent and we could see the current drawing entities under it. Transparency can be reached by Opacity property of the windows created with Windows Forms.

Create a new ObjectARX project named Book16 with the preferences as in the prevoius project[2].

Add book16 LISP function that would be called as ads_book16 C-function defined in acrxEntryPoint.cpp file (see listing 5.34).

Listing 5.34. The ads_book16 function

// Based on:
// N.Poleshchuk, Chapter 05\Book16\acrxEntryPoint.cpp
// In the book "AutoCAD: Application Development, Tuning and// Customization"
// (BHV-Petersburg Publishing House. Russia, 2006)
// ----- ads_book16 symbol (do not rename)
static int ads_book16(void)
acedRetVoid () ;
return (RSRSLT) ;

splash16 will be a managed code function. Add to the project Splash16.h and Splash16.cpp files (declaration and body of the splash16 function) and insert #include "Splash16.h" statement at the beginning of the acrxEntryPoint.cpp file.
The Splash16.h file besides splash16 declaration will contain Wform16 class definition for a dialog box. Code for the Splash16.h file is given in listing 5.35.

Listing 5.35. The Splash16.h file

// Based on:
// N.Poleshchuk, Chapter 05\Book16\Splash16.h
// In the book "AutoCAD: Application Development, Tuning and// Customization"
// (BHV-Petersburg Publishing House. Russia, 2006)
#pragma once
#using <system.drawing.dll>
#using <>

#include "StdAfx.h"
using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;

void splash16();

public __gc class Wform16: public Form
void OnTimerTick(Object *sender, System::EventArgs *ea);
void OnClick(Object *sender, System::EventArgs * ea);

Besides splash16 function prototype the Splash16.h file contains description of a managed class derived from the standard Form class. There are three member functions in the class:

  • Wform16 — Wform16 class constructor;
  • OnTimerTick — function handling the timer event (timer signal);
  • OnClick — function handling the second event (click in the client area of the dialog box).
Splash16.cpp file (shown in listing 5.36) includes all the function implementations.

Listing 5.36. The Splash16.cpp file

// Based on:
// N.Poleshchuk, Chapter 05\Book16\Splash16.cpp
// In the book "AutoCAD: Application Development, Tuning
// and Customization"
// (BHV-Petersburg Publishing House. Russia, 2006)
#include "StdAfx.h"
#include "Splash16.h"

using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace Autodesk::AutoCAD::ApplicationServices;

void splash16()
Wform16* pwf = new Wform16();

// Dialog box parameters
Size = System::Drawing::Size(370, 300);
StartPosition = FormStartPosition::Manual;
Location = Point(300, 150);
BackColor = Color::Aquamarine;
Opacity = 0.5;
FormBorderStyle = FormBorderStyle::None;

// Font
FontFamily *pFf = new FontFamily(L"Arial");
System::Drawing::Font *pFont = new System::Drawing::Font(pFf, 36, FontStyle::Bold);

// Text in the middle of the window
Label *pTxt1 = new Label();
pTxt1->Text = S"Book16";
pTxt1->Location = Point(90, 120);
pTxt1->AutoSize = true;
pTxt1->ForeColor = Color::Black;
pTxt1->Font = pFont;

// Handler of the Click event for the form
this->Click += new EventHandler(this, &Wform16::OnClick);

// Timer creation
System::Windows::Forms::Timer *tm = new Timer();
tm->Interval = 5000; // Signal interval
tm->Tick += new EventHandler(this, &Wform16::OnTimerTick);
tm->Enabled = true;

void Wform16::OnClick(Object *sender, System::EventArgs *e)
// by click close the window

// Reaction to the first (and the last) timer signal
void Wform16::OnTimerTick(Object *sender, System::EventArgs *ea)
System::Windows::Forms::Timer *t1 =
static_cast (sender);
// Timer stop
// Close the window after the first signal

splash16 function creates an instance of the dialog class and opens the splash screen window with the special ShowModelessDialog method in modeless mode. The dialog object is deleted as a result of watching two events: Tick (timer signal) and Click (click inside window but not on the text). Standard event list is reviewed in the next section.

Pic. 5.63 shows splash screen of our application over the current drawing background. The window is opened by the LISP expression (book16), entered in the AutoCAD command line.

Pic. 5.63. Window with transparent splash screen

This transparent window looks like the window being shown while starting AutoCAD session.
Let’s consider window constructor (Wform16::Wform16 function in the Splash16.cpp file). At first window parameters are being defined. The Size, StartPosition, Location and BackColor properties sense is familiar to us from the previous example[3].
The Opacity property sets the opacity ratio. It can take real values from 0 to 1. When 1 — the window is opaque, when 0 — absolutely transparent (and not seen). We use an average value (0.5).

The FormBorderStyle property is set to None that is a member of the FormBorderStyle enumeration. It means that the window has neither frame nor caption (as the AutoCAD splash screen has).

To place an inscription in the center of the window it is necessary to prepare the font. That is why the FontFamily and Font class instances are created. The font is used in the Label class instance which is added by the Add method to the Controls collection of the dialog.
The next constructor text line adds the Click event handler, that is a click inside the form (but not on the text control having its own Click event):

this->Click = new EventHandler(this, &Wform16::OnClick);

Event handler is an object representing the EventHandler class. Using the above text line we connect the object with a delegate (i.e. pointer to the Wform16::OnClick function). This is the function that will be called if event occured.

The Wform16::OnClick function has a very simple body — only Close method is run. That’s why after click inside the form the splash screen closes.

The last four statements in the constructor create a timer with definite features. The timer that issues signals with some frequency is an object of the Timer class. The FCL[4] classes with the same names exist in three namespaces: System.Timer, System.Threading and System.Windows.Forms. In our Book16 project we chose the last class.
When creating a timer at last the two properties should get their values:

  • Interval — time slot, after which the timer signals; the slot is measured in milliseconds, therefore 5000 value corresponds to 5 seconds of the real time;
  • Enabled — timer state; the true value is obligatory to activate the timer object.
The following line creates a handler of the Tick event (timer signals in given time slots):

tm->add_Tick(new EventHandler(this,&Wform16::TimerOnTick));

The first timer signal must be emitted in five seconds after start. This signal also must become the last one: the Wform16::TimerOnTick function stops the timer (Stop method is used) and closes the dialog box.

The timer should be stopped (another way is to set false to Enabled property), else after that garbage collector will free the memory used by the timer.

So in our sample the splash screen appears in a modeless mode (that is we may do some drafting in the document while seeing the splash) and disappears if the user clicks it or five seconds pass after start.

If there is a nonzero probability of launching the second copy of the splash screen then it is useful to add to our program the analysis of our splash screen presence in the main memory (it is sufficient to create a corresponding global variable and to check its value).

Event handling

Adding controls to the form and their event handling were considered in the previous section[5] Book16 sample project. Now we will emphasize some moments. For example we will take the Button control which is a button of our dialog box.
In order to add a button to a dialog we must create a new instance of the corresponding class:

Button *bt = new Button();

After this it is possible to set values to the properties, e.g.: Text, Size, Location, BackGroundImage, BackColor, ForeColor, Font etc. The created object is then included into collection of the form controls:


Each class is connected with many standard events that could be handled programmatically (your own events can be created too). Let’s mention some of the Button control events:

  • BackColorChanged — button background color was changed;
  • Click — there was a click on the button;
  • DragEnter — an object was dragged to the button;
  • ForeColorChanged — text color was changed;
  • GotFocus — button received focus;
  • KeyDown — key was pressed while button had focus;
  • MouseDown — mouse button was pressed when cursor was over the button;
  • MouseUp — mouse button was released when cursor was over the button;
  • VisibleChanged — button visibility state changed (connected with Visible property).
We must create an event callback function that will be called to analyze event parameters and running some actions. Mostly function names look like event names. For example we can expect that for Button object Click event the function name will be OnClick, OnButtonClick or OnBtClick.

Each of the selected events must be connected with the handler that is an object of the EventHandler class. Namely this handler calls necessary function if event occurs.
E.g. if we build for the Click event a handler that should call Wform16::OnBtClick function then the statement for the handler creation in the Wform16 form class constructor body will be as follows:

add_Click(new EventHandler(this, &Wform16::OnBtClick));

Just the same in a more modern manner (using overloaded += operator):

bt->Click += new EventHandler(this, &Wform16::OnBtClick);

Some events (for example Paint) have another form of the same thing:

Paint += new PaintEventHandler (this, OnPaint);

The last form looks like adding event handler in C# language (see chapter 7[6]).
Every callback function receives two arguments: pointer to an object whose event was generated and additional event data. For example:

void Wform16:: OnTimerTick(Object *sender, System::EventArgs *ea)

The first argument has universal System::Object* type therefore while applying we must bring it to the necessary type (use static_cast operator, see listing 5.36).

English Download page is accessible by link

[1] N.Poleshchuk “AutoCAD: Application Development, Tuning and Customization”, pp. 449–455.
[2] The previous project was created with ObjectARX Wizard using .NET mixed managed code support. (Author’s note)
[3] They define the size, coordinates and background color of the window. (Author’s note)
[4] Framework Class Library.
[5] Opaque Splash Screen As a Modal Dialog. (Author’s note)
[6] Chapter 7. Fortran, Delphi, C#, VB etc. (Author’s note)


Anonymous said...

you have a great idea of put this material in web, becouse is very useful, congratullations, buy the way, im trying to replicate this exercise but i have a problem about the use of sentence #using, can you help me with this. this is teh error:

1>c:\documents and settings\evazquez\escritorio\ejemplo splash\book16eng-2005(autocad2007)\StdAfx.h(43) : fatal error C1107: no se encuentra el ensamblado 'acdbmgd.dll': especifique la ruta de acceso de búsqueda del ensamblado utilizando /AI o estableciendo la variable de entorno LIBPATH

thanks in advanced

Ernesto Vázquez

Anonymous said...

very interesting

Fernando Malard said...

Hi Ernesto,

Check your VS Project directories:

- Open your VS2005
- Open Tools > Options
- Go to node Project and Solutions
- Open node VC++ Directories
- On the right side, select Reference files under Show directories for
- Add your ObjectARX inc folder to the list (the same you have used into Include Files option)
- Click OK
- Try to build your project again

This will allow VS2005 to find #using referenced .NET dlls. I prefer to use the ObjectARX version of it instead of the AutoCAD one because it is compatible with the SDK your are using.