精华内容
下载资源
问答
  • Java数组倒置 简单 Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印 util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...
  • 下面是ShowMethods.java的更好用的GUI版本 专门用来查找Swing组件里的addListener方法 这个程序为查询Swing组件所支持的事件类型提供了一种便利方式 一旦知道了某个组件支持哪些事件 不用参考任何资料就可以...

    设计中要遵循的一条基本原则是 让简单的事情变得容易 让困难的事情变得可行

    applet
    它是一种可以在Internet上传递 并在Web浏览器中运行的程序(出于安全性 只能在所谓的沙盒内运行)

    Swing基础
    大多数Swing应用都被构建在基础的JFrame内部 JFrame在你使用的任何操作系统中都可以创建视窗应用 视窗的标题可以像下面这样使用JFrame的构造器来设置
    在这里插入图片描述
    请注意最后一行
    在这里插入图片描述
    如果没有这行 你在屏幕上将什么也看不到
    我们可以通过在JFrame中添加一个JLable来使事情变得更有趣一些
    在这里插入图片描述
    在一秒钟之后 JLable的文本发生了变化 尽管这对于这个小程序来说既有趣又安全 但是对于main()线程来说 直接对GUI组件编写代码并非是一种好的想法 Swing有它自己的专用线程来接收UI事件并更新屏幕 如果你从其他线程着手对屏幕进行操作 那么就可能会产生冲突和死锁
    取而代之的是 其他线程 例如这里是像main()这样的线程 应该通过Swing事件分发线程提交要执行的任务 你可以通过将任务提交给SwingUtilities.invokeLater()来实现这种方式 这个方法会通过事件分发线程将任务放置到(最终将得到执行的)待执行事件队列中 如果我们将这种方式应用于上面的示例 那么它就会变成下面的样子
    在这里插入图片描述
    在这里插入图片描述
    现在你再也不用直接操作JLable了 取而代之的是 你提交一个Runnable 当事件分发线程在事件队列中获取这项任务时 它将执行实际的操作 并且在执行这个Runnable时 不会做其他任何事情 因此也就不会产生任何冲突 当然 前提是程序中的所有代码都遵循这种通过SwingUtilities.invokeLater()来提交操作的方式 这包括启动程序自身 即main()也不应该调用Swing的方法 就像上面的程序一样 它应该向事件队列提交任务 因此 所编写的恰当的程序看起来应该是下面的样子
    在这里插入图片描述

    一个显示框架
    我们可以创建一个显示框架 将其用于本章剩余部分的Swing示例中 从而使得上面的想法得以结合 并减少了冗余代码
    在这里插入图片描述

    创建按钮
    创建一个按钮非常简单 只要用你希望出现在按钮上的标签调用JButton的构造器即可 在后面你会看到一些更有趣的功能 比如在按钮上显示图形
    一般来说 要在类中为按钮创建一个字段 以便以后可以引用这个按钮
    JButton是一个组件 它有自己的小窗口 能作为整个更新过程的一部分而自动被重绘 也就是说 你不必显式绘制一个按钮或者别的类型的控件 只要把它们放在窗体上 它们可以自动绘制自己 通常你会在构造器内部把按钮加入窗体
    在这里插入图片描述

    捕获事件
    如果编译并运行前面的程序 那么当按下按钮的时候 什么也不会发生 事件驱动编程(包含了许多关于GUI的内容)的基础 就是把事件同处理事件的代码连接起来
    在Swing中 这种关联的方式就是通过清楚地分离接口(图形组件)和实现(当和组件相关的事件发生时 你要执行的代码)而做到的 每个Swing组件都能够报告其上所有可能发生的事件 并且它能单独报告每种事件 所以 你要是对诸如 鼠标移动到按钮上 这样的事件不感兴趣的话 那么你不注册这样的事件就可以了 这种处理事件驱动编程的方式非常直接和优雅 一旦你理解了其基本概念 就能够很容易将其应用到甚至从未见过的Swing组件之上 实际上 只要是JavaBean 这个模式都适用
    首先 对所使用的组件 我们只把重点放在它感兴趣的主要事件上 对于JButton 感兴趣的事件 就是按钮被按下 为了表明(注册)你对按钮按下事件感兴趣 可以调用JButton的addActionListener()方法 这个方法接受一个实现ActionListener接口的对象作为参数 ActionListener接口只包含一个actionPerformed()方法 所以要想把事件处理代码和JButton关联 需要在一个类中实现ActionListener接口 然后把这个类的对象通过addActionListener()方法注册给JButton 这样按钮按下的时候就会调用actionPerformed()方法(通常这也称为回调)
    但是按钮按下的时候应该有什么结果呢 我们希望看到屏幕有所改变 所以在这里介绍一个新的Swing组件 JTextField 这个组件支持用户输入文本 在本例中 或者像本例一样由程序插入文本 尽管有很多方法可以创建JTextField 但是最简单的方式就是告诉构造器你所希望的文本域宽度 一旦JTextField被放置到窗体上 就可以使用setText()方法来修改它的内容 下面就是其具体程序
    在这里插入图片描述
    在这里插入图片描述

    通常 把ActionListener实现成匿名内部类会更方便 尤其是对每个监听器类只使用一个实例的时候更是如此 可以像下面这样修改Button2.java 这里使用一个匿名内部类
    在这里插入图片描述

    文本区域
    除了可以有多行文本以及更多的功能不同之外 JTextArea与JTextField在其他方面都很相似 JTextArea有一个比较常用的方法是append() 因为可以往回滚动 所以比起在命令行程序中把文本打印到标准输出的做法 这就成为了一种进步 例如 下面的程序使用前几节中的Countries生成器的输出来填充JTextArea
    在这里插入图片描述

    控制布局

    BorderLayout
    除非你设置为其他的布局模式 否则JFrame将使用BorderLayout作为默认的布局模式 如果不加入其他指令 它将接受你调用add()方法而加入的组件 把它放置在中央 然后把组件向各个方向拉伸 直到与边框对齐
    BorderLayout具有四个边框区域和一个中央区域的概念 当向由BorderLayout管理的面板加入组件的时候 可以使用重载的add()方法 它的第一个参数接受一个常量值 这个值可以为以下任何一个
    在这里插入图片描述
    如果没有为组件指定放置的位置 默认情况下它将被放置到中央
    在下面的示例中使用了默认布局 因为默认情况下JFrame使用的就是BorderLayout
    在这里插入图片描述

    FlowLayout
    它直接将组件从左到右 流动 到窗体上 直到占满上方的空间 然后向下移动一行 继续流动
    在下面的例子中 先把布局管理器设置为FlowLayout 然后在窗体上放置按钮 你将注意到 在使用FlowLayout的情况下 组件将呈现出 合适 的大小 比如 一个JButton的大小就是其标签的大小
    在这里插入图片描述

    GridLayout
    GridLayout允许你构建一个放置组件的表格 在向表格里面添加组件的时候 它们将按照从左到右 从上到下的顺序加入 在构造器中要指定需要的行数和列数 它们将均匀分布在窗体上
    在这里插入图片描述

    GridBagLayout
    GridBagLayout提供了强大的控制功能 包括精确判断视窗区域如何布局 以及视窗大小变化的时候如何重新放置组件 不过 它也是最复杂的布局管理器 所以很难理解 它的目的主要是辅助GUI构造工具(它可能使用GridBagLayout而不是绝对位置来控制布局)自动生成代码 如果你发现自己的设计非常复杂 以至于需要使用GridBagLayout 那么你应该使用GUI构造工具来生成这个设计
    作为一种可替换的选择 你可能会考虑TableLayout 它不属于Swing类库 但是可以从http://java.sun.com处下载 这个组件被置于GridBagLayout之上 并且隐藏了其大多数细节 因此可以极大地简化使用这种模式的方式

    绝对定位
    我们也可以设置图形组件的绝对位置

    1. 使用setLayout(null)方法把容器的布局管理器设置为空
    2. 为每个组件调用setBounds()或者reshape()方法(取决于语言的版本) 为方法传递以像素坐标为单位的边界矩形的参数 根据你要达到的目的 可以在构造器或者paint()方法中调用这些方法

    BoxLayout
    由于人们在理解和使用GridBagLayout的时候遇到了很多问题 所以Swing还提供了BoxLayout 它具有GridBagLayout的许多好处 却不像GridBagLayout那么复杂 所以当你需要手工编写布局代码的时候 可以考虑使用它 BoxLayout使你可以在水平方向或者垂直方向控制组件的位置 并且通过所谓的 支架和胶水(struts and glue)的机制来控制组件的间隔

    最好的方式是什么
    Swing功能强大 用少数几行代码就可以做很多事情 通过组合简单布局 就能得到非常多的结果 不过 在某些情况下 手工编写GUI窗体就不太适合了 这样做太复杂 也不能充分利用编程时间 Java和Swing设计者的最初目的就是要使语言和库能对GUI构造工具提供支持 创建这些工具的明确的目的也是为了使你更容易地获取编程经验 只要理解了布局的方式以及如何处理事件 那么如何手工放置组件的细节就显得不那么重要了 应该让合适的工具帮你去做这些事情(毕竟 设计Java的目的是为了提高程序员的生产率)

    Swing事件模型

    事件与监听器的类型
    所有Swing组件都具有addXXXListener()和removeXXXListener()方法 这样就可以为每个组件添加或移除相应类型的监听器 注意 每个方法的 XXX 还表示方法所能接收的参数 比如addMyListener(MyListenerm) 下表包含相互关联的基本事件 监听器以及通过提供addXXXListener()和removeXXXListener()方法来支持这些事件的基本组件 记住 事件模型是可以扩展的 所以将来你也许会遇到表格里没有列出的事件和监听器
    在这里插入图片描述
    在这里插入图片描述
    可以观察到 每种组件所支持的事件类型都是固定的 为每个组件列出其支持的所有事件是相当困难的 一个比较简单的方法是修改前几节的ShowMethods.java程序 这样它就可以显示出你所输入的任意Swing组件所支持的所有事件监听器

    下面是ShowMethods.java的更好用的GUI版本 专门用来查找Swing组件里的addListener方法
    在这里插入图片描述
    在这里插入图片描述

    这个程序为查询Swing组件所支持的事件类型提供了一种便利方式 一旦知道了某个组件支持哪些事件 不用参考任何资料就可以处理这个事件了 你只要

    1. 获取事件类的名称 并移除单词 Event 然后将剩下的部分加上单词 Listener 得到的就是内部类必须实现的监听器接口
    2. 实现上面的接口 为要捕获的事件编写出方法 比如 你可能要查找鼠标移动 所以你可以为MouseMotionListener接口的mouseMoved()方法编写代码
    3. 为第二步编写的监听器类创建一个对象 然后通过调用方法向组件注册这个对象 方法名为 add 前缀加上监听器名称 比如addMouseMotionListener()
      下面是一些监听器接口
      在这里插入图片描述

    使用监听器适配器来进行简化
    在上面的表中可以发现 某些监听器接口只有一个方法 这种接口实现起来很简单 不过 具有多个方法的监听器接口使用起来却不太方便 比如 如果你想捕获一个鼠标单击事件(例如 某个按钮还没有替你捕获该事件) 那么就需要为mouseClicked()方法编写代码 但是因为MouseListener是一个接口 所以尽管接口里的其他方法对你来说没有任何用处 但是你还是必须要实现所有这些方法 这非常烦人
    要解决这个问题 某些(不是所有的)含有多个方法的监听器接口提供了相应的适配器(可以在上面的表中看到具体的名称) 适配器为接口里的每个方法都提供了默认的空实现 现在你要做的就是从适配器继承 然后仅覆盖那些需要修改的方法 比如 你要用的典型的MouseListener像这样
    在这里插入图片描述
    适配器的出发点就是为了使编写监听器类变得更容易 不过 适配器也有某种形式的缺陷 假设你写了一个与前面类似的MouseAdapter
    在这里插入图片描述
    这个适配器将不起作用 而且要想找出问题的根源也非常困难 这足以让你发疯 因为除了鼠标单击的时候方法没有被调用以外 程序的编译和运行都十分良好 你能发现这个问题吗 它出在方法的名称上 这里的名称是MouseClicked()而没有写成mouseClicked() 这个简单的大小写错误导致加入了一个新方法 它不是关闭视窗的时候所应该调用的方法 所以无法得到所希望的结果 尽管使用接口有些不方便 但可以保证方法被正确实现
    要想保证实际上的确是覆盖了某个方法 一种改进的方法是在这段代码的上面使用内建的@Override注解

    跟踪多个事件
    作为一个有趣的试验 也为了证明这些事件确实可以被触发 编写一个程序 使其能够跟踪JButton除了 是否被按下 事件以外的行为 将会显得很有价值 这个例子还演示如何从JButton中继承出自己的按钮对象
    在下面的代码中 MyButton是TrackEvent类的内部类 所以MyButton能访问父窗口 并操作其文本区域 这正是能够把状态信息写到父窗体的文本区域内所必需的 当然 这是一个受限的解决方案 因为MyButton被局限于只能与TrackEvent一起使用 这种情况有时称为 高耦合 代码
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    Swing组件一览

    按钮
    Swing提供了许多类型的按钮 所有的按钮 包括复选框 单选按钮 甚至菜单项 都是从AbstractButton继承而来 很快你就会看到菜单项的使用 下面的例子演示了几种按钮
    在这里插入图片描述

    按钮组
    要想让单选按钮表现出某种 排它 行为 必须把它们加入到一个 按钮组(ButtonGroup) 中 不过 正如下面的例子所演示的 任何AbstractButton对象都可以加入到按钮组中
    为了避免重复编写大量的代码 下面这个例子使用了反射功能来产生几组不同类型的按钮 注意makeBPanel()方法 它用来创建一个按钮组和一个JPanel 此方法的第二个参数是一个字符串数组 针对其中每个字符串 将创建一个由第一参数所代表的按钮实例然后将此按钮加入到JPanel中
    在这里插入图片描述
    在这里插入图片描述

    图标
    可以在JLable或者任何从AbstractButton(包括JButton JCheckBox JRadioButton以及几种不同JMenuItem)继承的组件中使用Icon 和JLable一起使用Icon的做法非常直接 下面的例子还研究了与按钮(或者从按钮继承的组件)搭配使用图标的所有方式
    可以使用任何想用的GIF文件 要打开一个文件并且得到图形 只需创建一个ImageIcon对象并把文件名传递给它即可 然后 就能在程序中使用得到的图标了
    在这里插入图片描述
    在这里插入图片描述

    工具提示
    前面的例子给按钮添加了一个 工具提示 用来创建用户接口的类 绝大多数都是从JComponet派生而来的 它们包含了一个setToolTipText(String)方法 所以 对于要放置在窗体上的组件 基本上所要做的就是(对于任何JComponet派生类的对象jc)像这样编写
    在这里插入图片描述
    当鼠标停留在这个JComponet上经过一段预先指定的时间之后 在鼠标旁边弹出的小方框里就会出现你所设定的文字

    文本域
    下面的例子演示了JTextField组件具有的其他功能
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    边框
    JComponet有一个setBorder()方法 它允许你为任何可视组件设置各种边框 下面的例子使用showBorder()方法演示了一些可用的边框 此方法先创建一个JPanel 然后设置相应的边框 此外 它还使用RTTI(运行时类型识别)来得到正在使用的边框名称(去掉了路径信息) 然后把这个名称放进面板中间的一个JLable中
    在这里插入图片描述
    在这里插入图片描述

    一个迷你编辑器
    JTextPane控件可以毫不费事地支持许多编辑操作 下面的例子是对这个组件的简单应用 其中忽略了该组件所能提供的其他的大量功能
    在这里插入图片描述

    复选框
    复选框提供了一种做出 选中 或 不选 单一选择的方式 它包含了一个小方框和一个标签 这个方框中通常是有一个 x 标记(或者其他能表明 选中 的标记)或者为空 这取决于复选框是否被选中
    通常会使用接受标签作为参数的构造器来创建JCheckBox 可以获取和设置状态 也可以获取和设置其标签 甚至可以在JCheckBox对象已经建立之后改变标签
    当JCheckBox被选中或清理选中时 将发生一个事件 你可以用与对付按钮相同的方式来捕获这个事件 使用ActionListener 在下面的例子中 将枚举所有被选中的复选框 然后在JTextArea里显示
    在这里插入图片描述

    单选按钮
    GUI编程中单选按钮的概念来源于电子按钮发明之前汽车上收音机使用的机械按钮 当按下其中的一个 其他被按下的按钮将被弹出 所以 单选按钮强制你在多个选项中只能选择一个
    要设置一组关联的JRadioButton 你需要把它们加入到一个ButtonGroup中(窗体上可以有任意数目的ButtonGroup) 可以选择将其中的一个按钮设置为选中(true)(在构造器的第二个参数中设置) 如果你把多个单选按钮的状态都设置为选中 那么只有最后设置的那个有效
    下面是使用了单选按钮的简单例子它展示了使用ActionListener来捕获事件
    在这里插入图片描述

    组合框
    与一组单选按钮的功能类似 组合框(下拉列表)也是强制用户从一组可能的元素中只选择一个 不过 这种方法更加紧凑 而且在不会使用户感到迷惑的前提下 改变下拉列表中的内容更容易(当然也可以动态改变单选按钮 不过这么做显然易造成冲突)
    默认状态下 JComboBox组合框与Windows操作系统下的组合框并不完全相同 后者允许从列表中选择 或者自己输入 要想得到这样的行为 必须调用setEditable()方法 使用JComboBox组合框 你能且只能从列表中选择一个元素 在下面的例子中 JComboBox组合框开始时已经有了一些元素 然后当一个按钮按下的时候 将向组合框中加入新的元素
    在这里插入图片描述

    列表框
    列表框和JComboBox组合框明显不同 这不仅仅体现在外观上 当激活JComboBox组合框时 会出现下拉列表 而JList总是在屏幕上占据固定行数的空间 大小也不会改变 如果要得到列表框中被选中的项目 只需调用getSelectedValues() 它可以产生一个字符串数组 里面是被选中的项目名称
    JList组件允许多重选择 要是按住Ctrl键 连续在多个项目上单击 那么原先被选中的项目仍旧保持选中状态 也就是说可以选中任意多的项目 如果选中了某个项目 按住 Shift 键并单击另一个项目 那么这两个项目之间的所有项目都将被选中 要从选中的项目组中去掉一个 可以按住Ctrl键在此项目上单击
    在这里插入图片描述
    在这里插入图片描述

    页签面板
    JTabbedPane允许你创建 页签式的对话框 这种对话框中沿着窗体的一边有类似文件夹的页签 当你在页签上点击时 就会向前进入到另一个不同的对话框中
    在这里插入图片描述

    消息框
    视窗环境下通常包含了一组标准的消息框 使得能够快速地把消息通知给用户 或者是从用户那里得到消息 在Swing中 这些消息框包含在JOptionPane组件里 你有许多选择(有些非常高级) 但最常用的可能就是消息对话框和确认对话框 它们分别可以通过调用静态的JOptionPane.showMessageDialog()和JOptionPane.showConfirmDialog()方法得到 下面的例子演示了JOptionPane中一些可用的消息框
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    菜单
    每个能够持有菜单的组件 包括JApplet JFrame JDialog以及它们的子类 它们都有一个setJMenuBar()方法 它接受一个JMenuBar对象(某个特定组件只能持有一个JMenuBar对象)作为参数 你先把JMenu对象添加到JMenuBar中 然后把JMenuItem添加到JMenu中 每个JMenuItem都能有一个相关联的ActionListener 用来捕获菜单项被选中时所触发的事件
    在Java和Swing中 必须在源代码中构造所有的菜单 下面是个非常简单的菜单例子
    在这里插入图片描述

    下面是一个更复杂的创建菜单的例子 这里仍然是冰激凌口味的例子 这个例子还演示了层叠式菜单 键盘快捷键 JCheckBoxMenuItem 以及动态改变菜单的方法
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    弹出式菜单
    要实现一个JPopupMenu 最直接的方法就是创建一个继承自MouseAdapter的内部类 然后对每个希望具有弹出式行为的组件 都添加一个该内部类的对象
    在这里插入图片描述
    在这里插入图片描述

    绘图
    如果使用好的GUI框架 绘图应该非常简单 Swing库正是如此 对于任何绘图程序 问题在于决定绘图位置的计算通常比对绘图功能的调用要复杂得多 并且这些计算程序常常与绘图程序混在一起 所以看起来程序的接口比实际需要的要更复杂
    为了简化问题 考虑一个在屏幕上表示数据的问题 在这里 数据将由内置的Math.sin()方法提供 它可以产生数学上的正弦函数 为了使事情变得更有趣一些 也为了进一步演示Swing组件使用起来有多么简单 我们在窗体底部放置了一个滑块 用来动态控制所显示的正弦波周期的个数 此外 如果调整了视窗的大小 你会发现正弦波能够自动调整 以适应新的视窗
    尽管在任何JComponent上都可以绘图 而且正因为如此 可以把它们当作画布 但是 要是你只是想有一个可以直接绘图的平面的话 典型的做法是从JPanel继承 唯一需要覆盖的方法就是paintComponent() 在组件必须被重新绘制的时候调用它(通常不必为此担心 因为何时调用由Swing决定) 当此方法被调用时 Swing将传入一个Graphics对象 然后就可以使用这个对象绘图了 或在平面上绘制了
    在下面的例子中 所有与绘制动作相关的代码都在SineDraw类中 SineWave类只是用来配置程序和滑块控制 在SineDraw中 setCycles()方法提供了一个钩子(hook) 它允许其他对象(在这个例子中就是滑块控制)控制周期的个数
    在这里插入图片描述
    在这里插入图片描述

    对话框
    对话框是从视窗弹出的另一个窗口 它的目的是处理一些具体问题 同时又不会使这些具体细节与原先窗口的内容混在一起 对话框通常应用于视窗编程环境中
    如果要编写一个对话框 就需要从JDialog继承 它只不过是另一种类型Window 与JFrame类似 JDialog具有一个布局管理器(默认情况下为BorderLayout) 并且要添加事件监听器来处理事件 下面是个简单的例子
    在这里插入图片描述
    在这里插入图片描述
    一旦创建了JDialog以后 必须调用setVisible(true)方法来显示和激活它 当对话框被关闭时 你必须通过调用display()来释放该对话框使用的资源
    下面的例子更加复杂 对话框由一个网格构成(使用GridLayout) 并且添加了一种特殊按钮 它由ToeButton类定义 按钮将先在自己周围画一个边框 然后根据状态的不同 在中央显示 空吧 x 或者 o 开始时的按钮状态为 空白 然后根据每一轮单击 变成 x 或者 o 而且 当你在非 空白 的按钮上单击的时候 它将在 x 和 o 之间翻转 以提供一种有趣的三值翻转(tic-tac-toe)概念的变体 此外 通过改变在主应用视窗中的数字 可以为对话框设置任意的行数和列数
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    文件对话框
    某些操作系统具有大量特殊的内置对话框 它们可以处理诸如选择字体 颜色 打印机等操作 基本上所有的图形操作系统都支持打开和保存文件 所以Java提供了JFileChooser 它封装了这些操作 使文件操作变得更加方便
    下面的程序演练了两个JFileChooser对话框 一个用来打开文件 一个用来保存文件 所有有趣的行为都集中在处理两个按钮单击事件的动作监听器中
    在这里插入图片描述
    在这里插入图片描述

    Swing组件上的HTML
    任何能接受文本的组件都可以接受HTML文本 且能根据HTML的规则来重新格式化文本 也就是说 可以很容易地在Swing组件上加入漂亮的文本 例如
    在这里插入图片描述

    滑块与进度条
    滑块能令用户通过前后移动滑点来输入数据 在某些情况下这显得很直观(比如音量控制) 进度条能以从 空 到 满 的动态方式显示数据 这也能给用户以直观的感受 下面的示例还展示了ProgressMonitor 这是一种功能更完备的弹出式对话框
    在这里插入图片描述
    把两个组件联系到一起的关键在于让它们共享一个模型 就像下面这一行一样
    在这里插入图片描述
    当然 也可以使用监听器进行控制 不过在简单的情况下这种方法更直接 ProgressMonitor并没有模型 因此需要使用监听器方式 注意 ProgressMonitor只能向前移动 并且一旦移动到底就会关闭

    选择外观
    可插拔外观 使你的程序能够模仿不同的操作系统的外观 你甚至可以在程序运行期间动态改变程序的外观 不过 通常只会在以下二者中选择一个 要么选择 跨平台 的外观(即Swing的 金属 外观) 要么选择程序当前所在系统的外观 这样你的Java程序看起来就好像是为该系统专门设计的(在大多数情况下 这的确是最好的选择 而且可以避免误导用户) 实现这两种行为的代码都很简单 不过你要确保在创建任何可视组件之前先调用这些代码 这是因为组件是根据当前的外观而创建的 而且创建之后就不会改变(很少会在程序运行的时候改变程序的外观 这个过程相当复杂)
    实际上 如果要使用跨平台的 金属 外观(它是Swing程序的特征) 那么什么都不用做 因为它是默认外观 不过要想使用当前操作系统的外观 那么加入下列代码即可 一般把这些代码添加在main()的开头 至少也要在添加任何组件之前
    在这里插入图片描述
    在catch子句中你什么也不用做 因为一旦你的设置代码失败了 UIManager默认将设置成跨平台的外观 不过在调试的时候 异常非常有用 所以你也许希望通过catch子句看看所发生的问题
    下面的程序能通过命令行参数选择外观 这里选择了几种组件 演示了它们在选择不同的外观时的表现
    在这里插入图片描述
    在这里插入图片描述

    树 表格和剪贴板

    JNLP与Java Web Start
    出于安全目的 我们可以为applet签名 经过签名的applet功能强大 能够有效取代应用程序 不过它们只能在浏览器中运行 这就需要在客户机上运行浏览器 从而增加了额外的开销 同时 它也限制了applet的用户界面 常常带来视觉上的混乱 因为Web浏览器有自己的菜单和工具条 它们会显示在applet的上方
    Java网络发布协议(Java Network Launch Protocol JNLP)在保持applet优点的前提下 解决了这个问题 通过一个JNLP程序 你可以在客户机上下载和安装单机版的Java应用程序 你可以通过命令行 桌面图标 或者与你的JNLP实现一起安装的应用程序管理器来执行这个程序 应用程序甚至可以从其最初被下载的网站上运行

    创建一个JNLP应用程序并不困难 要先编写一个标准应用程序 然后把它打包到一个JAR文件中 这时 需要提供一个启动文件 它是一个简单的XML文件 用来告诉客户端系统下载和安装这个程序所需的所有信息 如果你不准备为JAR文件签名 那么对于你将要在客户机上访问的每种类型的资源 必须使用JNLP API提供的服务进行访问
    下面是FileChooser Test.java的一种变体 它使用了JNLP服务来打开对话框 所以这个类可以被打包进未经签名的JAR文件 然后作为JNLP应用程序部署
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在JnlpFileChooser.java中 被注释的jar命令将产生必须的JAR文件 下面有一个为上面的例子准备的合适的启动文件
    在这里插入图片描述

    jnlp标记的另一个有用的子元素是security标记 这里并没有演示它 下面是一个security标记的例子
    在这里插入图片描述

    要想启动这个程序 你需要一个下载页面 它包含了一个链接到这个.jnlp文件的超文本链接 下面是这个页面的大致内容(没有第一行和最后一行)
    在这里插入图片描述

    Swing与并发

    长期运行的任务
    在使用图形化用户界面编程时最容易犯的错误之一 就是意外地使用了事件分发线程来运行长任务 下面是一个简单的示例
    在这里插入图片描述
    在这里插入图片描述
    当按下b1时 事件分发线程会突然被占用去执行这个长期运行的任务 此时你会看到 这个按钮甚至不会马上弹起来 因为正常情况下会重绘屏幕的事件分发线程现在处于忙状态 并且你也不能做其他任何事 例如按下b2 因为这个程序在b1的任务完成 从而使得事件分发线程再次可用之前 是不会做出响应的 b2中的代码是一种有缺陷的尝试 试图通过中断事件分发线程来解决这个问题
    解决之道当然是在单独的线程中执行长期运行的任务 下面是使用了单线程的Executor 它会自动将待处理的任务排队 然后每次执行其中的一个
    在这里插入图片描述
    在这里插入图片描述
    这个程序有了一些改进 但是当你按下b2时 它会在ExecutorService上调用shutdownNow() 从而会禁用它 如果你试图添加更多的任务 那么就会得到异常 因此 按下b2会使程序不起作用 我们想要的是在关闭当前任务(并放弃待处理任务)的同时 不会停止任何其他的事物 在前几节中描述的Java SE5的Callable/Future机制正是我们所需要的 我们将定义一个被称为TaskManager的新类 它包含多个元组 这些元组持有表示任务的Callable和从Callable中返回的Future 必须使用元组的原因是因为它使得我们可以跟踪最初的任务 这样就可以获取从Future中无法获得的额外信息 下面是示例
    在这里插入图片描述

    TaskManager可以当作通用使用工具来使用
    在这里插入图片描述
    在这里插入图片描述

    现在 它可以用在我们的示例中去管理长期运行的任务了
    在这里插入图片描述
    在这里插入图片描述

    为最终用户提供某种可视线索 以表示任务正在运行以及其执行进度 经常是一种非常重要的工具 这通常可以使用JProgressBar或ProgressMonitor来实现 下面的示例使用了ProgressMonitor
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    可视化线程机制
    下面的例子使一个实现了Runnable接口的Jpanel类可以在其自身上绘制不同的颜色 程序设定为从命令行接受参数 以决定颜色块的数目和颜色变化的时间间隔(线程休眠的时间) 尝试用不同的值运行程序 你可能会发现一些在你的平台之上的多线程实现的有趣的 难以言表的特性
    在这里插入图片描述
    在这里插入图片描述

    可视化编程与JavaBean

    JavaBean是什么

    1. 对于一个名称为xxx的属性 通常你要写两个方法 getXxx()和setXxx() 任何浏览这些方法的工具 都会把get或set后面的第一个字母自动转换为小写 以产生属性名 get方法返回的类型要与set方法里参数的类型相同 属性的名称与get和set所依据的类型毫无关系
    2. 对于布尔型属性 可以使用以上get和set的方式 不过也可以把get替换成is
    3. Bean的普通方法不必遵循以上的命名规则 不过它们必须是public的
    4. 对于事件 要使用Swing中处理监听器的方式 这与前面所见到的完全相同 addBounceListener(BounceListener)和removeBounceListener(BounceListener)用来处理BounceEvent事件 大多数情况下 内置的事件和监听器就能够满足需求了 不过也可以自己编写事件和监听器接口
      我们可以使用这些规则编写一个简单的Bean
      在这里插入图片描述

    使用Introspector抽取出BeanInfo
    JavaBean模式的最关键部分之一 表现在当你从选用区拖动一个Bean 然后把它放置到窗体上的时候 IDE构建工具必须能够创建这个Bean(如果有默认构造器就可以创建) 然后在不访问Bean的源代码的情况下抽取出所有必要信息 以创建属性和事件处理器的列表
    Java的反射机制能发现未知类的所有方法 对于解决JavaBean的这个问题 这是个完美的方案 你不用像其他可视化编程语言那样使用任何语言附加的关键字 实际上 Java语言里加入反射机制的主要原因之一就是为了支持JavaBean(尽管反射也支持对象序列化和远程方法调用) 所以 你也许会认为IDE构建工具的编写者将使用反射来抽取Bean的方法 然后在方法里面查找出Bean的属性和事件
    这当然是可行的 不过Java的设计者希望提供一个标准工具 不仅要使Bean用起来简单 而且对于创建更复杂的Bean也能够提供一个标准方法 这个工具就是Introspector(内省器)类 这个类最重要的就是静态的getBeanInfo()方法 向这个方法传递一个Class对象引用 它能够完全侦测这个类 然后返回一个BeanInfo对象 可以通过这个对象得到Bean的属性 方法和事件
    通常 你不用关心这些问题 也许能直接从货架上获得大多数想用的Bean 而不必知道底层的细节 你只需把Bean拖动到窗体上 配置它们的属性 然后为感兴趣的事件编写处理程序即可 不过 使用Introspector来显示Bean的信息是个值得学习的练习 下面就是这个工具
    在这里插入图片描述
    在这里插入图片描述

    在启动之后 程序强制评估frogbean.Frog 下面是程序输出 这里移除了不必要的额外细节
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    一个更复杂的Bean
    下面的例子稍微复杂一些(虽然它并不是很重要) 它是一个JPanel 当鼠标移动的时候 可以在鼠标周围绘制小圆圈 当你按下鼠标 单词 Bang 将出现在屏幕的中央 并且触发一个动作监听器
    你可以改变的属性包括 圆圈的大小 当按下鼠标时所显示的单词的颜色 大小和文本 BangBean类还具有addActionListener()和removeActionListener() 所以你可以自己编写监听器并与之关联 当用户在BangBean上单击的时候 你的监听器就会被触发 你应该能够识别它们支持的属性和事件
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    下面是测试Bean的BangBeanTest类
    在这里插入图片描述

    JavaBean与同步
    当创建Bean的时候 必须要假设它可能会在多线程环境下运行 也就是说

    1. 尽可能地让Bean中的所有公共方法都是synchronized(同步)的 当然 这将导致synchronized的运行时开销(在近几个版本的JDK中 这个开销已经大大降低了) 如果这么做会有问题 那么对那些不会导致临界区域问题的方法 可以考虑不同步 但要记住 这些方法并非总是这么容易做出判断 进行同步的方法应该尽可能短(比如下面例子中的getCircleSize()方法) 并且(或者)是 原子的 原子性是指 在调用含有这一小段代码的方法时 对象不能被改变 不同步这样的方法也许不会对程序的执行速度有明显的效果 所以最好是同步Bean的所有公共方法 只有在确实会有明显效果并且你可以安全地移除时 才在一个方法上移除synchronized关键字
    2. 当一个多路事件触发了一组对该事件感兴趣的监听器时 你必须假定 在你遍历列表进行通知的同时 监听器可能会被添加或移除
      第一点很容易处理 但第二点就需要做更多的思考 前面版本的BangBean.java通过忽略synchronized关键字并使用单路事件处理方式 回避了并发问题 下面是修改后的版本 它可以在多线程环境下工作 而且使用了多路事件处理方式
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

    把Bean打包
    在把JavaBean加入到某个支持Bean的IDE之前 必须把它置于一个Bean容器中 Bean容器 也就是一个JAR文件 它里面包含了Bean的所有.class文件以及能表明 这是一个Bean 的 清单(manifest)文件 清单文件是一个文本文件 它遵循特定的格式 对于BangBean 它的清单文件看起来像这样
    在这里插入图片描述

    唯一需要技巧的部分是 要确保在 Name 字段写上正确的路径 回过头看看前面的BangBean.java 就会发现它处于bangbean包中(也就是一个名为 bangbean 的子目录 它不包括在classpath中) 清单文件的名称字段必须含有这个包信息 此外 必须把清单文件放在包的根目录的上层目录中 这里就是把清单文件放在 bangbean 目录的父目录中 然后需要在清单文件所在的目录下调用jar工具 如下所示
    在这里插入图片描述

    你可能会奇怪 当我编译完BangBean.java之后 生成的其他.class文件在哪呢 其实 它们都在bangbean子目录下 上面jar命令行的最后一个参数就是bangbean目录名 当你把目录名传递给jar工具时 它将把整个目录打包进JAR文件(在本例中 包括了BangBean.java源文件 你也许不会选择在自己的Bean中包括源代码) 此外 如果你把刚才生成的JAR文件解包 就会发现里面并没有你指定的清单文件 jar工具创建了自己的清单文件(部分根据你提供的信息)MANIFEST.MF 这个文件放在 META-INF(元信息)目录下 打开这个文件 就会看到jar为每个文件都添加了数字签名信息 如下所示
    在这里插入图片描述

    对Bean更高级的支持

    你可以针对属性提供高级功能 前面的例子只演示了单一属性 但也可以使用数组来表示多重属性 这称为索引属性 只要提供恰当的方法(也就是根据命名规则给方法命名) Introspector将识别出索引属性 这样你的应用程序构建工具就可以正确工作
    属性可以被绑定 即它们能通过PropertyChangeEvent事件通知其他对象 这些被通知的对象可以根据Bean上的变化来决定如何改变自己
    属性可以被约束 即如果属性的改变是不可接受的 其他对象可以否决这个改变 这些对象也是通过PropertyChangeEvent事件得到通知的 而且能抛出PropertyVetoException异常来阻止属性的改变 然后恢复属性的旧值
    还可以改变Bean在设计阶段的表示方式

    1. 可以为自己的Bean提供一个自定义的属性表 对于所有其他Bean 将使用通常的属性表 但当你的Bean被选中的时候 将自动激活你提供的表
    2. 还可以为特定的属性提供自定义的编辑器 对于其他属性 将使用普遍编辑器 但是当你的特殊属性被编辑的时候 将自动激活的提供的编辑器
    3. 可以为你的Bean提供一个自定义的BeanInfo类 它可以产生与默认情况下由Introspector所提供的信息不同的信息
    4. 还可以把每一个FeatureDescriptor里的 专家 模式打开或者关闭 这样就能够区分简单功能和复杂功能

    Swing的可替代选择
    尽管Swing类库是Sun支持的GUI 但它决不是创建图形化用户界面的唯一方式 有两种重要的可替代选择 即用于Web之上的客户端GUI的使用MacroMedia的Flex编程系统的MacroMedia Flash 以及用于桌面应用的开源的Eclipse标准工具包(Standard Widget Toolkit SWT)类库

    用Flex构建Flash Web客户端

    Hello Flex
    请观察下面的MXML代码 它定义了一个用户界面
    在这里插入图片描述

    ActionScript是ECMAScript或JavaScript的某个版本 它看上去与Java很相似 并且除了支持动态脚本机制之外 还支持类和强类型 通过向本例中添加脚本 我们可以引入行为 在下面的示例中 MXML Script控件被用来直接将ActionScript放置到MXML文件中
    在这里插入图片描述

    编译MXML

    为了将MXML文件编译为Flash字节码 你有两个选择

    1. 你可以将MXML文件放在Java Web应用程序中 与JSP和HTML同处一个WAR文件中 然后在浏览器请求MXML文档的URL时 在运行时编译所请求的.mxml文件
    2. 你可以用Flex命令行编译器mxmlc编译MXML文件

    当你在命令行中调用Flex的mxmlc编译器时 就会产生SWF文件 可以按照你的意愿部署它们 mxmlc可执行程序位于Flex安装的bin目录下 调用它时不提供任何参数可以将有效的命令行选项列出来 通常 你需要指定Flex客户端组件库的位置 来作为-flexlib命令行选项 但是在像前面看到的两个非常简单的示例中 Flex编译器将假设组件库的位置 因此可以像下面这样编译前面的两个示例
    在这里插入图片描述
    这将产生一个helloflex2.swf文件 它可以在Flash中运行 或者与HTML一起置于任何HTTP服务器之上(一旦Flash被加载到Web浏览器中 你通常只需在SWF文件上双击就可以在浏览器中启动它)
    对于helloflex2.swf 你可以看到下面这个运行在Flash Player中的用户界面
    在这里插入图片描述
    在更复杂的应用程序中 你可以通过引用在外部ActionScript文件中的函数 来将MXML和ActionScript分离开 在MXML 可以使用下面用于Script控件的语法
    在这里插入图片描述
    这行代码使得MXML控件可以引用位于名为MyExternalScript.as的文件中的函数 就好像这些函数位于MXML文件中一样

    MXML与ActionScript
    MXML是ActionScript类的声明式快捷方式 无论你看到何种MXML标签 都有一个同名的ActionScript类与之对应 当Flex编译器解析MXML时 它首先将XML转换为ActionScript 并加载所引用的ActionScript类 然后将这些ActionScript编译链接为SWF

    容器与控制
    Flex组件库的可视化核心是一个容器集合 这些容器管理着布局 以及在容器中的控件数组 容器包括面板 垂直和水平箱体 瓦片 折叠夹 分格箱体以及网格等 控件是用户界面上的小部件 例如按钮 文本区域 滑块 日历和数据网格等等
    展示一个可以显示和排序音频文件列表的Flex应用程序 这个应用程序演示了容器 控件 以及如何从Flash连接到Java
    现在我们开始编写MXML文档 将一个DataGrid控件(更加复杂的Flex控件之一)放置到一个Panel容器中
    在这里插入图片描述
    在这里插入图片描述

    效果与样式
    Flash Player使用向量来呈现图形 因此它可以在运行时执行极富表现力的转换 Flex效果可以让你浅尝这些动画类型 效果是指可以通过使用MXML语法而应用到控件和容器上的转换

    通过Flex对层叠样式表(Cascading Style Sheets CSS)的支持 我们还可以进行样式标准化操作 如果你将一个CSS文件附着到MXML文件上 那么Flex控件将都遵循其中的样式 例如 songStyles.css包含下面的CSS声明
    在这里插入图片描述

    事件
    用户界面是一种状态机 它在状态发生变化时执行动作 在Flex中 这些变化是通过事件来管理的 Flex类库包含大量各种不同的控件 它们具有大量的事件 覆盖了鼠标移动和键盘点击的所有方面

    连接到Java
    在MXML文件末尾的RemoteObject标签设置了到外部Java类gui.flex.SongService的连接 Flex客户端将使用这个Java类中的getSongs()方法来为DataGrid获取数据 为了实现这一点 它必须看起来像是一个服务 一个用户可以用来交换消息的端点 在RemoteObject标签中定义的服务有一个source属性 它指示的是RemoteObject的Java类 并且还指定了一个在Java方法返回时被调用的ActionScript回调函数onSongs() 潜逃的methods标签声明了getSongs()方法 它可以使Java方法对Flex应用程序中的其他部分都是可访问的

    现在可以使用ActionScript从Flash中调用getSongs()方法了
    在这里插入图片描述
    根据MXML的配置 这将调用SongService类中的getSongs()方法
    在这里插入图片描述
    在这里插入图片描述
    每个Song对象都只是一个数据容器
    在这里插入图片描述

    下面是ActionScript的列表 在MXML文件中用Script控件将其导入
    在这里插入图片描述
    在这里插入图片描述
    为了处理对DataGrid单元格的选中操作 我们在MXML文件的DataGrid声明中添加了cellPress事件属性
    在这里插入图片描述
    当用户在DataGrid中点击一首歌时 将会调用上面的ActionScript中的selectSong()

    数据模型与数据绑定

    在最简单的数据绑定形式中 控件可以直接引用数据而不需要用粘合代码把数据复制到控件中 当数据更新时 引用它的控件也会自动更新 而不需要任何程序员的干预 Flex基础设施会恰当地响应数据变化事件 并且更新所有绑定到该数据的控件
    下面是数据绑定语法的简单示例
    在这里插入图片描述

    构建和部署
    在使用前面的示例时 你在命令行中可以不提供-flexlib标签 但是为了编译这个程序 必须使用-flexlib标签指定flex-config.xml文件的位置 对我的安装来说 下面的命令是可以工作的 但是你必须将其修改为适应你自己的配置(命令是单行的 即中间被包装的那一行)
    在这里插入图片描述

    另外 你必须配置服务器使得Flex应用程序可以成功地与Java文件对话 Flex试用包中包含一个JRun服务器 一旦你安装了Flex 就可以通过计算机菜单或者命令行来启动它
    在这里插入图片描述
    你可以通过在Web浏览器中打开http://localhost:8700/samples 并查看各种示例来验证这个服务器是否成功启动了(这还是一种熟悉Flex能力的好方式)

    创建SWT应用

    Hello SWT
    让我们以最简单的 hello world 风格的应用程序开始
    在这里插入图片描述

    为了证明Shell是主窗口 下面的程序将创建大量的Shell对象
    在这里插入图片描述

    SWT也使用了布局管理器 虽然它与Swing使用的不同 但是思想一致 下面是稍微复杂一些的示例 它接收从System.setProperties()中获得的文本 并将其添加到shell中
    在这里插入图片描述

    根除冗余代码
    有些事情是你在每个SWT应用程序中都会做的 这与Swing程序中的重复动作一样 对于SWT 你总是得创建Display 从Display中创建Shell 然后创建readAndDispatch()等等 当然 对于某些特殊情况 你可以不做这些 但是它非常普遍 绝对值得去根除这些重复代码
    我们需要强制每个应用程序遵循下面的接口
    在这里插入图片描述
    应用程序应该提交给了Composite对象(Shell是它的一个子类) 并且应该用它在createContents()内部创建其所有的内容 SWTConsole.run()会在恰当的地方调用createContents() 根据用户传递给run()的参数来设置shell的尺寸 打开shell 然后运行事件循环 最终在程序退出时释放shell
    在这里插入图片描述
    在这里插入图片描述

    我们可以创建一个DisplayProperties.java的变体 它可以用SWTConsole来显示机器环境
    在这里插入图片描述

    菜单
    为了演示基本的菜单 下面的程序将读入它自己的源代码 将其断开为单词 然后用这些单词组装菜单
    在这里插入图片描述
    在这里插入图片描述

    页签面板 按钮和事件

    为了演示各种基本部件 下面的程序在页签面板内部放置了大量的子示例 你还将看到如何创建Composite(大体上与Swing的JPanel相同) 以实现将一些部件放到其他的部件中
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    图形
    下面是将Swing程序SineWave.java转译为SWT的版本
    在这里插入图片描述
    在这里插入图片描述

    SWT中的并发
    尽管SWT/Swing是单线程的 但是如果产生非确定性的程序 那么仍旧有可能违反这种单线程性 基本上 你不会想要用多线程来编写显示功能 因为如果这样的话 它们就会以令人惊讶的方式互相改写了
    SWT根本不允许这样 如果你试图用多个线程来编写显示功能 那么它就会抛出异常 这可以防止程序员新手因不注意而犯此类错误 从而在程序中引入难以发现的缺陷
    下面是Swing版本的ColorBoxes.java程序转移为SWT的版本
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    SWT还是Swing
    在许多场合 SWT是一种比Swing更加简单的编写代码方式 但是采用SWT的GUI编程仍旧很复杂 因此你使用SWT的动机可能应该是 首先 为用户在使用你的应用系统时提供一种更加透明的体验(因为你的应用程序的感官与在用户平台上的其他应用程序相同) 其次 如果认为SWT提供的可响应性很重要 否则 Swing就可能是恰当的选择

    展开全文
  • Java 图形界面基础

    千次阅读 多人点赞 2016-03-22 19:51:58
    Java图形界面基础

    Java图形界面基础

    当你开始验证自己的PC的JDK环境是否配置完成的时候有没有想过这个窗体是怎么做出来的呢?
    这里写图片描述
    用几句简单的Java语言就可以做出这样的窗体,不信我可以写给给位看。

    import java.awt.Frame;
    
    public class MyTest{
    public static void main(String[][]args){
    Frame w = new Frame();
    w.setSize(300,400);
    w.show;
    }
    }

    我将这段代码写入eclipse运行看看会出现什么
    这里写图片描述
    这里写图片描述
    确实是出现了一个窗体。大小是300*400
    下面我们来分析一下代码

    import java.awt.Frame

    这里的awt全名(Abstract Windowing Toolkit),是Sun公司在发布JDK1.0时一个重要的组成部分,是Java提供的用来建立和设置Java的图形界面的基本工具。AWT中所有的工具类都保存在java.awt包中,此包中的所有操作类可以用来建立与平台无关的图形界面(GUI)的类。这些类又被叫做组件(Components)。 Frame这个当然是awt这个包中的类啦,通俗的将就是要借一下awt包中的Frame类。下面的代码,main是程序入口不用解释,那么main下面的代码又怎么解释呢

    Frame w = new Frame();
    w.setSize(300,400);
    w.show;

    其实啊这个w是Frame的一个对象,new Frame()的意思就是借Frame()一用我新建一个叫w的窗体,setSize很好理解,就是字面意思设置w窗体的大小,400和300分别是长和宽,最后的show()就是展示出w窗体的意思。
    代码中的等号我要解释一下,这可和数学里的等号不是一个意思,编程语言里的等号是赋值的意思,比如说a=b,这句话在程序里的意思就是把b的值赋给a,所以等号左边通常是装东西的容器,这样的容器,Java里叫做变量。
    我们先看一下属于程序的内存是怎么管理的,下面是一个内存的示意图
    这里写图片描述
    可以看到内存被划分为两个区域,一个是栈,另一个是堆,看的出来栈相对于堆来说是很小的,栈是操作系统按照薯片桶的管理方式管理的,先放进去的薯片,会在最后被取出来,而堆没有管理限制。
    还是回到等号,见到等号,我们就要看等号右边,看到第一个单词是new,new就意味着咱堆里分配了一块内存,分配内存干什么?new 后面跟着Frame这个类,那么分配内存就是为了装Frame的对象w,也就是说,等于号的右边已经创建了对象,如图
    这里写图片描述
    那么等于号左边是干什么的,上面提到过,在Java里等于号意味着将右边的东西送到左边去,左边通常是一个变量,变量在Java里分配内存的另一个手段。既然new用于在堆里分配对象,那么对象就被放在栈里,我们已经得到了一个Frame对象,为什么还要一个变量呢?是因为我们得到的这个对象不方便操作,new的那一刻之后就没办法找到它了,如果把这个对象的地址存到一个变量里,我们以后就可以通过这个变量随时随地找到这个对象,这个变量起到了电视遥控器的作用,为了方便操作,变量也不是什么都可以装的,需要提前说明它能装什么东西,这里的声明Frame w,及时表明w是能够装Frame对象的变量,我们管这种指向对象的变量叫做引用
    这里写图片描述
    上面的这段代码我讲一个通俗一点的例子:
    你想买一台电视机,你得到了一台电视机加上一个遥控器叫做w,遥控器w上面有很多功能键,这在Java里对象的引用提供的函数就是
    w的功能键,在Java里叫做方法。
    ## Java绘图 ##
    讲完了如何创建窗体,下一步就要说怎么在窗体里做点事儿了,就是怎么在窗体里绘画。这里有一个前提,Java语言不允许直接将图形画在窗体上,必须画在一个画布上,然后将画布放到窗体上。好消息是系统直接给你提供了画布类。那么之后我将带领大家做第一项目,那就是画一个王八,这个同样是我学Java时候的第一个项目。大家可以想一想,该怎么画呢。画布类不可能提供王八的画法,所以该怎么办呢?聪明的看官老爷应该已经想到了,是不是将系统提供的画布类new 成对象,然后在这个对象上画,可以的,如果可以想到这一点,说明对Java的理解已经越来越升入了。
    但是面向对象思想意味着有另一种方式能够更好的解决这个问题。如果我有一个类叫动物,我希望得到一个人的类,你会发现动物有的一切人也有,能不能把动物拿来改造一下呢,添加上人特有的就完成对人的定义,如果这样可行,那就太棒了,因为动物类描述的内容有太多类需要了,我们因此会得到一个叫做代码重用的好处,那么这个叫做继承。人类是从动物类继承而来的,所以人类拥有动物类的一切,事实上人类也是动物,是动物类的一个特例,那么动物类咱Java的术语中被称作是父类,而人类叫做子类,有一个说法,继承自什么就是什么,人类继承自动物,所以人类就是动物。当继承的想法真的主宰了你的思路时,你就会在一切可能的情况下优先使用继承这个手段。
    回到我们这个问题里,我现在有一个类,提供了一个没有内容的画布,你希望得到一个有内容的画布,怎么办?当然是通过继承产生一个有王八的新画布,Java代码是这么写的:

    class MyPanel extends Panel{
    
    }

    新的类叫做MyPanel,注意:这是一个类与类之间的关系,不是对象与对象之间的关系,extends是关键字。也就是Java里的继承,用于实现继承的类MyPanel叫做子类,被继承的类Panel叫做父类。
    Panel 就是系统提供的空画布,问题是在整个程序前面都需要导入这个类。

    import java.awt.Panel;

    还有一个小问题,随着程序越来越大,使用的类也越来越大,一个个类导入会占据很大的区域,所以Java允许用一种简洁的方式,将镇一个包中所有的类都导入。在现代的代码中,

    import java.awt.Panel;
    w.setSize(300,400);

    可以被替换成

    import java.awt.*;

    代码是节约了,但这样会将很多不需要的类都导入进来,这个完全不用担心,因为类知识定义,并不存在,在JDK进行翻译的时候,没有被使用的类会被完全的丢弃。

    import java.awt.*;
    
    public class MyTest{
    }

    我们来看看这段新代码

    class MyPanel extends Panel{
    
    }

    继承意味着,如果Panel中有5000行的代码,那么MyPanel相当于已经拥有了5000行的代码,如果Panel里有50个方法,那么MyPanel里已经有了50个方法。方法就是之前叫做函数的东西,以后就不能用函数这个叫法了。
    如果加上一个方法aaa,继续假设Panel里已经有50个方法了,那么现在MyPanel里有多少个方法?没错就是51个,我们增加一个。

    class MyPanel extends Panel{
    public class aaa(){
    
    }
    }

    继承是面向对象的三大特征之一,是非常重要的代码手段,不过Java只支持淡了继承,也就是说一个子类只能有一个直接的父类,就好像是你只有一个亲爹一样。Java里有一个非常特殊的类叫做Object,这就是我们常说的单根结构,Object是所有类的根。比如之前写的public class MyTest(){},表面看起来这个类没有继承,他等效于public MyTest extends Object{},这意味着Object中有的成员在Java中任何类都有。
    可是我现在要增加的不是这个叫aaa的方法,而是一个叫paint的方法。

    class MyPanel extends Panel{ 
    public void paint(Graphics g){ 
    } 
    } 

    看的出来,这个paint方法不是随随便便写出来的,如果Panel里有50个方法,那么加上paint方法,现在MyPanel里依旧是50个方法,因为Panel里也有一个paint方法,这就等于说是把父类的方法重写了一遍。这个行为在Java中叫做方法的覆盖。举例来说,父亲是动物,动物会有吃喝拉撒的方法,今天我们要继承一个人出来,但是人不能使用动物的”吃”的这个方法,所以我就在人的这个类里又写了一个”吃”的方法,那么父类的”吃”的方法去哪里了,动物的”吃”不起作用了,现在人的”吃”在起作用。
    我们看paint方法的参数Graphics g,注意到的第一个字母是大写的,第一个字母大写意味着什么?说明它是一个类,这个类也包含在java.awt.*里,第一句话就给导入了。这个类是系统提供了,千万不要写错了。
    我们来仔细看看这个paint方法是干什么的。用鼠标单机菜单栏里随便一个菜单,你看到了什么?一个弹出的菜单
    这里写图片描述
    我们注意到这个弹出的菜单成为屏幕最上面的一层,他盖住了后面的内容。在今天的计算机中,这种现象比比皆是,我们可以想象目前计算机上的第一层是这个菜单,第二层是记事本,记事本下面至少还盖着一个桌面,是不是?其实这些都是假的,计算机的屏幕只能显示一层,这么多层是假的,为了欺骗大多数人,菜单的边缘甚至还画上了阴影,让眼睛误以为后面的东西还在,其实后面的东西早就没有了,在这个菜单消失后,如果后面的东西立刻显示出来,人们才能认为后面的东西并没有消失,只是被盖住了。那么是怎么做到的呢?在Dos年代其实都是这么做的,如果你的程序准备弹出这个菜单,需要先计算好要盖住的区域是哪一个部分,在显示菜单前,程序要到显卡的显存里将马上就要被盖住的内容取出来,放到内存的一个地方保管下来,在菜单消失后,立刻将刚才保管住的内容重新放到显卡的那个区域里,因为计算机的速度很快,所以可以欺骗人的眼睛。
    刚才说的都是Dos的做法,windows并不是这么做的。在Windows里,程序如果想弹出菜单,什么都不要做,就在那个地方花菜单就好了,背后的东西当然是看不见了,菜单消失就消失好了,程序还是什么都不需要做。那么背后的东西是怎么出现的呢?在windows里,计算机一直砸扫描屏幕,就像之前说的扫描键盘一样,当菜单消失的时候,windows的操作系统会立刻发现屏幕上有一个区域没人管了,于是windows就会去追查由谁来管理负责这个区域,于是windows操作系统就会给记事本发出一道命令,让记事本重新将这块区域画好。windows如何向程序下达命令?只有一个办法,调用程序中特定的方法,此前系统让一个程序运行起来,是调用main方法,现在系统让程序重画一个区域就会调用paint方法,这既是为什么要重写一个paint的原因。
    不过为何windows不按照Dos的做法来做呢?貌似Dos更加合理。谁弄得谁负责。因为Windows里用户常常会运行很多程序,大多数程序会弹出一个窗口,而且往往是全屏的,按照Dos的做法,弹出一个窗口要盖住已经存在的整个屏幕,这就意味着如果屏幕的分辨率是1024*768De话,就要消耗1024*768再乘上了区分颜色的内存空间,这样或许同时打开几个程序,为了保存被挡住的内容将内存消耗完了,Dos年代同时打开几个程序的情况很少见,所以那个时代才不是问题,而且Dos的做法也有好处,虽然浪费了内存但是节约了CPU。回头看Windows的做法,虽然节约了内存,但是CPU要做很多事情,查找哪一个窗口是当前的,要调用paint方法里的语句来画图。这是一个程序员要考虑的权衡内存和CPU之间关系的问题。
    有人说为什么main是主函数,因为main是程序的入口,现在看来好像不能这么说,paint也是程序的入口,只不过这两个方法的进入时机不同,main是程序最初运行的时候被操作系统调用的。而paint是需要画界面的时候被调用的,别的书上做的总结:
    1.在界面第一次显示的时候paint方法被调用。
    2.当窗体改变大小的时候paint被调用
    3.当窗体被盖住重新显露出来的时候paint被调用
    第三点好像根本就不用去记,你想一下,你是操作系统,你什么时候去调用paint方法呢,当然是想用的时候。
    这样我们就清楚了。你准备一个paint方法给操作系统在需要的时候调用,你是方法的提供者,操作系统就是调用者,那么Graphics就是操作系统提供的参数,是在特定的区域画图的权利,我管他叫画笔。
    那么看看画笔的遥控器g有啥子功能,专业叫法不是遥控器,叫做引用。Graphics提供了如下用于绘制图形的方法。
    drawLine:绘制直线
    drawString: 绘制字符串
    drawRect:绘制矩形
    drawRoundRect:绘制圆角矩形
    drawOval:绘制椭圆
    drawPolygon:绘制多边形边框
    drawArc:绘制圆弧
    drawPolyline:绘制折线
    fillRect:填充一个矩形
    fillRoundRect:填充一个圆角矩形
    fillOval:填充椭圆
    fillPolygon:填充一个多边形
    fillArc:填充圆弧所包围的区域
    drawImage:绘制位图
    有兴趣的可以去多了解一些Java的API手册
    下面我们来尝试用Java语言来画一条直线

       import java.awt.*;
    
    public class Test {
    
        public static void main(String args[]){
            Frame w = new Frame();
            w.setSize(300, 400);
            MyPanel mp = new MyPanel();
            w.add(mp);
            w.show();
        }
    }
    class MyPanel extends Panel{
        public void paint(Graphics g){
            g.drawLine(30, 30, 100, 100);
        }
    } 

    看一下

    g.drawLine(x1, y1, x2, y2);

    大家一眼就能看出来这是两个点的坐标,两点确定一条直线。
    MyPanel类产生一个叫mp的引用对象,将mp这个画布放到窗体w上,我们看一下运行的结果
    这里写图片描述
    那么椭圆怎么画,而且是一个有颜色的圆呢,大家可以先尝试一下然后再看我的代码

    import java.awt.*;
    
    public class Test {
    
        public static void main(String args[]){
            Frame w = new Frame();
            w.setSize(300, 400);
            MyPanel mp = new MyPanel();
            w.add(mp);
            w.show();
        }
    }
    class MyPanel extends Panel{
        public void paint(Graphics g){
            g.setColor(Color.BLUE);
            g.drawOval(30, 30, 50, 100);
        }
    }

    这里写图片描述
    setColor(Color.BLUE)用于选择颜色
    你可以用这些方法画出任何你想要的图形。下一次带大家画一个组合图形-乌龟
    或许你已经有能力可以尝试着自己画一只乌龟了 ,大家多多练习这些代码,最好可以不用过大脑就可以敲出来。
    3月22日
    5:53pm
    by WhiteJavaCoder

    展开全文
  • 如果文件存储位置和cmd打开位置不一样,请使用绝对路径 五:命令行参数示例hello_argv.py hello_argv.py文件在桌面 import sys print("Hello,",sys.argv[1]) #这样写也行: #print("Hello,"+sys.argv[1]) 在桌面打开...

    (还在更新中…) 这篇博客花费了我的大量时间和精力,从创作到维护;若认可本篇博客,希望给一个点赞、收藏

    并且,遇到了什么问题,请在评论区留言,我会及时回复的


    这本书对Python的知识点的描述很详细,而且排版看的很舒服

    1. 几个例题: 假装自己从零开始学,将一些有代表性、有意思的例题抽取出来
    2. 部分复习题: 遇到有意思的复习题,我会拿出来,并且进行分析
    3. 上机实践: 全部上机实践题的解题思路

    文章目录

    第一章 Python概述


    几个例题

    一:Python3.7.4下载

    python3.7.4下载地址:https://www.python.org/downloads/release/python-374/
    页面最下面:

    下载,安装完python后:出现的四个玩意:Python 3.7 Module Docs,IDLE,Python 3.7 Manuals,Python 3.7(64-bit)

    1. Python 3.7 Module Docs(64-bit)
      点击之后,会出现一个网页(将我下载的Python3.7.4文件夹中包含的模块都列了出来,页面不止这么点,还可以往下拉)

    2. IDLE(Python 3.7 64-bit)
      一个Python编辑器,Python内置的集成开发工具

    3. Python 3.7 Manuals(64-bit)
      Python 3.7 开发手册

    4. Python 3.7(64-bit)
      控制台中运行Python

    二:更新pip和setuptools包,安装NumPy包,安装Matplotlib包

    以下三个命令都是在控制台(windows中的cmd)中运行

    更新pip和setuptools包

    1. pip用于安装和管理Python扩展包
    2. setuptools用于发布Python包
    python -m pip install -U pip setuptools
    

    安装NumPy

    Python扩展模块NumPy提供了数组和矩阵处理,以及傅立叶变换等高效的数值处理功能

     python -m pip install NumPy
    

    安装Matplotlib包

    Matplotlib是Python最著名的绘图库之一,提供了一整套和MATLAB相似的命令API,既适合交互式地进行制图,也可以作为绘图控件方便地嵌入到GUI应用程序中

    python -m pip install Matplotlib
    

    三:使用IDLE打开和执行Python源文件程序

    首先:
    有一个.py文件test.py
    在这里插入图片描述

    使用IDLE打开.py文件的两种方式:

    1. 右键test.py---->Edit With IDLE---->Edit With IDLE 3.7(64-bit)
    2. 打开IDLE,然后File---->Open(或者ctrl+O)选择.py文件

    运行

    Run---->Run Module(或者F5
    就会出现这个界面,执行结果显示在这个界面中

    补充一点:
    如果在IDLE中编辑.py文件,记得修改后要保存(ctrl+s),再运行(F5

    四:使用资源管理器运行hello.py

    hello.py文件在桌面

    import random
    
    print("hello,Python")
    print("你今天的随机数字是:",random.choice(range(10)))#输出在0-9之间随机选择的整数
    input()
    
    1. 在桌面打开PowerShell(还有两种输入方式:python hello.py或者.\hello.py
    2. 或者在桌面打开cmd, 就输入hello.py或者python hello.py

    补充:上述两种命令中的hello.py都是相对路径,因为文件在桌面,而且我是在桌面打开cmd,所以文件路劲可以这么简简单单的写。如果文件存储位置和cmd打开位置不一样,请使用绝对路径

    五:命令行参数示例hello_argv.py

    hello_argv.py文件在桌面

    import sys
    
    print("Hello,",sys.argv[1])
    #这样写也行:
    #print("Hello,"+sys.argv[1])
    
    1. 在桌面打开PowerShell(还有两种输入方式:python hello_argv.py 任意输入或者./hello_argv.py 任意输入
    2. 或者在桌面打开cmd,就输入hello_argv.py 任意输入或者python hello_argv.py 任意输入

    补充:以图中第一个命令举例,hello_argv.pysys.argv[0]Pythonsys.argv[1]

    第二章 Python语言基础


    选择题:1、3、7、8

    1. 在Python中,以下标识符合法的是

    A. _B. 3CC. it’sB. str

    答案:A

    1. 标识符的第一个字符必须是字母,下划线(_);其后的字符可以是字母、下划线或数字。
    2. 一些特殊的名称,作为python语言的保留关键字,不能作为标识符
    3. 以双下划线开始和结束的名称通常具有特殊的含义。例如__init__为类的构造函数,一般应避免使用

    B:以数字开头,错误
    C:使用了',不是字母、下划线或数字
    D:str是保留关键字

    3. 在下列Python语句中非法的是

    A. x = y =1B. x = (y =1)C. x,y = y,xB. x=1;y=1

    答案:B,C

    7. 为了给整型变量x,y,z赋初值10,下面Python赋值语句正确的是

    A. xyz=10B. x=10 y=10 z=10C. x=y=z=10B. x=10,y=10,z=10

    答案:C

    1. 分号;用于在一行书写多个语句
    2. python支持链式赋值

    A:赋值对象是xyz
    B:分号;用于在一行书写多个语句,而不是' '(即空格)
    D:分号;用于在一行书写多个语句,而不是,

    8. 为了给整型变量x,y,z赋初值5,下面Python赋值语句正确的是

    A. x=5;y=5;z=5B. xyz=5C. x,y,z=10B. x=10,y=10,z=10

    答案:A

    Pytho能支持序列解包赋值,但是变量的个数必须与序列的元素个数一致,否则会报错

    B:赋值对象是xyz
    C:序列解包赋值,变量的个数必须与序列的元素个数一致,否则会报错
    D:分号;用于在一行书写多个语句,而不是,

    思考题:9

    9.下列Python语句的输出结果是

    def f():pass
    print(type(f()))
    

    结果:<class 'NoneType'>

    NoneType数据类型包含唯一值None,主要用于表示空值,如没有返回值的函数的结果

    上机实践:2~6

    2. 编写程序,输入本金、年利率和年数,计算复利(结果保留两位小数)

    money = int(input("请输入本金:"))
    rate = float(input("请输入年利率:"))
    years = int(input("请输入年数:"))
    amount = money*((1+rate/100)**years)
    print(str.format("本金利率和为:{0:2.2f}",amount))
    

    运行:

    请输入本金:1000
    请输入年利率:6.6
    请输入年数:10
    本金利率和为:1894.84
    

    3. 编写程序,输入球的半径,计算球的表面积和体积(结果保留两位小数)

    import math
    r = float(input("请输入球的半径:"))
    area = 4 * math.pi * r**2
    volume = 4/3*math.pi*r**3
    print(str.format("球的表面积为:{0:2.2f},体积为:{1:2.2f}",area,volume))
    

    运行:

    请输入球的半径:666
    球的表面积为:5573889.08,体积为:1237403376.70
    

    4. 编写程序,声明函数getValue(b,r,n),根据本金b,年利率r和年数n计算最终收益v

    money = int(input("请输入本金:"))
    rate = float(input("请输入年利率(<1):"))
    years = int(input("请输入年数:"))
    
    def getValue(b,r,n):
        return b*(1+r)**n
    
    print(str.format("本金利率和为:{0:2.2f}",getValue(money,rate,years)))
    

    运行:

    请输入本金:10000
    请输入年利率(<1):0.6
    请输入年数:6
    本金利率和为:167772.16
    

    5. 编写程序,求解一元二次方程x2-10x+16=0

    from math import sqrt 
    x = (10+sqrt(10*10-4*16))/2
    y = (10-sqrt(10*10-4*16))/2
    print(str.format("x*x-10*x+16=0的解为:{0:2.2f},{1:2.2f}",x,y))
    

    运行:

    x*x-10*x+16=0的解为:8.00,2.00
    

    6. 编写程序,提示输入姓名和出生年份,输出姓名和年龄

    import datetime
    sName = str(input("请输入您的姓名:"))
    birthday = int(input("请输入您的出生年份:"))
    age = datetime.date.today().year - birthday
    print("您好!{0}。您{1}岁。".format(sName,age))
    

    运行:

    请输入您的姓名:zgh
    请输入您的出生年份:1999
    您好!zgh。您20岁。
    

    案例研究:使用Pillow库处理图像文件

    https://blog.csdn.net/Zhangguohao666/article/details/102060722

    通过此案例,进一步了解Python的基本概念:模块、对象、方法和函数的使用

    第三章 程序流程控制


    几个例题

    一:编程判断某一年是否为闰年

    闰年:年份能被4整除但不能被100整除,或者可以被400整除。
    口诀:四年一闰,百年不闰,四百必闰

    代码一:

    y = int(input("请输入要判断的年份:"))
    if((y % 4 == 0 and y % 100 != 0) or y % 400 == 0):
        print("是闰年")
    else:
        print("不是闰年")
    

    代码二(使用calendar模块的isleap()函数来判断):

    from calendar import isleap
    
    y = int(input("请输入要判断的年份:"))
    if(isleap(y)):print("闰年")
    else:print("不是闰年")
    

    二:利用嵌套循环打印九九乘法表

    九九乘法表:

    for i in range(1,10):
        s = ""
        for j in range(1,10):
            s += str.format("%d * %d = %02d  " %(i, j, i*j))
        print(s)
    

    下三角:

    for i in range(1,10):
        s = ""
        for j in range(1,i+1):
            s += str.format("%d * %d = %02d  " %(i, j, i*j))
        print(s)
    

    上三角:

    for i in range(1,10):
        s = ""
        for k in range(1,i):
            s += "                   "
        for j in range(i,10):
            s += str.format("%d * %d = %02d  " %(i, j, i*j))
        print(s)
    

    三:enumerate()函数和下标元素循环示例

    Python语言中的for循环直接迭代对象集合中的元素,如果需要在循环中使用索引下标访问集合元素,则可以使用内置的enumerate()函数

    enumerate()函数用于将一个可遍历的数据对象(例如列表、元组或字符串)组合为一个索引序列,并返回一个可迭代对象,故在for循环当中可直接迭代下标和元素

    seasons = ["Spring","Summer","Autumn","Winter"]
    for i,s in enumerate(seasons,start=1):    #start默认从0开始
        print("第{0}个季节:{1}".format(i,s))
    

    运行:

    第1个季节:Spring
    第2个季节:Summer
    第3个季节:Autumn
    第4个季节:Winter
    

    四:zip()函数和并行循环示例

    如果需要并行遍历多个可迭代对象,则可以使用Python的内置函数zip()

    zip()函数将多个可迭代对象中对应的元素打包成一个个元组,然后返回一个可迭代对象。如果元素的个数不一致,则返回列表的长度与最短的对象相同。

    利用运算符*还可以实现将元组解压为列表

    evens = [0,2,4,6,8]
    odds = [1,3,5,7,9]
    for e,o in zip(evens,odds):
        print("{0} * {1} = {2}".format(e,o,e*o))
    

    运行:

    0 * 1 = 0
    2 * 3 = 6
    4 * 5 = 20
    6 * 7 = 42
    8 * 9 = 72
    

    五:map()函数和循环示例

    如果需要遍历可迭代对象,并使用指定函数处理对应的元素,则可以使用Python的内置函数map()

    map(func,seq1[,seq2,...])
    
    • func作用于seq中的每一个元素,并将所有的调用结果作为可迭代对象返回。
    • 如果func为None,该函数的作用等同于zip()函数

    计算绝对值:

    >>> list(map(abs, [-1, 0, 7, -8]))
    [1, 0, 7, 8]
    

    计算乘幂:

    >>> list(map(pow, range(5), range(5)))
    [1, 1, 4, 27, 256]
    

    计算ASCII码:

    >>> list(map(ord, 'zgh'))
    [122, 103, 104]
    

    字符串拼接(使用了匿名函数lambda):

    >>> list(map(lambda x, y: x+y, 'zgh', '666'))
    ['z6', 'g6', 'h6']
    

    选择题:1、2、3

    1. 下面的Python循环体的执行次数与其他不同的是

    A.

    i = 0						
    while(i <= 10):
    	print(i)
    	i = i + 1
    

    B.

    i = 10
    while(i > 0):
    	print(i)
    	i = i - 1
    

    C.

    for i in range(10):
    	print(i)
    

    D.

    for i in range(10,0,-1):
    	print(i)
    

    答案:A

    A:[0,10] 执行11次
    B:[10,1] 执行10次
    C:[0,9) 执行10次
    D:[10,0) 执行10次

    2. 执行下列Python语句将产生的结果是

    x = 2; y = 2.0
    if(x == y): print("Equal")
    else: print("Not Equal")
    
    A. EqualB. Not EqualC. 编译错误D. 运行时错误

    答案:A

    Python中的自动类型转换:

    1. 自动类型转换注意针对Number数据类型来说的
    2. 当2个不同类型的数据进行运算的时候,默认向更高精度转换
    3. 数据类型精度从低到高:bool int float complex
    4. 关于bool类型的两个值:True 转化成整型是1;False 转化成整型是0

    int类型的2转化为float类型的2.0

    3. 执行下列Python语句将产生的结果是

    i= 1 	
    if(i): print(True) 	
    else: print(False)
    
    A. 输出1B. 输出TrueC. 输出FalseD. 编译错误

    答案:B

    在Python中,条件表达式最后被评价为bool值True或False。

    如果表达式的结果为数值类型(0),空字符串(""),空元组(()),空列表([]),空字典({}),其bool值为False,否则其bool值为True

    填空题:6

    6. 要使语句for i in range(_,-4,-2)循环执行15次,则循环变量i的初值应当为

    答案:26或者25

    一开始我给的答案是26,经过评论区 的提醒:
    在这里插入图片描述

    >>> a = 0
    >>> for i in range(26, -4, -2): a+=1
    
    >>> print(a)
    15
    
    >>> a = 0
    >>> for i in range(25, -4, -2): a+=1
    
    >>> print(a)
    15
    

    这种题目有一个规律:for i in range(x,y,z):
    若循环中没有break或者continue语句,
    执行次数的绝对值:result = (x-y)÷z

    但实际上没有这么简单:

    • 如果步长为 -1或者1,那么答案只有一个
    • 如果步长为 -2或者2,那么答案有两个
    • 如果步长为 -3或者3,那么答案有三个

    通过公式算出 x 之后,

    • 如果步长为2,还要计算 (x ± 1) - z × (result-1) 的值,然后再经过琐碎的判断即可
    • 如果步长为3,还要计算 (x ± 2) - z × (result-1) 的值,…

    虽然看着麻烦,但实际上是很好理解的

    思考题:3~6

    3. 阅读下面的Python程序,请问程序的功能是什么?

    from math import sqrt
    
    n = 0
    for m in range(101,201,2):
        k = int(sqrt(m))
        for i in range(2, k+2):
            if m % i == 0:break
        if i == k + 1:
            if n % 10 == 0:print()
            print('%d' % m,end = " ")
            n += 1
    

    输出101到200之间的素数
    每行输出10个,多余换行

    运行:

    101 103 107 109 113 127 131 137 139 149 
    151 157 163 167 173 179 181 191 193 197 
    199
    

    素数(质数)是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。

    4. 阅读下面的Python程序,请问输出的结果使什么?

    n = int(input("请输入图形的行数:"))
    for i in range(0, n):
        for j in range(0, 10 - i):print(" ", end=" ")
        for k in range(0, 2 * i + 1):print(" * ", end=" ")
        print("\n")
    

    输出的是一个金字塔

    运行:

    请输入图形的行数:4
                         *  
    
                       *   *   *  
    
                     *   *   *   *   *  
    
                   *   *   *   *   *   *   *  
    

    5. 阅读下面的Python程序,请问输出的结果使什么?程序的功能是什么?

    for i in range(100,1000):
        n1 = i // 100
        n2 = i // 10 % 10
        n3 = i % 10
        if(pow(n1, 3) + pow(n2, 3) + pow(n3, 3) == i):print(i, end=" ")
    

    输出三位数中所有的水仙花数

    运行:

    153 370 371 407 
    

    水仙花数 是指一个 3 位数,它的每个位上的数字的 3次幂之和等于它本身

    6. 阅读下面的Python程序,请问输出的结果使什么?程序的功能是什么?

    for n in range(1,1001):
        total = 0; factors = []
        for i in range(1, n):
            if(n % i == 0):
                factors.append(i)
                total += i
        if(total == n):print("{0} : {1}".format(n, factors))    
    

    输出1到1000的所有完数,并输出每个完数的所有因子

    运行:

    6 : [1, 2, 3]
    28 : [1, 2, 4, 7, 14]
    496 : [1, 2, 4, 8, 16, 31, 62, 124, 248]
    

    完数 所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身

    上机实践:2~14

    2. 编写程序,计算1=2+3+…+100之和

    1. 使用for循环(递增):
    total = 0
    for i in range(101):
        total += i
    print(total) 
    
    1. 使用求和公式:
    >>> (1 + 100) * 100 /2
    5050.0
    
    1. 使用累计迭代器itertools.accumulate
    >>> import itertools
    >>> list(itertools.accumulate(range(1, 101)))[99]
    5050
    

    3. 编写程序,计算10+9+8+…+1之和

    1. 使用for循环(递增):
    total = 0
    for i in range(11):
        total += i
    print(total) 
    
    1. 使用for循环(递减):
    total = 0
    for i in range(10,0,-1):
        total += i
    print(total)   
    
    1. 使用求和公式:
    >>> (1 + 10) * 10 / 2
    55.0
    
    1. 使用累计迭代器itertools.accumulate
    >>> import itertools
    >>> list(itertools.accumulate(range(1,11)))[9]
    55
    

    4. 编写程序,计算1+3+5+7+…+99之和

    1. 使用for循环(递增):
    total = 0
    for i in range(1,100,2):
        total += i
    print(total)     
    
    1. 使用求和公式:
    >>> (1 + 99) * 50 /2
    2500.0
    
    1. 使用累计迭代器itertools.accumulate
    >>> import itertools
    >>> list(itertools.accumulate(range(1,100,2)))[49]
    2500
    

    5. 编写程序,计算2+4+6+8+…+100之和

    1. 使用for循环(递增):
    total = 0
    for i in range(2,101,2):
        total += i
    print(total)     
    
    1. 使用求和公式:
    >>> (2 + 100) * 50 / 2
    2550.0
    
    1. 使用累计迭代器itertools.accumulate
    >>> import itertools
    >>> x = list(itertools.accumulate(range(2,101,2)))
    >>> x[len(x)-1]
    2550
    

    6. 编写程序,使用不同的实现方法输出2000~3000的所有闰年

    代码一:

    for y in range(2000,3001):
        if((y % 4 == 0 and y % 100 != 0) or y % 400 == 0):
            print(y,end = ' ')
    

    代码二(使用calendar模块的isleap()函数来判断):

    from calendar import isleap
    
    for y in range(2000,3001):
        if(isleap(y)):print(y,end = " ")
    

    运行:

    2000 2004 2008 2012 2016 2020 2024 2028 2032 2036 2040 2044 2048 2052 2056 2060 2064 2068 2072 2076 2080 2084 2088 2092 2096 2104 2108 2112 2116 2120 2124 2128 2132 2136 2140 2144 2148 2152 2156 2160 2164 2168 2172 2176 2180 2184 2188 2192 2196 2204 2208 2212 2216 2220 2224 2228 2232 2236 2240 2244 2248 2252 2256 2260 2264 2268 2272 2276 2280 2284 2288 2292 2296 2304 2308 2312 2316 2320 2324 2328 2332 2336 2340 2344 2348 2352 2356 2360 2364 2368 2372 2376 2380 2384 2388 2392 2396 2400 2404 2408 2412 2416 2420 2424 2428 2432 2436 2440 2444 2448 2452 2456 2460 2464 2468 2472 2476 2480 2484 2488 2492 2496 2504 2508 2512 2516 2520 2524 2528 2532 2536 2540 2544 2548 2552 2556 2560 2564 2568 2572 2576 2580 2584 2588 2592 2596 2604 2608 2612 2616 2620 2624 2628 2632 2636 2640 2644 2648 2652 2656 2660 2664 2668 2672 2676 2680 2684 2688 2692 2696 2704 2708 2712 2716 2720 2724 2728 2732 2736 2740 2744 2748 2752 2756 2760 2764 2768 2772 2776 2780 2784 2788 2792 2796 2800 2804 2808 2812 2816 2820 2824 2828 2832 2836 2840 2844 2848 2852 2856 2860 2864 2868 2872 2876 2880 2884 2888 2892 2896 2904 2908 2912 2916 2920 2924 2928 2932 2936 2940 2944 2948 2952 2956 2960 2964 2968 2972 2976 2980 2984 2988 2992 2996 
    

    7. 编写程序,计算Sn=1-3+5-7+9-11…

    代码一:

    n = int(input("项数:"))
    total = 0
    flag = True
    for i in range(1,2*n,2):
        if(flag):
            total += i
            flag = False
        else:
            total -= i
            flag = True
    print(total)
    

    代码二:

    n = int(input("项数:"))
    total = 0
    x = 2
    for i in range(1,2*n,2):
        total += pow(-1,x)*i
        x += 1 
    print(total)
    

    运行:

    项数:10
    -10
    

    8. 编写程序,计算Sn=1+1/2+1/3+…

    n = int(input("项数:"))
    total = 0.0
    for i in range(1,n+1):
        total += 1/i 
    print(total)
    

    运行:

    项数:10
    2.9289682539682538
    

    9. 编写程序,打印九九乘法表。要求输入九九乘法表的各种显示效果(上三角,下三角,矩形块等方式)

    矩形块:

    for i in range(1,10):
        s = ""
        for j in range(1,10):
            s += str.format("%d * %d = %02d  " %(i, j, i*j))
        print(s)
    

    下三角:

    for i in range(1,10):
        s = ""
        for j in range(1,i+1):
            s += str.format("%d * %d = %02d  " %(i, j, i*j))
        print(s)
    

    上三角:

    for i in range(1,10):
        s = ""
        for k in range(1,i):
            s += "                   "
        for j in range(i,10):
            s += str.format("%d * %d = %02d  " %(i, j, i*j))
        print(s)
    

    10. 编写程序,输入三角形的三条边,先判断是否可以构成三角形,如果可以,则进一步求三角形的周长和面积,否则报错“无法构成三角形!”

    from math import sqrt
    
    a = float(input("请输入三角形的边长a:"))
    b = float(input("请输入三角形的边长b:"))
    c = float(input("请输入三角形的边长c:"))
    
    if(a < b): a,b = b,a
    if(a < c): a,c = c,a
    if(b < c): b,c = c,b
    
    if(a < 0 or b < 0 or c < 0 or b+c <= a): print("无法构成三角形!")
    else:
        h = (a+b+c)/2
        area = sqrt(h*(h-a)*(h-b)*(h-c))
        print("周长:{0},面积:{1}".format(a+b+c,area))
    

    运行:

    请输入三角形的边长a:4
    请输入三角形的边长b:3
    请输入三角形的边长c:5
    周长:12.0,面积:6.0
    

    11. 编写程序,输入x,根据如下公式计算分段函数y的值。请分别用单分支语句,双分支语句结构以及条件运算语句等方法实现

    y = (x2-3x)/(x+1) + 2π + sinx (x≥0 )
    y = ln(-5x) + 6√(|x|+e4) - (x+1)3 (x<0)

    单分支语句:

    import math
    
    x = float(input("请输入x:"))
    if(x >= 0):
        y = (x*x - 3*x)/(x+1) + 2*math.pi + math.sin(x)
    if(x < 0):
        y = math.log(-5*x) + 6 * math.sqrt(abs(x) + math.exp(4)) - pow(x+1,3)
    
    print(y)
    
    
    

    双分支语句:

    import math
    
    x = float(input("请输入x:"))
    if(x >= 0):
        y = (x*x - 3*x)/(x+1) + 2*math.pi + math.sin(x)
    else:
        y = math.log(-5*x) + 6 * math.sqrt(abs(x) + math.exp(4)) - pow(x+1,3)
    
    print(y)
    

    条件运算语句:

    import math
    
    x = float(input("请输入x:"))
    y = ((x*x - 3*x)/(x+1) + 2*math.pi + math.sin(x)) if(x >= 0) \
    else (math.log(-5*x) + 6 * math.sqrt(abs(x) + math.exp(4)) - pow(x+1,3)) 
    
    print(y)
    

    运行一:

    请输入x:666
    668.2715406628656
    

    运行二:

    请输入x:-666
    294079794.1744833
    

    12. 编写程序,输入一元二次方程的3个系数a、b、c,求ax2+bx+c=0方程的解

    import math
    
    a = float(input("请输入系数a:"))
    b = float(input("请输入系数b:"))
    c = float(input("请输入系数c:"))
    
    delta = b*b -4*a*c
    
    if(a == 0):
        if(b == 0): print("无解")
        else: print("有一个实根:",-1*c/b)
    elif(delta == 0): print("有两个相等实根:x1 = x2 = ", (-1*b)/(2*a))
    elif(delta > 0): print("有两个不等实根:x1 = {0},x2 = {1}".format\
                           ((-1*b +math.sqrt(delta))/2*a,(-1*b -math.sqrt(delta))/2*a))
    elif(delta < 0): print("有两个共轭复根:x1 = {0},x2 = {1}".format\
                           (complex( (-1*b)/(2*a),math.sqrt(delta*-1)/(2*a)),complex( (-1*b)/(2*a),-1*math.sqrt(delta*-1)/(2*a))))
    

    运行一:

    请输入系数a:0
    请输入系数b:0
    请输入系数c:10
    无解
    

    运行二:

    请输入系数a:0
    请输入系数b:10
    请输入系数c:5
    有一个实根: -0.5
    

    运行三:

    请输入系数a:1
    请输入系数b:8
    请输入系数c:16
    有两个相等实根:x1 = x2 =  -4.0
    

    运行四:

    请输入系数a:1
    请输入系数b:-5
    请输入系数c:6
    有两个不等实根:x1 = 3.0,x2 = 2.0
    

    运行五:

    请输入系数a:5
    请输入系数b:2
    请输入系数c:1
    有两个共轭复根:x1 = (-0.2+0.4j),x2 = (-0.2-0.4j)
    

    13. 编写程序,输入整数n(n≥0),分别利用for循环和while循环求n!

    1. for循环
    n = int(input("请输入n:"))
    
    if(n == 0): total = 1
    if(n > 0):
        total = 1
        for i in range(n,0,-1):
            total *= i
    
    print(total)
    
    
    1. while循环
    n = int(input("请输入n:"))
    
    if(n == 0): total = 1
    if(n > 0):
        total = 1
        while(n >= 1):
            total *= n
            n -= 1
    
    print(total)
    
    1. 补充一个:使用累计迭代器itertools.accumulate
    >>> import itertools, operator
    >>> n = int(input('请输入n:'))
    请输入n:7
    >>> x = list(accumulate(range(1, n+1), operator.mul))
    >>> x[len(x)-1]
    5040
    

    14. 编写程序,产生两个0~100(包含0和100)的随机整数a和b,求这两个整数的最大公约数和最小公倍数

    1. 现有知识点解决方法
    
    import random
    
    a = random.randint(0,100)
    b = random.randint(0,100)
    sum = a*b
    
    print(a) #输出原来的a,b
    print(b)
    
    if(a < b): a,b = b,a
    
    while(a%b != 0):
        a,b = b,a%b
    
    print("最大公约数:{0},最小公倍数:{1}".format(b,sum/b))
    
    
    1. 补充:使用生成器(generate)函数:yield
    >>> def func(a, b):
    	if(a < b): a,b = b,a
    	while(a%b != 0):
    		a,b = b,a%b
    		yield b
    
    		
    >>> import random
    >>> if __name__ == '__main__':
    	a = random.randint(0,100)
    	b = random.randint(0,100)
    	sum = a*b
    	print(a,b)
    	t = list(iter(func(a, b)))
    	gcd = t[len(t)-1]
    	print("gcd = {0}, mcm = {1}".format(gcd, sum/gcd))
    
    	
    29 65
    gcd = 1, mcm = 1885.0
    
    1. 补充:使用math模块中的gcd(x,y)函数
    >>> import random
    >>> import math
    >>> if __name__ == '__main__':
    	a = random.randint(0,100)
    	b = random.randint(0,100)
    	sum = a*b
    	print(a,b)
    	gcd = math.gcd(a,b)
    	print("gcd = {0}, mcm = {1}".format(gcd, sum/gcd))
    
    	
    29 48
    gcd = 1, mcm = 1392.0
    

    案例研究:使用嵌套循环实现图像处理算法

    https://blog.csdn.net/Zhangguohao666/article/details/103935185

    通过图像处理算法案例,深入了解Python数据结构和基本算法流程

    第四章 常用内置数据类型


    几个例题

    一:Python内置数据类型概述

    Python中一切皆为对象,而每个对象属于某个数据类型

    Python的数据类型包括:

    1. 内置的数据类型
    2. 模块中定义的数据类型
    3. 用户自定义的类型

    四种内置的数值类型:int,float,bool,complex

    1. int
      与其他计算机语言有精度限制不同,Python中的整数位数可以为任意长度(只受限于计算机内存)。
      整型对象是不可变对象。
    2. float
      与其他计算机语言中的double和float对应
      Python的浮点类型的精度和系统相关
    3. bool
    4. complex
      当数值字符串中包含虚部j(或J)时即复数字面量

    序列数据类型:str,tuple,bytes,list,bytearray

    序列数据类型表示若干有序数据.

    不可变序列数据类型:

    1. str(字符串)
      表示Unicode字符序列,例如:“zgh666”
      在Python中没有独立的字符数据类型,字符即长度为1的字符串
    2. tuple(元组)
      表示任意数据类型的序列,例如:(“z”,“g”,“h”,6,6,6)
    3. bytes(字节序列)
      表示字节(8位)序列数据

    可变序列数据类型:

    1. list(列表)
      表示可以修改的任意类型数据的序列,比如:[‘z’,‘g’,‘h’,6,6,6]
    2. bytearray(字节数组)
      表示可以修改的字节(8位)数组

    集合数据类型:set,frozenset

    集合数据类型表示若干数据的集合,数据项目没有顺序,且不重复

    1. set(集)
      例如:{1,2,3}
    2. frozenset(不可变集)

    字典数据类型:dict

    字典数据类型用于表示键值对的字典
    例如:{1:"zgh", 2:666}

    NoneType,NotImplementedType,EllipsisType

    1. NoneType数据类型包含唯一值None,主要用于表示空值,如没有返回值的函数的结果
    2. NotImplementedType数据类型包含唯一值NotImplemented,在进行数值运算和比较运算时,如果对象不支持,则可能返回该值
    3. EllipsisType数据类型包含唯一值Ellipsis,表示省略字符串符号...

    其他数据类型

    Python中一切对象都有一个数据类型,模块、类、对象、函数都属于某种数据类型
    Python解释器包含内置类型,
    例如:
    代码对象Code objects
    框架对象Frame objects
    跟踪对象Traceback objects
    切片对象Slice objects
    静态方法对象Static method objects
    类方法对象Class method objects

    二:整型字面量示例

    Python3.7支持使用下划线作为整数或者浮点数的千分位标记,以增强大数值的可阅读性。
    二进制、八进制、十六进制则使用下划线区分4位标记

    1_000_000_000  #输出1000000000
    
    0xff_ff_ff_ff  #输出4294967295
    0x_FF_FF_FF_FF  #输出4294967295
    

    三:字符串字面量示例

    两个紧邻的字符串,如果中间只有空格分隔,则自动拼接位一个字符串

    'zgh' '666'  #输出'zgh666'
    'zgh' + "666"   #输出'zgh666'
    

    四:转义字符示例

    转义字符后跟Unicode编码也可以表示字符

    1. \ooo八进制Unicode码对应的字符
    2. \xhh十六进制Unicode码对应的字符
    '\101'  #输出'A'
    '\x41'  #输出'A'
    

    使用r’‘或者R’'的字符串称为原始字符串,其中包含的任何字符都不进行转义

    s = r'换\t行\t符\n'
    s  		  #输出:'换\\t行\\t符\\n'
    print(s)  #输出:换\\t行\\t符\\n
    

    五:字符串的格式化

    一:

    "student number:{0},score_average:{1}".format(2,100)
    #输出:'student number:2,score_average:100'
    

    二:

    str.format("student number:{0},score_average:{1}",2,100)
    #输出:'student number:2,score_average:100'
    

    三(兼容Python2的格式,不推荐使用):

     "student number:%4d,score_average:%2.1f" %(2,100)
     #输出:'student number:   2,score_average:100.0'
    

    六:字符串示例,格式化输出字符串堆积的三角形

    1. str.center()方法用于字符串两边填充
    2. str.rjust()方法用于字符串右填充
    print("1".center(20))		#一行20个字符,居中对齐
    print(format("121","^20"))	#一行20个字符,居中对齐
    print("1".rjust(20,"*"))	#一行20个字符,右对齐,加*
    print(format("121","*>20"))	#一行20个字符,右对齐,加*
    

    运行:

             1          
            121         
    *******************1
    *****************121
    

    选择题:11

    11. 关于Python字符串,下列说法错误的是

    A. 字符即长度为1的字符串
    B. 字符串以/0标识字符串的结束
    C. 用户既可以用单引号,也可以用双引号创建字符串
    D. 用三引号字符串中可以包含换行回车等特殊字符

    答案:B

    Python中字符串不是用\0来判断字符串结尾,
    每个字符串都存有字符串的长度,通过计数来判断是否到达结尾。

    虽然在c语言中\0就是来判断字符串的结尾;

    填空题:4、7、8、9、10、13、21

    4. Python表达式3 ** 2 ** 3的值为

    答案:6561

    表达式中,相同优先级的运算,从右往左

    7. Python语句print(pow(-3,2),round(18.67,1),round(18.67,-1))的输出结果是

    答案:9 18.7 20.0

    pow()幂运算
    round()四舍六入,五留双

    8. Python语句print(round(123.84,0),round(123.84,-2),floor(15.5))的输出结果是

    答案:124.0 100.0 15

    补充:floor()是math模块中的方法,向下取整

    9. Python语句print(int(‘20’,16),int(‘101’,2))的输出结果是

    答案:32 5

    注意:int(x,y)是指将y进制的数值x转化为10进制数

    10. Python语句print(hex(16),bin(10))的输出结果是

    答案:0x10 0b1010

    hex(x)将十进制数x转化为十六进制,以字符串形式输出
    bin(x)将十进制数x转化为二进制,以字符串形式输出

    13. Python语句print(gcd(12,16),divmod(7,3))的输出结果是

    答案:4 (2,1)

    gcd()是math模块中的函数,求最大公约数
    divmod()是内置函数,返回商和余数

    21. Python语句序列 x=True;y=False;z=False;print(x or y and z) 的运行结果是

    答案:True

    and优先级比or高

    思考题:5

    5. 阅读下面的Python程序,请问输出结果是什么?

    from decimal import *
    
    ctx = getcontext()
    ctx.prec = 2
    print(Decimal('1.78'))#1.78
    print(Decimal('1.78') + 0)#1.8
    ctx.rounding = ROUND_UP
    print(Decimal('1.65') + 0)#1.7
    print(Decimal('1.62') + 0)#1.7
    print(Decimal('-1.45') + 0)#-1.5
    print(Decimal('-1.42') + 0)#-1.5
    ctx.rounding = ROUND_HALF_UP
    print(Decimal('1.65') + 0)#1.7
    print(Decimal('1.62') + 0)#1.6
    print(Decimal('-1.45') + 0)#-1.5
    ctx.rounding = ROUND_HALF_DOWN
    print(Decimal('1.65') + 0)#1.6
    print(Decimal('-1.45') + 0)#-1.4
    

    上机实践:2~14

    2. 编写程序,格式化输出杨辉三角

    杨辉三角即二项式定理的系数表,各元素满足如下条件:第一列及对角线上的元素均为1;其余每个元素等于它上一行同一列元素与前一列元素之和

    我使用了一个更加精妙的规律
    比如第一行为1
    第二行:01 + 10 = 11
    第三行:011 + 110 = 121
    第四行:0121 + 1210 = 1331
    。。。

    def generate(numRows):
        l1 = [1]
        n = 0
        while n < numRows:
            print(str(l1).center(66))
            l1 = [sum(t) for t in zip([0] + l1, l1 + [0])]  #利用zip函数算出每一行 如第二行 zip([0,1],[1,0])=[1,1],以此类推
            n += 1
    a=int(input("请输入行数"))
    generate(a)
    

    运行:

    请输入行数4
                                   [1]                                
                                  [1, 1]                              
                                [1, 2, 1]                             
                               [1, 3, 3, 1]  
    

    3. 输入直角三角形的两个直角边,求三角形的周长和面积,以及两个锐角的度数。结果保留一位小数

    import math
    
    a = float(input("请输入直角三角形的直角边a:"))
    b = float(input("请输入直角三角形的直角边b:"))
    c = math.sqrt(a*a+b*b)
    
    p = a + b + c
    area = 0.5*a*b
    print("三角形的周长:{0:1.1f},面积:{1:1.1f}".format(p,area))
    
    sina = a/c
    sinb = b/c
    
    a_degree = round(math.asin(sina) * 180 / math.pi,0)
    b_degree = round(math.asin(sinb) * 180 / math.pi,0)
    
    print("三角形直角边a的度数:{0},b的度数:{1}".format(a_degree,b_degree))
    

    运行:

    请输入直角三角形的直角边a:3
    请输入直角三角形的直角边b:4
    三角形的周长:12.0,面积:6.0
    三角形直角边a的度数:37.0,b的度数:53.0
    

    4. 编程产生0~100(包含0和100)的三个随机数a、b、c,要求至少使用两种不同的方法,将三个数按从小到大的顺序排序

    方法一:

    import random
    
    a = random.randint(0, 100)
    b = random.randint(0, 100)
    c = random.randint(0, 100)
    
    print(str.format("原始值:{0},{1},{2}", a, b, c))
    
    if(a > b): a,b = b,a
    if(a > c): a,c = c,a
    if(b > c): b,c = c,b
    
    print(str.format("增序:{0},{1},{2}", a, b, c))
    

    方法二(使用内置函数max、min、sum):

    import random
    
    a = random.randint(0, 100)
    b = random.randint(0, 100)
    c = random.randint(0, 100)
    
    print(str.format("原始值:{0},{1},{2}", a, b, c))
    
    maxx = max(a, b, c)
    minx = min(a, b, c)
    median = sum([a, b, c]) - minx - maxx
    
    print(str.format("增序:{0},{1},{2}", minx, median, maxx))
    

    方法三(使用内置函数sorted):

    >>> import random
    >>> a = random.randint(0,100)
    >>> b = random.randint(0,100)
    >>> c = random.randint(0,100)
    >>> print("init value: {0} , {1} , {2}".format(a,b,c))
    init value: 17 , 6 , 59
    >>> sorted([a,b,c])
    [6, 17, 59]
    

    5. 编程计算有固定工资收入的党员每月所缴纳的党费。

    工资基数3000元及以下者,交纳工资基数的0.5%
    工资基数3000~5000元者,交纳工资基数的1%
    工资基数在5000~10000元者,交纳工资基数的1.5%
    工资基数超过10000元者,交纳工资基数的2%

    salary = float(input("请输入有固定工资收入的党员的月工资:"))
    if salary <= 3000: dues = salary*0.005
    elif salary <= 5000: dues = salary*0.01
    elif salary <= 10000: dues = salary*0.15
    else: dues = salary*0.02
    
    print("交纳党费:",dues)
    

    运行:

    请输入有固定工资收入的党员的月工资:10001
    交纳党费: 200.02
    

    6. 编程实现袖珍计算器,要求输入两个操作数和一个操作符(+、-、*、/、%),根据操作符输出运算结果。注意/和%运算符的零异常问题

    a = float(input("请输入操作数(左):"))
    b = float(input("请输入操作数(右):"))
    operator = input("请输入操作符(+、-、*、/、%):")
    
    if(b == 0 and (operator == '/' or operator == '%')):
        print("分母为零,异常!")
    else:
        if operator == '+': result = a+b
        elif operator == '-': result = a-b
        elif operator == '*': result = a*b
        elif operator == '/': result = a/b
        elif operator == '%': result = a%b
        print("{0} {1} {2}= {3}:".format(a,operator,b,result))
    

    运行:

    请输入操作数(左):10
    请输入操作数(右):5
    请输入操作符(+、-、*、/、%):+
    10.0 + 5.0= 15.0:
    

    7. 输入三角形的3条边a、b、c,判断此3边是否可以构成三角形。若能,进一步判断三角形的性质,即为等边、等腰、直角或其他三角形

    a = float(input("请输入三角形的边a:"))
    b = float(input("请输入三角形的边b:"))
    c = float(input("请输入三角形的边c:"))
    
    if(a > b): a,b = b,a
    if(a > c): a,c = c,a
    if(b > c): b,c = c,b
    
    result = "三角形"
    if(not(a>0 and b>0 and c>0 and a+b>c)):
        result = '此三边无法构成三角形'
    else:
        if a == b == c: result = '等边三角形'
        elif(a==b or a==c or b==c): result = '等腰三角形'
        elif(a*a+b*b == c*c): result = '直角三角形'
    
    print(result)
    

    运行:

    请输入三角形的边a:3
    请输入三角形的边b:4
    请输入三角形的边c:5
    直角三角形
    

    8. 编程实现鸡兔同笼问题

    已知在同一个笼子里共有h只鸡和兔,鸡和兔的总脚数为f,其中h和f由用户输入,求鸡和兔各有多少只?要求使用两种方法:一是求解方程;二是利用循环进行枚举测试

    h = int(input("请输入总头数:"))
    f = int(input("请输入总脚数:"))
    
    def fun1(h,f):
        rabbits = f/2-h
        chicken = h-rabbits
        if(chicken < 0 or rabbits < 0): return '无解'
        return chicken,rabbits
    
    def fun2(h,f):
        for i in range(0,h+1):
            if(2*i + 4*(h-i) == f):return i,h-i
        return '无解'
    
    if(h>0 and f>0 and f % 2 == 0):
        if fun1(h,f)=='无解':
            print("无解")
        else:
            print("方法一:鸡:{0},兔:{1}".format(fun1(h,f)[0],fun1(h,f)[1]))
            print("方法二:鸡:{0},兔:{1}".format(fun2(h,f)[0],fun2(h,f)[1]))
    else:
        print('输入的数据无意义')    
    

    运行:

    请输入总头数:100
    请输入总脚数:100
    无解
    

    9. 输入任意实数x,计算ex的近似值,直到最后一项的绝对值小于10-6为止

    ex = 1 + x + x2/2 + x3/3! + x4/4! + … + xn/n!

    x = int(input("请输入任意实数:"))
    
    e = 1
    i = 1
    t = 1
    a = 1
    while(a >= 10e-6):
        t *= i
        a = pow(x,i)/t
        e += a
        i += 1
    
    print(e)
    

    运行:

    请输入任意实数:1
    2.7182815255731922
    

    我发现了在Python中10e-6pow(10,-6)是有差别的,将上述代码中的10e-6改为pow(10,-6),输出结果会有细微的差别

    运行:

    请输入任意实数:1
    2.7182818011463845
    

    10. 输入任意实数a(a>=0),用迭代法求x=√a,要求计算的相对偏差小于10-6

    求平方根的公式:

    Xn+1 = 0.5(Xn + a/Xn)

    import math
    
    a = int(input("请输入任意实数a(>=0):"))
    
    x = a / 2
    y = (x + a/x) / 2
    
    while(abs(y-x) >= pow(10,-6)):
        x = y
        y = (x + a/x) / 2
    
    print(y)
    

    运行:

    请输入任意实数a(>=0):2
    1.414213562373095
    

    11. 即有一个数,用3除余2,用5除余3,用7除余2,请问0~1000中这样的数有哪些?

    我国古代有位大将,名叫韩信。他每次集合部队,只要求部下先后按1-3,1-5,1-7报数,然后再报告一下各队每次报数的余数,他就知道到了多少人。他的这种巧妙算法被人们称作“鬼谷算”,也叫“隔墙算”,或称为“韩信点兵”,外国人还称它为“中国余数定理”。

    for i in range(0,1001):
        if((i % 3 == 2 )and (i % 5 == 3) and (i % 7 == 2)): print(i, end="  ")
    

    运行:

    23  128  233  338  443  548  653  758  863  968
    

    12. 一球从100米的高度自由下落,每次落地后反弹回原高度的一半,再落下。求小球在第10次落地时共经过多少米?第10次反弹多高

    规律:
    第一次下落时的高度:100
    第二次下落时的高度(第一次反弹的高度):50
    第三次下落时的高度(第二次反弹的高度):25

    n = 10
    
    h_down = 100
    h_up = 0
    sum = 0
    for i in range(1,n+1):
        sum += h_down+h_up
        h_down = h_up = h_down/2
    
    print("小球在第十次落地时共经过:{0}米,第十次反弹高度:{1}米".format(sum,h_up))    
    

    运行:

    小球在第十次落地时共经过:299.609375米,第十次反弹高度:0.09765625米
    

    13. 猴子吃桃问题

    猴子第一天摘下若干个桃子,当天吃掉一半多一个;第二天接着吃了剩下的桃子的一半多一个;以后每天都吃了前一天剩下的桃子的一半多一个。到第八天发现只剩一个桃子了。请问猴子第一天共摘了多少个桃子?

    这是一个递推问题

    某天所剩桃子数x
    后一天所剩桃子数y = x - (x/2+1) = x/2-1

    则x = 2(y+1)

    result = 1
    for i in range(8,0,-1):
        print("第{0}天桃子数:{1}".format(i,result))
        result = 2*(result+1)
    

    运行:

    第8天桃子数:1
    第7天桃子数:4
    第6天桃子数:10
    第5天桃子数:22
    第4天桃子数:46
    第3天桃子数:94
    第2天桃子数:190
    第1天桃子数:382
    

    14. 计算Sn = 1+11+111+…+111…111(最后一项是n个1)。n是一个随机产生的1~10(包括1和10)中的正整数

    import random
    
    n = random.randint(1,10)
    
    x = 1
    s = 0
    for i in range(1,n+1):
        s += x
        x = 10*x+1
    
    print("n = {0},sn = {1}".format(n,s))
    

    运行:

    n = 6,sn = 123456
    

    random.randint(a, b)

    • 生成指定范围内的整数
    • 范围:[a, b]

    案例研究:科学计算和数据分析

    https://blog.csdn.net/Zhangguohao666/article/details/103941448

    通过Python科学计算和数据分析库的安装和基本使用,了解使用Python进行科学计算的基本方法

    第五章 序列数据类型


    几个例题

    一:Python中内置的序列数据类型

    • 元组也称为定值表,用于存储固定不变的表
    • 列表也称为表,用于存储其值可变的表
    • 字符串是包括若干字符的序列数据,支持序列数据的基本操作
    • 字节序列数据是包括若干字节的序列。Python抓取网页时返回的页面通常为utf-8编码的字节序列。

    字节序列和字符串可以直接相互转换(字节编码和解码):

    >>> s1 = b'abc'
    >>> s1
    b'abc'
    >>> s1.decode("utf-8")
    abc
    
    >>> s2 = "中国"
    >>> s2.encode("utf-8")
    b'\xe4\xb8\xad\xe5\x9b\xbd'
    

    二:序列的切片操作示例

    >>> s = 'zgh666'
    >>> s[0]
    'z'
    >>> s[2]
    'h'
    >>> s[:3]
    'zgh'
    >>> s[1:3]
    'gh'
    >>> s[3:6]
    '666'
    >>> s[3:55]
    '666'
    >>> s[::-1]
    '666hgz'
    >>> s[3:2]
    ''
    >>> s[:]
    'zgh666'
    >>> s[::2]
    'zh6'
    

    三:序列的连接和重复操作

    • 通过连接操作符+可以连接两个序列,形成一个新的序列对象
    • 通过重复操作符*可以重复一个序列n次
    • 连接操作符和重复操作符也支持复合赋值运算,即:+=*=
    >>> x = 'zgh'
    >>> y = '666'
    >>> x + y
    'zgh666'
    >>> x *2
    'zghzgh'
    >>> x += y
    >>> x
    'zgh666'
    >>> y *= 3
    >>> y
    '666666666'
    

    四:序列的成员关系操作

    • in
    • not in
    • s.count(x)
      x在s中出现的次数
    • s.index(x)
      x在s中第一次出现的下标
    >>> s = "zgh666"
    >>> 'z' in s
    True
    >>> 'g' not in s
    False
    >>> s.count('6')
    3
    >>> s.index('6')
    3
    

    五:序列的排序操作

    sorted(iterable,key=None,reverse=False)

    >>> sorted(s)
    [1, 3, 5, 9]
    >>> sorted(s,reverse=True)
    [9, 5, 3, 1]
    
    >>> s = 'zGhZgH'
    >>> sorted(s)
    ['G', 'H', 'Z', 'g', 'h', 'z']
    >>> sorted(s,key=str.lower)
    ['G', 'g', 'h', 'H', 'z', 'Z']
    >>> sorted(s,key=str.lower,reverse=True)
    ['z', 'Z', 'h', 'H', 'G', 'g']
    

    六:序列的拆分

    1. 变量个数与序列长度相等
      若变量个数与序列的元素个数不一致,将导致ValueError
    >>> data = (118,'zgh',(100,100,100))
    >>> sid,name,(chinese,english,math) = data
    >>> sid
    118
    >>> name
    'zgh'
    >>> chinese
    100
    >>> english
    100
    >>> math
    100
    
    1. 变量个数与序列长度不等
      如果序列长度未知,可以使用*元组变量,将多个值作为元组赋值给元组变量。在一个赋值语句中,*元组变量只允许出现一次,否则将导致SyntaxError
    >>> first,second,third,*middles,last = range(10)
    >>> first
    0
    >>> second
    1
    >>> third
    2
    >>> middles
    [3, 4, 5, 6, 7, 8]
    >>> last
    9
    
    >>> first,*middles,last = sorted([58,60,60,100,70,70])
    >>> sum(middles)/len(middles)
    65.0
    
    1. 使用临时变量_
      如果只需要部分数据,序列的其它位置可以使用临时变量_
    >>> record = ['zgh','858990471@qq.com','17354364147','15272502101']
    >>> name,_,*phone = record
    >>> name
    'zgh'
    >>> phone
    ['17354364147', '15272502101']
    

    七:使用元组字面量,tuple创建元组实例对象的实例

    >>> t1 = 1,2,3
    >>> t1
    (1, 2, 3)
    
    >>> t2 = (4,5,6)
    >>> t2
    (4, 5, 6)
    
    >>> t3 = (9,)
    >>> t3
    (9,)
    

    如果元组中只有一个项目,后面的逗号不能省略。

    Python解释器把(1)解释为整数1,将(1,)解释为元组

    >>> t1 = tuple()
    >>> t1
    ()
    
    >>> t2 = tuple("zgh666")
    >>> t2
    ('z', 'g', 'h', '6', '6', '6')
    
    >>> t3 = tuple(['z','g','h'])
    >>> t3
    ('z', 'g', 'h')
    

    八:使用列表字面量,list创建列表实例对象的实例

    >>> l1 = []
    >>> l1
    []
    
    >>> l2 = ['zgh666']
    >>> l2
    ['zgh666']
    
    >>> l3 = [(1,2,3)]
    >>> l3
    [(1, 2, 3)]
    
    >>> l1 = list()
    >>> l1
    []
    
    >>> l2 = list(b'zgh666')
    >>> l2
    [122, 103, 104, 54, 54, 54]
    
    >>> l3 = list(b'aAbBcC')
    >>> l3
    [97, 65, 98, 66, 99, 67]
    

    补充:列表是可变对象,故用户可以改变列表对象中元素的值,也可以通过del删除某元素

    九:列表解析表达式示例

    使用列表解析表达式可以简单,高效地处理一个可迭代对象,并生成结果列表

    >>> [(i,i**2) for i in range(10)]
    [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49), (8, 64), (9, 81)]
    
    >>> [i for i in range(10) if i%2==0]
    [0, 2, 4, 6, 8]
    
    >>> [(x,y,x*y) for x in range(1,4) for y in range(1,4) if x>=y]
    [(1, 1, 1), (2, 1, 2), (2, 2, 4), (3, 1, 3), (3, 2, 6), (3, 3, 9)]
    

    选择题:4、5、7、11、12

    4. Python语句序列“a = (1,2,3,None,(),[]);print(len(a))”的运行结果是

    >>> a = (1,2,3,None,(),[])
    >>> len(a)
    6
    

    5. Python语句序列“nums = set([1,2,2,3,3,3,4]);print(len(nums))”的运行结果是

    >>> nums = set([1,2,2,3,3,3,4])
    >>> nums
    {1, 2, 3, 4}
    >>> len(nums)
    4
    

    7. Python语句序列“s1=[4,5,6];s2=s1;s1[1]=0;print(s2)”的运行结果是

    Python中变量(如s1,s2)存储在栈中,存放的是地址
    [4,5,6]存储在堆中

    s1 = [4,5,6]即s1存储指向堆中[4,5,6]的地址
    s2 = s1地址赋值,即s2和s1都指向同一个地址
    所以对列表进行修改,两者的显示都会发生变化

    >>> s1 = [4,5,6]
    >>> s2 = s1
    >>> s1[1] = 0
    >>> s1
    [4, 0, 6]
    >>> s2
    [4, 0, 6]
    

    11. Python语句序列“s={‘a’,1,‘b’,2};print(s[‘b’])”的运行结果是

    A. 语法错B. ‘b’C. 1D. 2

    答案:A

    通过值访问集合是没有意义的,语法也不支持

    >>> s ={'a',1,'b',2}
    >>> print(s['b'])
    Traceback (most recent call last):
      File "<pyshell#29>", line 1, in <module>
        print(s['b'])
    TypeError: 'set' object is not subscriptable
    

    补充:集合set是无序不重复的,是无法通过下标访问的

    12. Python语句print(r"\nGood")的运行结果是

    A. 新行和字符串GoodB. r"\nGood"C. \nGoodD. 字符r、新行和字符串Good

    答案:C

    >>> print(r"\nGood")
    \nGood
    

    r""声明原始字符串

    填空题:1、5、6、12、13、14

    1. Python语句序列“fruits = [‘apple’,‘banana’,‘bear’];print(fruits[-1][-1])”的运行结果是

    注意:fruit[-1]是字符串’bear’
    所以:fruit[-1][-1]'bear[-1]'

    >>> fruits = ['apple','banana','pear']
    >>> fruits[-1]
    'pear'
    >>> fruits[-1][-1]
    'r'
    

    5. Python语句 print(’%d%%%d’%(3/2,3%2)) 的运行结果是

    >>> print('%d%%%d'%(3/2,3%2))
    1%1
    

    6. Python语句序列“s = [1,2,3,4];s.append([5,6]);print(len(s))”的运行结果是

    答案:5

    注意append()和extend()函数的区别
    s.append(x)将对象x追加到s尾部
    s.extend(x)将序列x追加到s尾部

    append

    >>> s = [1,2,3,4]
    >>> s.append([5,6])
    >>> s
    [1, 2, 3, 4, [5, 6]]
    >>> len(s)
    5
    

    extend

    >>> s = [1,2,3,4]
    >>> s.extend([5,6])
    >>> s
    [1, 2, 3, 4, 5, 6]
    >>> len(s)
    6
    

    12

    >>> s =('a','b','c','d','e')
    >>> s[2]
    'c'
    >>> s[2:3]
    ('c',)
    >>> s[2:4]
    ('c', 'd')
    >>> s[1::2]
    ('b', 'd')
    >>> s[-2]
    'd'
    >>> s[::-1]
    ('e', 'd', 'c', 'b', 'a')
    >>> s[-2:-1]
    ('d',)
    >>> s[-99:-5]
    ()
    >>> s[-99:-3]
    ('a', 'b')
    >>> s[::]
    ('a', 'b', 'c', 'd', 'e')
    >>> s[1:-1]
    ('b', 'c', 'd')
    

    13

    >>> s = [1,2,3,4,5,6]
    >>> s[:1] = []
    >>> s
    [2, 3, 4, 5, 6]
    
    >>> s[:2] = 'a'
    >>> s
    ['a', 4, 5, 6]
    
    >>> s[2:] = 'b'
    >>> s
    ['a', 4, 'b']
    
    >>> s[2:3] = ['x','y']
    >>> s
    ['a', 4, 'x', 'y']
    
    >>> del s[:1]
    >>> s
    [4, 'x', 'y']
    

    14

    >>> s = ['a','b']
    >>> s.append([1,2])
    >>> s
    ['a', 'b', [1, 2]]
    >>> s.extend('34')
    >>> s
    ['a', 'b', [1, 2], '3', '4']
    >>> s.extend([5,6])
    >>> s
    ['a', 'b', [1, 2], '3', '4', 5, 6]
    >>> s.insert(1,7)
    >>> s
    ['a', 7, 'b', [1, 2], '3', '4', 5, 6]
    >>> s.insert(10,8)
    >>> s
    ['a', 7, 'b', [1, 2], '3', '4', 5, 6, 8]
    >>> s
    ['a', 7, 'b', [1, 2], '3', '4', 5, 6]
    >>> s.remove('b')
    >>> s
    ['a', 7, [1, 2], '3', '4', 5, 6]
    >>> s[3:] =[]
    >>> s
    ['a', 7, [1, 2]]
    >>> s.reverse()
    >>> s
    [[1, 2], 7, 'a']
    >>> 
    

    思考题:2、3、5

    2. 阅读下面的Python语句,请问输出结果是什么?

    n = int(input('请输入图形的行数:'))
    
    for i in range(n,0,-1):
        print(" ".rjust(20-i),end=' ')
        for j in range(2*i-1):print(" * ",end=' ')
        print('\n')
    
    for i in range(1,n):
        print(" ".rjust(19-i),end=' ')
        for j in range(2*i+1):print(" * ",end=' ')
        print('\n')          
    

    运行一:

    请输入图形的行数:1
                         *  
    

    运行二:

    请输入图形的行数:2
                        *   *   *  
    
                         *  
    
                        *   *   *  
    

    运行三:

    请输入图形的行数:3
                       *   *   *   *   *  
    
                        *   *   *  
    
                         *  
    
                        *   *   *  
    
                       *   *   *   *   *  
    

    3. 阅读下面的Python语句,请问输出结果是什么?

    n = int(input('请输入上(或下)三角行数:'))
    
    for i in range(0,n):
        print(" ".rjust(19-i),end=' ')
        for j in range(2*i+1):print(" * ",end=' ')
        print('\n')
    
    for i in range(n-1,0,-1):
        print(" ".rjust(20-i),end=' ')
        for j in range(2*i-1):print(" * ",end=' ')
        print('\n')          
    

    运行:

    请输入上(或下)三角行数:4
                         *  
    
                        *   *   *  
    
                       *   *   *   *   *  
    
                      *   *   *   *   *   *   *  
    
                       *   *   *   *   *  
    
                        *   *   *  
    
                         *  
    

    5. 阅读下面的Python语句,请问输出结果是什么?

    先看这三句:

    >>> names1 = ['Amy','Bob','Charlie','Daling']
    >>> names2 = names1
    >>> names3 = names1[:]
    

    毫无疑问,此时names1,names2,names3的值都是[‘Amy’,‘Bob’,‘Charlie’,‘Daling’]
    但是

    >>> id(names1)
    2338529391368
    >>> id(names2)
    2338529391368
    >>> id(names3)
    2338529391560
    

    names1和names2指向同一个地址
    而names3指向另一个地址

    然后:

    >>> names2[0] = 'Alice'
    >>> names3[1] = 'Ben'
    >>> names1
    ['Alice', 'Bob', 'Charlie', 'Daling']
    >>> names2
    ['Alice', 'Bob', 'Charlie', 'Daling']
    >>> names3
    ['Amy', 'Ben', 'Charlie', 'Daling']
    

    最后:

    >>> sum = 0
    >>> for ls in(names1,names2,names3):
    	if ls[0] == 'Alice': sum+=1
    	if ls[1] == 'Ben':sum+=2
    
    	
    >>> print(sum)
    4
    

    上机实践:2~6

    2. 统计所输入字符串中单词的个数,单词之间用空格分隔

    s = input("请输入字符串:")
    
    num = 0
    for i in s:
        if((i >= 'a' and i <= 'z') or (i >= 'A' and i <= 'Z')):
            num += 1
    
    print("其中的单词总数:",num) 
    

    运行:

    请输入字符串:zgh666 ZGH6
    其中的单词总数: 6
    

    3. 编写程序,删除一个list里面重复元素

    方法一:利用set集合不重复的性质(但结果不能保证原来的顺序)

    l = [1,2,2,3,3,3,4,5,6,6,6]
    s = set(l)
    l = list(s)
    print(l)
    

    运行:

    [1, 2, 3, 4, 5, 6]
    

    方法二:既可以去除重复项,又可以保证原来的顺序

    def unique(items):
        items_existed = set()
        for item in items:
            if item not in items_existed:
                yield item
                items_existed.add(item)
    
    if __name__ == '__main__':
        a = [1, 8, 5, 1, 9, 2, 1, 10]
        a1 = unique(a)
        print(list(a1))
    
    

    运行结果:

    [1, 8, 5, 9, 2, 10]
    

    对代码的分析:

    • 可以看出,unique()函数返回的并不是items_existed,而是利用了yield

    在函数定义中,如果使用yield语句代替return返回一个值,则定义了一个生成器函数(generator)
    生成器函数是一个迭代器,是可迭代对象,支持迭代

    • a1 = unique(a) 这个函数返回的实际上是一个可迭代对象
      print(a1)得到的会是:<generator object unique at 0x0000016E23AF4F48>
    • 所以,要得到去掉重复后的列表的样子,需要将可迭代对象a1放在list()中
      运行:

    4. 编写程序,求列表[9,7,8,3,2,1,55,6]中的元素个数、最大值、最小值,以及元素之和、平均值。请思考有几种实现方法?

    内置函数:

    s = [9,7,8,3,2,1,55,6]
    
    print("元素个数:{0},最大值:{1},最小值:{2},和:{3},平均值:{4}".\
          format(len(s),max(s),min(s),sum(s),sum(s)/len(s)))
    

    直接访问元素列表(for i in s…):

    s = [9,7,8,3,2,1,55,6]
    
    sum = 0
    max = s[0]
    min = s[0]
    length = 0
    for i in s:
        sum += i
        length += 1
        if(i > max): max = i
        if(i < min): min = i
    
    print("元素个数:{0},最大值:{1},最小值:{2},和:{3},平均值:{4}".\
          format(length,max,min,sum,sum/length))
    
    

    间接访问列表元素(for i in range(0,len(s))…):

    s = [9,7,8,3,2,1,55,6]
    
    sum = 0
    max = s[0]
    min = s[0]
    length = len(s)
    for i in range(0,length):
        sum += s[i]
        if(s[i] > max): max = s[i]
        if(s[i] < min): min = s[i]
    
    print("元素个数:{0},最大值:{1},最小值:{2},和:{3},平均值:{4}".\
          format(length,max,min,sum,sum/length))
    
    

    正序访问(i=0;while i<len(s)…):

    s = [9,7,8,3,2,1,55,6]
    
    sum = 0
    max = s[0]
    min = s[0]
    length = len(s)
    
    i = 0
    while(i < length):
        sum += s[i]
        if(s[i] > max): max = s[i]
        if(s[i] < min): min = s[i]
        i += 1
    
    print("元素个数:{0},最大值:{1},最小值:{2},和:{3},平均值:{4}".\
          format(length,max,min,sum,sum/length))
    
    

    反序访问(i=len(s)-1;while i>=0…):

    s = [9,7,8,3,2,1,55,6]
    
    sum = 0
    max = s[0]
    min = s[0]
    length = len(s)
    
    i = length-1
    while(i >= 0):
        sum += s[i]
        if(s[i] > max): max = s[i]
        if(s[i] < min): min = s[i]
        i -= 1
    
    print("元素个数:{0},最大值:{1},最小值:{2},和:{3},平均值:{4}".\
          format(length,max,min,sum,sum/length))
    
    

    while True:…break

    s = [9,7,8,3,2,1,55,6]
    
    sum = 0
    max = s[0]
    min = s[0]
    length = len(s)
    
    i = 0
    while(True):
        if(i > length-1): break
        sum += s[i]
        if(s[i] > max): max = s[i]
        if(s[i] < min): min = s[i]
        i += 1
    
    print("元素个数:{0},最大值:{1},最小值:{2},和:{3},平均值:{4}".\
          format(length,max,min,sum,sum/length))
    

    运行:

    元素个数:8,最大值:55,最小值:1,和:91,平均值:11.375
    

    5. 编写程序,将列表[9,7,8,3,2,1,5,6]中的偶数变成它的平方,奇数保持不变

    l = [9,7,8,3,2,1,5,6]
    
    for i,value in enumerate(l):
        if(value % 2 == 0):l[i] = value**2
    
    print(l)
    

    运行:

    [9, 7, 64, 3, 4, 1, 5, 36]
    

    6. 编写程序,输入字符串,将其每个字符的ASCII码形成列表并输出

    s = input("请输入一个字符串:")
    l = list()
    for i in s:
        l.append(ord(i))
    
    print(l)
    

    运行:

    请输入一个字符串:zgh666
    [122, 103, 104, 54, 54, 54]
    

    案例研究:猜单词游戏

    https://blog.csdn.net/Zhangguohao666/article/details/103948234

    通过猜单词游戏的设计和实现,帮助读者了解使用Python系列数据类型和控制流程

    第六章 输入和输出


    几个例题

    一:运行时提示输入密码

    输入密码时,一般需要不明显,则可以使用模块getpass,以保证用户输入的密码在控制台中不回显

    import getpass
    
    username = input("user:")
    password = getpass.getpass("password:")
    if(username == 'zgh' and password == '666'):
        print('logined!')
    else:
        print('failed!')
    
    input()#为了看到输出结果。因为执行完毕后,控制台会立马关闭
    

    注意:上面这个代码,如果使用IDLE执行,会因为安全问题而执行失败

    但是,在控制台中执行就没问题,看输出结果(可以看到,输入的密码不会显示出来):

    user:zgh
    password:
    logined!
    

    二:重定向标准输出到一个文件的示例

    这种重定向由控制台完成,而与Python本身无关。

    格式:
    程序 > 输出文件

    其目的是将显示屏从标准输出中分离,并将输出文件与标准输出关联,即程序的执行结果将写入输出文件,而不是发送到显示屏中显示

    首先准备一个test.py文件(代码如下)

    import sys,random
    
    n = int(sys.argv[1])
    for i in range(n):
        print(random.randrange(0,100))
    

    然后在PowerShell中:python test.py 100 > scores.txt
    记住,切记,一定要注意:千万能省略python,这样写./test.py 100 > scores.txt会出现问题,生成的scores文件中会没有任何内容!!!(原因未知)

    然后在当前目录下,100个[0,100)范围内的的整数生成在scores.txt文件中了

    三:重定向文件到标准输入

    格式:
    程序 < 输入文件

    其目的是将控制台键盘从标准输入中分离,并将输入文件与标准输入关联,即程序从输入文件中读取输入数据,而不是从键盘中读取输入数据

    准备一个average.py文件(代码如下)

    import sys
    
    total =0.0
    count = 0
    for line in sys.stdin:
        count += 1
        total += float(line)
    
    avg = total/count
    print("average:",avg)
    

    然后问题总是不期而至,
    在PowerShell中:python average.py < scores.txt,会报错,PowerShell会提示你:“<”运算符是为将来使用而保留的
    很无奈,我只能使用cmd了,然后得出结果

    四:管道

    格式:
    程序1 | 程序2 | 程序3 | … | 程序4

    其目的是将程序1的标准输出连接到程序2的标准输入,
    将程序2的标准输出连接到程序3的标准输入,以此类推

    例如:
    打开cmd,输入python test.py 100 | average.py,其执行结果等同于上面两个例子中的命令

    使用管道更加简洁,且不用创建中间文件,从而消除了输入流和输出流可以处理的数据大小的限制,执行效率更高

    五:过滤器

    1. 使用操作系统实用程序more逐屏显示数据

    2. 使用操作系统实用程序sort排序输出数据

    more和sort都可以在一个语句中使用

    填空题:1、2

    print(value, ..., sep = ' ', end = '\n', file = sys.stdout, flush = False)

    1. sep(分隔符,默认为空格)
    2. end(换行符,即输入的末尾是个啥)
    3. file(写入到指定文件流,默认为控制台sys.stdout)
    4. flush(指定是否强制写入到流)

    1

    >>> print(1,2,3,4,5,sep='-',end='!')
    1-2-3-4-5!
    

    2

    >>> for i in range(10):
    	print(i,end=' ')
    
    	
    0 1 2 3 4 5 6 7 8 9 
    

    例题及上机实践:2~5

    2. 尝试修改例6.2编写的命令行参数解析的程序,解析命令行参数所输入边长的值,计算并输出正方形的周长和面积

    argparse模块用于解析命名的命令行参数,生成帮助信息的Python标准模块

    例6.2:解析命令行参数所输入的长和宽的值,计算并输出长方形的面积

    import argparse
    
    parser = argparse.ArgumentParser()
    parser.add_argument('--length', default = 10, type = int, help = '长度')
    parser.add_argument('--width', default = 5, type = int, help = '宽度')
    
    args = parser.parse_args()
    area = args.length * args.width
    print('面积 = ', area)
    
    input()#加这一句是为了可以看到输出结果
    

    输出:面积 = 50

    如果在执行这个模块时,加入两个命令行参数

    输出:面积 = 36

    基本上看了上面这个例子后,就可以理解argparse的用法了

    本题代码:

    import argparse
    
    parser = argparse.ArgumentParser()
    parser.add_argument('--length', default = 10, type = int, help = '长度')
    
    args = parser.parse_args()
    area = args.length ** 2
    perimeter = 4 * args.length
    print('面积 = {0},周长 = {1}'.format(area,perimeter))
    
    input()#加这一句是为了可以看到输出结果
    
    

    在PowerShell中输入.\test.py
    不给命令行参数,输出是以默认值来计算的
    输出:面积 = 100,周长 = 40

    给命令行参数:.\test.py --length 1
    输出:面积 = 1,周长 = 4

    3. 尝试修改例6.8编写读取并输出文本文件的程序,由命令行第一个参数确认所需输出的文本文件名

    f = open(file, mode = 'r' , buffering = -1, encoding = None)

    1. file是要打开或创建的文件名,如果文件不在当前路径,需指出具体路径
    2. mode是打开文件的模式,模式有:
      ‘r’(只读)
      ‘w’(写入,写入前删除就内容)
      ‘x’(创建新文件,如果文件存在,则导致FileExistsError)
      ‘a’(追加)
      ‘b’(二进制文件)
      ‘t’(文本文件,默认值)
      ‘+’(更新,读写)
    3. buffering表示是否使用缓存(缓存为-1,表示使用系统默认的缓冲区大小)
    4. encoding是文件的编码

    例6.8:读取并输出文本文件

    import sys
    
    filename = sys.argv[0]#就读取本文件,骚的呀皮
    f = open(filename, 'r', encoding = 'utf-8')
    
    line_no = 0
    while True:
        line_no += 1
        line = f.readline()
        if line:
            print(line_no, ":", line)
        else:
            break
    f.close()       
    

    输出(代码输出的就是本python文件):

    1 : import sys
    
    2 : 
    
    3 : filename = sys.argv[0]#就读取本文件,骚的呀皮
    
    4 : f = open(filename, 'r', encoding = 'utf-8')
    
    5 : 
    
    6 : line_no = 0
    
    7 : while True:
    
    8 :     line_no += 1
    
    9 :     line = f.readline()
    
    10 :     if line:
    
    11 :         print(line_no, ":", line)
    
    12 :     else:
    
    13 :         break
    
    14 : f.close()
    
    15 :         
    
    

    本题代码:

    对例题代码进行些许修改就可以了,首先将上例中的第二个语句改为:filename = sys.argv[0],再考虑下面怎么进行

    准备一个用来测试的文件test.txt:

    对于这个文件要注意一点(你们很可能回出现这个问题!!!),win10默认创建的文本文件的字符编码是ANSI

    代码怎么写,有两种:

    1. 将test.txt文本文件的编码修改为utf-8,代码如上所说
      记事本方式打开test.txt文件,点击文件,点击另存为,看到下方的编码(修改为utf-8)
    2. test.txt就用默认的ANSI编码方式,再将上例代码的第三个语句修改为f = open(filename, 'r', encoding = 'ANSI')

    在PowerShell中输入:./test.py test.txt
    输出:

    1 : 大家好
    
    2 : 我是Zhangguohao666
    
    3 : 如果本文章对大家有帮助,请点赞支持一下
    
    4 : 还有:
    
    5 : 如果发现了什么问题,请在评论区指出,我会积极改进
    

    4. 尝试修改例6.9编写利用with语句读取并输出文本文件的程序,由命令行第一个参数确认所需输出的文本文件名

    为了简化操作,Python语言中与资源相关的对象可以实现上下文管理协议,可以使用with语句,确保释放资源。
    with open(file,mode) as f:

    例6.9:利用with语句读取并输出文本文件

    import sys
    
    filename = sys.argv[0]
    
    line_no = 0
    with open(filename, 'r', encoding = 'utf-8') as f:
        for line in f:
            line_no += 1
            print(line_no, ":", line)
    f.close()
    

    基本上,看这个例子,就可以上手with语句了

    本题代码:

    还是上一题准备的文本文件,
    代码一(文本文件的编码为默认的ANSI):

    import sys
    
    filename = sys.argv[1]
    
    line_no = 0
    with open(filename, 'r', encoding = 'ANSI') as f:
        for line in f:
            line_no += 1
            print(line_no, ":", line)
    f.close()
          
    

    代码二(将文本文件的编码修改为utf-8):

    import sys
    
    filename = sys.argv[1]
    
    line_no = 0
    with open(filename, 'r', encoding = 'utf-8') as f:
        for line in f:
            line_no += 1
            print(line_no, ":", line)
    f.close()
          
    
    

    本题的输出,我再不要脸的放一次吧:

    1 : 大家好
    
    2 : 我是Zhangguohao666
    
    3 : 如果本文章对大家有帮助,请点赞支持一下
    
    4 : 还有:
    
    5 : 如果发现了什么问题,请在评论区指出,我会积极改进
    

    5. 尝试修改例6.12编写标准输出流重定向的程序,从命令行第一个参数中获取n的值,然后将0-n,0-n的2倍值,2的0-n次幂的列表打印输出到out.log文件中

    例6.12:从命令行第一个参数中获取n的值,然后将0-n,2的0-n次幂的列表打印输出到out.log文件中

    1. 标准输入流文件对象:sys.stdin,
      默认值为sys.__stdin__
    2. 标准输出流文件对象:sys.stdout,
      默认值为sys.__stdout__
    3. 错误输出流文件对象(标准错误流文件对象):sys.stderr
      默认值为sys.__stderr__

    书中给的代码是这样的:

    import sys
    
    n = int(sys.argv[1])
    power = 1
    i = 0
    
    f = open('out.log', 'w')
    sys.stdout = f
    
    while i <= n:
        print(str(i), ' ', str(power))
        power = 2*power
        i += 1
    sys.stdout = sys.__stdout__
    

    如果使用的编辑器是PyCharm(现在大多数编辑器会帮你对代码进行优化和处理一些隐患),运行书中的这个代码没有问题。

    但是:
    若使用的编辑器是python自带的IDLE,运行这个代码有问题!

    第一:out.log文件会生成,但是没有东西
    (发现文件关闭不了(就是×不掉),
    确定是文件没关闭(f.close())的原因)

    第二:控制台没有输出’done’语句(估计是IDLE编辑器处理不了__stdout__这个值)

    经过研究后,发现(基于IDLE编辑器):
    如果在上面的代码中加入f.close()后,该输入的东西都成功输入进out.log文件了,
    但是,
    还有一个问题
    控制台依旧没有输出’done’语句
    经过一步步的断点调试(就是手动写print)
    发现sys.stdout = sys.__stdout__不会执行

    然后进行改动后,就可以了,代码如下:
    (既然__stdout__不好使,就使用中间变量)

    import sys
    
    n = int(sys.argv[1])
    power = 1
    i = 0
    
    output = sys.stdout
    f = open('out.log', 'w')
    sys.stdout = f
    
    while i <= n:
        print(str(i), ' ', str(power))
        power = 2*power
        i += 1
    
    f.close()
    sys.stdout = output
    print('done!')#这一句是用来检测上面的代码是否成功执行
    
    

    问题虽然解决,但是原因没有彻底弄清楚,求助。。。。。。

    本题代码:

    import sys
    
    n = int(sys.argv[1])
    power = 1
    i = 0
    
    output = sys.stdout
    f = open('out.log', 'w')
    sys.stdout = f
    
    while i <= n:
        print(str(i), ' ',  str(2*i),  ' ', str(power))
        power = 2*power
        i += 1
    
    f.close()
    sys.stdout = output
    print('done!')#这一句是用来检测上面的代码是否成功执行
    
    

    比如时输入的命令行参数是6
    输出:

    案例研究:21点扑克牌游戏

    https://blog.csdn.net/Zhangguohao666/article/details/103948545

    通过21点扑克牌游戏的设计和实现,了解使用Python数据类型、控制流程和输入输出

    第七章 错误和异常处理


    Python语言采用结构化的异常处理机制捕获和处理异常

    而我感觉,Python在这方面的知识点其实和Java的差不多

    几个例题

    一:程序的错误和异常处理

    1. 语法错误

    指源代码中的拼写错误,这些错误导致Python编译器无法把Python源代码转换为字节码,故也称之为编译错误

    1. 运行时错误

    在解释执行过程中产生的错误

    例如:

    • 程序中没有导入相关的模块,NameError
    • 程序中包括零除运算,ZeroDivisionError
    • 程序中试图打开不存在的文件,FileNotFoundError
    1. 逻辑错误

    程序可以执行(程序运行本身不报错),但执行结果不正确。
    对于逻辑错误,Python解释器无能为力,需要用户根据结果来调试判断

    大部分由程序错误而产生的错误和异常一般由Python虚拟机自动抛出。另外,在程序中如果判断某种错误情况,可以创建相应的异常类的对象,并通过raise语句抛出

    >>> a = -1
    >>> if(a < 0): raise ValueError("数值不能为负数")
    
    Traceback (most recent call last):
      File "<pyshell#9>", line 1, in <module>
        if(a < 0): raise ValueError("数值不能为负数")
    ValueError: 数值不能为负数
    >>> 
    

    在程序中的某个方法抛出异常后,Python虚拟机通过调用堆栈查找相应的异常捕获程序。如果找到匹配的异常捕获程序(即调用堆栈中的某函数使用try…except语句捕获处理),则执行相应的处理程序(try…except语句中匹配的except语句块)

    如果堆栈中没有匹配的异常捕获程序,则Python虚拟机捕获处理异常,在控制台打印出异常的错误信息和调用堆栈,并中止程序的执行

    二:try …except…else…finally

    try:
    	可能产生异常的语句
    except Exception1:
    	发生Exception1时执行的语句
    except (Exception2,Exception3):
    	发生Exception2或Exception3时执行的语句
    except Exception4 as e:
    	发生Exception4时执行的语句,Exception4的实例是e
    except:
    	捕获其他所有异常
    else:
    	无异常时执行的语句
    finally:
    	不管异常发生与否都保证执行的语句			
    

    except语句可以写多个,但是要注意一点:系统是自上而下匹配发生的异常,所以用户需要将带有最具体的(即派生类程度最高的)异常类的except写在前面

    三:创建自定义异常,处理应用程序中出现的负数参数的异常

    自定义异常类一般继承于Exception或其子类。自定义异常类的名称一般以Error或Exception为后缀

    >>> class NumberError(Exception):
        def __init__(self,data):
            Exception.__init__
            (self,data)
            self.data = data
        def __str__(self):
            return self.data + ':非法数值(<0)'
    
    >>> 
    >>> def total(data):
        total = 0
        for i in data:
            if i < 0: raise NumberError(str(i))
            total += 1
        return total
    
    >>> 
    >>> data1 = (44, 78, 90, 80, 55)
    >>> print("sum: ",total(data1))
    sum:  5
    >>> 
    >>> data2 = (44, 78, 90, 80, -1)
    >>> print("sum: ",total(data2))
    Traceback (most recent call last):
      File "<pyshell#24>", line 1, in <module>
        print("sum: ",total(data2))
      File "<pyshell#18>", line 4, in total
        if i < 0: raise NumberError(str(i))
    NumberError: -1:非法数值(<0>>> 
    

    四:断言处理

    用户在编写程序时,在调试阶段往往需要判断代码执行过程中变量的值等信息:

    1. 用户可以使用print()函数打印输出结果
    2. 也可以通过断点跟踪调试查看变量
    3. 但使用断言更加灵活

    assert语句和AssertionError

    断言的声明:

    • assert <布尔表达式>
      即:if __debug__: if not testexpression: raise AssertionError
    • assert <布尔表达式>,<字符串表达式>
      即:if __debug__: if not testexpression: raise AssertionError(data)
      字符串表达式(即data)是断言失败时输出的失败消息

    __debug__也是布尔值,Python解释器有两种:调试模式和优化模式

    • 调试模式:__debug__ == True
    • 优化模式:__debug__ == False

    在学习中,对于执行一个py模块(比如test.py)我们通常在cmd中这么输入python test.py,而这默认是调试模式。
    如果我们要使用优化模式来禁用断言来提高程序效率,我们可以加一个运行选项-O,在控制台中这么输入python -O test.py

    看一下断言的示例吧,理解一下用法:

    a =int(input("a: "))
    b =int(input("b: "))
    assert b != 0, '除数不能为零'
    c = a/b
    print("a/b = ", c)
    

    cmd出场:
    输入正确数值时:

    输入错误数值时:

    禁用断言,并且输入错误数值时:

    案例研究:使用调试器调试Python程序

    https://blog.csdn.net/Zhangguohao666/article/details/103948568

    了解使用Python调试器调试程序的方法

    第八章 函数和函数式编程


    一些知识点总结和几个例题

    Python中函数的分类:

    1. 内置函数
      在程序中可以直接使用
    2. 标准库函数
      Python语言安装程序同时会安装若干标准库,例如math、random等
    3. 第三方库函数
      Python社区提供了许多其它高质量的库,在下载、安装这些库后,通过import语句可以导入库
    4. 用户自定义函数
    • 函数名为有效的标识符(命名规则为全小写字母,可以使用下划线增加可阅读性,例如my_func()
    • 函数可以使用return返回值
      如果函数体中包含return语句,则返回值
      否则不返回,即返回值为空(None),无返回值的函数相当于其它编程语言中的过程

    调用函数之前程序必须先执行def语句,创建函数对象

    • 内置函数对象会自动创建
    • import导入模块时会执行模块中的def语句,创建模块中定义的函数
    • Python程序结构顺序通常为import语句>函数定义>全局代码

    一:产生副作用的函数,纯函数

    打印等腰三角形

    n = int(input("行数:"))
    
    def print_star(n):
        print((" * " * n).center(50))
    
    for i in range(1, 2*n, 2):
        print_star(i)
    

    输出:

    行数:5
                            *                         
                         *  *  *                      
                      *  *  *  *  *                   
                   *  *  *  *  *  *  *                
                *  *  *  *  *  *  *  *  *             
    

    上面代码中的print_star()是一个产生副作用的函数,其副作用是向标准输出写入若干星号

    • 副作用:例如读取键盘输入,产生输出,改变系统的状态等
    • 在一般情况下,产生副作用的函数相当于其它程序设计语言中的过程,可以省略return语句

    定义计算并返回第n阶调和数(1+1/2+1/3+…+1/n)的函数,输出前n个调和数

    def harmonic(n):
        total = 0.0
        for i in range(1, n+1):
            total += 1.0/i
        return total
    
    n = int(input("n:"))
    
    print("输出前n个调和数的值:")
    for i in range(1, n+1):
        print(harmonic(i))
    

    输出:

     n:8
    输出前n个调和数的值:
    1.0
    1.5
    1.8333333333333333
    2.083333333333333
    2.283333333333333
    2.4499999999999997
    2.5928571428571425
    2.7178571428571425         
    

    上面代码中的harmonic()是纯函数

    纯函数:给定同样的实际参数,其返回值唯一,且不会产生其它的可观察到的副作用

    注意:编写同时产生副作用和返回值的函数通常被认为是不良编程风格,但有一个例外,即读取函数。例如,input()函数既可以返回一个值,又可以产生副作用(从标准输入中读取并消耗一个字符串)

    二:传递不可变对象、可变对象的引用

    • 实际参数值默认按位置顺序依次传递给形式参数。如果参数个数不对,将会产生错误

    在调用函数时:

    1. 若传递的是不可变对象(例如:int、float、bool、str对象)的引用,则如果函数体中修改对象的值,其结果实际上是创建了一个新的对象
    i = 1
    
    def func(i,n):
        i += n
        return i
    
    print(i)#1
    func(i,10)
    print(i)#1
    

    执行函数func()后,i依旧为1,而不是11

    1. 若传递的是可变对象(例如:list对象)的引用,则在函数体中可以直接修改对象的值
    import random
    
    def shuffle(a):
        n = len(a)
        for i in range(n):
            r = random.randrange(i,n)
            a[i],a[r] = a[r],a[i]
    
    a = [1,2,3,4,5]
    print("初始:",a)
    shuffle(a)
    print("调用函数后:",a)
    

    输出:

    初始: [1, 2, 3, 4, 5]
    调用函数后: [1, 5, 4, 3, 2]
    

    三:可选参数,命名参数,可变参数,强制命名参数

    可选参数

    • 在声明函数时,如果希望函数的一些参数是可选的,可以在声明函数时为这些参数指定默认值
    >>> def babbles(words, times=1):
    	print(words * times)
    
    	
    >>> babbles('Hello')
    Hello
    >>> 
    >>> babbles("Hello", 2)
    HelloHello
    >>> 
    

    注意到一点:必须先声明没有默认值的形参,然后再声明有默认值的形参,否则报错。 这是因为在函数调用时默认是按位置传递实际参数的。

    怎么理解上面那句话呢?

    默认是按位置传递实际参数(如果有默认值的形参在左边,无默认值的形参在右,那么在调用函数时,你的实参该怎么传递呢?)

    命名参数

    • 位置参数:当函数调用时,实参默认按位置顺序传递形参
    • 命名参数(关键字参数):按名称指定传入的参数
      参数按名称意义明确
      传递的参数与顺序无关
      如果有多个可选参数,则可以选择指定某个参数值

    基于期中成绩和期末成绩,按照指定的权重计算总评成绩

    >>> def my_sum(mid_score, end_score, mid_rate = 0.4):
    	score = mid_score*mid_rate + end_score*(1-mid_rate)
    	print(format(score,'.2f'))
    
    	
    >>> my_sum(80,90)
    86.00
    >>> my_sum(mid_score = 80,end_score = 90)
    86.00
    >>> my_sum(end_score = 90,mid_score = 80)
    86.00
    >>> 
    

    可变参数

    • 在声明函数时,可以通过带星号的参数(例如:def func(* param))向函数传递可变数量的实参,调用函数时,从那一点后所有的参数被收集为一个元组
    • 在声明函数时,可以通过带双星号的参数(例如:def func(** param))向函数传递可变数量的实参,调用函数时,从那一点后所有的参数被收集为一个字典

    利用带星的参数计算各数字的累加和

    >>> def my_sum(a,b,*c):
        total = a+b
        for i in c:
            total += i
        return total
    
    >>> print(my_sum(1,2))
    3
    >>> print(my_sum(1,2,3,4,5,6))
    21
    

    利用带星和带双星的参数计算各数字的累加和

    >>> def my_sum(a,b,*c,**d):
        total = a+b
        for i in c:
            total += i
        for key in d:
            total += d[key]
        return total
    
    >>> print(my_sum(1,2))
    3
    >>> print(my_sum(1,2,3,4))
    10
    >>> print(my_sum(1,2,3,4,male=1,female=2))
    13
    

    强制命名参数

    • 在带星号的参数后面声明参数会导致强制命名参数(Keyword-only),然后在调用时必须显式使用命名参数传递值
    • 因为按位置传递的参数默认收集为一个元组,传递给前面带星号的可变参数
    >>> def my_sum(*, mid_score, end_score, mid_rate = 0.4):
        score = mid_score*mid_rate + end_score*(1-mid_rate)
        print(format(score,'.2f'))
    
    >>> my_sum(mid_score=80,end_score=90)
    86.00
    >>> my_sum(end_score=90,mid_score=80)
    86.00
    >>> my_sum(80,90)
    Traceback (most recent call last):
      File "<pyshell#47>", line 1, in <module>
        my_sum(80,90)
    TypeError: my_sum() takes 0 positional arguments but 2 were given
    >>> 
    

    四:全局语句global示例,非局部语句nonlocal示例,输出局部变量和全局变量

    • 在函数体中可以引用全局变量,但是要为定义在函数外的全局变量赋值,需要使用global语句
    pi = 2.1415926
    e = 2.7182818
    
    def my_func():
        global pi
        pi = 3.14
        print("global pi = ", pi)
        e = 2.718
        print("local e = ", e)
    
    print('module pi = ', pi)
    print('module e = ', e)
    my_func()
    print('module pi = ', pi)
    print('module e = ', e)
    

    输出:

    module pi =  2.1415926
    module e =  2.7182818
    global pi =  3.14
    local e =  2.718
    module pi =  3.14
    module e =  2.7182818
    
    • 在函数体中可以定义嵌套函数,在嵌套函数中如果要为定义在上级函数体的局部变量赋值,可以使用nonlocal
    def outer_func():
        tax_rate = 0.17
        print('outer function tax rate is ',tax_rate)
        def inner_func():
            nonlocal tax_rate
            tax_rate = 0.01
            print('inner function tax rate is ',tax_rate)
        inner_func()
        print('outer function tax rate is ',tax_rate)
    
    outer_func()
    

    输出:

    outer function tax rate is  0.17
    inner function tax rate is  0.01
    outer function tax rate is  0.01
    
    • 输出局部变量和全局变量
    1. 内置函数locals(),局部变量列表
    2. 内置函数globals(),全局变量列表

    五:获取和设置最大递归数

    在sys模块中,函数getrecursionlimit()setrecursionlimit()用于获取和设置最大递归次数

    >>> import sys
    >>> sys.getrecursionlimit()
    1000
    >>> sys.setrecursionlimit(666)
    >>> sys.getrecursionlimit()
    666
    >>> 
    

    六:三个有趣的内置函数:eval()、exec()、compile()

    eval

    • 对动态表达式进行求值,返回值
    • eval(expression, globals=None, locals=None)
      expression是动态表达式的字符串
      globals和locals是求值时使用的上下文环境的全局变量和局部变量,如果不指定,则使用当前运行上下文
    >>> x = 2
    >>> str_func = input("请输入表达式:")
    请输入表达式:x**2+2*x+1
    >>> eval(str_func)
    9
    >>> 
    

    exec

    • 可以执行动态表达式,不返回值
    • exec(str, globals=None, locals=None)
    >>> exec("for i in range(10): print(i, end=' ')")
    0 1 2 3 4 5 6 7 8 9 
    >>> 
    

    compile

    • 编译代码为代码对象,可以提高效率
    • compile(source, filename, mode)
      source为代码语句的字符串;如果是多行语句,则每一行的结尾必须有换行符\n
      filename为包含代码的文件
      mode为编码方式,可以为'exec'(用于语句序列的执行),可以为'eval'(用于表达式求值),可以为'single'(用于单个交互语句)
    >>> co = compile("for i in range(10): print(i, end=' ')", '', 'exec')
    >>> exec(co)
    0 1 2 3 4 5 6 7 8 9 
    >>> 
    

    七:map(),filter()

    • map(f, iterable,…),将函数f应用于可迭代对象,返回结果为可迭代对象

    示例1:

    >>> def is_odd(x):
    	return x%2 == 1
    
    >>> list(map(is_odd,range(5)))
    [False, True, False, True, False]
    >>> 
    

    示例2:

    >>> list(map(abs,[1,-2,3,-4,5,-6]))
    [1, 2, 3, 4, 5, 6]
    >>> 
    

    示例3:

    >>> list(map(str,[1,2,3,4,5]))
    ['1', '2', '3', '4', '5']
    >>
    

    示例4:

    >>> def greater(x,y):
    	return x>y
    
    >>> list(map(greater,[1,5,7,3,9],[2,8,4,6,0]))
    [False, False, True, False, True]
    >>> 
    
    • filter(f, iterable),将函数f应用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素,返回结果为可迭代对象

    示例1(返回个位数的奇数):

    >>> def is_odd(x):
    	return x%2 == 1
    
    >>> list(filter(is_odd, range(10)))
    [1, 3, 5, 7, 9]
    >>> 
    

    示例2(返回三位数的回文):

    >>> list(filter(is_palindrome, range(100, 1000)))
    [101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 202, 212, 222, 232, 242, 252, 262, 272, 282, 292, 303, 313, 323, 333, 343, 353, 363, 373, 383, 393, 404, 414, 424, 434, 444, 454, 464, 474, 484, 494, 505, 515, 525, 535, 545, 555, 565, 575, 585, 595, 606, 616, 626, 636, 646, 656, 666, 676, 686, 696, 707, 717, 727, 737, 747, 757, 767, 777, 787, 797, 808, 818, 828, 838, 848, 858, 868, 878, 888, 898, 909, 919, 929, 939, 949, 959, 969, 979, 989, 999]
    >>> 
    

    八:Lambda表达式和匿名函数

    匿名函数广泛应用于需要函数对象作为参数、函数比较简单并且只使用一次的场合

    格式:

    lambda arg1,arg2... : <expression>
    

    其中,arg1、arg2等为函数的参数,<expression>为函数的语句,其结果为函数的返回值

    示例1(计算两数之和):

    >>> f = lambda x,y : x+y
    >>> type(f)
    <class 'function'>
    >>> f(1,1)
    2
    >>> 
    

    示例2(返回奇数):

    >>> list(filter(lambda x:x%2==1, range(10)))
    [1, 3, 5, 7, 9]
    >>> 
    

    示例3(返回非空元素):

    >>> list(filter(lambda s:s and s.strip(), ['A', '', 'B', None, 'C', ' ']))
    ['A', 'B', 'C']
    >>> 
    

    补充:

    • strip()用来去除头尾字符、空白符(\n,\r,\t,’’,即换行、回车、制表、空格)
    • lstrip()用来去除开头字符、空白符
    • rstrip()用来去除结尾字符、空白符

    再补充一点:

    • \n到下一行的开头
    • \r回到这一行的开头

    示例4(返回大于0的元素):

    >>> list(filter(lambda x:x>0, [1,0,-2,8,5]))
    [1, 8, 5]
    >>> 
    

    示例5(返回元素的平方):

    >>> list(map(lambda x:x*x, range(10)))
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    >>> 
    

    九:operator模块和操作符函数

    Python内置操作符的函数接口,它定义了对应算术和比较等操作的函数,用于map()、filter()等需要传递函数对象作为参数的场合,可以直接使用而不需要使用函数定义或者Lambda表达式,使得代码更加简洁

    示例1(concat(x,y)对应于x+y):

    >>> import operator
    >>> a = 'hello'
    >>>> operator.concat(a, ' world')
    'hello world'
    

    实例2(operator.gt对应于操作符>):

    >>> import operator
    >>> list(map(operator.gt, [1,5,7,3,9],[2,8,4,6,0]))
    [False, False, True, False, True]
    >>> 
    

    十:functools.reduce(),偏函数functools.partial(),sorted()

    functools.reduce()

    functools.reduce(func, iterable[, iterable[, initializer]])

    • 使用指定的带两个参数的函数func对一个数据集合的所有数据进行下列操作:
    • 使用第一个和第二个数据作为参数用func()函数运算,得到的结果再与第三个数据作为参数用func()函数运算,依此类推,最后得到一个结果
    • 可选的initialzer为初始值

    示例:

    >>> import functools,operator
    >>> functools.reduce(operator.add, [1,2,3,4,5])
    15
    >>> functools.reduce(operator.add, [1,2,3,4,5], 10)
    25
    >>> functools.reduce(operator.add, range(1,101))
    5050
    >>> 
    >>> functools.reduce(operator.mul, range(1,11))
    3628800
    

    偏函数functools.partial()

    functools.partial(func, *arg, **keywords)

    • 通过把一个函数的部分参数设置为默认值的方式返回一个新的可调用(callable)的partial对象
    • 主要用于设置预先已知的参数,从而减少调用时传递参数的个数

    示例(2的n次方):

    >>> import functools,math
    >>> pow2 = functools.partial(math.pow, 2)
    >>> list(map(pow2, range(11)))
    [1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0]
    >>> 
    

    十一:sorted()

    sorted(iterable, *, key=None, reverse=False)

    • iterable是待排序的可迭代对象
    • key是比较函数(默认为None,按自然顺序排序)
    • reverse用于指定是否逆序排序

    示例1(数值。默认自然排序):

    >>> sorted([1,6,4,-2,9])
    [-2, 1, 4, 6, 9]
    >>> sorted([1,6,4,-2,9], reverse=True)
    [9, 6, 4, 1, -2]
    >>> sorted([1,6,4,-2,9], key=abs)
    [1, -2, 4, 6, 9]
    

    示例2(字符串,默认按字符串字典序排序):

    >>> sorted(['Dod', 'cat', 'Rabbit'])
    ['Dod', 'Rabbit', 'cat']
    >>> sorted(['Dod', 'cat', 'Rabbit'], key=str.lower)
    ['cat', 'Dod', 'Rabbit']
    >>> sorted(['Dod', 'cat', 'Rabbit'], key=len)
    ['Dod', 'cat', 'Rabbit']
    

    示例3(元组,默认按元组的第一个元素排序):

    >>> sorted([('Bob', 75), ('Adam', 92), ('Lisa', 88)])
    [('Adam', 92), ('Bob', 75), ('Lisa', 88)]
    >>> sorted([('Bob', 75), ('Adam', 92), ('Lisa', 88)], key=lambda t:t[1])
    [('Bob', 75), ('Lisa', 88), ('Adam', 92)]
    

    十二:函数装饰器

    这玩意就很有意思了,很Java语言中的注解是很相像的

    示例1:

    import time,functools
    
    def timeit(func):
        def wrapper(*s):
            start = time.perf_counter()
            func(*s)
            end = time.perf_counter()
            print('运行时间:', end - start)
        return wrapper
    
    @timeit
    def my_sum(n):
        sum = 0
        for i in range(n): sum += i
        print(sum)
    
    if __name__ == '__main__':
        my_sum(10_0000)
    

    结果:

    4999950000
    运行时间: 0.013929100000000028
    

    怎么理解上面的代码呢?

    • 首先,timeit()返回的是wrapper,而不是执行(没有小括号)
    • @timeit相当于,在调用my_sum()的前一刻,会执行这么个语句:my_sum = timeit(my_sum)

    示例2:

    def makebold(fn):
        def wrapper(*s):
            return "<b>" + fn(*s) + "</b>"
        return wrapper
    
    def makeitalic(fn):
        def wrapper(*s):
            return "<i>" + fn(*s) + "</i>"
        return wrapper
    
    @makebold
    @makeitalic
    def htmltags(str1):
        return str1
    
    print(htmltags('Hello'))
    
    

    输出:

    <b><i>Hello</i></b>
    

    选择题:1~5

    1

    >>> print(type(lambda:None))
    <class 'function'>
    

    2

    >>> f = lambda x,y:x*y
    >>> f(12, 34)
    408
    

    3

    >>> f1 = lambda x:x*2
    >>> f2 = lambda x:x**2
    >>> print(f1(f2(2)))
    8
    

    4

    >>> def f1(p, **p2):
    	print(type(p2))
    
    	
    >>> f1(1, a=2)
    <class 'dict'>
    

    5

    >>> def f1(a,b,c):
    	print(a+b)
    
    	
    >>> nums = (1,2,3)
    >>> f1(*nums)
    3
    

    思考题:4~11

    4

    >>> d = lambda p:p*2
    >>> t = lambda p:p*3
    >>> x = 2
    >>> x = d(x)
    >>> x = t(x)
    >>> x = d(x)
    >>> print(x)
    24
    

    5

    >>> i = map(lambda x:x**2, (1,2,3))
    >>> for t in i:
    	print(t, end=' ')
    
    	
    1 4 9 
    

    6

    >>> def f1():
    	"simple function"
    	pass
    
    >>> print(f1.__doc__)
    simple function
    

    7

    >>> counter = 1
    >>> num = 0
    >>> def TestVariable():
    	global counter
    	for i in (1, 2, 3) : counter += 1
    	num = 10
    
    	
    >>> TestVariable()
    >>> print(counter, num)
    4 0
    

    8

    >>> def f(a,b):
    	if b==0 : print(a)
    	else : f(b, a%b)
    
    	
    >>> print(f(9,6))
    3
    None
    

    求最大公约数

    9

    >>> def aFunction():
    	"The quick brown fox"
    	return 1
    
    >>> print(aFunction.__doc__[4:9])
    quick
    

    10

    >>> def judge(param1, *param2):
    	print(type(param2))
    	print(param2)
    
    	
    >>> judge(1, 2, 3, 4, 5)
    <class 'tuple'>
    (2, 3, 4, 5)
    

    11

    >>> def judge(param1, **param2):
    	print(type(param2))
    	print(param2)
    
    	
    >>> judge(1, a=2, b=3, c=4, d=5)
    <class 'dict'>
    {'a': 2, 'b': 3, 'c': 4, 'd': 5}
    

    上机实践:2~5

    2. 编写程序,定义一个求阶乘的函数fact(n),并编写测试代码,要求输入整数n(n>=0)。请分别使用递归和非递归方式实现

    递归方式:

    def fact(n):
        if n == 0 :
            return 1
        return n*fact(n-1)
    
    n = int(input("请输入整数n(n>=0):"))
    print(str(n)+" ! =  " + str(fact(n)))
    
    

    非递归方式:

    def fact(n):
        t = 1
        for i in range(1,n+1):
            t *= i
        return t
    
    n = int(input("请输入整数n(n>=0):"))
    print(str(n)+" ! =  " + str(fact(n)))
    
    

    输出:

    请输入整数n(n>=0):5
    5 ! =  120
    

    3. 编写程序,定义一个求Fibonacci数列的函数fib(n),并编写测试代码,输出前20项(每项宽度5个字符位置,右对齐),每行输出10个。请分别使用递归和非递归方式实现

    递归方式:

    def fib(n):
        if (n == 1 or n == 2):
            return 1
        return fib(n-1)+fib(n-2)
    
    for i in range(1,21):
        print(str(fib(i)).rjust(5,' '),end = ' ')
        if i %10 == 0:
            print()
    

    非递归方式:

    def fib(n):
        if (n == 1 or n == 2):
            return 1
        n1 = n2 = 1
        for i  in range(3,n+1):
            n3 = n1+n2
            n1 = n2
            n2 = n3
        return n3
    
    for i in range(1,21):
        print(str(fib(i)).rjust(5,' '),end = ' ')
        if i %10 == 0:
            print()
    

    输出:

        1     1     2     3     5     8    13    21    34    55
       89   144   233   377   610   987  1597  2584  4181  6765
    

    4. 编写程序,利用可变参数定义一个求任意个数数值的最小值的函数min_n(a,b,*c),并编写测试代码。例如对于“print(min_n(8, 2))”以及“print(min_n(16, 1, 7, 4, 15))”的测试代码

    def min_n(a,b,*c):
        min_number = a if(a < b) else b
        for n in c:
            if n < min_number:
                min_number = n
        return min_number
    
    print(min_n(8, 2))
    print(min_n(16, 1, 7, 4, 15))
    

    输出:

    2
    1
    

    5. 编写程序,利用元组作为函数的返回值,求序列类型中的最大值、最小值和元素个数,并编写测试代码,假设测试代码数据分别为s1=[9, 7, 8, 3, 2, 1, 55, 6]、s2=[“apple”, “pear”, “melon”, “kiwi”]和s3="TheQuickBrownFox"

    def func(n):
        return (max(n),min(n),len(n))
        
    s1=[9, 7, 8, 3, 2, 1, 55, 6]
    s2=["apple", "pear", "melon", "kiwi"]
    s3="TheQuickBrownFox"
    
    for i in (s1,s2,s3):
        print("list = ", i)
        t = func(i)
        print("最大值 = {0},最小值 = {1},元素个数 = {2}".format(t[0], t[1], t[2]))
    

    输出:

    list =  [9, 7, 8, 3, 2, 1, 55, 6]
    最大值 = 55,最小值 = 1,元素个数 = 8
    list =  ['apple', 'pear', 'melon', 'kiwi']
    最大值 = pear,最小值 = apple,元素个数 = 4
    list =  TheQuickBrownFox
    最大值 = x,最小值 = B,元素个数 = 16
    

    案例研究:井字棋游戏

    https://blog.csdn.net/Zhangguohao666/article/details/103280740

    了解Python函数的定义和使用


    由于本文的内容太多了,导致了两个很不好的结果,
    一是:在网页中打开本篇博客的加载时间太长了,明显的卡顿很影响阅读体验;
    二是:本人在对本篇文章进行更新或者修改内容时,卡的要死。
    遂,
    将本文第八章后面的很多内容拆分到新的文章中,望大家理解


    第九章 面向对象的程序设计


    第十章 模块和客户端


    第十一章 算法与数据结构基础


    第十二章 图形用户界面


    我对图形用户界面基本无兴趣,无特殊情况,基本不打算碰这方面内容

    案例研究:简易图形用户界面计算器

    第十三章 图形绘制


    与上一章相同,我对于图形绘制的兴趣也基本没有,尝试做了2-7题,就完全没兴趣做下去了

    图形绘制模块:tkinter

    2. 参考例13.2利用Canvas组件创建绘制矩形的程序,尝试改变矩形边框颜色以及填充颜色

    from tkinter import *
    
    root = Tk()
    c = Canvas(root, bg = 'white', width = 130, height = 70)
    c.pack()
    
    c.create_rectangle(10, 10, 60, 60, fill = 'red')
    c.create_rectangle(70, 10, 120, 60, fill = 'green', outline = 'blue', width = 5)
    
    

    创建画布对象:

    • root = Tk()
      创建一个Tk根窗口组件root
    • c = Canvas(root, bg = 'white', width = 130, height = 70)
      创建大小为200 * 100、背景颜色为白色的画布
    • c.pack()
      调用组件pack()方法,调整其显示位置和大小

    绘制矩形:

    c.create_rectangle(x0, y0, x1, y1, option, ...)
    
    • (x0,y0)是左上角的坐标
    • (x1,y1)是右下角的坐标
    • c.create_rectangle(70, 10, 120, 60, fill = 'green', outline = 'blue', width = 5)
      用蓝色边框、绿色填充矩形,边框宽度为5

    3. 参考例13.3利用Canvas组件创建绘制椭圆的程序,尝试修改椭圆边框样式、边框颜色以及填充颜色

    from tkinter import *
    
    root = Tk()
    c = Canvas(root, bg = 'white', width = 280, height = 70)
    c.pack()
    
    c.create_oval(10, 10, 60, 60, fill = 'green')
    c.create_oval(70, 10, 120, 60, fill = 'green', outline = 'red', width = 5)
    c.create_oval(130, 25, 180, 45, dash = (10,))
    c.create_oval(190, 10, 270, 50, dash = (1,), width = 2)
    
    

    绘制椭圆

    c.create_oval(x0, y0, x1, y1, option, ...)
    
    • (x0,y0)是左上角的坐标
    • (x1,y1)是右下角的坐标
    • c.create_oval(70, 10, 120, 60, fill = 'green', outline = 'red', width = 5)
      绿色填充、红色边框,宽度为5
    • c.create_oval(130, 25, 180, 45, dash = (10,))
      虚线椭圆

    4. 参考例13.4利用Canvas组件创建绘制圆弧的程序,尝试修改圆弧样式、边框颜色以及填充颜色

    from tkinter import *
    
    root = Tk()
    c = Canvas(root, bg = 'white', width = 250, height = 70)
    c.pack()
    
    c.create_arc(10, 10, 60, 60, style = ARC)
    c.create_arc(70, 10, 120, 60, style = CHORD)
    c.create_arc(130, 10, 180, 60, style = PIESLICE)
    for i in range(0, 360, 60):
        c.create_arc(190, 10, 240, 60, fill = 'green', outline = 'red', start = i, extent = 30)
    
    

    绘制圆弧:

    c.create_arc(x0, y0, x1, y1, option, ...)
    
    • (x0,y0)是左上角的坐标
    • (x1,y1)是右下角的坐标
    • 选项start(开始角度,默认为0)和extend(圆弧角度,从start开始逆时针旋转,默认为90度)决定圆弧的角度范围
    • 选项start用于设置圆弧的样式

    5. 参考例13.5利用Canvas组件创建绘制线条的程序,尝试修改线条样式和颜色

    from tkinter import *
    
    root = Tk()
    c = Canvas(root, bg = 'white', width = 250, height = 70)
    c.pack()
    
    c.create_line(10, 10, 60, 60, arrow = BOTH, arrowshape = (3, 4, 5))
    c.create_line(70, 10, 95, 10, 120, 60, fill = 'red')
    c.create_line(130, 10, 180, 10, 130, 60, 180, 60, fill = 'green', width = 10, arrow = BOTH, joinstyle = MITER)
    c.create_line(190, 10, 240, 10, 190, 60, 240, 60, width = 10)
    
    

    绘制线条:

    c.create_line(x0, y0, x1, y1, ..., xn, yn, option, ...)
    
    • (x0,y0),(x1,y1),…,(xn,yn)是线条上各个点的坐标

    6. 参考例13.6利用Canvas组件创建绘制多边形的程序,尝试修改多边形的形状、线条样式和填充颜色

    from tkinter import *
    
    root = Tk()
    c = Canvas(root, bg = 'white', width = 250, height = 70)
    c.pack()
    
    c.create_polygon(35, 10, 10, 60, 60, 60, fill = 'red', outline = 'green')
    c.create_polygon(70, 10, 120, 10, 120, 60, fill = 'white', outline = 'blue')
    c.create_polygon(130, 10, 180, 10, 180, 60, 130, 60, outline = 'blue')
    c.create_polygon(190, 10, 240, 10, 190, 60, 240, 60, fill = 'white', outline = 'black')
    
    

    绘制多边形:

    c.create_polygon(x0, y0, x1, y1, ..., option, ...)
    
    • (x0,y0),(x1,y1),…,(xn,yn)是多边形上各个顶点的坐标

    7. 参考例13.7利用Canvas组件创建绘制字符串和图形的程序,绘制y = cos(x) 的图形

    绘制字符串:

    c.create_text(x, y, option, ...)
    
    • (x,y)是字符串放置的中心位置

    y = sin(x)

    from tkinter import *
    import math
    
    WIDTH, HEIGHT = 510, 210
    ORIGIN_X, ORIGIN_Y = 2, HEIGHT/2 #原点
    
    SCALE_X, SCALE_Y = 40, 100 #x轴、y轴缩放倍数
    ox, oy = 0, 0
    x, y = 0, 0
    arc = 0 #弧度
    END_ARC = 360 * 2 #函数图形画两个周期
    
    root = Tk()
    c = Canvas(root, bg = 'white', width = WIDTH, height = HEIGHT)
    c.pack()
    
    c.create_text(200, 20, text = 'y = sin(x)')
    c.create_line(0, ORIGIN_Y, WIDTH, ORIGIN_Y) 
    c.create_line(ORIGIN_X, 0, ORIGIN_X, HEIGHT) #绘制x轴,y轴
    for i in range(0, END_ARC+1, 10):
        arc = math.pi * i / 180
        x = ORIGIN_X + arc * SCALE_X
        y = ORIGIN_Y - math.sin(arc) * SCALE_Y
        c.create_line(ox, oy, x, y)
        ox, oy = x, y
    

    y = cos(x)

    from tkinter import *
    import math
    
    WIDTH, HEIGHT = 510, 210
    ORIGIN_X, ORIGIN_Y = 2, HEIGHT/2 #原点 
    
    SCALE_X, SCALE_Y = 40, 100 #x轴、y轴缩放倍数
    ox, oy = 0, 0
    x, y = 0, 0
    arc = 0 #弧度
    END_ARC = 360 * 2 #函数图形画两个周期
    
    root = Tk()
    c = Canvas(root, bg = 'white', width = WIDTH, height = HEIGHT)
    c.pack()
    
    c.create_text(200, 20, text = 'y = cos(x)')
    c.create_line(0, ORIGIN_Y, WIDTH, ORIGIN_Y) 
    c.create_line(ORIGIN_X, 0, ORIGIN_X, HEIGHT) 
    for i in range(0, END_ARC+1, 10):
        arc = math.pi * i / 180 
        x = ORIGIN_X + arc * SCALE_X
        y = ORIGIN_Y - math.cos(arc) * SCALE_Y
        c.create_line(ox, oy, x, y)
        ox, oy = x, y
    
    
    

    图形绘制模块:turtle


    后面章节内容:未完待续…

    第十四章 数值日期和时间处理


    第十五章 字符串和文本处理


    第十六章 文件和数据交换


    第十七章 数据访问


    第十八章 网络编程和通信


    第十九章 并行计算:进程、线程和协程


    第二十章 系统管理

    展开全文
  • Java Swing 图形界面开发通讯录管理系统

    千次阅读 多人点赞 2020-06-20 15:39:44
    主界面如下图: 4.2.2联系人信息查询 用户点击“查找联系人”按钮之后,系统弹出,查找查找联系人”窗口,用户可以在窗口中填写(至少一项)联系人的信息,系统返回符合用户所填信息的联系人,查找联系人窗口如下...

    目 录

    末尾下载源码

    1实习目的............................................... 2

    2实习内容............................................... 2

    3总体设计方案........................................... 2

    3.1总统功能结构图...................................................... 2

    3.2各子功能的主要算法流程图............................................ 3

    4系统实现............................................... 4

    4.1通讯录管理模块...................................................... 4

    4.1.1用户注册...................................................... 4

    4.1.2用户登录...................................................... 7

    4.1.3修改个人信息以及密码.......................................... 8

    4.2联系人管理......................................................... 10

    4.2.1联系人信息浏览............................................... 10

    4.2.2联系人信息查询............................................... 10

    4.2.3联系人新增................................................... 11

    4.2.4联系人信息修改............................................... 12

    4.2.5联系人删除................................................... 12

    4.2.6添加群组..................................................... 13

    4.2.7群发邮件..................................................... 14

    5总结.................................................. 15

    6参考文献.............................................. 15

    1实习目的

    通过“通信录管理系统”课程设计实习过程,进一步巩固《Java程序设计》课程所学的理论知识,增强学生利用所学内容获取相关知识,以解决实习过程中所面临的问题:良好的人机界面的布局设置,数据库连接,Java访问修改数据库,实现通讯录管理系统等的设计功能和技术难点:使用Java连接数据库,难度较大,这要求对Idea和相关数据库的熟练使用,对数据库要有一定的设计和使用能力,以提高利用Java语言实际动手进行程序设计的能力。

    2实习内容

    分析设计背景和现有系统的优缺点,说明进行系统设计的必要性。站在用户的角度,详细分析系统的功能需求。

    3总体设计方案

    3.1总统功能结构图

     

    3.2各子功能的主要算法流程图

     

    用户进入登录主界面,若选择登录,则在该界面输入账号以及密码,之后系统验证,验证通过,用户进入系统界面,若验证不成功,系统显示提示框,用户重新输入账号密码登录该系统;若是新用户,点击注册按钮,进入注册界面,填写相关注册信息。登录成功后,用户可以根据自己的需要来管理通讯录,流程图如图所示:

     

    1. 联系人流程图如图所示

    1. 联系人查询流程图如图所示

    1. 修改联系人信息流程图如图所示

     

    4系统实现

    4.1通讯录管理模块

    4.1.1用户注册

    未进行注册的用户,在登录时,点击“注册按钮”,系统显示注册界面,用户注册时需要填写相应的用户名、密码、确认密码、地址、手机号以及电子邮箱,填写完成后,点击提交,系统验证。以下是注册主界面图:

     

    用户注册成功时系统弹出提示框提示用户注册成功,以下是“注册成功”提示窗口图:

    当用户输入密码与确认密码不一致时,系统提示“密码不一致,请重新输入”。以下是用户输入密码不一致时,提示窗口图:

    实现以上功能主要代码如下:

      if (action == 0) {
                JOptionPane.showMessageDialog(
    null, "注册失败");
            }
    else {
                JOptionPane.showMessageDialog(
    null, "注册成功");
               
    this.setVisible(false);
            }
        }
    else {
            JOptionPane.showMessageDialog(
    null, "密码不一致重新输入");
           
    return;
        }
    }
    else {
       
    usernameinput.setText("");
       
    userpsdinput.setText("");
       
    userpsdconfirminput.setText("");
       
    userphoneinput.setText("");
       
    useraddressinput.setText("");
       
    useremailinput.setText("");

    当某个用户名已经被注册时,系统提示“用户名已存在”,功能实现主要代码如下:

       if (!userDao.checkusername(usernameinput.getText())) {
            JOptionPane.showMessageDialog(
    null, "用户名已存在,请重新输入");
           
    usernameinput.setText("");
           
    return;
        }

    以下为提示“用户名已存在”窗口图:
     

    用户在进行注册的时候,未将所有需要注册的信息添加完整,系统将提示“信息输入不完整”,功能实现主要代码如下:

     if(usernameinput.getText().equals("") || psd.equals("") ||      psdcomfirm.equals("") ||
          
    useraddressinput.getText().equals("")||     userphoneinput.getText().equals("")||        useremailinput.getText().equals("")) {
            JOptionPane.showMessageDialog(
    null, "信息输入不完整");
           
    return;
        }

       以下为提示“信息输入不完整”窗口图:

     

    除此之外,对用户密码的进行加密也是一个基础重要的功能,以下为对用户注册时,输入的密码进行加密的功能,功能实现的主要代码如下:

     if (psd.equals(psdcomfirm)) {
            MD5Util md5Util =
    new MD5Util();
           
    try {
                psd = md5Util.encode(psd);
            }
    catch (Exception ex) {
                ex.printStackTrace();
            }

    int action= userDao.insetuser(usernameinput.getText(),psd,psdcomfirm
                    
    useraddressinput.getText(),userphoneinput.getText(),

    userem ailinput.getText());

    4.1.2用户登录

    用户登录界面主要包括主界面欢迎语的展示,用户名、密码输入,登录、注册按钮以及取消按钮,以下为登录主界面窗口图:

    用户登录时,要输入的用户名或密码为空时,系统提示“登录名和密码不能为空”,以下为系统提示“登录名和密码不能为空”窗口图:

    当用户输入的密码或用户名错误时,系统提示“用户名或密码错误”,以下为系统提示“用户名或密码错误”窗口图:

    以下为实现以上功能的主要代码:

    if (username_input.getText().equals("") || userpsd_input.getText().equals("")) {
              JOptionPane.showMessageDialog(
    null, "登录名和密码不能为空!");
          }
    else {
              
    userid = userDao.checkpsd(username_input.getText(), new String(userpsd_input.getPassword()));
              
    if (userid == 0) {
                  JOptionPane.showMessageDialog(
    null, "用户名或密码错误");
              }
    else {
                  System.
    out.println("登录成功" + userid);
                  
    new Home(userid);
                  
    this.setVisible(false);
              }
             }
                }
    else if (source == register) {
                     
    new register(userid);
                }
    else {
                     
    username_input.setText("");
                     
    userpsd_input.setText("");
                }

     

    4.1.3修改个人信息以及密码

    用户可以根据自己的需要来修改用用户名、地址、手机号、电子邮箱以及修改密码等个人信息,修改个人信息主界面如下图所示:

    修改个人信息功能实现的代码如下:

    String sql = "update user set user_psd = ? where user_id = ? ";
       
    int action = 0;
       
    try {
            
    conn = dbUtils.getConnection();
           
    ps = conn.prepareStatement(sql);
           
    ps.setString(1, psd);
           
    ps.setInt(2, userid);
            action =
    ps.executeUpdate();
            System.
    out.println("修改成功 用户编号" + userid);
           
    dbUtils.freeConn(conn, ps, rs);
        }
    catch (SQLException e) {
            e.printStackTrace();
        }
       
    return action;
       点击修改密码按钮,进入修改密码主界面,用户需要输入旧密码、新密码以及确认密码,修改密码界面如下图:

    当输入的旧密码与之前的密码不一致时,系统提示“旧密码输入错误”,如下图:

    当输入的新密码与下面的输入的确认密码不一致时,系统提示“两次密码不一样”,如下图:

    实现以上功能主要代码如下:

    if (!md5Util.encode(oldpsdinput.getText()).equals(userspsd)) {
          JOptionPane.showMessageDialog(
    null, "旧密码输入错误");
           
    return;
        }
       
    if (userspsd == null || psd == null) {
          JOptionPane.showMessageDialog(
    null, "信息输入不完整");
           
    return;
        }
        
    if (psd.equals(psdcomfirm)) {
          
    if (userDao.setpsd(md5Util.encode(psd), userid) == 1) {
             JOptionPane.showMessageDialog(
    null, "修改成功");
            
    this.setVisible(false);
            
    selfinfo.setVisible(false);
            
    home.setVisible(false);
            
    new Login();
            }
    else {
                          JOptionPane.showMessageDialog(
    null, "密码错误");
            }
                }
    else {
            JOptionPane.showMessageDialog(
    null, "两次密码不一致");
                }
                   }
    catch (Exception ex) {
                ex.printStackTrace();
                   }

     

     

    4.2联系人管理

     

    4.2.1联系人信息浏览

    用户登录成功后,进入到界面,主界面主要包括:查找所有联系人、查找联系人(按照用户信息查找)、添加群组、新建联系人、退出以及查看个人信息、删除、更新以及发送邮件按钮。主界面如下图:

    4.2.2联系人信息查询

    用户点击“查找联系人”按钮之后,系统弹出,查找“查找联系人”窗口,用户可以在窗口中填写(至少一项)联系人的信息,系统返回符合用户所填信息的联系人,查找联系人窗口如下:

    例如,选择群组,同事,系统查询数据库中所有在同事群组中的联系人的信息并返回:

    实现查找联系人主要代码如下:

           ContactsDao contactsDao = new ContactsDao();
                  
    int index =                groups.get(contactgroupinput.getSelectedIndex()).getGroupid();
                   ArrayList<Contacts> contactsArrayList =
    new ArrayList<>();
                   contactsArrayList = contactsDao.selectcontacts(
    contactnameinput.getText().trim(),                contactphoneinput.getText().trim(),         contacttephoneinput.getText().trim(),
           
    contactsexinput.getText().trim(),              contactaddressinput.getText().trim(),                contactemailinput.getText().trim(),          contactbeizhuinput.getText().trim(), index, userid);
                  
    this.setVisible(false);
                  
    if (selectresu != null) {
                              
    selectresu.setVisible(false);
                   }
    else {
                              
    home.setVisible(false);
                                  }
                  
    new selectresu(userid, contactsArrayList);

     

    4.2.3联系人新增

    用户在主界面点击“新建联系人”按钮,系统弹出新建联系人窗口,用户可以在该窗口中,填写将要添加的联系人的各项信息,填写完毕后点击“添加”,系统提示“添加成功”,即可新增一个联系人。用户也可以选择点击“重置”按钮,重新填写联系人信息,新增联系人窗口如下图:

    实现新增联系人功能主要代码如下:

    ContactsDao contactsDao = new ContactsDao();
    int index = groups.get(contactgroupinput.getSelectedIndex()).getGroupid();
    int action = contactsDao.insetcontacts(contactnameinput.getText(), contactphoneinput.getText(), contacttephoneinput.getText(),
    contactsexinput.getText(), contactaddressinput.getText(), contactemailinput.getText(), contactbeizhuinput.getText(), index, userid);
    if (action == 1) {
        JOptionPane.showMessageDialog(
    null, "添加成功");
       
    this.setVisible(false);
    }

     

    4.2.4联系人信息修改

    用户可以根据自己的需要来更改某个联系人的信息,选择要进行信息更改的联系人,点击界面下方的“更新”按钮,系统弹出“更新联系人”窗口,在该窗口用户可以进行信息的修改,修改信息完成后,点击提交,系统提示“更新成功”即可完成修改联系人信息,同时,用户也可以选择“重置”,来清空当前信息,重新填写。修改联系人信息窗口如下:

    实现联系人信息修改的主要代码如下:

    ContactsDao contactsDao = new ContactsDao();
    int index = groups.get(contactgroupinput.getSelectedIndex()).getGroupid();
    int action = contactsDao.updatecontact(contacts.getContactid(), contactnameinput.getText(), contactphoneinput.getText(), contacttephoneinput.getText(),contactsexinput.getText(),

    contactaddressinput.getText(), contactemailinput.getText(), contactbeizhuinput.getText(), index, userid);
    if (action == 1) {
        JOptionPane.showMessageDialog(
    null, "更新成功");
       
    this.setVisible(false);
    }

    4.2.5联系人删除

    与修改联系人信息类似,用户可以选择某个联系人或者多个联系人,点击“删除”按钮来删除选中的联系人及其信息,点击“删除”按钮,系统将弹出确认窗口,系统提示“删除成功”。删除联系人界面如下图:

    在弹出的窗口中,用户选择“是”按钮后,系统将选中的用户的信息删除并且提示“删除成功”,提示框如下图:

    实现删除联系人主要代码如下:

    for (int i = 0; i < selectrows.length; i++) {
          name = name +
    contactss.get(selectrows[i]).getContactsname() + ",";
        }
       
    int valuex = JOptionPane.showConfirmDialog(

                     null, "你确认要删除" + name + "这几个联系人吗?", "请确认",
              JOptionPane.
    YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
      
    if (valuex == JOptionPane.YES_OPTION) {
          
    for (int i = 0; i < selectrows.length; i++) {
              action = contactsDao.deletecontact(
    contactss.get(selectrows[i]).

    getContactid(), userid);
          }
          
    if (action == 1) {
              JOptionPane.showMessageDialog(
    null, "删除成功");
              
    this.setVisible(false);
              
    new Home(userid);
        }

     

    4.2.6添加群组

    该系统还提供了群组的功能,将多个联系人划归到某个分组中,用户可以在主界面点击“添加群组”,进行分组的添加,系统弹出添加分组对话框,用户在该对话框中,输入要添加的群组的名称。添加群组窗口如下图:

    输入群组名称后,用户点击“添加”按钮,系统提示,群组添加成功,同样的,用户也可以选择重置,此时所输入的群组名称将被清空,待用户重新填写。添加成功窗口如下图:

    实现添加群组功能主要代码如下:

    GroupDao groupDao = new GroupDao();
    int action =  groupDao.insetgroup(groupnameinput.getText(),userid);
    if(action==1){
        JOptionPane.showMessageDialog(
    null,"群组"+groupnameinput.getText()+"添加成功");
       
    this.setVisible(false);
    }

     

    4.2.7群发邮件

    除了以上的联系人管理功能外,本系统还具有群发邮件的功能,用户可以在主界面选择多个用户,点击“发送邮件”按钮,系统将弹出“输入”窗口,用户在此窗口中输入要发送的信息内容。电子邮件输入框如下图:

    邮件内容输入完毕后,点击“确定”,系统将提示“发送成功”。邮件发送成功界面如下图:

    实现群发邮件功能主要代码如下:

    public  boolean sendEmail(String emailaddress,String code){
          
    try {
              HtmlEmail email =
    new HtmlEmail();
              email.setHostName(
    "smtp.163.com");
              email.setCharset(
    "UTF-8");
              email.addTo(emailaddress);
              email.setFrom(
    "15161130626@163.com", "通讯录管理系统");
              email.setAuthentication(
    "15161130626@163.com", "522672296q");
              email.setSubject(
    "通讯录管理系统");
              email.setMsg(code);
              email.send();
              
    return true;
          }
          
    catch(Exception e){
              e.printStackTrace();
              
    return false;
          }

    5总结

     

     

    6参考文献

    [1] 王国辉,王易.JSP数据库系统开发案例精选[M].北京:人民邮电出版社.2006.5 

    [2] 王家华.软件工程[M].沈阳:东北大学出版社.2005 

    [3] 周影.网络编程语言JSP实例教程[M].北京:电子工业出版社.2003.6

    [4] 萨师煊,王珊.数据库系统概论(第三版)[M].北京:高等教育出版社.2000

    [5] 张新曼.精通JSP-Web开发技术与典型应用[M].北京:人民邮电出版社.2007

    [6] 张海藩.软件工程导论[M].北京:清华大学出版社.2003

    [7] 武延军,黄飞跃.精通JSP编程技术[M].北京:人民邮电出版社.2001.8

    [8] 邹竹彪.JSP网络编程从入门到精通[M].北京:清华大学出版社.2007

    [9] 黄理,李积善,曹林有,张勇.用JSP轻松开发Web网站(第一版)[M].北京:北京希望电子出版社.2001

     

     

    下载地址(点击下载)

    下载地址2(防止失效)

     

    展开全文
  • java仓库管理系统

    2019-02-11 10:24:37
    java工程是使用java swing 图形界面开发的仓库管理系统,功能包括用户管理,权限管理,角色管理,库存管理,报表统计及导出功能可用于高校毕业设计及二次开发,已将源码和mysql建表脚本上传至该压缩包,将工程导入...
  • 如代码所示,同时我们在初始化一个图形界面的时候,都会直接在主方法的主线程里,直接调用如下代码来进行初始化 new TestFrame().setVisible(true); 如果是小程序这没有什么问题,如果是复杂的程序就有可能产生...
  • 前端面试题

    万次阅读 多人点赞 2019-08-08 11:49:01
    怎样添加、移除、移动、复制、创建和查找节点(原生JS,实在基础,没细写每一步) 61 有这样一个URL: http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e,请写一段JS程序提取URL中的各个GET参数(参数名和参数...
  • 测试开发笔记

    万次阅读 多人点赞 2019-11-14 17:11:58
    测试开发笔记 第一章 测试基础 7 什么是软件测试: 7 ★软件测试的目的、意义:(怎么做好软件测试) 7 3.软件生命周期: 7 第二章 测试过程 8 1.测试模型 8 H模型: 8 V模型 9 2.内部测试 10 ...
  • 什么是php?php是什么?

    万次阅读 多人点赞 2019-04-10 10:26:45
    什么是php? PHP 是 PHP Hypertext Preprocessor(超文本与处理器)的首字母缩写。这种方法叫做递归缩写。 ​ ... ​ ...它的很多语法来自 C,Java 和 Perl,并具有几个 PHP 独有的特点。该语言的主要目标...
  • jaxen-1.1-beta-6.jar (dom4j的依赖包,使用XPath路径查找节点就需要此包) 程序为什么需要字符串摘要:因为xml节点名称不能有特殊字符,但是文件夹名可以使用, 所以有点文件名进行了摘要,有的没有,可以...
  • 【MATLAB】MATLAB的基础知识

    千次阅读 多人点赞 2017-04-12 11:52:00
    方式一:双击操作系统桌面上的MATLAB快捷方式,即可启动并打开MATLAB命令窗口。 方式二:单击【开始】菜单,依次指向【程序】→【MATLAB】即可启动并打开MATLAB命令窗口。 2.MATLAB的退出 退出MATLAB非常简单,...
  • 之前只有用c#拖拽按钮设计界面的经历但没尝试过在java里写界面,于是查找下这两种方法的区别。C#比较简单,容易上手,适合初学者。弄出来的界面相对美观。Java图形界面较难,不美观。也可以用Jbui
  • MIT的研究人员设计了一种新颖的图形脚本语言Sikuli,计算机用户只须有最基本的编程技能(比如会写print"hello world"),他不需要去写出一行行代码,而是用屏幕截图的方式,用截出来的图形元素组合出神奇的程序。
  • Java资源包01

    2016-08-31 09:16:25
    JGraphEd 是一个 Java图形编辑应用和绘图框架。 Java 穿越NAT方案 JSTUN.tar JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM...
  • java开源包101

    2016-07-13 10:11:08
    JGraphEd 是一个 Java图形编辑应用和绘图框架。 Java 穿越NAT方案 JSTUN.tar JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM...
  • 本书以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用Java进行桌面程序开发各个方面的知识和技巧,主要包括Java语法与面向对象技术、Java高级应用、窗体与控件应用、文件操作典型应用和...
  • MATLAB 2018b 安装与简介

    万次阅读 多人点赞 2019-02-18 13:07:00
    该版本是mathworks官方开发的新版本的商业数学软件,可以帮助用户不仅仅将自己的创意停留在桌面,还可以对大型数据集运行分析,并扩展到群集和云。另外matlab代码可以与其他语言集成,使您能够在Web、企业和生产系统...
  • 基于物品的协同过滤算法实现图书推荐系统

    万次阅读 多人点赞 2019-09-14 21:20:24
    Python的多样性,意味着可以横跨多个领域,绝不仅限于Web开发、桌面程序、移动应用,甚至包含硬件开发等。所以并没有被束缚在单一的平台之上,Python具有良好的可移植性,在图书推荐系统开发上使用Python可以大大方便...
  • 通讯录管理系统Java完成

    热门讨论 2010-03-29 14:29:05
    数据库要求: •一个结点包括:姓名、电话号码、分类(可选项有:1 办公类 2 个人类 3 商务类)、电子邮件)。例如: ...功能要求: •查看功能:选择此功能时,列出下列三类选择(1 办公类 2 个人类 3 商务类),当选...
  • java开源包10

    热门讨论 2013-06-28 10:06:40
    JGraphEd 是一个 Java图形编辑应用和绘图框架。 Java 穿越NAT方案 JSTUN.tar JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM...
  • java开发调试定位分析工具大全

    千次阅读 2018-09-30 09:36:19
    Java是一种非常强大的编程语言,自问世以来就广受欢迎。作为现今十分流行的移动平台——Android的核心语言,它大大促进了移动通信行业的发展。因此可以肯定,随着Android平台的不断扩张,Java开发人员的需求量也会...
  • 对于Java桌面应用来说,比较烦琐的就是安装部署问题,如:客户端是否安装有jre、jre版本、jre在哪里下载、如何用jre启动Java应用等等。不要说刚接触电脑的人,就算是比较熟悉电脑,如果没有接触过Java,面对一个Java...
  • Linux实用教程(第三版)

    万次阅读 多人点赞 2019-08-27 22:55:59
    近几年来,Linux系统又以其友好的图形界面、丰富的应用程序及低廉的价格,在桌面领域得到了较好的发展,受到了普通用户的欢迎。 1.1.2 Linux系统的产生 Linux系统的内核最早是由芬兰大学生Linus Torvalds开发,并于...
  • Java高级教程3_图形用户界面GUI

    千次阅读 2013-01-25 13:36:38
    张老师的Java高级教程中图形用户界面GUI对应的笔记 网络编辑器还要重新排版,提供原始文件下载,先看个概貌   Java高级3_图形用户界面GUI AWT的基础知识 GUI:Graphical User Interface图形用户界面。JDK中提供了...
  • 阿里Java面经大全(整合版)

    万次阅读 多人点赞 2018-08-03 16:10:12
    阿里巴巴,三面,java实习 昨天晚上11点打电话来,问我可以面试不,我说不可以,然后就约到了今天, 1.上来问我项目用的框架,然后问我springmvc里面有的参数的设定,问的是细节,然后问我如果传的多个值是一个...
  • 牛逼!Java 从入门到精通,超全汇总版

    万次阅读 多人点赞 2021-05-06 19:40:33
    文章目录Java 基础Head First JavaJava 核心技术卷一Java 编程思想设计模式Head First 设计模式图解设计模式设计模式重学 Java 设计模式Java 进阶Java 并发编程实战Java 并发编程艺术Java 并发编程之美图解Java多...
  • java开源包11

    热门讨论 2013-06-28 10:10:38
    JGraphEd 是一个 Java图形编辑应用和绘图框架。 Java 穿越NAT方案 JSTUN.tar JSTUN 是另外一个用来解决穿越 NAT 进行通讯的 Java 解决方案,是 STUN 协议的 Java实现。 在浏览器上运行Java程序 Doppio DoppioVM...
  • Java经典编程300例(code)

    千次下载 热门讨论 2013-01-09 10:26:53
    实例061 计算几何图形的面积 93 实例062 简单的汽车销售商场 95 实例063 使用Comparable接口自定 义排序 96 实例064 策略模式的简单应用 98 实例065 适配器模式的简单应用 100 实例066 普通内部类的简单应用 102 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,693
精华内容 5,477
关键字:

java查找桌面图形位置

java 订阅