转 第十六章 3D 线条与填充(1) (as3.0)

本文介绍如何在Flash中创建真实的3D模型,包括3D点、线条、填充和立体图形的制作方法。通过实例演示如何利用Point3D类实现3D图形的旋转和平移。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 第十五章我们介绍了 3D,但只是将物体置于 3D 空间中,设置大小与位置。物体实际
上还是 2D 的。这就像老的 3D 游戏中,我们可以绕着某个物体或人物走,这些对象会转
过来面对我们。这些物体或人物并不是真正的会转过来 —— 只是看上去是这样的,因为它
们都是 2D 物体,那是我们看到它唯一的一个视角。
    本章,我们将真正地在 Flash 中创建 3D 模型。具体说来有创建并使用 3D 点,线条,
填充以及立体图形。学习完本章,大家就可以任意在三维空间中创建各种形状,并对它们执
行移动和旋转。
创建点和线条
    如果只在 3D 中创建点而不创建线条的话是没有任何意义的。因为理论上讲,一个点
是没有维度并且不可见的。开始时,我们还将使用 Ball3D 类,给一个非常小的半径,只要
能看到点在哪就够了。这样,只需要再创建几条线将这些小球连起来就行了。相当简单。我
们前面做过这样的例子,不过这次要在小球上添加透视,将它们放入 3D 空间。
    可以将点的实例设为黑色,10 像素宽。创建一些点的实例,根据鼠标的位置对它们进
行旋转(如前一章最后所讲的一样)然后在点间绘制一些线条。代码与上一章的 RotateXY.as
文件几乎相同。主要的区别在 onEnterFrame 的最后一块儿,从第一个点循环绘制线条到剩
下所有的点。同时,我还删除了 sortZ 方法,因为在这里有没有都一样。以下是 Lines3D1.as
的全部代码。

运行结果如图 16-1 所示。

转 <wbr>第十六章 <wbr>3D <wbr>线条与填充(1) <wbr>(as3.0)
         图 16-1 3D 点与线


     实际来说,没有太多可改的地方。如果要转为立体 3D 模型,就要舍弃所有的这些黑
点。第一个尝试非常简单。只要在创建时将每个 Ball3D 实例的半径设置为 0 即可,如下:
    var ball:Ball3D = new Ball3D(0);


运行结果如图 16-2 所示。

转 <wbr>第十六章 <wbr>3D <wbr>线条与填充(1) <wbr>(as3.0)

图 16-2 3D 线条,点不可见
     回过头再看看先前的代码,   这时我们发现有很多地方是多余的。比如,scaleX, scaleY 以
及 visible 对于一个看不到的点来说完全没有用的。没有可见的或可缩放的对象。根据这条
线索,更深层地思考认识一下这个继承自 Sprite 类的一般类,现在它实际上只是五个变量
的容器:xpos, ypos, zpos, x, y。实在有些过分。一个影片有许多功能——发送事件,绘图,
容纳其它 sprite 影片等等 —— 并且占用了大量资源。如此使用一个 sprite 影片就像开着
坦克到市区里捡一块面包。
    如果只需要存储变量的话,不如让我们创建一个只用于存储这些变量作为属性的类。事
实上, 如果再将透视和坐标旋转再放入这个类中,比单纯只存储几个属性更有意义。  女士们、
先生们,现在我把这个 Point3D 类送与各位:

package {
 public class Point3D {
  public var fl:Number = 250;
  private var vpX:Number = 0;
  private var vpY:Number = 0;
  private var cX:Number = 0;
  private var cY:Number = 0;
  private var cZ:Number = 0;
  public var x:Number = 0;
  public var y:Number = 0;
  public var z:Number = 0;
public function Point3D(x:Number=0, y:Number=0, z:Number=0) {
  this.x = x;
  this.y = y;
  this.z = z;
}
public function setVanishingPoint(vpX:Number, vpY:Number):void {
  this.vpX = vpX;
  this.vpY = vpY;
}
public function setCenter(cX:Number,cY:Number,cZ:Number=0):void {
  this.cX = cX;
  this.cY = cY;
  this.cZ = cZ;
}
public function get screenX():Number {
  var scale:Number = fl / (fl + z + cZ);
  return vpX + cX + x * scale;
}
public function get screenY():Number {
  var scale:Number = fl / (fl + z + cZ);
  return vpY + cY + y * scale;
}
public function rotateX(angleX:Number):void {
  var cosX:Number = Math.cos(angleX);
  var sinX:Number = Math.sin(angleX);
  var y1:Number = y * cosX - z * sinX;
  var z1:Number = z * cosX + y * sinX;
  y = y1;
  z = z1;
    }
    public function rotateY(angleY:Number):void {
      var cosY:Number = Math.cos(angleY);
      var sinY:Number = Math.sin(angleY);
      var x1:Number = x * cosY - z * sinY;
      var z1:Number = z * cosY + x * sinY;
      x = x1;
      z = z1;
    }
    public function rotateZ(angleZ:Number):void {
      var cosZ:Number = Math.cos(angleZ);
      var sinZ:Number = Math.sin(angleZ);
      var x1:Number = x * cosZ - y * sinZ;
      var y1:Number = y * cosZ + x * sinZ;
      x = x1;
      y = y1;
    }
  }
}
       现在,在使用这个类创建 3D 点时,可以传入 x, y, z 坐标,或者使用公共的 x, y, z 属
性 进 行 设 置 。 类 中 包 涵 了 一 个 默 认 的 fl 属 性 以 及 用 于 存 放 消 失 点 的 属 性 , 可通过setVanishingPoint() 方法进行设置。使用三种旋转方法,可以绕着某一轴的中心点进行旋转。
还可以用 setCenter 方法改变中心点。大家马上会看到这些应用。最后,它还可以为我们处
理所有的透视。当我们已经旋转或设置了点的位置时,只需要用 screenX 和 screenY 即可
获得透视的点在屏幕上的位置。
     这个类会让我们后面两章的程序变得简单许多。
     使用这个新的类重新编写上面线条旋转的程序将会惊人的简单,如 Lines3D2.as 所示:
转 <wbr>第十六章 <wbr>3D <wbr>线条与填充(1) <wbr>(as3.0)

图 16-3 3D 空间中的正方形坐标
     注意,所有的 z 值都相同。这是一个平面上的正方形。将一个正方形放在平面上的最
简单的办法就是让所有的点在某个轴上的位置都相同(这里我选择了 z 轴),还要定义正方
形的其它两个轴(x 和 y 轴)。以下代码将代替循环随机创建的点:
points[0] = new Point3D(-100, -100, 100);
points[1] = new Point3D( 100, -100, 100);
points[2] = new Point3D( 100, 100, 100);
points[3] = new Point3D(-100, 100, 100);
我们还要手动设置每个点的消失点。在循环中做是再简单不过的了:
for (var i:uint = 0; i < numPoints; i++) {
  points[i].setVanishingPoint(vpX, vpY);
}
因为现在有四个点,我们将不得不把 numPoints 改为 4。剩下的代码还可以正常工作,但
是我们还要多做一步:绘制一条连接最后一个点与第一个点的线,用于将图形封闭。以下是
全部代码,可见 Square3D.as(运行结果如图 16-4 所示):


转 <wbr>第十六章 <wbr>3D <wbr>线条与填充(1) <wbr>(as3.0)
图 16-4 3D 旋转正方形
     太奇妙了——一个旋转的正方形!现在我们应该可以创建出任何的平面图形了。我通常
都预先将所有的这些点在方格纸上标出(如图 16-5 所示) ,用来帮助作图。

转 <wbr>第十六章 <wbr>3D <wbr>线条与填充(1) <wbr>(as3.0)
图 16-5 使用方格纸标出所有的点
     通过这个草稿,可以用来帮助创建所需的这些点:
points[0] = new Point3D(-150, -250, 100);
points[1] = new Point3D( 150, -250, 100);
points[2] = new Point3D( 150, -150, 100);
points[3] = new Point3D( -50, -150, 100);
points[4] = new Point3D( -50, -50, 100);
points[5] = new Point3D( 50, -50, 100);
points[6] = new Point3D( 50, 50, 100);
points[7] = new Point3D( -50, 50, 100);
points[8] = new Point3D( -50, 150, 100);
points[9] = new Point3D( 150, 150, 100);
points[10] = new Point3D( 150, 250, 100);
points[11] = new Point3D(-150, 250, 100);
这样就完成了 SpinningE.as 中的旋转字母 E 的效果,运行结果如图 16-6 所示。不要忘记
将 numPoints 改为 12。稍后我们要使用 points.length 让这个值可以动态改变。

转 <wbr>第十六章 <wbr>3D <wbr>线条与填充(1) <wbr>(as3.0)

图 16-6 3D 旋转字母 E

 

      执行后我们注意到当字母 E 向我们旋转过来时,某些点会变得非常近,并且与第一个
3D 例子一样会发生倒置。您也许首先会想到增加所有点的 z 值,但这实际上会让效果变
得更糟。例如,假设将 z 设为 500。旋转的时候,z 将从 500 到 -500,甚至会让有些点
运动到观察点更往后的位置,会让事情更糟糕。不过我们可以使用 setCenter 方法将所有点
向 z 轴推移,如下:
for (var i:uint = 0; i < numPoints; i++) {
  points[i].setVanishingPoint(vpX, vpY);
  points[i].setCenter(0, 0, 200);
}
打开 Point3D 类,我们会看到 scale 的计算方法为:
     var scale:Number = fl / (fl + z + cZ);
这样就将整个系统推移了 200 像素,包括旋转系统。原来 z 的值保持不变,只是因为计算
透视的值更高了,那么所有物体都将呈现在观察着的前面。试用其它的值进行替换,观察运
动效果。稍后,我们会让这个图形在其它的轴上也能运动起来。

(如果要转载请注明出处http://blog.sina.com.cn/jooi,谢谢)

3.1 year = int(input("请输入年份: ")) if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0): print(year,"是闰年") else: print(year ,"不是闰年") 3.6 for i in range(1, 10): for j in range(1, i + 1): print(f"{j}×{i}={i * j}", end="\t") print() 1.外层for循环for i in range(1, 10)控制乘法表的行数,i从 1 到 9 分别对应 1 到 9 的乘数。 2.内层for循环for j in range(1, i + 1)控制每行内部的列数,j从 1 到i ,实现每一行里从1×i到i×i的乘法表达式。 print(f"{j}×{i}={i * j}", end="\t") 用于格式化输出每个乘法式子,end="\t" 让式子之间用制表符\t隔开,保证排版整齐;内层循环结束后,print() 用于换行,开始下一行的输出。 3.7 for num in range(2, 101): is_prime = True # 内层循环用于判断是否为素数,遍历 2 到 num - 1 的数字 for i in range(2, num): if num % i == 0: is_prime = False break if is_prime: print(num, end=&#39; &#39;) 1. 外层循环:for num in range(2, 101) 会依次取出 2 到 100 的每个整数,赋值给 num ,准备判断 num 是否为素数。 2. 标记变量:is_prime = True 先假设当前 num 是素数,后续通过内层循环验证。 3. 内层循环:for i in range(2, num) 遍历 2 到 num - 1 的数,用 num % i == 0 判断 num 能否被 i 整除。若能整除,说明 num 不是素数,把 is_prime 设为 False 并通过 break 跳出内层循环。 4. 输出素数:内层循环结束后,若 is_prime 仍为 True ,说明 num 是素数,用 print 输出(end=&#39; &#39; 让输出的素数用空格隔开,更整齐 )。 3.8 e = 1 n = 10 # 这里n取10,可根据需要调整,n越大越接近真实的e值 factorial = 1 for i in range(1, n + 1): factorial = factorial * i # 计算i的阶乘 e = e + 1 / factorial # 累加每一项 print(e) 1.首先初始化e = 1,因为公式的第一项是1。 2.设定n表示计算到\frac{1}{n!}这一项,这里取10,可按需调整。 3.factorial用于存储当前项的阶乘值,初始化为1。 4.在for循环中,每次循环通过factorial = factorial * i计算当前i的阶乘,然后通过e = e + 1 / factorial将当前项\frac{1}{i!}累加到e上。最后输出计算得到的e的近似值。 3.9 import random num_list = [random.randint(100, 200) for _ in range(10)] # 生成10个[100, 200]内的随机整数 max_num = num_list[0] # 假设第一个数是最大数 for num in num_list[1:]: # 从第二个数开始遍历 if num > max_num: # 如果当前数比假设的最大数大 max_num = num # 更新最大数 print(max_num) 1.首先通过import random导入随机数模块。 2.使用列表推导式[random.randint(100, 200) for _ in range(10)]生成包含103.在区间[100, 200]内随机整数的列表num_list。 初始化max_num = num_list[0],将列表的第一个数设为当前认为的最大数。 4.然后通过for循环遍历列表中从第二个数开始的元素(num_list[1:]),每次将当前数nummax_num比较,如果num更大,就将max_num更新为num。最后输出找到的最大数max_num。 3.12 # 初始化前两项 a, b = 1, 1 # 输出前两项 print(a, end=" ") print(b, end=" ") # 从第三项开始计算并输出,循环 18 次(因为前两项已输出) for _ in range(18): c = a + b print(c, end=" ") a, b = b, c 1. 首先手动初始化斐波那契数列的前两项 a = 1,b = 1,并直接输出它们。 2. 然后通过 for 循环,从第三项开始计算。每次循环中,新的数 c 是前两项 a 和 b 之和,计算出 c 后输出它,接着更新 a 和 b 的值(让 a 变为原来的 b,b 变为新计算出的 c ),这样循环 18 次(因为前两项已经输出,总共要输出 20 项 ),就能得到完整的斐波那契数列前 20 项。 3.14 # 定义函数,使用迭代法求平方根 def sqrt_iteration(a): # 初始值设置,一般可以取 x0 = a 或者其他合理值,这里取 x0 = a x = a while True: # 根据迭代公式计算下一个近似值 next_x = (x + a / x) / 2 # 判断前后项差的绝对值是否小于 10^-5,满足则认为达到精度要求 if abs(next_x - x) < 1e-5: return next_x x = next_x # 测试示例,求 9 的平方根 a = 9 result = sqrt_iteration(a) print(f"{a} 的平方根(迭代法)为:{result}") 1. 函数定义:sqrt_iteration 函数接收参数 a,用于求其平方根。 2. 初始值:先将 x 初始化为 a ,作为迭代的起始近似值(也可选择其他合理初始值,比如 x = 1 等,这里选 x = a 方便演示 )。 3. 迭代过程:在 while True 循环里,不断根据公式 next_x = (x + a / x) / 2 计算下一个近似值 next_x 。然后判断 next_x 和 x 的差的绝对值是否小于 1e-5(即 10^{-5} ),若满足,说明达到精度要求,返回 next_x 作为最终的平方根近似值;若不满足,把 next_x 赋值给 x ,继续下一轮迭代。 4. 测试:最后以求 9 的平方根为例进行测试,你也可以替换成其他想要求平方根的正数 a (注意 a 一般应为非负数,若为负数在实数范围内无意义,这里代码未做额外负数处理,实际使用可根据需求添加 )。 5.7 exampleFile=open("d:\\python\\example.txt","w") exampleFile.write("0123456789") exampleFile.seek(3) exampleFile.write("ZUT") exampleFile.close() exampleFile=open("d:\\python\\example.txt") s=exampleFile.read() print(s) exampleFile.close() 6.2 class Complex: def __init__(self, realpart, imagpart): self.r = realpart self.i = imagpart x = Complex(3.0,-4.5) print(x.r, x.i) 6.3 class Person: num=1 #类属性 def __init__(self, str,n): #构造函数 self.name = str #实例属性 self.age=n def SayHello(self): #成员函数 print("Hello!") def PrintName(self): #成员函数 print("姓名:", self.name, "年龄:", self.age) def PrintNum(self): #成员函数 print(Person.num) #由于是类属性,所以不写self .num #主程序 P1= Person("夏敏捷",42) P2= Person("王琳",36) P1.PrintName() P2.PrintName() 7.1 import tkinter #导入Tkinter模块 win = tkinter.Tk() #创建Windows窗口对象 win.title(&#39;我的第一个GUI程序&#39;) #设置窗口标题 win.mainloop() #进入消息循环,也就是显示窗口 7.8 import tkinter as tk def convert_temperature(): """ 换温度的函数:获取Entry中的摄氏度,换为华氏度并显示 """ try: celsius = float(entry.get()) fahrenheit = (celsius * 1.8) + 32 result_label.config(text=f"{celsius:.1f} C = {fahrenheit:.1f} F") except ValueError: result_label.config(text="请输入有效的数字") # 创建主窗口 root = tk.Tk() root.title("Entry Test") # 创建Entry对象,用于输入摄氏度 entry = tk.Entry(root) entry.pack(pady=10) # 创建按钮,点击时触发换函数 convert_button = tk.Button(root, text="换温度", command=convert_temperature) convert_button.pack(pady=5) # 用于显示换结果的标签 result_label = tk.Label(root, text="") result_label.pack(pady=10) # 启动主循环 root.mainloop() 1. 输入部分:通过 input 函数在控制台接收用户输入的字符串,提示语为 请输入摄氏度数值: ,模拟类似图形界面里 Entry 输入框的交互(只不过是在控制台 )。 2. 换逻辑:用 try-except 包裹代码,尝试把输入的字符串成浮点数(float 换),若成功,就用公式 (celsius * 1.8) + 32 计算华氏度;若换失败(比如输入字母等非数字内容),进入 except 块,提示用户输入有效数字。 3. 输出部分:用 print 函数在控制台输出结果,格式和图形界面示例里的 37.00 C = 98.60 F 类似,通过 :.1f 控制输出保留一位小数(也可根据需求调整,比如 :.2f 保留两位等 )。 7.24 import tkinter as tk # 创建主窗口 root = tk.Tk() root.title("Canvas Tags Example") # 创建Canvas画布 cv = tk.Canvas(root, width=200, height=200) cv.pack() # 示例1:给矩形设置单个标记 &#39;r1&#39; rt1 = cv.create_rectangle(10, 10, 110, 110, tags=&#39;r1&#39;) # 示例2:给矩形设置多个标记 (&#39;r1&#39;,&#39;r2&#39;,&#39;r3&#39;) rt2 = cv.create_rectangle(30, 30, 130, 130, tags=(&#39;r1&#39;, &#39;r2&#39;, &#39;r3&#39;)) # 使用 find_withtag 获取指定 tag 的图形对象 objects_with_r1 = cv.find_withtag(&#39;r1&#39;) print("带有 &#39;r1&#39; 标记的图形对象ID:", objects_with_r1) # 启动主循环 root.mainloop() 代码说明 1. 环境创建窗口:导入 tkinter 库,创建主窗口 root 并设置标题,再创建 Canvas 画布对象 cv 用于绘制图形,将画布添加到窗口显示。 2. 绘制矩形并设置 tags: (1)用 create_rectangle 绘制矩形,参数 (x1,y1,x2,y2) 是矩形坐标(左上角和右下角 )。 (2)第一个矩形 rt1 设置 tags=&#39;r1&#39;(单个标记 );第二个矩形 rt2 设置 tags=(&#39;r1&#39;,&#39;r2&#39;,&#39;r3&#39;)(多个标记,用元组传递 )。 3. 通过 tag 获取对象:调用 cv.find_withtag(&#39;r1&#39;) ,会返回所有带有 &#39;r1&#39; 标记的图形对象 ID(rt1 和 rt2 都会被获取到 ),并打印结果。 4. 启动循环:root.mainloop() 让 GUI 保持显示并响应交互,运行代码后,窗口会显示绘制的矩形,控制台会输出带 &#39;r1&#39; 标记的对象 ID 。 7.25 import tkinter as tk root = tk.Tk() canvas = tk.Canvas(root, width = 300, height = 300) canvas.pack() # 创建第一种圆弧(起始角度0,结束角度90样式为扇形) arc1 = canvas.create_arc(50, 50, 150, 150, start = 0, extent = 90, style = tk.PIESLICE) # 创建第二种圆弧(起始角度45,结束角度135,样式为圆弧线) arc2 = canvas.create_arc(180, 50, 280, 150, start = 45, extent = 90, style = tk.ARC) # 创建第三种圆弧(起始角度180,结束角度270样式为弦) arc3 = canvas.create_arc(50, 180, 150, 280, start = 180, extent = 90, style = tk.CHORD) root.mainloop() 1. 导入库创建主窗口: (1)import tkinter as tk:导入Tkinter库,并使用tk作为别名,这是Python用于创建图形用户界面(GUI)的标准库。 (2)root = tk.Tk():创建一个Tkinter的主窗口对象,这是所有GUI元素的容器。 2. 创建画布: (1)canvas = tk.Canvas(root, width = 300, height = 300):在主窗口root上创建一个宽300像素、高300像素的画布canvas,画布用于绘制各种图形。 (2)canvas.pack():使用pack布局管理器将画布放置在主窗口中。 3. 创建圆弧: ◦ arc1的创建: ◦ canvas.create_arc(50, 50, 150, 150, start = 0, extent = 90, style = tk.PIESLICE): ◦ (50, 50, 150, 150):这四个参数指定了一个矩形区域,圆弧是基于这个矩形区域绘制的。矩形的左上角坐标是(50, 50),右下角坐标是(150, 150)。 ◦ start = 0:表示圆弧的起始角度为0度(以水平向右为0度方向,逆时针为正方向)。 ◦ extent = 90:表示圆弧的角度范围是90度,即从0度到90度。 ◦ style = tk.PIESLICE:指定圆弧的样式为扇形,即会从圆心连接到圆弧的两端,形成一个扇形。 ◦ arc2的创建: ◦ canvas.create_arc(180, 50, 280, 150, start = 45, extent = 90, style = tk.ARC): ◦ (180, 50, 280, 150):定义了另一个矩形区域。 ◦ start = 45:起始角度为45度。 ◦ extent = 90:角度范围90度,从45度到135度。 ◦ style = tk.ARC:样式为单纯的圆弧线,不会连接圆心。 ◦ arc3的创建: ◦ canvas.create_arc(50, 180, 150, 280, start = 180, extent = 90, style = tk.CHORD): ◦ (50, 180, 150, 280):确定矩形区域。 ◦ start = 180:起始角度180度。 ◦ extent = 90:角度范围90度,从180度到270度。 ◦ style = tk.CHORD:样式为弦,会连接圆弧的两端,形成一个类似弓形的图形。 4. 主事件循环: ◦ root.mainloop():启动Tkinter的主事件循环,使窗口保持显示,并处理用户的各种交互操作。 上述代码运行后,会弹出一个窗口,在窗口的画布上绘制出三种不同样式的圆弧,对应常见的create_arc()方法的使用场景。 7.26 from tkinter import * root = Tk() cv = Canvas(root, bg = &#39;white&#39;, width = 200, height = 100) cv.create_line(10, 10, 100, 10, arrow=&#39;none&#39;) #绘制没有箭头线段 cv.create_line(10, 20, 100, 20, arrow=&#39;first&#39;) #绘制起点有箭头线段 cv.create_line(10, 30, 100, 30, arrow=&#39;last&#39;) #绘制终点有箭头线段 cv.create_line(10, 40, 100, 40, arrow=&#39;both&#39;) #绘制两端有箭头线段 cv. create_line(10,50,100,100,width=3, dash=7) #绘制虚线 cv.pack() root.mainloop() 1. 整体代码功能概述: 这段代码使用Python的tkinter库创建一个图形用户界面(GUI)窗口,并在窗口内的画布(Canvas)上绘制不同样式线条。tkinter是Python标准的GUI库,用于创建桌面应用程序的图形界面。 2. 代码逐行分析: (1)from tkinter import *:这行代码导入tkinter库中的所有内容。通过这种导入方式,可以直接使用tkinter库中的各种类、函数和常量,而不需要在调用时加上tkinter.前缀。不过,在大型项目中,这种导入方式可能会导致命名冲突,一般推荐显式导入,如import tkinter as tk,然后使用tk.Tk()等形式调用。 (2)root = Tk():创建一个主窗口对象,Tk()是tkinter库中用于创建主窗口的类。这个主窗口是整个GUI应用程序的基础,所有其他组件(如这里的画布)都将放置在这个窗口内。 (3)cv = Canvas(root, bg = &#39;white&#39;, width = 200, height = 100):创建一个Canvas(画布)对象,它是tkinter中用于绘制图形(如线条图形、文本等)的组件。root参数表示这个画布将放置在之前创建的主窗口root中。bg = &#39;white&#39;设置画布的背景颜色为白色,width = 200和height = 100分别设置画布的宽度为200像素,高度为100像素。 (4)cv.create_line(10, 10, 100, 10, arrow=&#39;none&#39;):使用create_line()方法在画布cv上绘制一条线段。(10, 10)是线段的起点坐标,(100, 10)是线段的终点坐标。arrow=&#39;none&#39;表示这条线段没有箭头。 (5)cv.create_line(10, 20, 100, 20, arrow=&#39;first&#39;):同样是绘制线段,起点为(10, 20),终点为(100, 20)。arrow=&#39;first&#39;表示在这条线段的起点处绘制一个箭头。 (6)cv.create_line(10, 30, 100, 30, arrow=&#39;last&#39;):绘制起点为(10, 30),终点为(100, 30)的线段。arrow=&#39;last&#39;意味着在这条线段的终点处绘制一个箭头。 (7)cv.create_line(10, 40, 100, 40, arrow=&#39;both&#39;):绘制起点(10, 40),终点(100, 40)的线段,arrow=&#39;both&#39;表示在这条线段的两端都绘制箭头。 (8)cv.create_line(10, 50, 100, 100, width = 3, dash = 7):绘制一条起点为(10, 50),终点为(100, 100)的线段。width = 3设置线段的宽度为3像素,dash = 7表示绘制虚线,这里dash参数的值表示虚线中每一段实线和空白的长度(在这个例子中,实线和空白长度都为7像素 ,实际显示效果可能因系统和显示设置略有不同)。 (9)cv.pack():使用pack()几何管理器将画布cv放置在主窗口root中。pack()是tkinter中一种简单的布局管理器,它会自动调整组件的大小和位置以适应主窗口。 (10)root.mainloop():启动主窗口的事件循环。这个循环会持续监听用户的操作(如鼠标点击、键盘输入等),并根据相应的事件触发相应的处理程序。只有当关闭主窗口时,这个事件循环才会结束,程序才会退出。 总结来说,这段代码展示了如何使用tkinter库中Canvas组件的create_line()方法绘制不同样式(有无箭头、虚线等)的线条。 7.32 import tkinter as tk def draw_hourglass(canvas, x, y): """绘制沙漏:上梯形+沙子+下梯形""" top = [x+10, y, x+20, y, x+25, y+15, x+5, y+15] # 上半部分 sand = [x+5, y+15, x+25, y+15, x+25, y+25, x+5, y+25] # 中间沙子 bottom = [x+5, y+25, x+25, y+25, x+20, y+40, x+10, y+40] # 下半部分 canvas.create_polygon(top, outline=&#39;black&#39;, fill=&#39;white&#39;) canvas.create_polygon(sand, outline=&#39;black&#39;, fill=&#39;gray&#39;) canvas.create_polygon(bottom, outline=&#39;black&#39;, fill=&#39;white&#39;) def draw_cute_face(canvas, center_x, center_y): """绘制可爱表情:棕色轮廓+粉色腮红+绿叶""" # 脸部轮廓 canvas.create_oval(center_x-40, center_y-40, center_x+40, center_y+40, outline=&#39;brown&#39;, fill=&#39;white&#39;) # 眼睛(黑色瞳孔) canvas.create_oval(center_x-25, center_y-15, center_x-15, center_y-5, outline=&#39;black&#39;, fill=&#39;black&#39;) # 左眼 canvas.create_oval(center_x+15, center_y-15, center_x+25, center_y-5, outline=&#39;black&#39;, fill=&#39;black&#39;) # 右眼 # 腮红(粉色椭圆) canvas.create_oval(center_x-35, center_y+10, center_x-25, center_y+20, fill=&#39;pink&#39;, outline=&#39;&#39;) canvas.create_oval(center_x+25, center_y+10, center_x+35, center_y+20, fill=&#39;pink&#39;, outline=&#39;&#39;) # 舌头(粉色椭圆) canvas.create_oval(center_x-10, center_y+15, center_x+10, center_y+25, fill=&#39;pink&#39;, outline=&#39;black&#39;) # 叶子(对称小三角) canvas.create_polygon(center_x-10, center_y-50, center_x-15, center_y-60, center_x-5, center_y-60, fill=&#39;green&#39;, outline=&#39;green&#39;) # 左叶 canvas.create_polygon(center_x+10, center_y-50, center_x+15, center_y-60, center_x+5, center_y-60, fill=&#39;green&#39;, outline=&#39;green&#39;) # 右叶 def draw_card(canvas, x, y, suit, color): """绘制扑克牌:支持方块(diamond)和梅花(club)""" # 牌框 canvas.create_rectangle(x, y, x+70, y+100, outline=&#39;black&#39;, fill=&#39;white&#39;) # 角落文字"A" canvas.create_text(x+5, y+5, text=&#39;A&#39;, font=(&#39;Arial&#39;, 16), fill=color, anchor=&#39;nw&#39;) canvas.create_text(x+65, y+95, text=&#39;A&#39;, font=(&#39;Arial&#39;, 16), fill=color, anchor=&#39;se&#39;) # 绘制花色 if suit == &#39;diamond&#39;: # 红方块 # 左上角小方块 canvas.create_polygon(x+35, y+25, x+40, y+30, x+35, y+35, x+30, y+30, fill=color, outline=color) # 中间大方块 canvas.create_polygon(x+35, y+50, x+45, y+40, x+35, y+30, x+25, y+40, fill=color, outline=color) # 右下角小方块 canvas.create_polygon(x+35, y+75, x+40, y+70, x+35, y+65, x+30, y+70, fill=color, outline=color) elif suit == &#39;club&#39;: # 黑梅花 # 中心圆 canvas.create_oval(x+30, y+30, x+40, y+40, fill=color, outline=color) # 上瓣 canvas.create_polygon(x+35, y+20, x+30, y+25, x+35, y+30, x+40, y+25, fill=color, outline=color) # 下瓣 canvas.create_polygon(x+35, y+60, x+30, y+55, x+35, y+50, x+40, y+55, fill=color, outline=color) # 左瓣 canvas.create_polygon(x+20, y+35, x+25, y+30, x+30, y+35, x+25, y+40, fill=color, outline=color) # 右瓣 canvas.create_polygon(x+50, y+35, x+45, y+30, x+40, y+35, x+45, y+40, fill=color, outline=color) def main(): root = tk.Tk() root.title("匹配截图的示例") canvas = tk.Canvas(root, width=800, height=500, bg=&#39;white&#39;) canvas.pack() # ===================== 1. 顶部符号区 ===================== x, y = 50, 50 # 起始坐标 # 符号1:圆圈斜杠(⊘) canvas.create_oval(x, y, x+20, y+20, outline=&#39;black&#39;, fill=&#39;white&#39;) canvas.create_line(x, y+20, x+20, y, fill=&#39;black&#39;, width=2) x += 30 # 符号2:字母 i canvas.create_text(x, y+10, text=&#39;i&#39;, font=(&#39;Arial&#39;, 16), anchor=&#39;nw&#39;) x += 30 # 符号3:问号 ? canvas.create_text(x, y+10, text=&#39;?&#39;, font=(&#39;Arial&#39;, 16), anchor=&#39;nw&#39;) x += 30 # 符号4:沙漏 draw_hourglass(canvas, x, y) x += 60 # 沙漏宽度较大,调整间距 # 符号5:问号 ? canvas.create_text(x, y+10, text=&#39;?&#39;, font=(&#39;Arial&#39;, 16), anchor=&#39;nw&#39;) x += 30 # 符号6:感叹号 ! canvas.create_text(x, y+10, text=&#39;!&#39;, font=(&#39;Arial&#39;, 16), anchor=&#39;nw&#39;) x += 30 # 符号7-10:四个点阵矩形(stipple模拟不同密度) stipples = [&#39;gray12&#39;, &#39;gray25&#39;, &#39;gray50&#39;, &#39;gray75&#39;] for style in stipples: canvas.create_rectangle(x, y, x+30, y+20, fill=&#39;black&#39;, outline=&#39;black&#39;, stipple=style) x += 40 # ===================== 2. 可爱表情区 ===================== draw_cute_face(canvas, center_x=220, center_y=250) # ===================== 3. 扑克牌区(红方块A + 黑梅花A) ===================== # 红方块A(x=350, y=200) draw_card(canvas, 350, 200, suit=&#39;diamond&#39;, color=&#39;red&#39;) # 黑梅花A(x=500, y=200) draw_card(canvas, 500, 200, suit=&#39;club&#39;, color=&#39;black&#39;) root.mainloop() if __name__ == &#39;__main__&#39;: main() 7.34 from tkinter import * def move_piece(): canvas.move(chess_piece, 150, 150) # 向右下角移动棋子 root = Tk() root.title("象棋棋子移动演示") canvas = Canvas(root, width=300, height=300, bg=&#39;#CDBA96&#39;) canvas.pack() # 1. 加载棋子图像 try: chess_img = PhotoImage(file=&#39;shuai.png&#39;) # 替换实际路径 except: # 备选方案:绘制文字棋子 chess_piece = canvas.create_text(50, 50, text="帅", font=("楷体", 24), fill=&#39;red&#39;) else: chess_piece = canvas.create_image(50, 50, anchor=NW, image=chess_img) # 2. 添加操作按钮 Button(root, text="移动棋子", command=move_piece, bg=&#39;#8E8E8E&#39;).pack(pady=10) root.mainloop() 7.39 from tkinter import Tk, Label, messagebox def callback(event): """事件处理函数""" # 打印按键信息 print(f"你按下了: {event.char}") # 弹出消息框 messagebox.showinfo("Python command", "人生苦短,我用 Python") # 创建主窗口 root = Tk() root.title("KeyPress 事件示例") root.geometry("300x200") # 创建一个标签,提示用户按键盘 label = Label(root, text="请在窗口中按下键盘按键") label.pack(pady=50) # 绑定键盘按键事件(<KeyPress>)到 callback 函数 root.bind("<KeyPress>", callback) # 进入主循环 root.mainloop() 1. 依赖:Tkinter 是 Python 标准库,无需额外安装;messagebox 用于弹出提示框。 2. 事件绑定:root.bind("<KeyPress>", callback) 将键盘按键事件 callback 函数关联,按下任意按键时触发。 3. 功能:按下键盘后,控制台会打印按键字符(event.char),同时弹出消息框显示“人生苦短,我用 Python”,题目示例逻辑一致。 运行代码后,点击窗口获得焦点,再按键盘按键即可看到效果,完美匹配题目中“触发 KeyPress 键盘事件”的需求。
06-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值