DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: teacherlau
今日帖子: 62
在线用户: 24
导航: 论坛 -> 移动应用开发 斑竹:flyers,iamdream  
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/3/8 23:49:11
标题:
是否与ListView有关呢? 浏览:1035
加入我的收藏
楼主: 当执行小于3的时候可以正常执行下去,结果也是对的;当循环大于4或者5时,App闪退了,try也捕捉不到异常(至少是看不到);代码如下:
   Mythreadtask1 := TTask.Create (procedure ()
   var I,j,Lv:integer;
   begin
     try
        dpath:='1-';apath:='1-';
        ClientModule1.ClientDataSet1.close;
        ClientModule1.ClientDataSet1.commandText:='select BasePath from B_Stock where BaseNo='''+ckid+''' ';
        ClientModule1.ClientDataSet1.Open;
        kpath:=ClientModule1.ClientDataSet1.FieldByName('BasePath').AsString;
        kpath:=kpath+'-';
//        showmessage('Kpath:'+kpath);
        ClientModule1.ClientDataSet1.close;
        ClientModule1.ClientDataSet1.commandText:='select BasePath from B_Client where BaseNo='''+khid+''' ';
        ClientModule1.ClientDataSet1.Open;
        bpath:=ClientModule1.ClientDataSet1.FieldByName('BasePath').AsString;
        bpath:=bpath+'-';
//        showmessage('bpath:'+bpath);
        ClientModule1.ClientDataSet1.close;
        ClientModule1.ClientDataSet1.commandText:='select BasePath from B_Person where BaseNo='''+empid+''' ';
        ClientModule1.ClientDataSet1.Open;
        epath:=ClientModule1.ClientDataSet1.FieldByName('BasePath').AsString;
        epath:=epath+'-';
//        showmessage('Epath:'+Epath);
//       showmessage('表格条目: '+inttostr(ListView1.ItemCount));
        lv:=ListView1.ItemCount;
        for I := 0 to Lv-1 do
        begin
          unitname:=ListView1.Items.AppearanceItem[I].Data['Text14'].AsString;
          sql:='select isnull(cast((case when  BasicUnit='''+unitname+''' then 1 ';
          sql:=sql+'        when AssistUniton_e='''+unitname+'''  then 2 ';
          sql:=sql+'        when AssistUnitTwo='''+unitname+'''  then 3 ';
          sql:=sql+'        when AssistUnitThree='''+unitname+''' then 4 end) as varchar(100)),'''+jb_yi+''') as unitindex, ';
          sql:=sql+' isnull(cast((case when  BasicUnit='''+unitname+''' then PercentBasic ';
          sql:=sql+'      when AssistUniton_e='''+unitname+'''   then PercentOne';
          sql:=sql+'      when AssistUnitTwo='''+unitname+'''   then PercentTwo';
          sql:=sql+'      when AssistUnitThree='''+unitname+'''  then PercentThree  end) as varchar (100)),'''+jb_yi+''') as huansuanlv ';
          sql:=sql+'  from b_goods  where baseno=cast('''+ListView1.Items.AppearanceItem[I].Data['Text9'].AsString+''' as int)';
          ClientModule1.ClientDataSet1.Close;
          ClientModule1.ClientDataSet1.CommandText:= sql;
          ClientModule1.ClientDataSet1.Open;
          if ClientModule1.ClientDataSet1.RecordCount>0 then
          begin
          unitindex:=ClientModule1.ClientDataSet1.FieldByName('unitindex').AsString;
          unithuansuan:=ClientModule1.ClientDataSet1.FieldByName('huansuanlv').AsString;
          end else
          begin
          unitindex:='1';
          unithuansuan:='1';
          end;
//          showmessage('商品换算率执行完毕:'+unitindex+':  '+unithuansuan);
          try
          ClientModule1.ClientDataSet1.close;
          ClientModule1.ClientDataSet1.commandText:='select BasePath from B_Goods where BaseNo='''+ListView1.Items.AppearanceItem[I].Data['Text9'].AsString+''' ';
          ClientModule1.ClientDataSet1.Open;
          ppath:=ClientModule1.ClientDataSet1.FieldByName('BasePath').AsString;
          ppath:=ppath+'-';
          showmessage(inttostr(I)+' : '+Ppath);


          sql:='select isnull(price,'''+jb_yi+''') as cb from S_GoodsInfo where ptypeid='''+ListView1.Items.AppearanceItem[I].Data['Text9'].AsString+''' ';
          showmessage(sql);
          ClientModule1.ClientDataSet1.Close;
          ClientModule1.ClientDataSet1.CommandText:=sql;
          showmessage('Ptypeid:' + ListView1.Items.AppearanceItem[I].Data['Text9'].AsString );
          showmessage('开始执行:'+sql);
          ClientModule1.ClientDataSet1.Open;
          showmessage('执行结束:'+sql);
          if ClientModule1.ClientDataSet1.RecordCount>0 then
          begin
          cbdj:=ClientModule1.ClientDataSet1.FieldByName('cb').AsString;
          end else cbdj:='1';
          showmessage('成本单价:  '+cbdj);
          showmessage('数量 : '+ListView1.Items.AppearanceItem[I].Data['Text4'].AsString);
          cbje:=FormatFloat('0.00',0-(strtofloat(cbdj)*strtofloat(ListView1.Items.AppearanceItem[I].Data['Text4'].AsString)* strtofloat(unithuansuan)));
          showmessage('成本金额:  '+cbje);
          except
          On E:Exception do
          showmessage(e.Message);

          end;

          try
          //My_Arrzh[0][0]是名称
          kmid:='0000100001';
          sqlz:=' insert into R_SaleDetail (Vchcode,atypeid,btypeid,';
          sqlz:=sqlz+'etypeid,ktypeid,PtypeId,Qty,discount,';
          sqlz:=sqlz+'DiscountPrice,costtotal,costprice,price,total,';
          sqlz:=sqlz+'taxprice,taxTotal,date,usedtype,period,';
          sqlz:=sqlz+'tax_total,discounttotal,vchtype,unit,';
          sqlz:=sqlz+'ppath,bpath,kpath,epath,dpath,apath';
          sqlz:=sqlz+') values (';
          sqlz:=sqlz+'cast('''+newVchCode+''' as numeric),'''+kmid+''',cast('''+khid+''' as int),';
          sqlz:=sqlz+'cast('''+empid+''' as int),cast('''+ckid+''' as int),cast('''+ListView1.Items.AppearanceItem[I].Data['Text9'].AsString+''' as int),';
          sqlz:=sqlz+'cast('''+FormatFloat('0.00',0-strtofloat(ListView1.Items.AppearanceItem[I].Data['Text4'].AsString)*StrToFloat(unithuansuan))+''' as numeric(18,4)),cast('''+Edit7.Text+''' as numeric(18,4)),';
          sqlz:=sqlz+'cast('''+ListView1.Items.AppearanceItem[I].Data['Text7'].AsString+''' as numeric(18,4))*cast('''+Edit7.Text+''' as numeric(18,4)),cast('''+cbje+''' as numeric(18,4)),cast('''+cbdj+''' as numeric(18,4)),';
          sqlz:=sqlz+'cast('''+FormatFloat('0.00',StrtoFloat(ListView1.Items.AppearanceItem[I].Data['Text7'].AsString) / StrToFloat(unithuansuan))+''' as numeric(18,4)),';
          sqlz:=sqlz+'cast('''+FormatFloat('0.00',0-(strtofloat(ListView1.Items.AppearanceItem[I].Data['Text4'].AsString)*strtofloat(ListView1.Items.AppearanceItem[I].Data['Text7'].AsString)))+''' as numeric(18,4)),';
          sqlz:=sqlz+'cast('''+ListView1.Items.AppearanceItem[I].Data['Text7'].AsString+''' as numeric(18,4))*cast('''+Edit7.Text+''' as numeric(18,4)),cast('''+ling+''' as int),'''+FormatDateTime('YYYY-MM-DD',DateEdit1.Date)+''',cast('''+yi+''' as numeric),cast('''+period+''' as numeric),';
          sqlz:=sqlz+'cast('''+FormatFloat('0.00',0-(strtofloat(ListView1.Items.AppearanceItem[I].Data['Text4'].AsString)*strtofloat(ListView1.Items.AppearanceItem[I].Data['Text7'].AsString)*strtofloat(Edit7.Text)))+''' as numeric(18,4)),';
          sqlz:=sqlz+'cast('''+FormatFloat('0.00',0-(strtofloat(ListView1.Items.AppearanceItem[I].Data['Text4'].AsString)*strtofloat(ListView1.Items.AppearanceItem[I].Data['Text7'].AsString)*strtofloat(Edit7.Text)))+''' as numeric(18,4)),';
          sqlz:=sqlz+'cast('''+vchtype+''' as numeric),cast('''+unitindex+''' as numeric),';
          sqlz:=sqlz+''''+ppath+''','''+bpath+''','''+kpath+''','''+epath+''','''+dpath+''','''+apath+''') ';
//          showmessage(sqlz);
          ClientModule1.ClientDataSet1.Close;
          ClientModule1.ClientDataSet1.CommandText:=sqlz;
          ClientModule1.ClientDataSet1.Execute;
//          showmessage('第  '+inttostr(I)+'  执行完毕');
          except
          On E:Exception do
          showmessage(e.Message);
          end;

        end;
     except
        On E:Exception do
        showmessage(e.Message);

     end;
     end);

   Mythreadtask1.ExecuteWork;


由于DEBUG模式下,缺少了文件,不能进行调试,每次执行到 
// showmessage('商品换算率执行完毕:'+unitindex+':  '+unithuansuan);
显示完此条showmessage后就闪退了,百思不得其解,为啥循环少的时候可以,循环一旦大于4时就执行不下去了。怀疑跟LISTVIEW有关。但是找不到原因,只好求助大家给看看
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/3/9 1:36:38
1楼: 你这代码完全没法看。

先把代码模块化吧。至少把里面的一些代码归纳到几个不同的函数里面去。

另外,你这里既然是 Task 里面跑,那就是在线程里面跑。我好像又看到有操作界面 UI 的代码,比如 ShowMessage ,这样就难保不出问题。线程里面,如果需要操作界面 UI,必须加上同步。

操作 ListView 的代码,也是影响 UI 界面的,也需要放到同步里面去。

还有,你在客户端用串字符串的方式生成 SQL 语句传递给服务器端,这样的做法很不好。最好是服务器端写 SQL 语句,客户端只穿参数过去。
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/3/9 2:40:29
2楼: aaaaaaaaaahhhhhhhhhh!

I'm crazy....


Please, @sxfgf, don't do this!
This code is indecipherable!!!
It's horrible!!!

try to organize each task more legibly and logically!!!

I think you could use a "Master/Detail" style here, as you are querying many tables in the database to find the desired values... so think about using "Store Procedure" or "View" to make your work easier.. .

Study about SQL "Union", "Join", "Master/Detail", "Stored Procedure", "View", etc...

Don't mix "multi-threaded" tasks with something "does everything"!!! It's not like this.


Do not mix "thread" tasks with screen visualization tasks.
Do not mix database tasks with "thread", be cautious in this part... any error and the "thread" freezes or crashes the application!!!

Try to modularize your procedures! Do not create such long procedures... always try to keep a minimum of lines per task in the procedure!!! something around 20 lines maximum per procedure!!!

If you divide your "long task" into "small tasks", few lines, it becomes easier to maintain and understand the code!
此帖子包含附件:
JPEG 图像
大小:60.5K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/3/9 12:01:00
3楼: 哦,说的是那么回事,因为不是正式项目,所以随意(Xi惯不好)了。见笑了

追问一下:

   如果想从ListView中取值写入Sql,比如ListView中显示了商品的ID,数量,单价
就势必会访问ListView,那么是否是:

procedure A;
begin
  //一些访问ListView值的
  //showmessage等
end;

Procedure B;
begin
  //读取ListView、edit等Item的值
  //写入SQL数据库 insert \ update 
end;

procedrue C;
begin
  //获取Edit等控件的值进行数据库查询
  //sql open查询或者视图或者存储过程
end;

Procedure MainButt;
begin
   Mythreadtask1 := TTask.Create (procedure ()
   begin
     A;
   end;
   Mythreadtask1.start;

   Mythreadtask1 := TTask.Create (procedure ()
   begin
     B;
   end;
   Mythreadtask1.start;

   Mythreadtask1 := TTask.Create (procedure ()
   begin
    C;
   end;
   Mythreadtask1.start;


end;

这样子么?
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 zhyhero (zhyhero) ★☆☆☆☆ -
盒子活跃会员
2023/3/9 13:45:51
4楼: 别的不清楚
重构一下,能让你的代码看起来清晰不少……

TClientdataset_Helper=class helper for TClientDataSet
   procedure DoQuery(Sql:string);
end;

procedure TClientdataset_Helper.DoQuery(Sql:string);
begin
  Close;
  CommandText:=Sql;
  Open;  
end;

TListView_Helper=class helper for TListView
  function ItemAsString(ItemIndex:integer;DataName:String):string;
  function ItemAsFloat(ItemIndex:integer;DataName:String):Double;
end;

function TListView_Helper.ItemAsString(ItemIndex:integer;DataName:String):string;
begin
  result:=Items.AppearanceItem[ItemIndex].Data[DataName].AsString;
end;

function TListView_Helper.ItemAsDouble(ItemIndex:integer;DataName:String):Double;
begin
  result:=StrToFloat(ItemAsString(ItemIndex,DataName));
end;
----------------------------------------------
z@S7
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/3/9 21:51:41
5楼: @sxfgf you can do this way:

take all the values in the ListView and store them in a variable, so you avoid having to work with the screen (visual components);

Then, pass this variable to your "thread". This way, you avoid having to access the ListView all the time... a part can be solved this way!

type
  TMyProductData = record
    Id: integer;
    ItemsTotal: integer;
    Price: double; // currency...
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyProductData    : TMyProductData;
  MyListProductData: TArray<TMyProductData>;  // NO NEEDS create TList, etc..
begin
  // store all values in my list...
  for var i := 0 to (ListView1.Items.Count - 1) do
    begin
      MyProductData.Id         := 0; // the values in each ListView1 item....
      MyProductData.ItemsTotal := 0;
      MyProductData.Price      := 0;
      //
      MyListProductData := MyListProductData + [MyProductData];
    end;
  //
  // ListView1 it's free for another actions, now!!!
  //
  // now you can call your thread passing the "MyListProductData" with all data from ListView1
  //
  // RunMyThread( MyListProductData );
end;
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/3/9 22:07:09
6楼: The "INSERT" part in the table, I think you should think better about how to do it!!!

If an error occurs in the "thread", the "INSERT" can fail at any point in the task... So, you should think better at this point!

When you work with "database", you always have to "start" and "end" a transaction:



procedure xxx;
begin
  //
  // Always verify if exists a transaction opened...
  //
  if not DBxxxx._IS_NOT_IN_TRANSACTION then
    DBxxxx._START_A_TRANSACTION_HERE;
  //
  try
    try
      // insert, update, delete tasks ...
      //
      // ex:
      for var MyData in MyListProductData do
      begin
         MyTable.InsertXXXX(........ );
         // or
         MyTable.UpdateXXXX(........ );
         // or
         MyTable.DeleteXXXX(........ );
      end;
      //
      //
      //
      // if all "inserts", "updates" or "deletes" = OK ... then "commit"
      DBxxxxx.COMMIT;  // = SAVE ON DB, AND "END" THE TRANSACTION!!! = OK!!!
    except
      // WHAT TO DO IF SOME EXCEPTION ????
    end;
  finally
    DBxxxx._ROLLBACK_IF_ANY_ERROR_ABOVE;
    //
    // etc... close table, or others actions
  end;
end;
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/3/10 0:11:14
7楼: 楼主,你的代码里面,其它问题我不知道,因为代码太乱实在没办法看。

至少,你改变界面的代码,不能用线程来执行。如果仅仅是从界面元素读值,而不是改变界面元素,用线程执行也没问题。

你的代码里面,至少有个 ShowMessage 是界面操作,放线程里面就不行。

另外,数据库操作,你的 ClientDataSet 去操作后台数据库,那就要看你的 ClientDatSet 和后台数据库之间的连接采用什么方式了。

假设你采用的是最早的 DCOM 的方式,或者 WebService 的方式,那么,线程调用,你都要加上 COM 的 CoInitialize(nil); 这句。因为 WebService 的客户端操作在 WINDOWS 底下是通过 COM 调用 WINDOWS 系统提供的 HTTP 库来实现的。

多线程调用 COM,必须加上 CoInitialize 和 CoUnintialize。
----------------------------------------------
-
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/3/10 10:16:30
8楼: @pcplayer,showmessage是因为我的DEBUG模式缺少文件了,无法跟踪步进,所以才出此下策看看运行到那里出了错误。哈哈哈(尴尬)!

原本意图是从ListView里读取数据,写入数据库表。没有改变LIstView中Item的值

emailx45最后的建议我觉得非常值得一试。非常感谢emailx45。
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/3/11 0:39:03
9楼: 你虽然没改变 ListView 的值,但是,你改变了 ClientDataSet 的值。如果这个 ClientdataSet 的值会显示到界面上,比如数据绑定或者通过 DataSource 绑定到数据敏感控件上,也同样是操作了界面。

总结一下:
1. 有没用操作界面?如果有,先把操作界面的因素排除再测试;
2. ClientdataSet 是如何与后台数据库通讯的,是否涉及到需要做 CoInitialize 的问题。
----------------------------------------------
-
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/3/11 15:50:15
10楼: 感谢大家的建议。

请问一下,如果把ListView里所有的item都写入到数组或者类型里,再调用数据库的存储过程,势必这样效率会提高很多,那么如何将数组或者类型作为参数传递给数据库的存储过程里呢?有什么好的方法或者介绍么?
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/3/11 22:44:52
11楼: First, let's evaluate the size of the "parameter" to be passed to the "Stored Procedure"... if it's too big, then, I think it won't be very easy... if it's small (few items), then, I I think you'll be able to pass without any problems!

A "Stored Procedure" is like a "Procedure" in Delphi, however, it uses the PSQL language of the database!
You can use a "Stored Procedure" as you use a "Table", that is, you can use the "SP" as a data source (table), ex:
"Select * from MyStoredProcedureXXX where FieldX = 1" etc... etc...

So, if the amount of parameters is not too big, you could use a "Stored Procedure" in the same way that you use a "Table" in the SQL component (ex. TFDQuery, etc...)

If the data you need to use is already in the database (in a table), then you can create your "Stored Procedure" using "select ...", "For Select ....", and all SQL commands to create your end result...
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/3/11 22:49:36
12楼: look this "complex example" of "Stored Procedure"
--------

CREATE PROCEDURE dbo.usp_userwise_columns_value( @userid BIGINT )  // 1 param
AS 
BEGIN
        DECLARE @maincmd NVARCHAR(max);
        DECLARE @columnlist NVARCHAR(max);
        DECLARE @columnname VARCHAR(150);
        DECLARE @nickname VARCHAR(50);

        SET @maincmd = '';
        SET @columnname = '';
        SET @columnlist = '';
        SET @nickname = '';

        DECLARE CUR_COLUMNLIST CURSOR FAST_FORWARD
        FOR
          SELECT columnname , nickname
          FROM dbo.v_userwise_columns 
          WHERE userid = @userid

        OPEN CUR_COLUMNLIST
        IF @@ERROR <> 0
          BEGIN
          ROLLBACK
          RETURN
          END   

        FETCH NEXT FROM CUR_COLUMNLIST
        INTO @columnname, @nickname

        WHILE @@FETCH_STATUS = 0
          BEGIN
          SET @columnlist = @columnlist + @columnname + ','

          FETCH NEXT FROM CUR_COLUMNLIST
          INTO @columnname, @nickname
          END
        CLOSE CUR_COLUMNLIST
        DEALLOCATE CUR_COLUMNLIST  

        IF NOT EXISTS (SELECT * FROM sys.views WHERE name = 'v_userwise_columns_value')
          BEGIN
          SET @maincmd = 'CREATE VIEW dbo.v_userwise_columns_value AS SELECT sjoid, CONVERT(BIGINT, ' + CONVERT(VARCHAR(10), @userid) + ') as userid , ' 
          + CHAR(39) + @nickname + CHAR(39) + ' as nickname, ' 
          + @columnlist + ' compcode FROM dbo.SJOTran '
          END
        ELSE
          BEGIN
          SET @maincmd = 'ALTER VIEW dbo.v_userwise_columns_value AS SELECT sjoid, CONVERT(BIGINT, ' + CONVERT(VARCHAR(10), @userid) + ') as userid , ' 
          + CHAR(39) + @nickname + CHAR(39) + ' as nickname, ' 
          + @columnlist + ' compcode FROM dbo.SJOTran '
          END

        EXECUTE sp_executesql @maincmd
END

----------  
How call in your code, for example:

SELECT * FROM dbo.v_userwise_columns_value
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行70.3125毫秒 RSS