中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » 用QB编译,可以在DOS全屏下显示汉字的小程序
作者:
标题: 用QB编译,可以在DOS全屏下显示汉字的小程序 上一主题 | 下一主题
jmsxdp
新手上路





积分 12
发帖 4
注册 2010-3-9
状态 离线
『楼 主』:  用QB编译,可以在DOS全屏下显示汉字的小程序 [已使用 LLM 解释]

下面是一段用QB编写的能在英文下显示汉字的小程序片断,可以运行,运行后会在全屏幕状态下显示汉字,程序利用的是UCDOS的16点阵汉字库,用兴趣可以试一下。这是很多年前用过的,拿出来大家分享。其实QB编的小程序很有用,现在本人还时常编一段,用来应付一些烦人的转换,例如将两个STR电影字幕文件合并到一起,等等等等....,说远了,奉上程序:

'西文下显示汉字模块,需要文件UCDOS汉字库文件hzk16支持
DECLARE SUB xshz16 (zf$) '点阵坐标用,待显字符串
DIM SHARED xsys
DIM SHARED hzk$
DIM SHARED er$
ON ERROR GOTO erro
er$ = "f"
OPEN "b", #4, "HZK16" '汉字库文件
IF er$ = "t" THEN
hzk$ = "f"
END IF
SCREEN 12
xsys = 11 '字符颜色,数值为0-15,7:浅白,15:亮白,其他为彩色
' '++++++以下添加需要程序++++++

LOCATE 20, 1 '需要显示坐标
zf$ = "显示汉字123ABC" '显示的字符
CALL xshz16(zf$)

q: '程序退出
SYSTEM

erro: '错误处理
errs = ERR
er$ = "t"
RESUME NEXT

SUB xshz16 (zf$) '显示汉字模块
IF xsys = 0 THEN xsys = 15
IF hzk$ = "f" GOTO hzkcl1
l = LEN(zf$)
zftmp$ = ""
FOR i = 1 TO l
m$ = MID$(zf$, i, 1)
IF m$ = "1" THEN m$ = "1"
IF m$ = "2" THEN m$ = "2"
IF m$ = "3" THEN m$ = "3"
IF m$ = "4" THEN m$ = "4"
IF m$ = "5" THEN m$ = "5"
IF m$ = "6" THEN m$ = "6"
IF m$ = "7" THEN m$ = "7"
IF m$ = "8" THEN m$ = "8"
IF m$ = "9" THEN m$ = "9"
IF m$ = "0" THEN m$ = "0"
IF m$ = "q" THEN m$ = "q"
IF m$ = "Q" THEN m$ = "Q"
IF m$ = "w" THEN m$ = "w"
IF m$ = "W" THEN m$ = "W"
IF m$ = "e" THEN m$ = "e"
IF m$ = "E" THEN m$ = "E"
IF m$ = "r" THEN m$ = "r"
IF m$ = "R" THEN m$ = "R"
IF m$ = "t" THEN m$ = "t"
IF m$ = "T" THEN m$ = "T"
IF m$ = "y" THEN m$ = "y"
IF m$ = "Y" THEN m$ = "Y"
IF m$ = "u" THEN m$ = "u"
IF m$ = "U" THEN m$ = "U"
IF m$ = "i" THEN m$ = "i"
IF m$ = "I" THEN m$ = "I"
IF m$ = "o" THEN m$ = "o"
IF m$ = "O" THEN m$ = "O"
IF m$ = "p" THEN m$ = "p"
IF m$ = "P" THEN m$ = "P"
IF m$ = "

" THEN m$ = "]"
IF m$ = "}" THEN m$ = "}"
IF m$ = "\" THEN m$ = "\"
IF m$ = "|" THEN m$ = "|"
IF m$ = "a" THEN m$ = "a"
IF m$ = "A" THEN m$ = "A"
IF m$ = "s" THEN m$ = "s"
IF m$ = "S" THEN m$ = "S"
IF m$ = "d" THEN m$ = "d"
IF m$ = "D" THEN m$ = "D"
IF m$ = "f" THEN m$ = "f"
IF m$ = "F" THEN m$ = "F"
IF m$ = "g" THEN m$ = "g"
IF m$ = "G" THEN m$ = "G"
IF m$ = "h" THEN m$ = "h"
IF m$ = "H" THEN m$ = "H"
IF m$ = "j" THEN m$ = "j"
IF m$ = "J" THEN m$ = "J"
IF m$ = "k" THEN m$ = "k"
IF m$ = "K" THEN m$ = "K"
IF m$ = "l" THEN m$ = "l"
IF m$ = "L" THEN m$ = "L"
IF m$ = ";" THEN m$ = ";"
IF m$ = ":" THEN m$ = ":"
IF m$ = CHR$(39) THEN m$ = "'"
IF m$ = CHR$(34) THEN m$ = """
IF m$ = "z" THEN m$ = "z"
IF m$ = "Z" THEN m$ = "Z"
IF m$ = "x" THEN m$ = "x"
IF m$ = "X" THEN m$ = "X"
IF m$ = "c" THEN m$ = "c"
IF m$ = "C" THEN m$ = "C"
IF m$ = "v" THEN m$ = "v"
IF m$ = "V" THEN m$ = "V"
IF m$ = "b" THEN m$ = "b"
IF m$ = "B" THEN m$ = "B"
IF m$ = "n" THEN m$ = "n"
IF m$ = "N" THEN m$ = "N"
IF m$ = "m" THEN m$ = "m"
IF m$ = "M" THEN m$ = "M"
IF m$ = "," THEN m$ = ","
IF m$ = "<" THEN m$ = "<"
IF m$ = "." THEN m$ = "."
IF m$ = ">" THEN m$ = ">"
IF m$ = "/" THEN m$ = "/"
IF m$ = "?" THEN m$ = "?"
IF m$ = "!" THEN m$ = "!"
IF m$ = "@" THEN m$ = "@"
IF m$ = "#" THEN m$ = "#"
IF m$ = "$" THEN m$ = "$"
IF m$ = "%" THEN m$ = "%"
IF m$ = "^" THEN m$ = "︿"
IF m$ = "&" THEN m$ = "&"
IF m$ = "*" THEN m$ = "*"
IF m$ = "(" THEN m$ = "("
IF m$ = ")" THEN m$ = ")"
IF m$ = "_" THEN m$ = "_"
IF m$ = "+" THEN m$ = "+"
IF m$ = "-" THEN m$ = "-"
IF m$ = CHR$(32) THEN m$ = " "
IF m$ = "~" THEN m$ = "~"
IF m$ = CHR$(96) THEN m$ = "‘"
IF m$ = "=" THEN m$ = "="
zf1 = ASC(m$)
IF zf1 < 160 THEN m$ = " "
zftmp$ = zftmp$ + m$
NEXT i
zf$ = zftmp$
hzbz = CSRLIN
zzbz = POS(hzb)
zzb = hzbz * 16 - 15
hzb = zzbz * 8 - 7
IF xsys = 0 THEN xsys = 7
IF hzb = 0 THEN hzb = 1
IF zzb = 0 THEN zzb = 1
hzbtmp = hzb
zzbtmp = zzb
l = LEN(zf$)
FOR i = 2 TO l STEP 2
zf1$ = MID$(zf$, i - 1, 1)
zf2$ = MID$(zf$, i, 1)
zf1 = ASC(zf1$)
zf2 = ASC(zf2$)
no = ((zf1 - 160 - 1) * 94 + zf2 - 160 - 1) * 32 + 1
SEEK #4, no
cch$ = INPUT$(32, 4)
FOR a = 1 TO 16
ch1$ = MID$(cch$, a * 2 - 1, 1)
ch2$ = MID$(cch$, a * 2, 1)
ch$ = ch2$ + ch1$
s = CVI(ch$)
LINE (hzb, zzb)-(hzb + 15, zzb), xsys, , s
zzb = zzb + 1
IF zzb - zzbtmp = 16 THEN
zzb = zzbtmp
hzb = hzb + 16
END IF
NEXT a
NEXT i
GOTO xshz16subq
hzkcl1:
PRINT zf$
xshz16subq:
END SUB


   此帖被 +2 点积分    点击查看详情   
评分人:【 aq2007 分数: +2  时间:2010-10-29 00:27
LLM 解释

程序功能与核心机制

该QBASIC程序实现了在DOS英文环境下直接渲染16×16点阵汉字的功能,核心依赖UCDOS的HZK16字库文件,通过手动解析点阵数据并在图形模式下逐行绘制实现。

关键技术细节

  1. 图形模式选择
    使用SCREEN 12切换到VGA 640×480×16色图形模式——这是DOS下常见的高分辨率模式,支持直接像素操作,为点阵汉字渲染提供基础。

  2. HZK16字库解析
    UCDOS的HZK16GB2312编码的16×16点阵字库,每个汉字占32字节(16行×2字节/行,每行对应16个像素)。程序通过GB2312编码计算字库偏移量:

    • 汉字的GB2312编码由两个字节组成(均为0xA1~0xFE,对应ASCII 161~254);
    • 偏移量公式:((区码-161)×94 + (位码-161))×32 + 1(区码=首字节ASCII,位码=次字节ASCII,94为每区汉字数,32为每个汉字的字节数)。
  3. 点阵渲染逻辑
    读取32字节点阵数据后,通过LINE语句的位掩码模式(第四个参数s)逐行绘制:

    • 每2字节表示汉字的一行(共16行),通过CVI(ch2$+ch1$)将字节序反转后转为整数(因QBASIC的CVI是小端序,而HZK16的点阵行是大端存储);
    • LINE (hzb, zzb)-(hzb+15, zzb), xsys, , s会根据掩码s的二进制位,在指定行绘制16个像素(位为1则显色,0则透明)。
  4. 字符处理差异
    程序分为两个版本:

    • 第一个版本zf$="显示汉字123ABC"):将ASCII字符(数字、字母、符号)替换为对应的全角字符(如"1""1"),确保与汉字宽度(16像素)对齐;
    • 第二个版本zf$="显示1234;"):保留ASCII字符原样,通过LOCATE定位后直接用PRINT输出(半角字符占8像素,与汉字宽度适配)。

当年常见的设计思路与限制

  1. 为什么不依赖DOS中文系统?
    DOS中文系统(如UCDOS、CCDOS)需要驻留内存并替换BIOS中断,而该程序通过直接操作图形模式绕过了系统依赖,适合无需完整中文环境的轻量场景(如启动界面、工具提示)。

  2. 字库依赖的必然性
    DOS英文环境的系统字库仅包含ASCII字符,无法直接显示汉字。使用UCDOS的HZK16是当年的常见选择——因其是公开流传的标准点阵字库,且格式简单易解析。

  3. 错误处理的局限性
    程序通过ON ERROR GOTO erro检测字库文件是否存在,但错误处理逻辑存在瑕疵:er$的赋值逻辑冗余(仅在出错时设为"t",但未正确传递给后续判断),可能导致字库缺失时仍尝试渲染。

技术瑕疵与当年的“经验性补丁”

  1. 全角替换的冗余性
    第一个版本中,将ASCII字符替换为全角字符的代码(如"1""1")是不必要的——全角字符本身就是GB2312编码的一部分,直接在zf$中使用全角字符即可(如zf$="显示汉字123ABC"),无需手动替换。

  2. 坐标计算的近似性
    程序通过hzb = zzbz * 8 -7(列→X坐标)和zzb = hzbz *16 -15(行→Y坐标)将文本模式的LOCATE坐标转换为图形模式坐标,这是基于“文本模式每行16像素、每列8像素”的经验假设,仅在SCREEN 12下近似成立,若切换到其他图形模式(如SCREEN 13为320×200×256色)则会错位。

  3. 未处理非汉字字符
    zf$中包含ASCII字符(未替换为全角),第一个版本会将其替换为全角空格(" "),导致非汉字字符无法显示;第二个版本通过分支处理,保留了ASCII字符的显示能力,设计更合理。

总结

该程序是DOS时代**“不依赖中文系统显示汉字”的典型实现**,核心思路是“直接解析点阵字库+图形模式像素操作”。其设计反映了当年的技术限制:内存资源紧张、中文系统笨重,因此轻量的自定义渲染方案更受欢迎。程序的瑕疵(如冗余替换、坐标近似)则源于当年文档不足和经验性调试——开发者通过“试错”弥补了对字库格式或图形坐标的理解偏差。



2010-4-6 10:43
查看资料  发短消息  网志   编辑帖子  回复  引用回复
jmsxdp
新手上路





积分 12
发帖 4
注册 2010-3-9
状态 离线
『第 2 楼』:   使用 LLM 解释/回答一下

汉字库为UCDOS16点阵字库,可以上网查找。


2010-4-6 10:45
查看资料  发短消息  网志   编辑帖子  回复  引用回复
jmsxdp
新手上路





积分 12
发帖 4
注册 2010-3-9
状态 离线
『第 3 楼』:   使用 LLM 解释/回答一下

另一个,这个不是把英文字母统统转化成中文字母,而是按原样显示:

'西文下显示汉字模块,需要文件UCDOS汉字库文件hzk16支持
DECLARE SUB xshz16 (zf$) '点阵坐标用,待显字符串
DIM SHARED xsys
DIM SHARED hzk$
DIM SHARED er$
ON ERROR GOTO erro
er$ = "f"
OPEN "b", #4, "HZK16" '汉字库文件hzk16
IF er$ = "t" THEN
hzk$ = "f"
END IF
SCREEN 12
xsys = 14 '字符颜色0-15,7:浅白,15:亮白,其他为彩色
' '++++++以下添加需要程序++++++

LOCATE 20, 10 '需要显示坐标,为第20行10列
zf$ = "显示1234;" '显示的字符
CALL xshz16(zf$) '调用程序显示



' '--------------添加部分结束-------------
q: '程序退出
SYSTEM

erro: '错误处理
errs = ERR
er$ = "t"
RESUME NEXT

SUB xshz16 (zf$) '显示汉字模块
IF xsys = 0 THEN xsys = 14
IF hzk$ = "f" GOTO hzkcl1
l = LEN(zf$)
hzbz = CSRLIN
zzbz = POS(hzb)
zzb = hzbz * 16 - 15
hzb = zzbz * 8 - 7
IF hzb = 0 THEN hzb = 1
IF zzb = 0 THEN zzb = 1
hzbtmp = hzb
zzbtmp = zzb
l = LEN(zf$)
txtmp = 2
xsmk1:
FOR i = txtmp - 1 TO l
zf1$ = MID$(zf$, i, 1)
zf2$ = MID$(zf$, i + 1, 1)
zf1 = ASC(zf1$)
zf2 = ASC(zf2$)
IF zf1 < 159 GOTO xsasc
no = ((zf1 - 160 - 1) * 94 + zf2 - 160 - 1) * 32 + 1
SEEK #4, no
cch$ = INPUT$(32, 4)
FOR a = 1 TO 16
ch1$ = MID$(cch$, a * 2 - 1, 1)
ch2$ = MID$(cch$, a * 2, 1)
ch$ = ch2$ + ch1$
s = CVI(ch$)
LINE (hzb, zzb)-(hzb + 15, zzb), xsys, , s
zzb = zzb + 1
IF zzb - zzbtmp = 16 THEN
zzb = zzbtmp
hzb = hzb + 16
END IF
NEXT a
i = i + 1
NEXT i
GOTO xshz16subq
xsasc:
LOCATE zzb / 16 + 1, hzb / 8 + 1
PRINT zf1$
txtmp = i + 2
i = txtmp
hzb = hzb + 8
GOTO xsmk1
hzkcl1:
PRINT zf$
xshz16subq:
END SUB


2010-4-6 10:51
查看资料  发短消息  网志   编辑帖子  回复  引用回复
070
高级用户

苏醒的沉睡者


积分 659
发帖 217
注册 2003-2-15
来自 福建
状态 离线
『第 4 楼』:   使用 LLM 解释/回答一下

QB确实还挺有用的,就像写小工具,也是还可以用到20年前的Turbo c




好久没碰Dos,手都生了,赶紧回来练练.嘿嘿
2010-4-8 15:15
查看资料  发送邮件  发短消息  网志  OICQ (181315400)  编辑帖子  回复  引用回复
lqg2118
初级用户





积分 36
发帖 16
注册 2010-6-30
状态 离线
『第 5 楼』:   使用 LLM 解释/回答一下

真的很不错,用来做启动界面很好的。


2010-7-2 11:45
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
cnch
中级用户




积分 326
发帖 70
注册 2003-1-10
状态 离线
『第 6 楼』:   使用 LLM 解释/回答一下

还在用QB啊,也算是老法师啦.


2010-9-5 14:52
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
aq2007
初级用户





积分 20
发帖 9
注册 2007-4-27
状态 离线
『第 7 楼』:   使用 LLM 解释/回答一下

~~不错啊,好东西....正在准备在用...谢谢..


2010-10-29 00:23
查看资料  发短消息  网志   编辑帖子  回复  引用回复
lswd
初级用户





积分 52
发帖 25
注册 2010-2-9
状态 离线
『第 8 楼』:   使用 LLM 解释/回答一下

谢谢分享


2020-2-7 14:06
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: