写一个调色板控件(2)

HD6845图形模式,一个图片块(8X8象素组成的一个小图片,称为Tile)最多只能支持8种颜色,整个屏幕最多可显示64种颜色。这点和任天堂红白机不太一样。差不多用一个星期的工作日时间,改写RAM、内存数据,查资料,并通过获得的数据,推算出结果,在IC板上确认。最终结果就是:一个Tile最多8种颜色,整个屏幕64色。CRT显示管拍照方式无法找到正确颜色显示值,最终只能采取近似的方法确定:R,G,B的颜色值只能取 $0, $40,$BF, $FF,这4个。组合成的64色,如下图:
64色(图一)
用Tile显示图形字符时,如显示A时会出下面这的情况:
这里写图片描述 一个或者多Tile组成。(图二)

控件必须要有上面两种功能!!
那么接下来的目标是要实现:定义行列个数;每个小正方形之间的间隔可调整,8X8个小正方形之间在用粗线分开(直观的显示出Tile)。
控件要增加属性Row,Col,相应的定义:FPaletteBin:: array [0 .. 16*16-1] of TRGBColor就要改变了,跟据实际需要,4X4个TILE(32X32个小正方形)完全能够满足需要,那么数组就改为:FPaletteBin:: array [0 .. 32*32-1] of TRGBColor。为了方便操作增加一个私有变量:PalCount:共有多少个小正方形:

private
    FPalCount: Integer;
published
    property Col: Integer read FCol write SetCOL;  //不能write FCol因为FCol有最大限制
    property Row: Integer read FRow write SetRow;
……
constructor TPaletteBoxVCL.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FCanDraw:=true;

  FCol := 16;  //初始值
  FRow := 16;
end;

procedure TPaletteBoxVCL.SetCol(const Value: Integer);
begin
  if Value > 0 then begin
    if (Value * FRow) <= 1024 then begin
      FCol := Value;
      FPalCount := FCol * FRow;
      Paint;
    end;
  end;
end;

procedure TPaletteBoxVCL.SetRow(const Value: Integer);
begin
  if Value > 0 then begin
    if (FCol * Value) <= 1024 then begin
      FRow := Value;
      FPalCount := FCol * FRow;
      Paint;
    end;
  end;
end;

接下来就要改Paint里面代码了。分三步走:
第一步,按设定的Col,Row画控件:这个很简单(见 16 改为 FCol 或 FRow)
将Pw := (Width - 2) div 16 改为 : Pw := (Width - 2) div FCol
Ph := (Height - 2) div 16 改为: Ph := (Height - 2) div FRow;
for i := 0 to 15 do begin 改为:for i := 0 to Row-1 do begin
for j := 0 to 15 do begin 改为:for j := 0 to Col-1 do begin 就OK了。
第二步,实现可调整间隔,在这这前代码,间隔值是默认为2。需将它改为属性变量。

published
    property Interval: Integer read FInterval write SetInterva;
……
//初始值 2 代码略
procedure TPaletteBoxVCL.SetInterva(const Value: Integer);
begin
  if Value >= 0 then begin
    FInterval := Value;
    Paint;   //设计期间立即看到效果
  end;
end;    

同时更改 Paint 内代码:见 2 改为 FInterval ;同时增加FInterval := 0 只画细线。更改后代码:

procedure TPaletteBoxVCL.Paint;
  function RGBtoColor(R,G,B:Byte):TColor;
  begin
    result:=TColor((B shl 16) +(G shl 8)+R);
  end;
var
  i, j, a: integer;
  Pw, Ph: integer;
  R: TRect;
  BMP:TBitmap;
begin
  if not FCanDraw then exit;
  BMP:=TBitmap.Create;   //防闪烁
  BMP.Width:=Width;
  BMP.Height:=Height;

  Pw := (Width - FInterval) div FCol; // 留边 2Pix
  Ph := (Height - FInterval) div FRow;
  Pw := min(Pw, Ph);
  Pw := Pw - FInterval; // 相距 2PIX
  Ph:= Pw;

  with BMP do begin
    Canvas.Pen.Color:=clGray;
    Canvas.Brush.Color := clbtnFace;
    Canvas.Rectangle(0, 0, Width, Height);

    Canvas.Brush.Color := clGray;

    Canvas.Pen.Width:=1;
    a:=0;
    for i := 0 to Row-1 do begin
      R := RECT(0, 0, Pw, Ph);
      R.Offset(FInterval, FInterval);
      R.Offset(0, i*(Ph+FInterval));
      for j := 0 to Col-1 do begin
        Canvas.Pen.Color:=clGray;
        Canvas.Brush.Color := RGBtoColor(FPaletteBin[a].R,FPaletteBin[a].G,FPaletteBin[a].B);
          if FInterval > 0 then  //加判断
            Canvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom)
          else begin //新增代码 间隔为 0 ,画线, 
            Canvas.FillRect(RECT(R.Left + 1, R.Top + 1, R.Right, R.Bottom));
            if i = 0 then begin // 顶上一根线
              Canvas.MoveTo(R.Left, R.Top);
              Canvas.LineTo(R.Right, R.Top);
            end;
            if j = 0 then begin
              Canvas.MoveTo(R.Left, R.Top);
              Canvas.LineTo(R.Left, R.Bottom);
            end;

            Canvas.MoveTo(R.Left, R.Bottom);
            Canvas.LineTo(R.Right, R.Bottom);

            Canvas.MoveTo(R.Right, R.Top);
            Canvas.LineTo(R.Right, R.Bottom);

          end;
        R.Offset(Pw+FInterval, 0);
        inc(a);
      end;
    end;
  end;

  Canvas.Draw(0,0,BMP);
  BMP.Free;
end;

每三步:8X8之间用粗线分隔,一个8X8就是一个Tile,为了以后方便使用增加一个属性:ShowTile:boolean。定义略过, 为方便维护,不加入原有循环中,代码如下:

procedure TPaletteBoxVCL.Paint;
……
  with BMP do begin
  ……
    if (FInterval = 0) and FShowTile then begin
      Canvas.Pen.Width := 2;
      Canvas.Pen.Color := clGray;
      for i := 1 to (FCol div 8) - 1 do begin
        Canvas.MoveTo(i * 8 * Pw, 0);
        Canvas.LineTo(i * 8 * Pw, Ph * FRow);
      end;
      for i := 1 to (FRow div 8) - 1 do begin
        Canvas.MoveTo(0, i * 8 * Ph);
        Canvas.LineTo(Ph * Col, i * 8 * Ph);
      end;
    end;
  end;
  Canvas.Draw(0,0,BMP);
  BMP.Free;
end;

实现目标:
效果

图一的实现:
属性设置: Col:16,Row:4;Interval:2;
代码:

procedure TForm3.Button1Click(Sender: TObject);
  function RGBtoColor(R, G, B: Byte): Dword;
  begin
    result := (B shl 16) + (G shl 8) + R;
  end;
const
  Cs: array [0 .. 3] of Byte = ($0, $40, $BF, $FF);
var
  i, j, k, a: Integer;
  Cl: TColor;
begin
  a := 0;
  PaletteBoxVCL1.BeginUpdate;
  for i := 0 to 3 do
    for j := 0 to 3 do
      for k := 0 to 3 do begin
        Cl := RGBtoColor(Cs[k], Cs[j], Cs[i]);
        PaletteBoxVCL1.SetColor(a, Cl);
        inc(a);
      end;
  PaletteBoxVCL1.EndUpdate;
end;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值