电阻色环工具的难点并非把颜色换成数字,而是同一种颜色出现在不同位置时具有不同含义。金色放在倍率位置表示十分之一,放在误差位置表示百分之五;把所有位置共用一份数字映射,界面就可能给出形式完整却含义错误的结果。本篇为四环电阻建立按角色取值的规则,再把计算结果接入HarmonyOS页面。

四环角色与阻值区间

先明确读取方向和四个角色

四环依次表示第一位有效数字、第二位有效数字、倍率和误差。计算式为前两位组成的整数乘以十的倍率指数,误差区间则由标称值乘以误差比例得到。工具要求用户先确认读取方向,再输入四个位置;本篇不从照片识别颜色,也不根据颜色间距自动判断方向。

初始样本为棕、黑、红、金。前两位组成十,红色倍率为十的二次方,因此标称值为一千欧姆;金色误差为百分之五,对应九百五十至一千零五十欧姆。页面中的1.00 kΩ是显示单位转换,计算层始终以欧姆保存数值,不会把千欧姆字符串继续参与乘法。

工程在entry/src/main/ets下设置model/BandRule.ets、service/Resistance.ets和pages/Index.ets。规则表放入模型文件,计算函数不读取页面控件,页面只维护颜色选择和提示。这样后续增加反向查色与五环模式时,可以扩展角色集合,而不必重写当前界面的每个按钮。

// model/BandRule.ets
export interface BandRule {
  code: string;
  label: string;
  paint: string;
  digit: number;
  exponent: number;
  tolerance: number;
}

export const RULES: BandRule[] = [
  { code: 'black', label: '黑', paint: '#222222', digit: 0, exponent: 0, tolerance: -1 },
  { code: 'brown', label: '棕', paint: '#805333', digit: 1, exponent: 1, tolerance: 1 },
  { code: 'red', label: '红', paint: '#CD4545', digit: 2, exponent: 2, tolerance: 2 },
  { code: 'orange', label: '橙', paint: '#EC8D36', digit: 3, exponent: 3, tolerance: -1 },
  { code: 'yellow', label: '黄', paint: '#E7C83D', digit: 4, exponent: 4, tolerance: -1 },
  { code: 'green', label: '绿', paint: '#429566', digit: 5, exponent: 5, tolerance: -1 },
  { code: 'blue', label: '蓝', paint: '#456EBD', digit: 6, exponent: 6, tolerance: -1 },
  { code: 'violet', label: '紫', paint: '#8D59A8', digit: 7, exponent: 7, tolerance: -1 },
  { code: 'gray', label: '灰', paint: '#888888', digit: 8, exponent: 8, tolerance: -1 },
  { code: 'white', label: '白', paint: '#F3F3F3', digit: 9, exponent: 9, tolerance: -1 },
  { code: 'gold', label: '金', paint: '#B7954C', digit: -1, exponent: -1, tolerance: 5 },
  { code: 'silver', label: '银', paint: '#ADB3B8', digit: -1, exponent: -2, tolerance: 10 }
];

export function findBand(code: string): BandRule {
  for (const rule of RULES) {
    if (rule.code === code) return rule;
  }
  throw new Error('颜色不在当前规则表中');
}

规则表采用明确的支持范围:有效数字支持黑至白,倍率额外支持金银,误差支持棕、红、金、银四种。其余颜色的误差字段写为负一,表示当前工具不接受该组合。这个值是字段自己的无效标记,不能把倍率中的负一次方也当成错误。后续扩充误差档位时,应同时补充规则说明和入口选项。

颜色代码是业务身份,中文色名负责显示,十六进制颜色值负责绘制。三者不能相互替代。换一套深色主题时,可以调整绘制颜色而保留代码;界面增加英文时,也不必修改计算输入。第一位使用黑色在当前设计中会被拒绝,零欧姆器件不通过四环普通电阻的入口处理。

在计算入口落实位置约束

计算函数接收四个颜色代码,先检查数量,再按位置取规则。第一位必须大于零,第二位允许为零;金银没有有效数字,因而不能出现在前两位。误差必须为正,随后计算上下限。函数返回结构化数值和色名,不返回拼好的整页文本,避免显示语言绑住后续算法。

// service/Resistance.ets
import { BandRule, findBand } from '../model/BandRule';

export interface ResistanceResult {
  ohms: number;
  tolerance: number;
  low: number;
  high: number;
  labels: string[];
}

export function resistance(first: number, second: number,
  exponent: number): number {
  return (first * 10 + second) * Math.pow(10, exponent);
}

export function decodeFour(codes: string[]): ResistanceResult {
  if (codes.length !== 4) throw new Error('四环需要四个颜色');
  const first: BandRule = findBand(codes[0]);
  const second: BandRule = findBand(codes[1]);
  const multiplier: BandRule = findBand(codes[2]);
  const tolerance: BandRule = findBand(codes[3]);
  if (first.digit <= 0 || second.digit < 0) {
    throw new Error('有效数字位置不接受当前颜色');
  }
  if (tolerance.tolerance <= 0) throw new Error('误差位置不接受当前颜色');
  const ohms: number = resistance(first.digit, second.digit, multiplier.exponent);
  if (!Number.isFinite(ohms) || ohms <= 0) throw new Error('阻值超出计算范围');
  const delta: number = ohms * tolerance.tolerance / 100;
  return { ohms, tolerance: tolerance.tolerance,
    low: ohms - delta, high: ohms + delta,
    labels: [first.label, second.label, multiplier.label, tolerance.label] };
}

export function formatOhms(value: number): string {
  if (value >= 1000000) return `${(value / 1000000).toFixed(2)} MΩ`;
  if (value >= 1000) return `${(value / 1000).toFixed(2)} kΩ`;
  return `${Number(value.toFixed(4))} Ω`;
}

decodeFour是对外校验入口,较底层的resistance负责算术,调用者需要经过颜色规则校验后再使用它。表内倍率覆盖范围固定,因此有效输入的数值规模可控。格式化函数保留标称值的两位显示小数,范围以欧姆显示到至多四位小数;显示舍入不回写计算结果。需要导出精确编码时应保存色环代码,不能从舍入后的文本反推颜色。

本例没有把浮点计算结果直接写成严格相等的业务判断。金银倍率会引入小数,后续进行标准阻值比较时,应使用统一精度或相对误差规则。误差上下限本身描述的是参数容许范围,不能把该范围当成对某个实际器件测量值的确认。

页面保留输入,成功计算后一起更新结果

页面初始展示棕黑红金,按钮在红色和橙色倍率之间切换。一次点击同时更新色名、色带、标称值与区间,没有自动改变误差角色。这里使用两个确定倍率,是为了把规则入口和页面联动做完整;完整颜色选择器可以在下一篇加入,沿用同一个计算函数。

// pages/Index.ets
import { findBand } from '../model/BandRule';
import { decodeFour, formatOhms, ResistanceResult } from '../service/Resistance';

@Entry
@Component
struct Index {
  @State codes: string[] = ['brown', 'black', 'red', 'gold'];
  @State result: ResistanceResult = decodeFour(['brown', 'black', 'red', 'gold']);
  @State message: string = '色名与数值同时显示';
  private positions: number[] = [0, 1, 2, 3];
  private roles: string[] = ['第一位', '第二位', '倍率', '误差'];

  private changeMultiplier(): void {
    const next: string[] = this.codes.slice();
    next[2] = next[2] === 'red' ? 'orange' : 'red';
    try {
      const calculated: ResistanceResult = decodeFour(next);
      this.codes = next;
      this.result = calculated;
      this.message = '色名与数值同时显示';
    } catch (error) {
      this.message = error instanceof Error ? error.message : '计算失败';
    }
  }

  build() {
    Scroll() {
      Column({ space: 18 }) {
        Text('电阻色环工作台').fontSize(26).fontWeight(FontWeight.Bold)
        Text('四环电阻').fontSize(16)
        Row({ space: 18 }) {
          ForEach(this.positions, (position: number) => {
            Text('').width(18).height(64)
              .backgroundColor(findBand(this.codes[position]).paint)
          }, (position: number) => position.toString())
        }.padding(18).backgroundColor('#E7D5B4').borderRadius(24)
        ForEach(this.positions, (position: number) => {
          Row() {
            Text(this.roles[position]).layoutWeight(1)
            Text(this.result.labels[position])
          }.width('100%').padding(12).backgroundColor('#FFFFFF')
        }, (position: number) => position.toString())
        Text(`${formatOhms(this.result.ohms)} ±${this.result.tolerance}%`)
          .fontSize(30).fontColor('#18796C')
        Text(`${Number(this.result.low.toFixed(4))}–${Number(this.result.high.toFixed(4))} Ω`)
          .fontSize(18)
        Button('切换倍率').onClick(() => { this.changeMultiplier(); })
        Text(this.message).fontSize(14)
      }.padding(20).width('100%').constraintSize({ maxWidth: 520 })
    }.width('100%').height('100%').backgroundColor('#F4F9F6')
  }
}

角色规则、计算函数与开发预览

更新时先在局部变量中得到完整结果,再提交页面状态。发生校验异常时,旧输入和旧结果继续对应,提示文本说明本次失败原因。若以后换成允许编辑任意颜色的表单,则需要增加草稿输入和已确认结果两个层次,明确提示“待计算”,不能让新草稿的色带搭配旧阻值。

手机上的纵向布局把四个角色逐行展开,避免把四个下拉控件压在同一窄行里。色带只是辅助信息,色名和角色文字始终可读,不能要求使用者靠色觉完成全部操作。较宽窗口采用相同数据模型,后续可以将选择区和结果区并排放置,而计算入口继续只接收颜色代码。

调试围绕角色和单位展开

恢复初始输入后,标称值应为一千欧姆,误差百分之五,上下限分别为九百五十和一千零五十。点击切换倍率,第三环变橙,标称值变为一万欧姆,范围变为九千五百至一万零五百;再次点击回到初始状态。若误差百分比也跟着变化,应检查是否误用了第三环规则。

在函数入口另行检查棕黑金金,标称值应为一欧姆,上下限为零点九五和一点零五。这一条件专门区分合法的负倍率指数与非法数字角色。将首环改为金色,或者把第四环改为黑色,应进入不同位置的失败路径;输入不足四环时,数量检查先失败,不应尝试读取不存在的数组项。

棕黑红金的标称阻值与区间

这条工程主线把颜色、角色与数值分开:规则表表达可用组合,计算层产生统一欧姆数值,界面层再组织色名和显示单位。下一篇增加角色感知的选项过滤时,仍保留计算层的校验,因为界面筛选不能代替数据入口的约束。

规则扩展应保留已有输入的含义

规则表不是把所有器件规格一次性装进页面的清单,而是当前四环入口的明确约定。以后增加五环模式时,前三环将共同组成有效数字,原来第三环的倍率角色会后移。因此保存记录时除了四个颜色代码,还需要保存模式。缺少模式的数组即使长度足够,也不能直接套用另一个解码函数。旧记录应由对应模式读取,不随当前界面的选项自动改变解释方式。

误差的显示也要避免产生额外精度。标称值写成一千欧姆,误差写成百分之五,说明的是编码参数;把结果增加到很多小数位,并不会让器件参数变得更精确。页面应清楚区分标称值、上下限和后续可能接入的测量输入。测量数值有自己的单位、采集时间和来源,不能覆盖颜色解码得到的标称值。

调试输入时可将四个颜色代码、位置角色和计算后的欧姆数值分别观察。若界面显示一点零零千欧姆,而内部值只有一,则问题在单位转换之前;若内部是一千但显示一千千欧姆,则是格式化层重复转换。沿着这条数据链逐层检查,比在按钮事件中同时调整颜色、倍率和显示文本更容易找出错误,也能为下一篇的选择器过滤建立稳定的回归样本。

相关官方资料

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐