
Hello.
Today we will discuss the implementation of the subsystem of issuing information messages to the user. The standard way to inform a user about something is to use the “
Report ” procedure. However, in some cases, I want to create a separate list that will not trash its output with the main list of platform messages. It is also desirable to be able to highlight different messages in color (depending on their type, for example). In general, I will tell you how I did it. The solution given in the article can be embedded in your program without any adaptation.
Prehistory
At one time, while working with the
Perforce version control system, namely with its graphic clients, I noticed a convenient interface element - a multi-line message output field at the bottom of the main program window. After the user made any calls to the server of the system, text messages were added to this field describing the process of interaction between the client and the server (what actions were performed and the result of their execution). I don’t know why Perforce made such an impression on me, although I watched absolutely the same system before and after in various graphic IDEs (Delphi, C ++, etc.) - the message window of that console program (compiler or version control client) ), which serves as a shell graphic program. But however, the article is not about Perforce at all, I just think that a convenient way to multiline output messages in the process of doing some lengthy work. To get a large list of messages is much better (more informative) than a single MessageBox at the very end of this work. By the way, we see a similar approach in antivirus programs.
To create my own message subsystem, I was prompted to implement a program that performs a relatively long data processing process (i.e., the user pressed the “
Run ” button, and then, relatively speaking, can wait for a few minutes while the process is running). Similar programs (processing) are in typical 1C configurations (mainly, these are different unloading-loading). The standard message window of the platform (where the information is displayed by the “
Report ” procedure) did not suit me. I wanted the messages related to my processing to be grouped, and not mixed with any other messages. I also wanted the list of messages to be somehow saved just in case (to a text file, as is done in antiviruses). Well and most importantly, I planned to make different types of messages (information, warnings, error messages). Well, respectively, paint them in different colors.
In this example, the table of the message output (
Tabular field interface element) looks like this:

')
Description of implementation.
In general, I will describe here what happened. For implementation, I will again use my own technology “OOP in 1C” (the method is described in detail
here ). Accordingly, a “class” will be created: “
Messages ”.
In the following explanations, we will assume that we are doing external processing.
We need icons to display message statuses. Let's load from the corresponding BMP-files (are attached to this article) into resources (“Binary data” type layouts)
Picture | Source file name | Layout Name |
---|
 | statok.bmp | PictureMessageStatus |
 | statwarning.bmp | PictureMessageStatusWarning |
 | staterror.bmp | ImageMessageStatusError |
Then you will need to somehow upload these pictures for use - turn them into resources.
In the main module, we define the global variable “Collection of Pictures” in the form of a structure from objects of the standard class “Picture”. We will write the subprogram “Create a Collection of Pictures”, which will initialize the collection. We will call this subroutine in the initialization section of the module.
Also, our messages will have some numeric types - levels. The level number will affect the number of indents from the whitespace characters on the left when displaying a message in the interface or file (as if we clearly show the level of nesting of the messages into each other).
Title | Description | Numerical value |
---|
TIPSOBNG_NEWRED | Indefinite value | 0 |
TIPSOOLER_LEVER1 | Nesting level 1 | one |
TIPSOOLER_LEVER_2 | Nesting level 2 | 2 |
TIPSOOBT_LEVER3 | Nesting level 3 | 3 |
Each message has a specific status indicating what the message is.
Title | Description | Numerical value |
---|
STATSGET_NEWR | Indefinite value | 0 |
STATSMOB_G | Nesting level 1 | one |
STATSMOBSH_PRODUPR | Nesting level 2 | 2 |
STATSGEND_ERVISION | Nesting level 3 | 3 |
Imagine types and statuses as numeric constants, as is done in C / C ++ (
#define ) or Pascal (
const ). In 1C, we will simulate the constants by inserting them into the global variable structure (the key of the structure element is the symbolic name of the constant, and the value of the structure element is the numerical value of the constant).
() = ;
We will also need to get the current time in milliseconds. We use for this the JavaScript machine as a global variable of the COM object.
Here’s what happened in the main module:
A set of messages exists in the form of a table of values ​​(standard Table of Values ​​class) with the following columns:
Column name | Data type | Purpose |
---|
TypeCommun | Number | Message type (level) - one of the constants TIPSOOBSH_ |
StatusMessage | Number | Message status - one of the constants |
Report Text | Line | The main text of the message. Here we usually indicate which action is being performed by a long process at the moment. |
CommentMessage | Line | Additional message text. Here we usually indicate the result of performing the action described in the TextCommon column. If the action failed, then the error message is given in the same column. |
This table of values ​​can already be displayed in some user interface elements (for example, in the
Table Field object).
A set of messages will be implemented as a class with the following methods:
Method header | Description |
---|
Function Messages_Constructor () | The initial creation of the object. Returns an object of the class "Messages". |
Procedure Messages_MostAtrib (Mess, Form, TabField, TabSnach) | Set object attributes. Need to pass: - link to the form (Form), which will display a list of messages; - a form element of the Tabular Field type (Tab Field) in which messages will be displayed; - Table of Values ​​(Tab), in which the actual list of messages will be stored.
|
Message Procedure Initialization (Messag) | A Table of Values ​​will be initialized (previously set by the Messages_Astrib Message procedure) |
Procedure Messages_Update (Messag) | Performs a forced drawing of a list of messages on a form (previously established by the Messages_Atatrib procedure) |
Function Messages_Add (Messaging, MessageType, Message Text, StatusMess = Undefined, CommentComment = Undefined) | Adds a new message to the set with the appropriate attributes. Returns the message identifier with which, this message can be accessed later. |
Message Procedure_Change (Messaging, Message ID, Message Type = Undefined, Message Text = Undefined, Status Message = Undefined, Comment Message = Undefined) | Changes the attributes of an already existing message with the specified id. |
Procedure Messages_Remove (Messag, IDSoobsch) | Delete the previously added message with the corresponding identifier. |
Procedure Messages_Clear (Messag.) | Delete all messages set. |
Function Messages_GetType (Messag., IdSobsch) | Get the attribute "Type" for an existing message with the specified identifier. |
Procedure Messages_InstallType (Messag, IdCommun, TypeCommun) | Set the attribute "Type" for an existing message with the specified identifier. |
Function Messages_ReceiveStatus (Messag., IdA Report) | Get the “Status” attribute for an existing message with the specified id. |
Procedure Messages_InstallStatus (Messag, IdMessages, StatusMessages) | Set the attribute "Status" for an existing message with the specified identifier. |
The function Messages_ReceiveText (Messag., IdMessage) | Get the Message Text attribute for an existing message with the specified id. |
Procedure Messages_InstallText (Messaging, IdMess, TextMess) | Set the attribute "Message text" for an existing message with the specified identifier. |
Function Messages_ReceiveComment (Messag., IdA Report) | Get the attribute “Comment” for an existing message with the specified id. |
Procedure Messages_Install a Comment (Soobs, IdCommun, CommentCommun) | Set the attribute "Comment" for an existing message with the specified identifier. |
Function Messages_ColorText (Message Type, Status Message) | Define the text color for the specified status. Used when coloring messages in the interface. |
MessageColorCommentMessages Function (TypeCommun, StatusMess) | Define the color of the additional text (comment) of the message for the specified status. Used when coloring messages in the interface. |
Function Messages_Picture (TypeCommun, StatusMess) | Define an icon for a message with the specified status. Used when displaying messages in the interface. |
Function Messages_SaveFile (Messaging) | Save a set of messages to a text file (the file name asks the user). |
So, the full text of the main processing module:
Please note that when performing a lengthy process in a loop, the user interface is blocked, and therefore the fact of adding or changing messages will not be visible to the user - no drawing will be made. To force the drawing to work, you must call the Update () method of the form that displays the messages. But the frequent call of this method will slow down the work, therefore, it is necessary to call it only occasionally (albeit with a small interval so that the user does not notice lags - in this implementation, the update interval is no more than once every 0.5 seconds). To implement the update, use the class method Messages_Update .An example of use.
In this example, the form that displays a set of messages looks like this:
Instead of the “ Start Process ” button , in reality there should be something more useful - some kind of user interface. The “ Start Process ” button simulates filling in the list of messages, demonstrating how messages could be displayed during the actual execution of a long-term operation.A table of values - “Messages” was created as the details of the form . We do not initialize it at all, but simply pass as parameters to the corresponding methods of the class “Messages_”, and they are already creating the necessary columns: = _(); _(, , ., ); _();
To display the Table of Meaning "Messages", on the form is placed a visual component of the type " TabularField " - "TabularFieldMessages". When creating columns in the Tabular Field, we take into account the following columns of the Table of Values ​​(described earlier):- TypeCommun ;- StatusMess ;- Text Message ;- CommentMess .The text of the main processing form module (display messages):The form for viewing messages.
There is also a separate window for viewing the list of messages (corresponding to the Table of Values). It is designed so that you can more conveniently analyze a large list (since in the main Tabular dialog box, the message field cannot be stretched much in height - other interface elements will interfere).The form looks something like this:
The code for the form module is quite simple. Here is this:Download the source texts of the message subsystem and the considered example (processing for 1C 8.2) here .That's all. Good luck to all.
See you.PS
In the next article I plan to talk about working with the FireBird server (databases) from 1C.We will find out:- how to properly connect to the server (database) and disconnect;- how to perform requests: send and receive data;- how to work with binary fields and strings in different encoding;- how to call stored procedures and get the results of their work;- how to get around such a nuisance as an automatic disconnection of the client connection from the server side of FireBird (a simple and understandable method, which for some reason is not described anywhere on the Internet).We will create separate and portable sets of subroutines ("classes"):- to connect to the database (we will be able to connect to the server, the database and execute queries);- to work with query parameters (it will be possible to set and set parameters almost as in Delphi);And:
- to work with sets of integers and strings (it is convenient to set multiple parameters for queries);- convenient storage of connection profiles to various FireBird databases, as well as a user interface (form for editing a set of connection profiles)In general, I think it will be interesting. Once again, good luck ...