上一篇文章:CGY-OS 正式开源!_cgy091107的博客-CSDN博客
一、软件编写基础要求
在编写CGY-OS的应用程序之前,您需要:
1. 安装python3.10,配置好CGY-OS。
2.掌握python3的基本语法、lambda表达式、各种简单的数据结构。
3.对python的tkinter库有基本的了解,并使用它编写过简单的应用程序。
4.仔细阅读过上一篇文章。(这很重要!否则后文的传参将让您头疼)
如果您认为您满足此要求,请继续向下翻看。
二、配置CGY-OS
以后再说。u
三、编写第一个“ULoop”程序:numAdder
3.1 “ULoop”和“Loop”:
由于CGY-OS 的GUI控件中,大多(如Button、Entry)都有command参数,所以在处理一些简单的任务(如按下按钮执行一个函数)时,无需一个一直在后台执行的进程处理这些任务,所以我们不需要在应用程序里编写一个类似于cos的oneloop的函数(关于cos.oneloop,参见上一篇文章),这种程序,被称为“ULoop”。
反之,在处理一些复杂的、不能中断的任务(如计时器、游戏)时,我们在程序里必须设置一个在后台一直执行的函数(def run():),这种程序被称为“Loop”。
3.2 编写程序
其实在上一篇文章的2.1中,已经带领大家编写过了一个“ULoop"程序。所以,框架在此不再解释。
在cos\apps新建文件,命名为“numAdder.py”,输入基础框架,并在cos\apps\__init__.py第一行末尾追加“numAdder”(详见见上一篇文章的2.1)。
from apilib import *
from classes import *
import cos
# 导入包
def cosmain(): # 主函数
screen = cos.window # 绑定显示器
root = Tk(screen, 10, 105, 350, 450, "Basic") # 创建窗口
api_hook(root, 'Basic') # 绑定窗口
在cos应用程序编写中,最稳妥的方式是先添加控件,再调整root的大小(root的大小基本总是不合适的)。我们现在来添加一个文本框:
def cosmain():
screen = cos.window
root = Tk(screen, 10, 105, 350, 450, "Basic")
entry = Entry(screen, root, 5, 5, 70) #这里
entry.pack() #这里
api_hook(root, 'Basic')
运行一下(如果您无法运行,请检查cos\apps\__init__.py的第一行的import语句是否包含numAdder、您的文件名称和App_starter中的输入,如果您问我如何在App_starter的文本框内输入,那么请仔细查看上一篇文章,如果还是输入不了,请换Windows+python3.10+高配置并重试几遍),结果如图:
很好!接下来 我们在添加一个“+”(使用Label)和另一个文本框。
def cosmain():
screen = cos.window
root = Tk(screen, 10, 105, 350, 450, "Basic")
entry = Entry(screen, root, 5, 5, 70)
entry.pack()
Label(screen, root, "+", 83, 5, bg=None).pack() #从这里
entry2 = Entry(screen, root, 100, 5, 70)
entry2.pack() #到这里
api_hook(root, 'Basic')
对于像“+”这样既不获取其值,又不对其加以改变的控件,我们可以不使用变量,直接调用其pack方法(学过tkinter的都懂)。运行结果如图:
在创建一个calc函数(函数体为空)和一个按钮、一个状态栏(就是label),并将calc绑定到按钮和文本框中。
def cosmain():
def calc(): #这里
pass
screen = cos.window
root = Tk(screen, 10, 105, 350, 450, "Basic")
entry = Entry(screen, root, 5, 5, 70, command=calc)#这里
entry.pack()
Label(screen, root, "+", 83, 5, bg=None).pack()
entry2 = Entry(screen, root, 100, 5, 70, command=calc)#这里
entry2.pack()
Button(screen, root, "Calc", 175, 5, 45, command=calc).pack()#从这里
label = Label(screen, root, "Welcome!", 5, 35, bg=None)
label.pack() #到这里
api_hook(root, 'Basic')
接下来可以更改窗口了。
from apilib import *
from classes import *
import cos
def cosmain():
def calc():
pass
screen = cos.window
root = Tk(screen, 10, 105, 230, 55, "numAdder") #这里
entry = Entry(screen, root, 5, 5, 70, command=calc)
entry.pack()
Label(screen, root, "+", 83, 5, bg=None).pack()
entry2 = Entry(screen, root, 100, 5, 70, command=calc)
entry2.pack()
Button(screen, root, "Calc", 175, 5, 45, command=calc).pack()
label = Label(screen, root, "Welcome!", 5, 35, bg=None)
label.pack()
api_hook(root, 'numAdder') #这里
至此,UI界面编写完成。运行结果:
接下来编写运算函数,先获取两数的值并相加、显示:
def calc():
num1 = int(entry.get())
num2 = int(entry2.get())
ans = num1 + num2
label.config(text=f"{num1}+{num2}={ans}", fg=blue) #使用蓝色显示答案
再运行一下:
很好,没有问题,但是当我们输入非数字时……
cos崩溃了。 我们必须避免这种问题,解决方案当然是try...except...语句。
def calc():
try:
num1 = int(entry.get())
num2 = int(entry2.get())
except ValueError:
label.config(text="Must be a number.", fg=red)
else:
ans = num1 + num2
label.config(text=f"{num1}+{num2}={ans}", fg=blue) # 使用蓝色显示答案
再试一次,就没有问题了!
3.3 Label.maxlenth 体验 & 程序优化
当我们输入的数过长时,label的显示会出现问题:
接下来让我们解决这种问题。
方法1:长度限制:因为Entry没有maxlenth之类的参数(当然以后会有),所以我们只能在程序中限制:
def calc():
try:
num1 = int(entry.get())
num2 = int(entry2.get())
except ValueError:
label.config(text="Must be a number.", fg=red)
else:
if len(entry.get()) > 10 or len(entry2.get()) > 10:
label.config(text="Number's length mustn't bigger than 10.", fg=red)
else:
ans = num1 + num2
label.config(text=f"{num1}+{num2}={ans}", fg=blue) # 使用蓝色显示答案
运行结果:
好吧,这样也超了,所以我们才需要第二种方案:
方法2:更改cosmain中的这一行代码,然后查看结果:
def cosmain():
def calc():
try:
num1 = int(entry.get())
num2 = int(entry2.get())
except ValueError:
label.config(text="Must be a number.", fg=red)
else:
if len(entry.get()) > 10 or len(entry2.get()) > 10:
label.config(text="Number's length mustn't bigger than 10.", fg=red)
else:
ans = num1 + num2
label.config(text=f"{num1}+{num2}={ans}", fg=blue) # 使用蓝色显示答案
screen = cos.window
root = Tk(screen, 10, 105, 230, 80, "numAdder")##这里!(80原来是55)
entry = Entry(screen, root, 5, 5, 70, command=calc)
entry.pack()
Label(screen, root, "+", 83, 5, bg=None).pack()
entry2 = Entry(screen, root, 100, 5, 70, command=calc)
entry2.pack()
Button(screen, root, "Calc", 175, 5, 45, command=calc).pack()
######################################################这里!!!
label = Label(screen, root, "Welcome!", 5, 35, bg=None, maxlength=20) #这里!
label.pack()
api_hook(root, 'numAdder')
再次运行呢?
我们看到它自动换行了。这是Label的高级功能。
3.4 恭喜!
恭喜!!!您已经成功的做出了一个安全的、完整的、实用的CGY-OS应用程序了!
附上源代码:
from apilib import *
from classes import *
import cos
def cosmain():
def calc():
try:
num1 = int(entry.get())
num2 = int(entry2.get())
except ValueError:
label.config(text="Must be a number.", fg=red)
else:
if len(entry.get()) > 10 or len(entry2.get()) > 10:
label.config(text="Number's length mustn't bigger than 10.", fg=red)
else:
ans = num1 + num2
label.config(text=f"{num1}+{num2}={ans}", fg=blue)
screen = cos.window
root = Tk(screen, 10, 105, 230, 80, "numAdder")
entry = Entry(screen, root, 5, 5, 70, command=calc)
entry.pack()
Label(screen, root, "+", 83, 5, bg=None).pack()
entry2 = Entry(screen, root, 100, 5, 70, command=calc)
entry2.pack()
Button(screen, root, "Calc", 175, 5, 45, command=calc).pack()
label = Label(screen, root, "Welcome!", 5, 35, bg=None, maxlength=20)
label.pack()
api_hook(root, 'numAdder')
四、编写第一个"Loop"应用程序
4.1 概述
在本程序中,我们要通过canvas控件创建一个动画,动画中,我们每隔0.1秒刷新一次(具体画什么后面自知)。
4.2 编写程序框架
新建文件animation.py(animation为“动画”的英文),输入应用程序框架,并在cos\apps\__init__.py第一行结尾追加,运行无误后进行下一步。
为了在后台运行我们的进程,我们在cosmain中添加一个run函数,并用root.add_unapply_hook来添加它(之所以用add_unapply_hook,是为了在root隐藏时可以继续运行run函数,虽然本示例用不到它,但是这是一个好的习惯)。
def cosmain():
def run():
pass
screen = cos.window
root = Tk(screen, 10, 105, 350, 450, "Basic")
root.add_unapply_hook(run)
api_hook(root, 'Basic')
重点:run函数要写成oneloop的形式,也就是说它的函数体不是循环,而是循环内的所有代码。
4.3 计时器
计时器类来自cpu.py的Time类,它被apilib间接导入到应用程序中。
我们使用一个程序(直接该animation.py源代码)来说明这个类,这个程序显示一个Label,它从0开始,每一秒增加1.
from apilib import *
from classes import *
import cos
def cosmain():
def run():
nonlocal i # nonlocal:问你的python老师去
if (not timer.is_sleeping() # 如果上一次计时结束
or timer.sec == 0): # 或者刚刚开始
timer.sleep(1) # 计时1秒
i += 1
label.config(text=f"{i}") # 更新
screen = cos.window
root = Tk(screen, 10, 105, 55, 30, "Time")
timer = Time()
i = 0
label = Label(screen, root, f"{i}", 5, 5, bg=None)
label.pack()
root.add_unapply_hook(run)
api_hook(root, 'Time')
运行结果:
4.4 编写程序
我们先把4.3的文件删掉,换成4.2的框架。
我们的GUI编写非常简单,只需要添加一个canvas并改变窗口就可以了。
from apilib import *
from classes import *
import cos
def cosmain():
def run():
pass
screen = cos.window
root = Tk(screen, 10, 105, 200, 200, "Animation")
canvas = Canvas(screen, root, 0, 0, 200, 200)
canvas.pack()
root.add_unapply_hook(run)
api_hook(root, 'Animation')
我们再来添加一个画方块的函数box,并添加一个测试用的按钮来调用它
from apilib import *
from classes import *
import cos
import random
def cosmain():
def box(i):
pen = canvas.rect(100 - i * 5, 100 - i * 5, i * 10, i * 10,
(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
pens.append(pen)
def run():
pass
pens = []
screen = cos.window
root = Tk(screen, 10, 105, 200, 200, "Animation")
canvas = Canvas(screen, root, 0, 0, 200, 200)
canvas.pack()
Button(screen, root, "test", 5, 5, 45, lambda: box(15)).pack()
root.add_unapply_hook(run)
api_hook(root, 'Animation')
点击按钮,屏幕上出现了一个颜色随机的正方形。
接下来,我们删除button,参考4.3中的内容,使run函数每隔0.5秒执行一次(i先传参15):
def cosmain():
def box(i):
pen = canvas.rect(100 - i * 5, 100 - i * 5, i * 10, i * 10,
(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
pens.append(pen)
def run():
if not timer.is_sleeping() or timer.sec==0:
timer.sleep(0.5)
box(15)
pens = []
screen = cos.window
root = Tk(screen, 10, 105, 200, 200, "Animation")
timer = Time()
canvas = Canvas(screen, root, 0, 0, 200, 200)
canvas.pack()
# Button(screen, root, "test", 5, 5, 45, lambda: box(15)).pack()
root.add_unapply_hook(run)
api_hook(root, 'Animation')
我们在增加一个i变量,从20开始,每0.5秒减少1,直到为0为止。
from apilib import *
from classes import *
import cos
import random
def cosmain():
def box(i):
pen = canvas.rect(100 - i * 5, 100 - i * 5, i * 10, i * 10,
(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
pens.append(pen)
def run():
nonlocal i
if not timer.is_sleeping() or timer.sec == 0:
timer.sleep(0.5)
if i != 0:
box(i)
i -= 1
pens = []
i = 20
screen = cos.window
root = Tk(screen, 10, 105, 200, 200, "Animation")
timer = Time()
canvas = Canvas(screen, root, 0, 0, 200, 200)
canvas.pack()
# Button(screen, root, "test", 5, 5, 45, lambda: box(15)).pack()
root.add_unapply_hook(run)
api_hook(root, 'Animation')
运行结果:
接下来,我们增加一个功能:在i=0(结束绘图)是将所有正方形从外到内删除,直到画布为空白。
def cosmain():
def box(i):
pen = canvas.rect(100 - i * 5, 100 - i * 5, i * 10, i * 10,
(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
pens.append(pen)
def run():
nonlocal i, flag
if not timer.is_sleeping() or timer.sec == 0:
timer.sleep(0.5)
if not flag: # 没有停止过
if i != 0:
box(i)
i -= 1
else:
flag = True
else:
if len(pens) != 0: # 如果还有绘图句柄:
canvas.remove_pen(pens[0])
pens.pop(0) # 删除第一个元素
pens = []
i = 20
flag = False # 是否停止
screen = cos.window
root = Tk(screen, 10, 105, 200, 200, "Animation")
timer = Time()
canvas = Canvas(screen, root, 0, 0, 200, 200)
canvas.pack()
# Button(screen, root, "test", 5, 5, 45, lambda: box(15)).pack()
root.add_unapply_hook(run)
api_hook(root, 'Animation')
我们来实现最后一个功能:动画循环播放(说白了只用增加3行代码):
from apilib import *
from classes import *
import cos
import random
def cosmain():
def box(i):
pen = canvas.rect(100 - i * 5, 100 - i * 5, i * 10, i * 10,
(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
pens.append(pen)
def run():
nonlocal i, flag
if not timer.is_sleeping() or timer.sec == 0:
timer.sleep(0.5)
if not flag: # 没有停止过
if i != 0:
box(i)
i -= 1
else:
flag = True
else:
if len(pens) != 0: # 如果还有绘图句柄:
canvas.remove_pen(pens[0])
pens.pop(0) # 删除第一个元素
else: # 从这里
flag = False
i = 20 # 到这里
pens = []
i = 20
flag = False # 是否停止
screen = cos.window
root = Tk(screen, 10, 105, 200, 200, "Animation")
timer = Time()
canvas = Canvas(screen, root, 0, 0, 200, 200)
canvas.pack()
# Button(screen, root, "test", 5, 5, 45, lambda: box(15)).pack()
root.add_unapply_hook(run)
api_hook(root, 'Animation')
最后,将timer.sleep中的数据减小一点“timer.sleep(0.5)”—>"timer.sleep(0.05)",观看效果——完美!
4.5 恭喜
恭喜又完成了一件大作!相信您在此时一定收获颇多。CGY-OS的程序就是这么简单,只要可以熟练使用库就好了。
下一节,我们将制作一个GUI设计很有挑战性的程序:计算器。
五、计算器
5.1 原理、ui
让我们先打开python控制台,输入以下代码:
eval("57+38-10*(5-4)")
输出:85
所以eval表达式可以计算一个Python语句(表达式)的值。通过这个,我们可以通过追加表达式的方法实现计算的功能,此思路和大部分计算器的编写思路是一样的。
顺便说一句,因为cos内核过于简单,UI功能有限,所以我们的ui长这样(漂亮吧!):
5.2 Python实现
这次改规矩了,先写函数,再写UI。
import cos
from apilib import *
from classes import *
def cosmain():
def update(x): #将x追加到evaler后面
nonlocal evaler
if evaler != '0':
evaler += x
else:
evaler = x
def backspace(): #退格
nonlocal evaler
if evaler != '0' and evaler != '':
evaler = evaler[:-1]
if evaler == '':
evaler = '0'
def c():#清零
nonlocal evaler
evaler = '0'
def calc(): #计算
nonlocal evaler
try:
int(eval(evaler)) #使用eval计算和试错
except(SyntaxError, Exception):
pass #先不管他
finally:
evaler = '0' #怎么着都得重置
screen = cos.window
evaler = "0" #数学表达式
root = Tk(screen, 10, 105, 270, 65, "calc")
api_hook(root, 'calc')
注释很清楚,写过计算器的应该都能看懂。
再加一个Label:
def cosmain():
def update(x):
nonlocal evaler
if evaler != '0':
evaler += x
else:
evaler = x
if len(evaler) < len("Error:Invalid expression."):
label.config(text=evaler, fg=black)#成功增加
else:
label.config(text="Error:Line too long.", fg=red)#失败(太长了)
def backspace():
nonlocal evaler
if evaler != '0' and evaler != '':
evaler = evaler[:-1]
if evaler == '':
evaler = '0'
label.config(text=evaler, fg=black)#成功
def c():
nonlocal evaler
evaler = '0'
label.config(text=evaler, fg=black)#成功
def calc():
nonlocal evaler
try:
label.config(text=f"={int(eval(evaler))}", fg=green) #成功
except(SyntaxError, Exception):
label.config("Error:Invalid expression.", fg=red) #语法错误
finally:
evaler = '0'
screen = cos.window
evaler = "0"
root = Tk(screen, 10, 105, 270, 65, "calc")
Canvas(screen, root, 5, 5, 260, 15).pack()#为了使背景为白色,增加一个白色的canvas(正方形)
label = Label(screen, root, evaler, 5, 5)
label.pack()
api_hook(root, 'calc')
最后一堆按钮:
Button(screen, root, "C", 5, 25, 10, lambda: c()).pack()
Button(screen, root, "1", 20, 25, 10, lambda: update('1')).pack()
Button(screen, root, "2", 35, 25, 10, lambda: update('2')).pack()
Button(screen, root, "3", 50, 25, 10, lambda: update('3')).pack()
Button(screen, root, "4", 65, 25, 10, lambda: update('4')).pack()
Button(screen, root, "5", 80, 25, 10, lambda: update('5')).pack()
Button(screen, root, "6", 95, 25, 10, lambda: update('6')).pack()
Button(screen, root, "7", 110, 25, 10, lambda: update('7')).pack()
Button(screen, root, "8", 125, 25, 10, lambda: update('8')).pack()
Button(screen, root, "9", 140, 25, 10, lambda: update('9')).pack()
Button(screen, root, "0", 155, 25, 10, lambda: update('0')).pack()
Button(screen, root, "BackSpace", 170, 25, 95, lambda: backspace()).pack()
Button(screen, root, "+", 5, 45, 10, lambda: update('+')).pack()
Button(screen, root, "-", 20, 45, 10, lambda: update('-')).pack()
Button(screen, root, "*", 35, 45, 10, lambda: update('*')).pack()
Button(screen, root, "/", 50, 45, 10, lambda: update('/')).pack()
Button(screen, root, "%", 65, 45, 10, lambda: update('%')).pack()
Button(screen, root, "//", 80, 45, 20, lambda: update('//')).pack()
Button(screen, root, "(", 105, 45, 10, lambda: update('(')).pack()
Button(screen, root, ")", 120, 45, 10, lambda: update(')')).pack()
Button(screen, root, "Calc it!", 135, 45, 85, lambda: calc()).pack()
5.3 恭喜!
计算器这个程序虽然简单,但意义非凡,它代表着CGY-OS在不断地向实用的操作系统买进!
本节写的简单了一些,以后也只会越来越简单。
全部源码:
import cos
from apilib import *
from classes import *
def cosmain():
def update(x):
nonlocal evaler
if evaler != '0':
evaler += x
else:
evaler = x
if len(evaler) < len("Error:Invalid expression."):
label.config(text=evaler, fg=black)
else:
label.config(text="Error:Line too long.", fg=red)
def backspace():
nonlocal evaler
if evaler != '0' and evaler != '':
evaler = evaler[:-1]
if evaler == '':
evaler = '0'
label.config(text=evaler, fg=black)
def c():
nonlocal evaler
evaler = '0'
label.config(text=evaler, fg=black)
def calc():
nonlocal evaler
try:
label.config(text=f"={int(eval(evaler))}", fg=green)
except(SyntaxError, Exception):
label.config("Error:Invalid expression.", fg=red)
finally:
evaler = '0'
screen = cos.window
evaler = "0"
root = Tk(screen, 10, 105, 270, 65, "calc")
Canvas(screen, root, 5, 5, 260, 15).pack()
label = Label(screen, root, evaler, 5, 5)
label.pack()
Button(screen, root, "C", 5, 25, 10, lambda: c()).pack()
Button(screen, root, "1", 20, 25, 10, lambda: update('1')).pack()
Button(screen, root, "2", 35, 25, 10, lambda: update('2')).pack()
Button(screen, root, "3", 50, 25, 10, lambda: update('3')).pack()
Button(screen, root, "4", 65, 25, 10, lambda: update('4')).pack()
Button(screen, root, "5", 80, 25, 10, lambda: update('5')).pack()
Button(screen, root, "6", 95, 25, 10, lambda: update('6')).pack()
Button(screen, root, "7", 110, 25, 10, lambda: update('7')).pack()
Button(screen, root, "8", 125, 25, 10, lambda: update('8')).pack()
Button(screen, root, "9", 140, 25, 10, lambda: update('9')).pack()
Button(screen, root, "0", 155, 25, 10, lambda: update('0')).pack()
Button(screen, root, "BackSpace", 170, 25, 95, lambda: backspace()).pack()
Button(screen, root, "+", 5, 45, 10, lambda: update('+')).pack()
Button(screen, root, "-", 20, 45, 10, lambda: update('-')).pack()
Button(screen, root, "*", 35, 45, 10, lambda: update('*')).pack()
Button(screen, root, "/", 50, 45, 10, lambda: update('/')).pack()
Button(screen, root, "%", 65, 45, 10, lambda: update('%')).pack()
Button(screen, root, "//", 80, 45, 20, lambda: update('//')).pack()
Button(screen, root, "(", 105, 45, 10, lambda: update('(')).pack()
Button(screen, root, ")", 120, 45, 10, lambda: update(')')).pack()
Button(screen, root, "Calc it!", 135, 45, 85, lambda: calc()).pack()
api_hook(root, 'calc')
六、“超级画板”
6.1 一个新的类
为了使这个应用程序可以使用,我专门写了一个新的类:ImageButton,它为Button的子类。
class ImageButton(Button):
def __init__(self, screen, root, img, x, y, w, h, table, command, bg=lightgray):
super().__init__(screen, root, "", x, y, w, command, bg)
self.image = img
self.table = table
self.h = h
def printImg(self):
for i in range(len(self.image)):
for j in range(len(self.image[i])):
if self.table[self.image[i][j]] is not None:
Io.io_put_point(self.screen, self.x + self.root.x + j, self.y + self.root.y + i,
self.table[self.image[i][j]])
def config(self, x=None, y=None, w=None, h=None, command=None, fg=None, bg=None, image=None, table=None):
if x is not None:
self.x = x
if y is not None:
self.y = y
if w is not None:
self.w = w
if h is not None:
self.h = h
if command is not None:
self.command = command
if fg is not None:
self.fg = fg
if bg is not None:
self.bg = bg
if image is not None:
self.image = image
if table is not None:
self.table = table
def draw(self):
global s_mode
mx, my = pygame.mouse.get_pos()
if self.check_click(mx, my):
Io.io_put_box(self.screen, self.x - 1 + self.root.x, self.y - 1 + self.root.y, self.w + 1, self.h + 1,
black)
Io.io_put_box(self.screen, self.x + self.root.x, self.y + self.root.y, self.w + 1, self.h + 1, white)
Io.io_put_box(self.screen, self.x + self.root.x, self.y + self.root.y, self.w, self.h, self.bg)
self.printImg()
else:
Io.io_put_box(self.screen, self.x - 1 + self.root.x, self.y - 1 + self.root.y, self.w + 1, self.h + 1,
white)
Io.io_put_box(self.screen, self.x + self.root.x, self.y + self.root.y, self.w + 1, self.h + 1, black)
Io.io_put_box(self.screen, self.x + self.root.x, self.y + self.root.y, self.w, self.h, self.bg)
self.printImg()
if self.on(mx, my):
cell.m_state = mouse3
s_mode = True
if self.runcmd() and self.check_click(mx, my):
self.command()
这里说一下:img是一个二维数组,table是一个字典,用于描述img的颜色。
有了类就要有图片,前面说了,img是二维数组,所以图片都写在代码里:
image0 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
image1 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
image2 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
image3 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
image4 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
6.2 代码
没错,直接上代码,说都懒得说……
先来UI:
def cosmain():
def changeColor(color, iten):
pass
def clear():
pass
def widthUpdate(num):
pass
screen = cos.window
pen_color = black
width = 5
root = Tk(screen, 10, 105, 450, 450, "Draw")
canvas = Canvas(screen, root, 30, 0, 420, 450)
canvas.pack()
btn_green = ImageButton(screen, root, image0, 5, 5, 16, 16, {0: "green", 1: "black"},
lambda: changeColor(green, btn_green))
btn_green.pack()
btn_red = ImageButton(screen, root, image0, 5, 25, 16, 16, {0: "red", 1: "black"},
lambda: changeColor(red, btn_red))
btn_red.pack()
btn_black = ImageButton(screen, root, image0, 5, 45, 16, 16, {0: "black", 1: "white"},
lambda: changeColor(black, btn_black))
btn_black.pack()
btn_yellow = ImageButton(screen, root, image0, 5, 65, 16, 16, {0: "yellow", 1: "black"},
lambda: changeColor(yellow, btn_yellow))
btn_yellow.pack()
btn_blue = ImageButton(screen, root, image0, 5, 85, 16, 16, {0: "blue", 1: "black"},
lambda: changeColor(blue, btn_blue))
btn_blue.pack()
btn_lightblue = ImageButton(screen, root, image0, 5, 105, 16, 16, {0: "lightblue", 1: "black"},
lambda: changeColor(lightblue, btn_lightblue))
btn_lightblue.pack()
btn_orange = ImageButton(screen, root, image0, 5, 125, 16, 16, {0: "orange", 1: "black"},
lambda: changeColor(orange, btn_orange))
btn_orange.pack()
btn_purple = ImageButton(screen, root, image0, 5, 145, 16, 16, {0: "purple", 1: "black"},
lambda: changeColor(purple, btn_purple))
btn_purple.pack()
btn_pink = ImageButton(screen, root, image0, 5, 165, 16, 16, {0: "pink", 1: "black"},
lambda: changeColor(pink, btn_pink))
btn_pink.pack()
bth_clear = ImageButton(screen, root, image2, 5, 185, 16, 16, {0: None, 1: "black"}, clear)
bth_clear.pack()
bth_up = ImageButton(screen, root, image3, 5, 205, 16, 10, {0: None, 1: 'black'}, command=lambda: widthUpdate(1))
bth_up.pack()
label = Label(screen, root, str(width).zfill(2), 5, 220, bg=None) # zfill为补零的小技巧
label.pack()
bth_down = ImageButton(screen, root, image4, 5, 240, 16, 10, {0: None, 1: 'black'}, command=lambda: widthUpdate(-1))
bth_down.pack()
buttons = [btn_pink, btn_purple, btn_orange, btn_lightblue, btn_blue, btn_yellow, btn_black, btn_red, btn_green]
def run():
pass
root.add_unapply_hook(run)
api_hook(root, 'Drawer')
再上逻辑:
def changeColor(color, iten):
nonlocal pen_color
pen_color = color
iten.config(image=image1)
for i in buttons:
if i is iten: continue
i.config(image=image0)
def clear():
canvas.remove_all()
def widthUpdate(num):
nonlocal width
if 3 <= width + num <= 50:
width += num
label.config(text=str(width).zfill(2))
#……
def run():
is_on, mx, my = canvas.mouse_is_on()
if is_on and Io.io_check_mouse()[0]:
canvas.rect(mx + 15 + 8, my - 15 + 8, width, width, pen_color)
最后把全部代码一上:
from apilib import *
from classes import *
import cos
import hankaku
image0 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
image1 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
image2 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
image3 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
image4 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
def cosmain():
def changeColor(color, iten):
nonlocal pen_color
pen_color = color
iten.config(image=image1)
for i in buttons:
if i is iten: continue
i.config(image=image0)
def clear():
canvas.remove_all()
def widthUpdate(num):
nonlocal width
if 3 <= width + num <= 50:
width += num
label.config(text=str(width).zfill(2))
screen = cos.window
pen_color = black
width = 5
root = Tk(screen, 10, 105, 450, 450, "Draw")
canvas = Canvas(screen, root, 30, 0, 420, 450)
canvas.pack()
btn_green = ImageButton(screen, root, image0, 5, 5, 16, 16, {0: "green", 1: "black"},
lambda: changeColor(green, btn_green))
btn_green.pack()
btn_red = ImageButton(screen, root, image0, 5, 25, 16, 16, {0: "red", 1: "black"},
lambda: changeColor(red, btn_red))
btn_red.pack()
btn_black = ImageButton(screen, root, image0, 5, 45, 16, 16, {0: "black", 1: "white"},
lambda: changeColor(black, btn_black))
btn_black.pack()
btn_yellow = ImageButton(screen, root, image0, 5, 65, 16, 16, {0: "yellow", 1: "black"},
lambda: changeColor(yellow, btn_yellow))
btn_yellow.pack()
btn_blue = ImageButton(screen, root, image0, 5, 85, 16, 16, {0: "blue", 1: "black"},
lambda: changeColor(blue, btn_blue))
btn_blue.pack()
btn_lightblue = ImageButton(screen, root, image0, 5, 105, 16, 16, {0: "lightblue", 1: "black"},
lambda: changeColor(lightblue, btn_lightblue))
btn_lightblue.pack()
btn_orange = ImageButton(screen, root, image0, 5, 125, 16, 16, {0: "orange", 1: "black"},
lambda: changeColor(orange, btn_orange))
btn_orange.pack()
btn_purple = ImageButton(screen, root, image0, 5, 145, 16, 16, {0: "purple", 1: "black"},
lambda: changeColor(purple, btn_purple))
btn_purple.pack()
btn_pink = ImageButton(screen, root, image0, 5, 165, 16, 16, {0: "pink", 1: "black"},
lambda: changeColor(pink, btn_pink))
btn_pink.pack()
bth_clear = ImageButton(screen, root, image2, 5, 185, 16, 16, {0: None, 1: "black"}, clear)
bth_clear.pack()
bth_up = ImageButton(screen, root, image3, 5, 205, 16, 10, {0: None, 1: 'black'}, command=lambda: widthUpdate(1))
bth_up.pack()
label = Label(screen, root, str(width).zfill(2), 5, 220, bg=None) # zfill为补零的小技巧
label.pack()
bth_down = ImageButton(screen, root, image4, 5, 240, 16, 10, {0: None, 1: 'black'}, command=lambda: widthUpdate(-1))
bth_down.pack()
buttons = [btn_pink, btn_purple, btn_orange, btn_lightblue, btn_blue, btn_yellow, btn_black, btn_red, btn_green]
def run():
is_on, mx, my = canvas.mouse_is_on()
if is_on and Io.io_check_mouse()[0]:
canvas.rect(mx + 15 + 8, my - 15 + 8, width, width, pen_color)
root.add_unapply_hook(run)
api_hook(root, 'Drawer')
唉,越来越懒了……
6.3 BUG
本程序有一个bug。当我们运行它,并连续点击使画笔粗细变成50时,如果我们把鼠标放的太靠边的话:
这并不是 draw应用程序的问题,而是COS操作系统的问题,请不要着急,下一版本《有可能》(十分“有”可能)修复~
七、下载地址:
https://pan.baidu.com/s/1OqZ4R52dvnPCuUP1qaH3CA?pwd=CGY6
https://download.csdn.net/download/cgy091107/88255436 https://download.csdn.net/download/cgy091107/88255436