TRichView Multiple Thread Problem

General TRichView support forum. Please post your questions here
Post Reply
Justin Clayman
Posts: 1
Joined: Tue Apr 08, 2008 5:59 pm

TRichView Multiple Thread Problem

Post by Justin Clayman »

The company I work for recently purchased thesoftware. We are using it primarily as a tool to paint the processed data to a virtual canvas, and than using that data as a bitmap to send raw bitmap data to inkjet printers. We are developing using Builder 6.0 C++.

The application is used in a realtime production environment, were multiple documents might be printed at a given time. There are a variety of other events that occur while running, so each inkjet printer operates in it’s own thread. At Thread creation a TRichView Object is created for each thread, so there is no resource sharing between threads. The event that affects the TRichView is when the next document to print is sent to the thread. At this time we use a variety of CustomRichView controls (AddNL, AddPictureEx, Format, and a variety of changing fonts, line spacing, justification, etc). The end result is that the data is painted onto a canvas which is used to than be send on to the printer from another thread.

Were I am running into problems, is that as the number of printers on a production line grows, the number of TRichView objects grow. I have found that if one TRichView object is being used, we’ll say “Thread for Printer #1” is in the midst of assembling it’s data, and “Thread for Printer #2” begins to receive data, that once both of them begin accessing TRichView calls in their independent TRichView Objects, a thread will exception. As long as Thread #1 finishes first, thread #2 never has this problem.

Is there something I should be looking at?
Sergey Tkachenko
Site Admin
Posts: 17555
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Though TRichView code never change values of global variables or other shared resources, I am afraid that using them in threads must be very limited, because VCL library itself is not a thread safe.
I highly recommend to call all methods allocating and freeing memory or resources (that includes Add***, Format and many other TRichView methods), as well as all drawing methods in the context of the main process, using Synchronize method. And of course, several documents cannot be printed at the same time (because printing uses methods changing global state, such as Printer.BeginDoc/Page, etc.)
mohsen24000
Posts: 75
Joined: Fri Jan 06, 2012 8:13 pm

Post by mohsen24000 »

I have to insert many rows into a table, it's so time consuming.
Is it possible implement with threads!? how?
thanks a lot
Sergey Tkachenko
Site Admin
Posts: 17555
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

If preparing data for this table is time consuming, you can prepare them in threads.
But as for adding rows to the table, I am afraid no, you need to do it in the main process.
However, I believe that not adding rows, but reformatting takes 99% of time.
A large table can be generated very fast, if it is formatted once after preparing.
How do you insert these rows?
mohsen24000
Posts: 75
Joined: Fri Jan 06, 2012 8:13 pm

Post by mohsen24000 »

Table is global variable

Code: Select all

  table := TRVTableItemInfo.CreateEx(NewMsgQry.RecordCount,1,rvchat.RVData);

  table.BestWidth := 0;
  table.ParaNo := -1;
  table.Color := TColor($1FFFFFFF);//clNone ;
  table.BorderVSpacing := 0;
  table.BorderHSpacing := 1;
  table.CellPadding := 0;
  table.BorderWidth := 0;
  table.CellBorderWidth := 0;
  table.BorderStyle := rvtbColor;
  table.CellBorderStyle := rvtbColor;
  table.CellVSpacing:=5;

  rvchat.AddItem('',table);
  rvchat.Format;
mohsen24000
Posts: 75
Joined: Fri Jan 06, 2012 8:13 pm

Post by mohsen24000 »

Then : Table.Cells[row,0].AddHotPictureTag(...)
mohsen24000
Posts: 75
Joined: Fri Jan 06, 2012 8:13 pm

Post by mohsen24000 »

Preparing data for this table needs generating data in TRichView, but TRichViewEdit must have a parent.
Otherwise I'll do it.
mohsen24000
Posts: 75
Joined: Fri Jan 06, 2012 8:13 pm

Post by mohsen24000 »

sample preparing cell's data:

Code: Select all

 ParseString(RVtemp,author+'('+Qry.FieldByName('authorname').AsString+')',1);
  RVtemp.AddBreakEx(2,rvbs3d,0);
  sMSG:= Qry.FieldByName('msg').AsString;
  mtype:= Qry.FieldByName('mtype').AsString;
  if mtype='text' then begin
  ParseString(RVtemp,sMSG,0);
  end else if (mtype='image') or (mtype='video') then begin
      imgstream:= ...
      gr := RV_CreateGraphics(TGraphicClass(TJPEGImage));
      gr.LoadFromStream(imgstream);
      imgstream.Free;
      FRVData.AddHotPictureTag(Qry.FieldByName('id').AsString,gr,0,rvvaBaseline,Qry.FieldByName('url').AsansiString);
      prg:= TProgressBar.Create(nil);
      prg.Width:=gr.Width;
     FRVData.AddControlExTag('',prg,0,rvvaAbsBottom,Qry.FieldByName('id').AsString);
  end;
mohsen24000
Posts: 75
Joined: Fri Jan 06, 2012 8:13 pm

Post by mohsen24000 »

sample preparing cell's data:

Code: Select all

 ParseString(RVtemp,author+'('+Qry.FieldByName('authorname').AsString+')',1);
  RVtemp.AddBreakEx(2,rvbs3d,0);
  sMSG:= Qry.FieldByName('msg').AsString;
  mtype:= Qry.FieldByName('mtype').AsString;
  if mtype='text' then begin
  ParseString(RVtemp,sMSG,0);
  end else if (mtype='image') or (mtype='video') then begin
      imgstream:= ...
      gr := RV_CreateGraphics(TGraphicClass(TJPEGImage));
      gr.LoadFromStream(imgstream);
      imgstream.Free;
      RVtemp.AddHotPictureTag(Qry.FieldByName('id').AsString,gr,0,rvvaBaseline,Qry.FieldByName('url').AsansiString);
      prg:= TProgressBar.Create(nil);
      prg.Width:=gr.Width;
     RVtemp.AddControlExTag('',prg,0,rvvaAbsBottom,Qry.FieldByName('id').AsString);
  end; 
...
RVtemp.SaveRvfToStream(MS);
MS.position:=0;
Table.Cells[ROW,0].Clear;
Table.Cells[ROW,0].InsertRVFFromStream(MS,0,cl,Background,Layout,True,nil);
Sergey Tkachenko
Site Admin
Posts: 17555
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

May be you can prepare data directly in a table cell, without copying?

In your code, I see no formatting of RVTemp. Actually, for building a document and saving to RVF it is not needed. Without formatting, you can use an editor without a parent. Also, you can use TRVReportHelper.RichView, it does not need a parent (and must never be formatted by calling Format)

You end generation of the cell content by calling InsertRVFFromStream? Without formatting the main editor?

rvchat, is it TRichView or TRichViewEdit?
mohsen24000
Posts: 75
Joined: Fri Jan 06, 2012 8:13 pm

Post by mohsen24000 »

rvchat is TRichView.
You end generation of the cell content by calling InsertRVFFromStream?
main editor formats in end of the process and rows inserting.
Sergey Tkachenko
Site Admin
Posts: 17555
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

In this case, I do not know why it is slow.
Ideas:
- do not format RVTemp, or, better, generate the content directly in the table cells
- do not add rows one by one, add all rows at once.
mohsen24000
Posts: 75
Joined: Fri Jan 06, 2012 8:13 pm

Post by mohsen24000 »

How pass cells to thread in order to generating contents!?
Sergey Tkachenko
Site Admin
Posts: 17555
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

I'd suggest to find ways to speed up the code without using threads.

You can pass a cell as any object, but I never tried to add content in the editor in a thread; probably problems are possible if objects are created in one thread and freed in another one.
Post Reply