Page 1 of 1

who can help me?

Posted: Wed Mar 22, 2006 7:17 am
by comeonwh
Hello ,
I have a program that use TRichViewEdit to list info , but run several minutes it show " Raise exception class EInvalidOperation with Message 'Canvas does not allow drawing'". who can help me !
This is my all code:

Main Form code

Code: Select all

unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,SyncObjs, ToolWin, ComCtrls, StdCtrls, ImgList,UwriteThread,UreadThread,
  RVStyle, RVScroll, RichView, RVEdit, CRVFData;

type
  TMainForm = class(TForm)
    ToolBar1: TToolBar;
    ImageList1: TImageList;
    ToolButton1: TToolButton;
    ToolButton2: TToolButton;
    ToolButton3: TToolButton;
    RichViewEdit1: TRichViewEdit;
    RVStyle1: TRVStyle;
    Label1: TLabel;
    ImageList2: TImageList;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure ToolButton3Click(Sender: TObject);
    procedure ToolButton1Click(Sender: TObject);
    procedure ToolButton2Click(Sender: TObject);
    procedure RichViewEdit1Jump(Sender: TObject; id: Integer);
  private
    { Private declarations }
  public
   { Public declarations }
   Function MakeTag(s:String):Integer;
   function GetTagStr(tag:integer):string;   //»сИЎ±кЗ©ПВµДЦµЈ¬
  end;

type
  myInfo = class
    id:integer;
    name:string;
end;

var
  MainForm: TMainForm;
  GLogCS: TCriticalSection;
  aList:TList;
  Twrite:writeThread;
  Tread:readThread;

implementation

{$R *.dfm}


procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
   aList.Clear;
   FreeAndNil(GLogCS);
   FreeAndNil(aList);
   Action:=caFree;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  RichViewEdit1.Clear;
  RichViewEdit1.Format;
  GLogCS := TCriticalSection.Create;
  aList:=TList.Create;
end;

procedure TMainForm.ToolButton3Click(Sender: TObject);
begin
  if Tread <> nil then
     Tread.Terminate;
  if Twrite <> nil then
     Twrite.Terminate;
   close;
   Application.Terminate;
end;

procedure TMainForm.ToolButton1Click(Sender: TObject);
begin
  try
    if Tread = nil then
      Tread:=readThread.Create(aList)
    else
      Tread.Resume;

    if Twrite = nil then
       Twrite:=writeThread.Create(aList,RichViewEdit1)
    else
       Twrite.Resume;
  except
     if Twrite <> nil then
       Twrite.Terminate;
     Twrite:=writeThread.Create(aList,RichViewEdit1);
  end;
end;

procedure TMainForm.ToolButton2Click(Sender: TObject);
begin
  if Tread <> nil then
     Tread.Suspend;
  if Twrite <> nil then
     Twrite.Suspend;
end;

function TMainForm.MakeTag(s: String): Integer;
begin
  Result := Integer(StrNew(PChar(s)));
end;

function TMainForm.GetTagStr(tag: integer): string;
var i: Integer;
begin
  Result := PChar(tag);
  for i := 1 to Length(Result) do
    if Result[i]=#1 then
      Result[i] := ' ';
end;

procedure TMainForm.RichViewEdit1Jump(Sender: TObject; id: Integer);
  var
   RVData: TCustomRVFormattedData;
   ItemNo: Integer;
   i:integer; 
   hideInfo:string; 
begin 
   RichViewEdit1.GetJumpPointLocation(id,Rvdata,itemNo);
    
   if RVData<>nil then begin 
      hideInfo := GetTagStr(RVData.GetItemTag(ItemNo));
      RichViewEdit1.ReadOnly := false;

      RichViewEdit1.SetItemTextEd(ItemNo,'ХвКЗТюІШєуµДРЕПўЈє'+hideInfo);//¶ЇМ¬ЙиЦГПФКѕµДРЕПўОЄТюІШµДРЕПўДЪИЭ

      RichViewEdit1.ReadOnly := true;
      RichViewEdit1.Refresh;

  end;
end;

end.
write thread code

Code: Select all

unit UwriteThread;

interface

uses
  Classes,SysUtils, StdCtrls, RVEdit, RVStyle,Graphics;

type
  writeThread = class(TThread)
  private
    writeList:TList;
    RichViewEdit: TRichViewEdit;
  protected
    procedure writeToMemo;
    procedure Execute; override;
  public
    constructor Create(strList:TList;me:TRichViewEdit);
  end;

implementation

uses main;
{ Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,

      Synchronize(UpdateCaption);

  and UpdateCaption could look like,

    procedure writeThread.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }

{ writeThread }

constructor writeThread.Create(strList:TList;me:TRichViewEdit);
begin
   writeList:=strList;
   RichViewEdit :=me;
   //Memo:=me;
   FreeOnTerminate := True; // ЧФ¶ЇЙѕіэ
   inherited Create(false);
end;

procedure writeThread.Execute;
begin
   while not Terminated do
   begin
     //Synchronize(writeToMemo);
     writeToMemo;
     sleep(1000);
   end;
end;

procedure writeThread.writeToMemo;
var
  sinfo:myInfo;
begin

  if writeList.Count > 0 then begin
  sinfo:=myInfo.create;
   try
     GLogCS.Enter;
     sinfo:=writeList[0];
     writeList.Delete(0);
     GLogCS.Leave;

     RichViewEdit.ReadOnly:=false;
     RichViewEdit.TopLevelEditor.BeginUndoGroup(rvutInsert);
     RichViewEdit.TopLevelEditor.SetUndoGroupMode(True);
     RichViewEdit.InsertText(#13);
     RichViewEdit.ApplyParaStyle(2);
     RichViewEdit.ApplyTextStyle(0);
     RichViewEdit.InsertText('title');
     RichViewEdit.InsertTab;

     if RichViewEdit.InsertHotspot(0,0,Mainform.ImageList2) then begin
       RichViewEdit.SetCurrentItemText('phone');
       RichViewEdit.SetCurrentTag(mainform.MakeTag(sinfo.name));
     end;

     RichViewEdit.InsertText(#13);
     RichViewEdit.ApplyParaStyle(0);
     RichViewEdit.ApplyTextStyle(2);
     RichViewEdit.InsertStringTag(sinfo.name, mainform.MakeTag(sinfo.name));
     RichViewEdit.InsertBreak(0, rvbsLine, clRed);
     RichViewEdit.ReadOnly:=true;

     RichViewEdit.FormatTail;

     RichViewEdit.SetSelectionBounds(0, RichViewEdit.GetOffsBeforeItem(0), 0, RichViewEdit.GetOffsBeforeItem(0));

   finally
     RichViewEdit.TopLevelEditor.SetUndoGroupMode(False);
     sinfo.Free;
   end;
 end;
end;

end.

read thread code

Code: Select all

unit UreadThread;

interface

uses
  Classes,SysUtils, StdCtrls;

type
  readThread = class(TThread)
  private
    readList:TList;
  protected
    procedure Execute; override;
    procedure readText;
  public
    constructor Create(strList:TList);
  end;

implementation

uses main;
{ Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,

      Synchronize(UpdateCaption);

  and UpdateCaption could look like,

    procedure readThread.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }

{ readThread }

constructor readThread.Create(strList: TList);
begin
   readList:=strList;
   FreeOnTerminate := True; // ЧФ¶ЇЙѕіэ
   inherited Create(false);
end;

procedure readThread.Execute;
begin
  while not Terminated do
   begin
     readText;
     sleep(15000);
   end;
end;

procedure readThread.readText;
var
  f:TextFile;
  S:string;
  sinfo:myInfo;
begin
   try
    AssignFile(f, '.\log.txt');
    Reset(f);
    while not eof(F)do
    begin
     sinfo:=myInfo.create;
      Readln(F, S);
      GLogCS.Enter;

      sinfo.id:=0;
      sinfo.name:=S;
      readList.Add(sinfo);
      GLogCS.Leave;
      Mainform.Label1.Caption:=inttostr(readList.Count);
    end;
   finally
     FreeAndNil(sinfo);
     CloseFile(F);
   end;
end;

end.
project code

Code: Select all

program ThreadTest;

uses
  Forms,
  main in 'main.pas' {MainForm},
  UwriteThread in 'UwriteThread.pas',
  UreadThread in 'UreadThread.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TMainForm, MainForm);
  Application.Run;
end.

Use Synchronize

Posted: Wed Mar 22, 2006 7:27 am
by Rob
Before you do *anything* else, take a note of the comment in your thread-classes. You totally omit the use of Synchronize:

Code: Select all


{ Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,

      Synchronize(UpdateCaption);

  and UpdateCaption could look like,

    procedure writeThread.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }

Posted: Wed Mar 22, 2006 8:46 am
by comeonwh
I have tested, use Synchronize method " Synchronize(writeToMemo) " the wrong still exist. so on above code , I have remark the Synchronize method.

Posted: Wed Mar 22, 2006 9:34 am
by Rob
To totally rule out any problems regarding threads, please put the thread-code into TTimer events. If the problem persists in just one thread, fixing it may be easier.

Posted: Thu Mar 23, 2006 7:12 am
by Sergey Tkachenko
TRichView content must not be added in a thread context, without Synchronize.

Posted: Thu Mar 23, 2006 7:16 am
by comeonwh
I have put the thread-code into TTimer events. but the problem is still exist. I am suspicious of RichView have some bug, otherwise,my program can not have problem.

Posted: Thu Mar 23, 2006 7:41 am
by comeonwh
Sergey Tkachenko wrote:TRichView content must not be added in a thread context, without Synchronize.
what is mean? Can you give me some code!

Posted: Thu Mar 23, 2006 9:50 am
by Sergey Tkachenko
Please send this sample project (where timers are used instead of threads) to richview@gmail.com

Posted: Thu Mar 23, 2006 10:20 am
by comeonwh
Sergey Tkachenko wrote:Please send this sample project (where timers are used instead of threads) to richview@gmail.com
I have send the Project to your e-mail.

Posted: Thu Mar 23, 2006 11:17 am
by Sergey Tkachenko
I received this project, but I cannot reproduce the problem.
I stopped, the label shows 9160, MainForm.RichViewEdit1.ItemCount=3530.
How long should I wait until the problem occurs?

As I understand, this project adds items in TRichView infinitely.
May be the system simply runs out of memory?
To reduce memory usage slightly, you can set RichViewEdit1.UndoLimit=0, if you do not need undo.

Posted: Fri Mar 24, 2006 1:16 am
by comeonwh
Sergey Tkachenko wrote:I received this project, but I cannot reproduce the problem.
I stopped, the label shows 9160, MainForm.RichViewEdit1.ItemCount=3530.
That is the problem,and it happen in write RichViewEdit. So ,I want to know how to modify my code.

Posted: Fri Mar 24, 2006 11:28 am
by Sergey Tkachenko
Sorry, what is the problem? Wrong numbers? What number the label must show?