当前位置: 首页 > news >正文

Tkinter制作登录界面以及登陆后页面切换(一)

Tkinter制作登录界面以及登陆后页面切换(一)

  • 前言
  • 序言
    • 1. 由来
    • 2. 思路
    • 3. 项目结构描述
    • 4. 项目实战
      • 1. 登录界面实现(代码)
      • 2. 首页界面实现(代码)
      • 3. 打包build.py(与main.py同级目录)
      • 4. 打包安装包

前言

本帖子,默认您已了解Tkinter的基础操作,以及原理,文中仅会对部分逻辑描述,不会对Tkinter讲解.

序言

1. 由来

入职以来,很长时间都是在做网页版的后台,用到最多的就是Java语言,框架主要是:Spring Boot,Spring Cloud 。中间件大多用:Mq,Redis,Nacos等,但是随着项目的发展,网页版已经无法满足客户的需求以及业务生态的发展,需要增加客户端应用,由于公司没有此类开发经验,重担就留给了俺,一个小趴菜(报头痛哭)…好了,废话不多说,开搞。说到客户端第一时间想到的就是python的PyQt5,因为以前了解过。但是随着深入了解,好是好,功能也齐全,但是由于作者比较笨,也比较懒实在不想去烧脑学习了,就盯上了较为简单快捷的Tkinter。

2. 思路

制作客户端主要流程被我分为(不考虑后台服务情况下):明白需求(了解业务)、设计架构(主要是使用的语言以及怎么模块化开发,方便后续升级管理)、打包部署(Inno setup 打包)、测试调优(测试人员)。

3. 项目结构描述

下文中出现的如: login/ui.py 这样的文件名称时则代表的是,在包login下的ui.py文件,后续可以自行修改。

4. 项目实战

1. 登录界面实现(代码)

  1. 图片展示:
    在这里插入图片描述

  2. login/ui.py

    from tkinter import *
    from tkinter.ttk import *class WinGUI(Tk):def __init__(self):super().__init__()self.__win()self.iconbitmap('favicon.ico')self.tk_input_username_label = Entry(self, )self.tk_input_username_label.place(relx=0.5367, rely=0.2471, relwidth=0.4000, relheight=0.1471)self.tk_input_password_label = Entry(self, show='*')self.tk_input_password_label.place(relx=0.5367, rely=0.4441, relwidth=0.4000, relheight=0.1471)self.tk_button_login_button = Button(self, text="立即登录", takefocus=False, )self.tk_button_login_button.place(relx=0.5367, rely=0.6824, relwidth=0.4000, relheight=0.1471)self.tk_label_register = Label(self, text="还没有账号?立即注册", anchor="center", )self.tk_label_register.place(relx=0.6933, rely=0.8676, relwidth=0.2250, relheight=0.0882)self.tk_canvas_login_canvas = Canvas(self, )self.tk_canvas_login_canvas.place(relx=0.0000, rely=0.0000, relwidth=0.4667, relheight=1.0000)self.tk_label_welcome = Label(self, text="项目介绍(自定义)", anchor="center", )self.tk_label_welcome.place(relx=0.4667, rely=0.0588, relwidth=0.5333, relheight=0.1471)def __win(self):self.title("登录界面")width, height = 600, 340screenwidth = self.winfo_screenwidth()screenheight = self.winfo_screenheight()geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)self.geometry(geometry)self.minsize(width=width, height=height)def login(self):username = self.tk_input_username_label.get()password = self.tk_input_password_label.get()return username, passwordclass Win(WinGUI):def __init__(self, controller):self.ctl = controllersuper().__init__()self.__event_bind()self.__style_config()self.ctl.init(self)def __event_bind(self):self.tk_input_password_label.bind('<Return>', self.ctl.login_submit)self.tk_button_login_button.bind('<Button-1>', self.ctl.login_submit)self.tk_button_login_button.bind('<Return>', self.ctl.login_submit)self.tk_label_register.bind('<Button-1>', self.ctl.register)passdef __style_config(self):pass
    
  3. login/control.py

    import tkinter.messageboxfrom login.ui import WinGUIclass Controller:# 导入UI类后,替换以下的 object 类型,将获得 IDE 属性提示功能ui: WinGUIdef __init__(self):self.url = "登录地址"def init(self, ui):"""得到UI实例,对组件进行初始化配置"""self.ui = uidef close_windows(self):print("点击了菜单")if self.ui:self.ui.destroy()def version(self):print("点击了菜单")tkinter.messagebox.showinfo("版本信息", "当前版本: V1.0.0")def login_submit(self, evt):u, p = self.ui.login()if u is None or len(u) == 0:tkinter.messagebox.showinfo("登录提示", "请输入登录用户名!")elif p is None or len(p) == 0:tkinter.messagebox.showinfo("登录提示", "请输入登录密码!")print(f"触发了登录操作,地址:{self.url},账号:{u},密码:{p}")# 模拟登录操作if u == 'admin' and p == 'admin':print(f'登录成功')# 关闭登录窗口self.ui.destroy()from home.control import Controller as HomeUIControllerfrom home.ui import Win as MainWin# 这里创建首页界面,并进入GUI循环,可以将登陆后的Token统一管理,不想管理的可以当作参数传过去不过比较麻烦app = MainWin(HomeUIController())app.mainloop()else:tkinter.messagebox.showinfo("登录提示", "登陆失败了,请检查账号密码是否正确.")def register(self, evt):print(f"触发了注册操作,地址:{self.url}")
  4. 启动类main.py

    # 导入窗口控制器
    from login.control import Controller as MainUIController
    # 导入布局文件
    from login.ui import Win as MainWinif __name__ == "__main__":app = MainWin(MainUIController())app.iconbitmap('favicon.ico')# 启动app.mainloop()
    

2. 首页界面实现(代码)

  1. 图片展示
    在这里插入图片描述

  2. home/ui.py

    from tkinter import *
    from tkinter.ttk import *class WinGUI(Tk):def __init__(self):super().__init__()self.__win()# 当前页数self.index = 1self.total = 10self.data = []self.tk_table_m1ef1meg = self.__tk_table_m1ef1meg(self)self.tk_label_m1ef4id7 = self.__tk_label_m1ef4id7(self)self.tk_input_query = self.__tk_input_query(self)self.tk_button_query = self.__tk_button_query(self)self.tk_button_head = self.__tk_button_head(self)self.tk_button_previous__page = self.__tk_button_previous__page(self)self.tk_button_next_page = self.__tk_button_next_page(self)self.tk_button_last = self.__tk_button_last(self)def __win(self):self.title("项目名称")# 设置窗口大小、居中width = 800height = 600screenwidth = self.winfo_screenwidth()screenheight = self.winfo_screenheight()geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)self.iconbitmap('favicon.ico')self.geometry(geometry)self.minsize(width=width, height=height)def scrollbar_autohide(self, vbar, hbar, widget):"""自动隐藏滚动条"""def show():if vbar: vbar.lift(widget)if hbar: hbar.lift(widget)def hide():if vbar: vbar.lower(widget)if hbar: hbar.lower(widget)hide()widget.bind("<Enter>", lambda e: show())if vbar: vbar.bind("<Enter>", lambda e: show())if vbar: vbar.bind("<Leave>", lambda e: hide())if hbar: hbar.bind("<Enter>", lambda e: show())if hbar: hbar.bind("<Leave>", lambda e: hide())widget.bind("<Leave>", lambda e: hide())def v_scrollbar(self, vbar, widget, x, y, w, h, pw, ph):widget.configure(yscrollcommand=vbar.set)vbar.config(command=widget.yview)vbar.place(relx=(w + x) / pw, rely=y / ph, relheight=h / ph, anchor='ne')def h_scrollbar(self, hbar, widget, x, y, w, h, pw, ph):widget.configure(xscrollcommand=hbar.set)hbar.config(command=widget.xview)hbar.place(relx=x / pw, rely=(y + h) / ph, relwidth=w / pw, anchor='sw')def create_bar(self, master, widget, is_vbar, is_hbar, x, y, w, h, pw, ph):vbar, hbar = None, Noneif is_vbar:vbar = Scrollbar(master)self.v_scrollbar(vbar, widget, x, y, w, h, pw, ph)if is_hbar:hbar = Scrollbar(master, orient="horizontal")self.h_scrollbar(hbar, widget, x, y, w, h, pw, ph)self.scrollbar_autohide(vbar, hbar, widget)def __tk_table_m1ef1meg(self, parent):# 表头字段 表头宽度columns = {"序列": 79, "姓名": 239, "民族": 79, "年龄": 79, "简介": 319}tk_table = Treeview(parent, show="headings", columns=list(columns), )for text, width in columns.items():  # 批量设置列属性tk_table.heading(text, text=text, anchor='center')tk_table.column(text, anchor='center', width=width, stretch=False)  # stretch 不自动拉伸tk_table.place(relx=0.0000, rely=0.1817, relwidth=0.9988, relheight=0.7500)return tk_tabledef __tk_button_next_page(self, parent):btn = Button(parent, text="下一页", takefocus=False, )btn.place(relx=0.8313, rely=0.9500, relwidth=0.0625, relheight=0.0500)return btndef __tk_button_previous__page(self, parent):btn = Button(parent, text="上一页", takefocus=False, )btn.place(relx=0.7462, rely=0.9500, relwidth=0.0625, relheight=0.0500)return btndef __tk_label_m1ef4id7(self, parent):label = Label(parent, text="当前第3页/总130页", anchor="center", )label.place(relx=0.4625, rely=0.9500, relwidth=0.1938, relheight=0.0500)return labeldef __tk_input_query(self, parent):ipt = Entry(parent, )ipt.place(relx=0.0000, rely=0.1183, relwidth=0.2500, relheight=0.0500)return iptdef __tk_button_query(self, parent):btn = Button(parent, text="搜索", takefocus=False, )btn.place(relx=0.2612, rely=0.1183, relwidth=0.0788, relheight=0.0500)return btndef __tk_button_head(self, parent):btn = Button(parent, text="首页", takefocus=False, )btn.place(relx=0.6675, rely=0.9500, relwidth=0.0625, relheight=0.0500)return btndef __tk_button_last(self, parent):btn = Button(parent, text="尾页", takefocus=False, )btn.place(relx=0.9187, rely=0.9500, relwidth=0.0625, relheight=0.0500)return btndef page_add_index(self):# 下一页if self.index < self.total:self.index += 1return self.indexdef page_sub_index(self):# 上一页if self.index > 1:self.index -= 1return self.indexdef update_table(self):if self.data and len(self.data) > 0:if self.tk_table_m1ef1meg.get_children():for get_child in self.tk_table_m1ef1meg.get_children():self.tk_table_m1ef1meg.delete(get_child)for index, datum in enumerate(self.data):self.tk_table_m1ef1meg.insert("", "end", text='',values=(index + 1, datum.get('name', ''), datum.get('nation', ''),datum.get('age', ''), datum.get('info', '')))class Win(WinGUI):def __init__(self, controller):self.ctl = controllersuper().__init__()self.__event_bind()self.__style_config()self.config(menu=self.create_menu())self.ctl.init(self)def create_menu(self):"""创建自定义的菜单,可以不要"""menu = Menu(self, tearoff=False)menu.add_cascade(label="设置", menu=self.menu_m1ecaoyu(menu))menu.add_cascade(label="帮助", menu=self.menu_m1eccdqt(menu))return menudef menu_m1ecaoyu(self, parent):menu = Menu(parent, tearoff=False)menu.add_command(label="关闭界面", command=self.ctl.close_windows)return menudef menu_m1eccdqt(self, parent):menu = Menu(parent, tearoff=False)menu.add_command(label="版本信息", command=self.ctl.version)return menudef __event_bind(self):"""此处对组件绑定事件"""# 搜索框绑定回车事件,回车直接搜索self.tk_input_query.bind('<Return>', self.ctl.select_member_data)# 搜索按钮绑定点击事件self.tk_button_query.bind('<Button-1>', self.ctl.select_member_data)# 首页事件self.tk_button_head.bind('<Button-1>', lambda event: self.ctl.load_member_data_next(self.index))self.tk_button_last.bind('<Button-1>', lambda event: self.ctl.load_member_data_next(self.total))self.tk_button_previous__page.bind('<Button-1>',lambda event: self.ctl.load_member_data_next(self.page_sub_index()))self.tk_button_next_page.bind('<Button-1>', lambda event: self.ctl.load_member_data_next(self.page_add_index()))passdef __style_config(self):pass
    

3. 打包build.py(与main.py同级目录)

import subprocessdef main_windows_package():# 定义 PyInstaller 命令pyinstaller_command = ['pyinstaller', '--onefile', '-w','--icon', 'favicon.ico', 'main.py']try:subprocess.run(pyinstaller_command, check=True)except subprocess.CalledProcessError as e:print(f"An error occurred while running PyInstaller: {e}")if __name__ == '__main__':main_windows_package()

4. 打包安装包

各位可以自行选择工具,由于此处项目过于简单,即开即用没有做打包的脚本,后续做到需要打包时会在后面写出来,当然有需要的也可以留言,看到后可以义务帮助。

执行了 build.py 后同级会出现一个dist目录,里边会有main.exe可执行文件,这个就是程序打包后的啦,好啦,到此结束。

相关文章:

Tkinter制作登录界面以及登陆后页面切换(一)

Tkinter制作登录界面以及登陆后页面切换&#xff08;一&#xff09; 前言序言1. 由来2. 思路3. 项目结构描述4. 项目实战1. 登录界面实现&#xff08;代码&#xff09;2. 首页界面实现&#xff08;代码&#xff09;3. 打包build.py&#xff08;与main.py同级目录&#xff09;4.…...

Colorful/七彩虹将星X17 AT 23 英特尔13代处理器 Win11原厂OEM系统 带COLORFUL一键还原

安装完毕自带原厂驱动和预装软件以及一键恢复功能&#xff0c;自动重建COLORFUL RECOVERY功能&#xff0c;恢复到新机开箱状态。 【格式】&#xff1a;iso 【系统类型】&#xff1a;Windows11 原厂系统下载网址&#xff1a;http://www.bioxt.cn 注意&#xff1a;安装系统会…...

《Ubuntu20.04环境下的ROS进阶学习8》

一、中断和定时器中断 在ROS中我们经常会遇到要使用中断函数的情况&#xff0c;中断函数的触发方式有很多种&#xff0c;比如检测到某个引脚的电平变化&#xff0c;或某个数据达到了一定的范围&#xff0c;但最实用的中断触发方式还是定时器中断。 二、编写ROS的中断代码 ros中…...

ubuntu24.04 怎么调整swap分区的大小,调整为16G

在Ubuntu中&#xff0c;swap分区的大小通常建议为物理内存的1到2倍&#xff0c;具体取决于你的使用需求和系统内存。例如&#xff0c;如果你有8GB内存&#xff0c;swap可以设置为8GB到16GB。swap的主要作用是当物理内存不足时&#xff0c;提供额外的虚拟内存&#xff0c;帮助防…...

【论文阅读】视觉里程计攻击

Adversary is on the Road: Attacks on Visual SLAM using Unnoticeable Adversarial Patch 一、视觉SLAM的不安全因素 根据论文的分析&#xff0c;视觉SLAM由于完全依赖于特征&#xff0c;缺少验证机制导致算法不安全。前端在受到干扰的情况下&#xff0c;会导致误匹配增加&…...

解决 Git LFS 切换分支失败问题

场景描述 在本地已有分支 A 的情况下&#xff0c;目前工作在分支 B。当尝试从 B 分支切回 A 分支时&#xff0c;由于 A 分支存在 LFS 上传的大文件&#xff0c;导致切换失败。这个问题通常是因为某些 LFS 文件在服务器上不存在或没有权限访问。 报错日志 切换分支时遇到的错…...

BaoStock 的安装

安装 pip3 install baostock使用这个库登录免费帐户时有时候会出现登录失败的问题 import baostock as bs # 登录系统 lg bs.login() # 登出系统 bs.logout()login failed! logout failed!可能是由于高版本的python需要验证ssl&#xff0c;本地将其设置为可信服务器地址可以…...

聚势启新 智向未来 | 重庆华阳通用科技有限公司揭牌成立

助推两江新区汽车产业高质量发展 (以下文字内容转载自两江新区网&#xff09; 9月26日&#xff0c;重庆华阳通用科技有限公司&#xff08;华阳通用重庆子公司&#xff09;在两江新区揭牌成立&#xff0c;将致力于智能座舱、智能驾驶两大领域&#xff0c;不断加大技术研发投入…...

【数据结构与算法】Z算法(扩展KMP)(C++和Python写法)

Z算法&#xff08;扩展KMP&#xff09; 文章目录 Z算法&#xff08;扩展KMP&#xff09;朴素求法线性求法力扣类型题变种题&#xff1a;[3303. 第一个几乎相等子字符串的下标](https://leetcode.cn/problems/find-the-occurrence-of-first-almost-equal-substring/) 所谓Z算法&…...

免费语音转文字软件全览:开启高效记录新时代

在当今快节奏的信息时代&#xff0c;高效地处理和记录信息变得至关重要。语音转文字技术的出现&#xff0c;为我们带来了极大的便利&#xff0c;今天&#xff0c;就让我们一同探讨这些语音转文字免费的软件的使用方法。 1.365在线转文字 链接直达&#xff1a;https://www.pdf…...

PHP“===”的意义

在PHP中&#xff0c; 运算符被称为“恒等比较运算符”&#xff08;Identical Comparison Operator&#xff09;&#xff0c;它用于比较两个变量的值和类型是否完全相同。这个运算符与双等号 &#xff08;等值比较运算符&#xff09;不同&#xff0c;后者在比较时会对两边的值进…...

Tomcat架构解析

Tomcat: 是基于JAVA语言的轻量级应用服务器&#xff0c;是一款完全开源免费的Servlet服务器实现。 1. 总体设计 socket: 其实就是操作系统提供给程序员操作“网络协议栈”的接口&#xff0c;你能通过socket的接口&#xff0c;来控制协议&#xff0c;实现网络通信&#xff0c;达…...

如何在 Kubernetes 上部署和配置开源数据集成平台 Airbyte?

在 Kubernetes 上部署和配置 Airbyte 是一个复杂但非常有价值的过程&#xff0c;特别是对于需要强大数据集成和数据处理能力的企业或团队。Airbyte 是一个开源的数据集成平台&#xff0c;允许用户从各种来源提取数据并加载到目标存储中。其强大的插件系统支持多种数据源与目标&…...

信息技术与商业变革:机遇与挑战

信息技术与商业变革&#xff1a;机遇与挑战 目录 引言信息技术推动商业变革的主要因素 数字化转型的加速客户需求的个性化创新技术的应用 信息技术在企业中的应用场景 供应链管理的智能化营销与客户关系管理财务与资源管理的自动化远程工作和协作 信息技术带来的挑战 网络安全…...

JavaWeb之过滤器

1. 过滤器的概念 过滤器是Java Servlet规范中定义的组件&#xff0c;用于在请求到达Servlet之前或响应返回客户端之前&#xff0c;对请求或响应进行拦截和处理。过滤器可以实现以下功能&#xff1a; 日志记录&#xff1a;记录请求的详细信息&#xff0c;如URI、参数、时间等。…...

学习 笔记

bin log/redo log/undo log MySQL日志主要包括查询日志、慢查询日志、事务日志、错误日志、二进制日志等。其中比较重要的是 bin log&#xff08;二进制日志&#xff09;和 redo log&#xff08;重做日志&#xff09;和 undo log&#xff08;回滚日志&#xff09;。 慢SQL查询&…...

Flask-1

文章目录 Flask准备创建flask项目flask加载项目配置的二种方式 路由的基本定义接收任意路由参数接收限定类型参数自定义路由参数转换器 终端运行Flask项目http的请求与响应flask的生命周期请求获取请求中各项数据获取请求URL参数获取请求体获取请求头相关信息 响应响应html文本…...

pve 直通硬盘

qm set <vm_id> –<disk_type>[n] /dev/disk/by-id/- b r a n d − brand- brand−model_$serial_number <vm_id> : 为创建虚拟机时指定的VM ID。 <disk_type>[n]&#xff1a; 导入后的磁盘的总线类型及其编号&#xff0c;总线类型可以选择IDE、SATA…...

NLP_情感分类_机器学习(w2v)方案

文章目录 项目背景数据清洗导包导入数据切分评论及标签Word2Vec构造w2v 数据切分模型训练查看结果 同类型项目 项目背景 项目的目的&#xff0c;是为了对情感评论数据集进行预测打标。在训练之前&#xff0c;需要对数据进行数据清洗环节&#xff0c;前面已对数据进行清洗&…...

240929-CGAN条件生成对抗网络

240929-CGAN条件生成对抗网络 前面我们学习了GAN&#xff08;240925-GAN生成对抗网络-CSDN博客&#xff09;和DCGAN&#xff08;240929-DCGAN生成漫画头像-CSDN博客&#xff09;&#xff0c;接下来继续来看CGAN&#xff08;Conditional GAN&#xff09;条件生成对抗网络。 流…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...