用 Tkinter 实现一个简单的罗马数字转化工具

背景

TkDocs tutorial 里介绍了 Tkinter\text{Tkinter} Tkinter,其中有 A First (Real) Example 一文,这篇文章里有一个使用 Tkinter\text{Tkinter} Tkinter 生成图形化界面的简单例子。我想在那篇文章的基础上实战一下,于是想到可以写一个正整数 ➡️ 罗马数字(输入的正整数不能大于 39993999 3999)的简易转化工具。

正文

如何将正整数转化为罗马数字

转化规则可以参考 12. 整数转罗马数字 这道题目。以 20262026 2026 为例,我们可以对每个数位进行转化

  • 千位是 22 2: M\text{M} M 表示 10001000 1000, MM\text{MM} MM 表示 20002000 2000
  • 百位是 00 0:不用转化
  • 十位是 22 2: X\text{X} X 表示 1010 10, XX\text{XX} XX 表示 2020 20
  • 个位是 66 6: I\text{I} I 表示 11 1, V\text{V} V 表示 55 5, VI\text{VI} VI 表示 66 6

合在一起,就是 MMXXVI\text{MMXXVI} MMXXVI

程序可以这样写 ⬇️

python 复制代码
def to_roman(value):
    convert_result = ""
    digit_base = 1
    while value > 0:
        remainder = value % (digit_base * 10)
        convert_result = convert_one_digit_to_roman(remainder, digit_base) + convert_result
        digit_base *= 10
        value -= remainder
    return convert_result

def convert_one_digit_to_roman(raw_value, digit_base):
    candidates = "IVXLCDM"
    index = 0
    temp = digit_base
    while temp > 1:
        temp /= 10
        index += 2
    value = raw_value // digit_base
    if value <= 3:
        return candidates[index] * value
    if value == 4:
        return candidates[index] + candidates[index + 1]
    if value <= 8:
        return candidates[index + 1] + candidates[index] * (value - 5)
    if value == 9:
        return candidates[index] + candidates[index + 2]
    raise ValueError("无效输入: " + str(raw_value))

完整的代码

A First (Real) Example 一文中有使用 Tkinter\text{Tkinter} Tkinter 生成图形化界面的简单例子。在它的基础上,可以写出以下 Python3\text{Python3} Python3 代码

python 复制代码
from tkinter import *
from tkinter import ttk

def convert():
    try:
        value = num.get()
        if (value <= 0) or (value > 3999):
            result.set("无效输入")
            return
        result.set(to_roman(value))
    except ValueError:
        pass

def to_roman(value):
    convert_result = ""
    digit_base = 1
    while value > 0:
        remainder = value % (digit_base * 10)
        convert_result = convert_one_digit_to_roman(remainder, digit_base) + convert_result
        digit_base *= 10
        value -= remainder
    return convert_result

def convert_one_digit_to_roman(raw_value, digit_base):
    candidates = "IVXLCDM"
    index = 0
    temp = digit_base
    while temp > 1:
        temp /= 10
        index += 2
    value = raw_value // digit_base
    if value <= 3:
        return candidates[index] * value
    if value == 4:
        return candidates[index] + candidates[index + 1]
    if value <= 8:
        return candidates[index + 1] + candidates[index] * (value - 5)
    if value == 9:
        return candidates[index] + candidates[index + 2]
    raise ValueError("无效输入: " + str(raw_value))


root = Tk()
root.title("整数转罗马数字小工具")

mainframe = ttk.Frame(root, padding=(3, 3, 12, 12))
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))

num = IntVar()
num_entry = ttk.Entry(mainframe, width=4, textvariable=num)
num_entry.grid(column=2, row=1, sticky=(W, E))

ttk.Button(mainframe, text="转化为罗马数字", command=convert).grid(column=1, row=2, sticky=W)

ttk.Label(mainframe, text="请输入一个正整数 (不要超过3999)").grid(column=1, row=1, sticky=W)

result = StringVar()
ttk.Label(mainframe, textvariable=result).grid(column=2, row=2, sticky=W)

root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
mainframe.columnconfigure(2, weight=1)
for child in mainframe.winfo_children(): 
    child.grid_configure(padx=5, pady=5)

num_entry.focus()
root.bind("<Return>", convert)

root.mainloop()

运行

请将上一小节展示的完整代码保存为 to_roman.py。使用如下命令可以运行 to_roman.py

复制代码
python3 to_roman.py

运行效果如下

我们输入一个正数,例如当前年份 20262026 2026,然后点击"转化为罗马数字"按钮,效果如下

再用其他数字验证一下(例如 1949\text{1949} 1949)

运行结果符合预期

参考资料

相关推荐
codeGoogle21 小时前
自研 IM 还是选择第三方 SDK?企业开发者应该如何权衡?
前端·后端·程序员
数字化转型分享点滴1 天前
富士康、蓝思科技为何选择四化信息?MES制造执行系统的实践
python·科技
wling03011 天前
vasp虚频计算-python脚本
开发语言·windows·python·vasp计算
魔镜前的帅比1 天前
(开源项目)x-claw(总)
python·ai·rust·开源
xrandzj1 天前
Python面向对象编程入门:类、实例、初始化与封装实践
开发语言·python
DLYSB_1 天前
API 网关流量洪峰与突发 CC 攻击:我用 Go 写了个“现场物理防御哨兵”,把故障响应压缩到秒级
开发语言·后端·golang·报警灯
markinmarkin1 天前
Spring 中Bean 的作用域有哪些?
java·后端·spring
橙子家1 天前
使用方法 ToDictionary() 来优化查询时间复杂度:O(N*M) -> O(1*M)【C# 基础】
后端
matlabgoodboy1 天前
计算机毕设代做|Java Python Matlab APP 全套开发设计
java·python·课程设计
IT_陈寒1 天前
我又被JavaScript的隐式类型转换坑了
前端·人工智能·后端