Page 1 of 1

TRichView Multiple Thread Problem

Posted: Tue Apr 08, 2008 6:02 pm
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?

Posted: Wed Apr 09, 2008 6:04 am
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.)

Posted: Tue Oct 21, 2014 1:14 pm
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

Posted: Tue Oct 21, 2014 1:22 pm
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?

Posted: Tue Oct 21, 2014 1:27 pm
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;

Posted: Tue Oct 21, 2014 1:30 pm
by mohsen24000
Then : Table.Cells[row,0].AddHotPictureTag(...)

Posted: Tue Oct 21, 2014 1:36 pm
by mohsen24000
Preparing data for this table needs generating data in TRichView, but TRichViewEdit must have a parent.
Otherwise I'll do it.

Posted: Tue Oct 21, 2014 1:43 pm
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;

Posted: Tue Oct 21, 2014 1:59 pm
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);

Posted: Wed Oct 22, 2014 9:33 am
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?

Posted: Wed Oct 22, 2014 12:39 pm
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.

Posted: Wed Oct 22, 2014 1:58 pm
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.

Posted: Wed Oct 22, 2014 3:13 pm
by mohsen24000
How pass cells to thread in order to generating contents!?

Posted: Wed Oct 22, 2014 3:54 pm
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.