You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Topaz ActiveX的LCDWriteString方法写入超LCD垂直限制致运行时错误

Topaz 1x5 LCD文本显示越界问题排查与修复

问题背景

在Topaz 1x5 LCD屏幕上展示长文本段落,通过「继续」按钮分页切换,待文本全部展示后采集签名。已通过GetLCDSize()获取屏幕最大尺寸,将垂直最大值存入yMax;使用LCDWriteString()在当前yPos位置写入文本行,通过GetLCDStringSize()获取行尺寸后递增yPos,虽添加了yPos与yMax的校验逻辑,但仍出现越界触发运行时错误。

现有代码

//-----------------------------------------------------------------------------------
//will display a chuck full of words up to the point where display fills up
//method returns the point in aWords where it stoped.
//aWords is an array of words to be written 
METHOD ShowText( aWords, i )
   Local xSize, ySize := 0
   Local cLine    := ''
   Local cTmp     := ''
   Local yPos     := 0

   While ++i <= Len( aWords ) .and. yPos < ( ::yMax - ySize )

      cTmp += aWords[ i ] + ' '
      xSize := nLoWord( ::SigPlus1:GetLCDStringSize( cTmp ) ) //width in LCD pixels of line to be written
      ySize := nHiWord( ::SigPlus1:GetLCDStringSize( cTmp ) ) //height of line in LCD pixels 

      If xSize < ::xMax //if line width does not exceed LCD width

         cLine := cTmp 

      End 

      //if line exceed LCD width or at last word then write line of text on current at yPos
      if xSize >= ( ::xMax-5 ) .OR. i == Len( aWords )  

         xSize := nLoWord( ::SigPlus1:GetLCDStringSize( cLine ) ) 
         ::SigPlus1:LCDWriteString( 0, 2, 0, yPos, xSize, ySize, 0, cLine )

         //advance yPos to next line
         yPos += nHiWord( ::SigPlus1:GetLCDStringSize( cLine ) )
         cLine := ''
         cTmp  := ''

         i += iif( i == Len( aWords ), 0, -1 ) //if not at end, then go back 1 word.

      End 

   End 

RETURN i 

问题根源分析

  1. 循环条件校验时机错误:原循环用临时行cTmp的高度ySize预判剩余空间,但临时行未触发换行时ySize并非最终行高,会导致错误允许继续添加单词,最终写入时yPos加行高超出yMax。
  2. 写入前无精准空间校验:仅在循环开始前预判,未在实际执行LCDWriteString()前检查当前行高加yPos是否超过屏幕垂直边界。
  3. 尺寸计算冗余且易出错:多次重复调用GetLCDStringSize(),可能因字符串临时变化导致尺寸值不一致。

修复方案

修改后的代码

//-----------------------------------------------------------------------------------
// 显示文本至屏幕填满,返回停止时的单词索引
// aWords 为待写入的单词数组
METHOD ShowText( aWords, i )
   Local xSize, lineHeight := 0
   Local cLine    := ''
   Local cTmp     := ''
   Local yPos     := 0
   Local totalWords := Len( aWords )

   While ++i <= totalWords
      // 临时拼接当前单词
      cTmp += aWords[ i ] + ' '
      // 获取临时行的尺寸
      Local tmpSize := ::SigPlus1:GetLCDStringSize( cTmp )
      Local tmpWidth := nLoWord( tmpSize )
      Local tmpHeight := nHiWord( tmpSize )

      // 如果临时行宽度未超过屏幕,更新当前行内容与行高
      If tmpWidth < ::xMax
         cLine := cTmp
         lineHeight := tmpHeight
      End 

      // 触发换行条件:行宽接近屏幕边界 或 已到最后一个单词
      If tmpWidth >= ( ::xMax - 5 ) .OR. i == totalWords
         // 检查当前行是否能放入剩余屏幕空间
         If yPos + lineHeight > ::yMax
            // 剩余空间不足,回退当前单词并终止循环
            i -= 1
            Exit
         End

         // 获取最终行宽度并写入屏幕
         xSize := nLoWord( ::SigPlus1:GetLCDStringSize( cLine ) )
         ::SigPlus1:LCDWriteString( 0, 2, 0, yPos, xSize, lineHeight, 0, cLine )

         // 更新yPos到下一行起始位置
         yPos += lineHeight
         cLine := ''
         cTmp  := ''

         // 非最后一个单词时,回退索引以便重新处理当前单词
         If i != totalWords
            i -= 1
         End
      End 
   End 

RETURN i 

关键修复点

  • 写入前精准校验空间:在执行LCDWriteString()前,明确检查yPos + lineHeight是否超过yMax,超出则回退单词并终止循环,彻底避免越界。
  • 统一行高变量:用lineHeight存储当前待写入行的高度,减少重复调用GetLCDStringSize()的冗余操作,避免尺寸值不一致。
  • 简化逻辑判断:将原循环中依赖临时值的预判逻辑移至换行触发时,逻辑更清晰可靠;用直观的条件判断替换iif,降低代码复杂度。

内容的提问来源于stack exchange,提问作者reinaldo Crespo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 03:37:45