Neovim,要尝一口不?

Posted 堆码志

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Neovim,要尝一口不?相关的知识,希望对你有一定的参考价值。

Neovim 风评很好,我机器上其实早装了它来替代 vim。只不过这两年用 vscode 较多,冷落了它,除了偶尔改改配置文件,很少用。难得大过年的有点儿空,就来倒腾它一下子,最终效果如下。

基础配置

0.5 版开始,Neovim 允许使用 Lua 代替 VimL 作为配置语言,所以这里也直接从 init.lua 开始了。

mkdir -p ~/.config/nvim
touch ~/.config/nvim/init.lua

打开此文件,开始配置。

nvim ~/.config/nvim/init.lua

先设置一下缩进,默认是 8 个字符,改为 4 个字符且按 tab 键自动补空格:

vim.g.shiftround = true
vim.bo.expandtab = true
vim.bo.shiftwidth = 4
vim.bo.softtabstop = 4
vim.bo.tabstop = 4

再来显示下行号及右边界警示线。右边界一般建议为 80,即代码超过 80 个字符应该注意换行。对现在的屏幕分辨率来说,80 其实有些窄,可以设为 120。

vim.wo.number = true
vim.wo.colorcolumn = "120"

neovim 默认打开了不少之前在 vim 中需要单独设置的选项,比如说自动缩进、文件类型检测、语法高亮等等。有了上面这几行,基础的配置差不多就够了,其它的安装插件后再调整。

插件管理

选用 lazy,与 packer 相比,它不需要编译、更快、界面也好看些,还有其它优点,不罗列了。总之,就是它了。

local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system(
    "git",
    "clone",
    "--filter=blob:none",
    "git@github.com:folke/lazy.nvim.git",
    "--branch=stable",
    lazypath,
  )
end
vim.opt.rtp:prepend(lazypath)

注意与官方文档相比,我把 clone 地址由 https://github.com/folke/lazy.nvim.git 改为了 git@github.com:folke/lazy.nvim.git,原因你知道的,国内访问 Github 网址抽风,改用后者要好一些。

接着就是让 lazy 起作用了,加入如下配置:

require("lazy").setup(
	-- 插件写这里
, 
    git = 
        url_format = "git@github.com:%s"
    
)

以上同样加了些针对 git 下载路径的自定义设置,原因同上。

需要特别说明的是,为了节省篇幅,后续凡是提到安装插件的,相关代码都是追加到如下注释的地方:

-- 以上省略
require("lazy").setup(
	-- 插件相关配置在这里追加
, 
-- 以下省略

然后输入如下命令就可以打开安装界面进行安装了:

:Lazy

配色方案

配色方案也是插件,可选的太多了,我使用 Nightfox。它本身又包含了多套方案,如下用的是 nordfox

    
        "EdenEast/nightfox.nvim",
        lazy = false,
        priority = 1000,
        config = function()
            vim.cmd([[colorscheme nordfox]])
        end,
    ,

安装之后,界面长这样:

还是很好看的。

字体与图标

首先打开 NERD FONTS,找一款你喜欢的编程字体装进系统里,然后设置你的终端使用该字体。接下来安装插件 nvim-web-devicons

    "nvim-tree/nvim-web-devicons",

以上操作目的是为了给 neovim 提供图标支撑,目前暂时看不到变化,算是为后续做些准备工作。

状态栏

选用 lualine 插件:

    
        "nvim-lualine/lualine.nvim",
        opts = 
            options = 
                section_separators = \'\',
                component_separators = \'\'
            
        
    ,

其实可以只保留如下一行,显示效果可能还好一些。我个人偏爱简洁样式,用上述选项是为了去掉分隔符。

    "nvim-lualine/lualine.nvim",

文件管理

nvim-tree,用的人多,比较活跃。

    
        "nvim-tree/nvim-tree.lua",
        config = function()
            vim.g.loaded_netrw = 1
            vim.g.loaded_netrwPlugin = 1
            vim.g.termguicolors = true

            require("nvim-tree").setup(
                sort_by = "case_sensitive",
            )
        end,
    ,

安装后,输入命令:

:NvimTreeToggle

就会打开文件树,如下图:

但是每次输入命令打开关闭文件树不太爽,用快捷键就好多了。

快捷键

先定义一下全局的快捷起始键,通常用空格或逗号,如下定义为逗号:

vim.g.mapleader = ","

如下定义 ,+空格 取消搜索高亮:

vim.keymap.set("n", "<leader><space>", "<cmd>nohlsearch<cr>",  silent = true )

快捷键用熟了很好,刚定义时容易忘。想要提示的话,可以用 which-key 插件来定义快捷键。

    
        "folke/which-key.nvim",
        config = function()
            vim.o.timeout = true
            vim.o.timeoutlen = 300

            local wk = require("which-key")
            -- 快捷键在这里定义
            wk.setup()
        end,
    ,

注意其中的注释,后续对快捷键定义如无特殊说明,都写在上述注释所在的位置。

现在可以试一下了,按下 Ctrl-W 组合键,效果如下:

Amazing,比较带劲是不是?

接下来注册自己想要的快捷键,比如:

            wk.register(
                ["<space>"] =  "<cmd>nohlsearch<cr>", "取消搜索高亮" ,
                ["d"] =  "<cmd>NvimTreeToggle<cr>", "显示/隐藏目录树" ,
            ,  prefix = "<leader>" )

这样就可以用 ,+d 来切换目录树的显示了。顺便的,当使用 /? 搜索时,匹配项会高亮显示,现在可以使用 ,+空格 来取消高亮了。如果按下 , 键,则会弹出以上快捷键的说明。相当不错!

多文档

vim/neovim 有两种模式支持多文档编辑:标签页或缓冲区。这里选择使用缓冲区,bufferline 插件可以展示多个缓冲区的文档标签:

    
        "akinsho/bufferline.nvim",
        tag = "v3.*",
        config = function()
            vim.g.termguicolors = true

            require("bufferline").setup()
        end,
    ,

试下效果吧。用 ,+d 打开目录树,按 jk 选中个文件,再按 o 或直接回车就打开了,注意上方多出来的标签页

试试用鼠标点击标签页以及其中的关闭按纽,功能正是你想要的,对吧?不过在 vim 中用鼠标似乎有些 low,用命令 :bn:bp 算是正常途径。也可以定义快捷键,如下:

            vim.keymap.set("n", "<leader>bp", "<cmd>BufferLineCyclePrev<cr>",  silent = true )
            vim.keymap.set("n", "<leader>bn", "<cmd>BufferLineCycleNext<cr>",  silent = true )
            vim.keymap.set("n", "<leader>bd", "<cmd>bd<cr>",  silent = true )

配置到现在,乍一看很象回事了。但是用来写代码的话,还不太够,所以继续。

参考线及特殊字符

先加两行全局配置,以区分空格与制表符、以及折行与回车换行:

vim.o.listchars = "eol:↵,lead:‧"
vim.wo.list = true

然后装个 indent-blankline 插件:

    
	    "lukas-reineke/indent-blankline.nvim",
    ,

代码片断

使用插件 luasnip,与自动完成的集成稍后再说。

    
        "L3MON4D3/LuaSnip",
        version = "^1.1.0",
        dependencies = 
            "rafamadriz/friendly-snippets",
        ,
        config = function()
            require("luasnip.loaders.from_vscode").lazy_load()
        end,
    ,

自动完成

从这里开始,进入稍微复杂的配置部分。先来弄自动完成。自动完成的原材料可以来源于当前文档关键字、可以来源于代码片断,当然我们更希望它来源于我们的编程上下文语义,即 LSP 集成。如下是相关插件配置。

    
        "hrsh7th/nvim-cmp",
        dependencies = 
            "hrsh7th/cmp-buffer",
            "hrsh7th/cmp-path",
            "hrsh7th/cmp-nvim-lsp",
            "L3MON4D3/LuaSnip",
            "saadparwaiz1/cmp_luasnip",
        ,
        config = function()
            local cmp = require("cmp")

            cmp.setup(
                snippet = 
                    expand = function(args)
                        require("luasnip").lsp_expand(args.body)
                    end,
                ,
                mapping = cmp.mapping.preset.insert(
                    [\'<C-b>\'] = cmp.mapping.scroll_docs(-4),
                    [\'<C-f>\'] = cmp.mapping.scroll_docs(4),
                    [\'<C-Space>\'] = cmp.mapping.complete(),
                    [\'<C-e>\'] = cmp.mapping.abort(),
                    [\'<CR>\'] = cmp.mapping.confirm( select = true ),
                ),
                sources = cmp.config.sources(
                     name = \'nvim_lsp\' ,
                     name = \'luasnip\' ,
                , 
                     name = \'buffer\' ,
                     name = "path" ,
                ),
            )
        end,
    ,

看起来比较复杂,对吧?简单解释一下:

  • 自动完成使用了 nvim-cmp 插件;
  • 提示内容可以来源于当前文档、路径、代码片断及上下文语义;
  • 定义了几个快捷键;

上下文语义(LSP)

可能是最复杂的部分,配置如下:

    
        "neovim/nvim-lspconfig",
        dependencies = 
            "williamboman/mason.nvim",
            "williamboman/mason-lspconfig.nvim",
            "hrsh7th/cmp-nvim-lsp",
        ,
        config = function()
            require("mason-lspconfig").setup(
                ensure_installed = 
                    "bashls",
                    "clangd",
                    "denols",
                    "pyright",
                    "rust_analyzer",
                ,
            )

            local capabilities = require(\'cmp_nvim_lsp\').default_capabilities()

            local lspcfg = require("lspconfig")
            lspcfg.bashls.setup(
                capabilities = capabilities,
                on_attach = on_attach
            )
            lspcfg.clangd.setup(
                capabilities = capabilities,
                on_attach = on_attach
            )
            lspcfg.denols.setup(
                capabilities = capabilities,
                on_attach = on_attach
            )
            lspcfg.pyright.setup(
                capabilities = capabilities,
                on_attach = on_attach
            )
            lspcfg.rust_analyzer.setup(
                capabilities = capabilities,
                on_attach = on_attach
            )
        end,
    ,

仍然是最简单的解释一下:

  • 使用了 nvim-lspconfig 插件来做 LSP 的配置;
  • 不同的编程语言要安装不同的语言服务,使用 mason 来统一管理这些语言服务组件;
  • 自动安装 bash、c/c++、js/ts、python、rust 语言服务;
  • 集成上述编程语言的语义化自动完成功能;

其中有个 on_attach 在给出的配置代码中暂未给出,是因为这是个公用函数,下文的代码格式化也会用到,所以稍后再描述。

格式化及诊断

这两项内容均使用 null-ls 插件实现,配置如下:

    
        "jose-elias-alvarez/null-ls.nvim",
        dependencies = 
            "nvim-lua/plenary.nvim",
        ,
        config = function()
            local nl = require("null-ls")
            local sources = 
                nl.builtins.diagnostics.eslint_d,
                nl.builtins.diagnostics.ruff,
                nl.builtins.formatting.beautysh,
                nl.builtins.formatting.black,
                nl.builtins.formatting.clang_format,
                nl.builtins.formatting.prettierd,
                nl.builtins.formatting.rustfmt,
                nl.builtins.formatting.sql_formatter,
            
            nl.setup(
                sources = sources,
                on_attach = on_attach,
            )
        end,
    ,

很明显,诊断与格式化也都与编程语言相关,同样依赖一些第三方组件。尽管上述配置没用明确给出,也可以通过 mason 管理,之前已经安装过些插件。输入 :Mason 即可打开其界面如下:

可以看到我已经安装了 LSP 及格式化与诊断相关的几个组件。

是时候说一下 on_attach 了,其代码如下:

local on_attach = function(client, bufnr)
    vim.api.nvim_buf_set_option(bufnr, \'omnifunc\', \'v:lua.vim.lsp.omnifunc\')

    local bufopts =  noremap=true, silent=true, buffer=bufnr 
    vim.keymap.set(\'n\', \'gD\', vim.lsp.buf.declaration, bufopts)
    vim.keymap.set(\'n\', \'gd\', vim.lsp.buf.definition, bufopts)
    vim.keymap.set(\'n\', \'gi\', vim.lsp.buf.implementation, bufopts)
    vim.keymap.set(\'n\', \'gr\', vim.lsp.buf.references, bufopts)
    vim.keymap.set(\'n\', \'K\', vim.lsp.buf.hover, bufopts)
    vim.keymap.set(\'n\', \'<C-k>\', vim.lsp.buf.signature_help, bufopts)
    vim.keymap.set(\'n\', \'<leader>wa\', vim.lsp.buf.add_workspace_folder, bufopts)
    vim.keymap.set(\'n\', \'<leader>wr\', vim.lsp.buf.remove_workspace_folder, bufopts)
    vim.keymap.set(\'n\', \'<leader>wl\', function()
        print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
    end, bufopts)
    vim.keymap.set(\'n\', \'<leader>D\', vim.lsp.buf.type_definition, bufopts)
    vim.keymap.set(\'n\', \'<leader>rn\', vim.lsp.buf.rename, bufopts)
    vim.keymap.set(\'n\', \'<leader>ca\', vim.lsp.buf.code_action, bufopts)
    vim.keymap.set(\'n\', \'<leader>f\', function()
        vim.lsp.buf.format  async = true 
    end, bufopts)

    local augroup = vim.api.nvim_create_augroup("LspFormatting", )
    if client.supports_method("textDocument/formatting") then
        vim.api.nvim_clear_autocmds( group = augroup, buffer = bufnr )
        vim.api.nvim_create_autocmd("BufWritePre", 
            group = augroup,
            buffer = bufnr,
            callback = function()
                vim.lsp.buf.format(
                    filter = function(client)
                        return client.name == "null-ls"
                    end,
                    bufnr = bufnr,
                )
            end,
        )
    end
end

主要是定义了一些快捷键,例如:

  • gd 可以跳转至关键字定义;
  • gi 可以跳转至类型实现;
  • ,D 可以跳转至类型定义;
  • ,f 代码格式化;
  • 保存时自动进行代码格式化;

其它

  • 注释,使用插件:comment.nvim;
  • 错误列表,使用插件:trouble.nvim;

完整配置

vim.o.listchars = "eol:↵,lead:‧"
vim.wo.list = true
vim.wo.number = true
vim.wo.signcolumn = "yes"
vim.wo.colorcolumn = "80"

vim.g.shiftround = true
vim.bo.expandtab = true
vim.bo.shiftwidth = 4
vim.bo.softtabstop = 4
vim.bo.tabstop = 4

vim.g.termguicolors = true
vim.g.completeopt = "menu,menuone,noselect"

vim.g.mapleader = ","
vim.keymap.set("n", "<leader><space>", "<cmd>nohlsearch<cr>",  silent = true )

-- vim.lsp.set_log_level("debug")
local on_attach = function(client, bufnr)
    vim.api.nvim_buf_set_option(bufnr, \'omnifunc\', \'v:lua.vim.lsp.omnifunc\')

    local bufopts =  noremap=true, silent=true, buffer=bufnr 
    vim.keymap.set(\'n\', \'gD\', vim.lsp.buf.declaration, bufopts)
    vim.keymap.set(\'n\', \'gd\', vim.lsp.buf.definition, bufopts)
    vim.keymap.set(\'n\', \'gi\', vim.lsp.buf.implementation, bufopts)
    vim.keymap.set(\'n\', \'gr\', vim.lsp.buf.references, bufopts)
    vim.keymap.set(\'n\', \'K\', vim.lsp.buf.hover, bufopts)
    vim.keymap.set(\'n\', \'<C-k>\', vim.lsp.buf.signature_help, bufopts)
    vim.keymap.set(\'n\', \'<leader>wa\', vim.lsp.buf.add_workspace_folder, bufopts)
    vim.keymap.set(\'n\', \'<leader>wr\', vim.lsp.buf.remove_workspace_folder, bufopts)
    vim.keymap.set(\'n\', \'<leader>wl\', function()
        print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
    end, bufopts)
    vim.keymap.set(\'n\', \'<leader>D\', vim.lsp.buf.type_definition, bufopts)
    vim.keymap.set(\'n\', \'<leader>rn\', vim.lsp.buf.rename, bufopts)
    vim.keymap.set(\'n\', \'<leader>ca\', vim.lsp.buf.code_action, bufopts)
    vim.keymap.set(\'n\', \'<leader>f\', function()
        vim.lsp.buf.format  async = true 
    end, bufopts)

    local augroup = vim.api.nvim_create_augroup("LspFormatting", )
    if client.supports_method("textDocument/formatting") then
        vim.api.nvim_clear_autocmds( group = augroup, buffer = bufnr )
        vim.api.nvim_create_autocmd("BufWritePre", 
            group = augroup,
            buffer = bufnr,
            callback = function()
                vim.lsp.buf.format(
                    filter = function(client)
                        return client.name == "null-ls"
                    end,
                    bufnr = bufnr,
                )
            end,
        )
    end
end

local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
    vim.fn.system(
        "git",
        "clone",
        "--filter=blob:none",
        "git@github.com:folke/lazy.nvim.git",
        "--branch=stable",
        lazypath,
    )
end
vim.opt.rtp:prepend(lazypath)

require("lazy").setup(
    "nvim-tree/nvim-web-devicons",
    
        "EdenEast/nightfox.nvim",
        lazy = false,
        priority = 1000,
        config = function()
            vim.cmd([[colorscheme nordfox]])
        end,
    ,
    
        "nvim-tree/nvim-tree.lua",
        config = function()
            vim.g.loaded_netrw = 1
            vim.g.loaded_netrwPlugin = 1

            require("nvim-tree").setup(
                sort_by = "case_sensitive",
            )

            vim.keymap.set("n", "<leader>d", "<cmd>NvimTreeToggle<cr>",  silent = true )
        end,
    ,
    
        "nvim-lualine/lualine.nvim",
        dependencies = 
            "nvim-tree/nvim-web-devicons",
        ,
        opts = 
            options = 
                section_separators = "",
                component_separators = "⁞",
            ,
        ,
    ,
    
        "akinsho/bufferline.nvim",
        version = "^3.1.0",
        config = function()
            require("bufferline").setup()

            vim.keymap.set("n", "<leader>bp", "<cmd>BufferLineCyclePrev<cr>",  silent = true )
            vim.keymap.set("n", "<leader>bn", "<cmd>BufferLineCycleNext<cr>",  silent = true )
            vim.keymap.set("n", "<leader>bd", "<cmd>bd<cr>",  silent = true )
        end,
    ,
    
        "lukas-reineke/indent-blankline.nvim",
        opts = 
            show_end_of_line = true,
            space_char_blankline = " ",
        ,
    ,
    
        "L3MON4D3/LuaSnip",
        version = "^1.1.0",
        dependencies = 
            "rafamadriz/friendly-snippets",
        ,
        config = function()
            require("luasnip.loaders.from_vscode").lazy_load()
        end,
    ,
    
        "hrsh7th/nvim-cmp",
        dependencies = 
            "hrsh7th/cmp-buffer",
            "hrsh7th/cmp-path",
            "hrsh7th/cmp-nvim-lsp",
            "L3MON4D3/LuaSnip",
            "saadparwaiz1/cmp_luasnip",
        ,
        config = function()
            local cmp = require("cmp")

            cmp.setup(
                snippet = 
                    expand = function(args)
                        require("luasnip").lsp_expand(args.body)
                    end,
                ,
                mapping = cmp.mapping.preset.insert(
                    [\'<C-b>\'] = cmp.mapping.scroll_docs(-4),
                    [\'<C-f>\'] = cmp.mapping.scroll_docs(4),
                    [\'<C-Space>\'] = cmp.mapping.complete(),
                    [\'<C-e>\'] = cmp.mapping.abort(),
                    [\'<CR>\'] = cmp.mapping.confirm( select = true ),
                ),
                sources = cmp.config.sources(
                     name = \'nvim_lsp\' ,
                     name = \'luasnip\' ,
                , 
                     name = \'buffer\' ,
                     name = "path" ,
                ),
            )
        end,
    ,
    
        "williamboman/mason.nvim",
        opts = 
            ui = 
                check_outdated_packages_on_open = false,
            ,
        ,
    ,
    
        "neovim/nvim-lspconfig",
        dependencies = 
            "williamboman/mason.nvim",
            "williamboman/mason-lspconfig.nvim",
            "hrsh7th/cmp-nvim-lsp",
        ,
        config = function()
            require("mason-lspconfig").setup(
                ensure_installed = 
                    "bashls",
                    "clangd",
                    "denols",
                    "pyright",
                    "rust_analyzer",
                ,
            )

            local capabilities = require(\'cmp_nvim_lsp\').default_capabilities()

            local lspcfg = require("lspconfig")
            lspcfg.bashls.setup(
                capabilities = capabilities,
                on_attach = on_attach
            )
            lspcfg.clangd.setup(
                capabilities = capabilities,
                on_attach = on_attach
            )
            lspcfg.denols.setup(
                capabilities = capabilities,
                on_attach = on_attach
            )
            lspcfg.pyright.setup(
                capabilities = capabilities,
                on_attach = on_attach
            )
            lspcfg.rust_analyzer.setup(
                capabilities = capabilities,
                on_attach = on_attach
            )
        end,
    ,
    
        "jose-elias-alvarez/null-ls.nvim",
        dependencies = 
            "nvim-lua/plenary.nvim",
        ,
        config = function()
            local nl = require("null-ls")
            local sources = 
                nl.builtins.diagnostics.eslint_d,
                nl.builtins.diagnostics.ruff,
                nl.builtins.formatting.beautysh,
                nl.builtins.formatting.black,
                nl.builtins.formatting.clang_format,
                nl.builtins.formatting.prettierd,
                nl.builtins.formatting.rustfmt,
                nl.builtins.formatting.sql_formatter,
            
            nl.setup(
                sources = sources,
                on_attach = on_attach,
            )
        end,
    ,
    
        \'numToStr/Comment.nvim\',
        config = true,
    ,
    
        "folke/trouble.nvim",
        dependencies = 
            "nvim-tree/nvim-web-devicons",
        ,
        config = true,
    ,
, 
    git = 
        url_format = "git@github.com:%s",
    ,
)

用代码过中秋,python海龟月饼你要不要尝一口?

        目 录:

一、2022年中秋祝福

二、Python 海龟画图主要方法

(1)海龟画图的主要步骤

(2)海龟画图的坐标体系

(3)海龟画图的一些建议

三、海龟画图常用命令

1、初始化

2、画笔属性

3、画笔运动命令

4、 画笔颜色控制命令

5、全局控制命令

四、中秋月饼图片欣赏

五、收集的“用代码画月饼”作品系列:​

1.冰皮月饼

2、Crossin牌“月饼”

3、福字月饼

4、花纹月饼

5、MATLAB绘制一款2.5D月饼

六、2022中秋节程序员作品集


一、2022年中秋祝福

   这次2022年CSDN中秋征文的主题是程序员过中秋的一百种方式,我属程序员吗?答案是否定的。如果一个人能越早把自己清晰定位,就能在某个方面做到极致,越早做出成绩,这种方法是正确的。每个人的天赋不一样,人生际遇也不一样。我没有把自己定位在某一个固定点上,因为我觉得很多东西都是看似无关,但却有联系,懂了,你就能发现理解一些。。。

  这个世界每天都在变化,特别是一些高科技(不特指某一个方面,是各种高新技术的综合体)的突飞猛进,有时真的会让人觉得。。。如果你遇到一些不可思议的事情,请不要害怕,照顾好自己,珍惜身边每一个对你好的人。平时不要轻易自满,这个世界上永远会有比你本事高的人和团体。

  话题扯远了,还是聊中秋吧。程序员过中秋,可以用代码编织一份与众不同的祝福,为身边的人送上一份独特的礼物。例如,用代码定制月饼,定制中秋贺卡等等。

  这次中秋我用python画了一个月饼送给大家,python动画画面构思:江山如画,皓月当空,琴音袅袅,逆境清醒借CSDN这个平台和大家一起分享中秋月饼,祝大家中秋快乐!

  走寻半生仍笑叹,愿你释怀世间愁与冷,得失看平淡。愿你开怀永不孤单,让快乐弥漫。愿星光为你,漆黑里指路,萤火明晰双眼,辨分真与假。愿你的身后,总有力量,愿你成为自己的太阳!愿你永驻时光!

二、Python 海龟画图主要方法

  海龟绘图(turtle库)是python的内部模块,使用前导入即可 import turtleku

  海龟有几个关键属性:方向、位置和画笔属性

(1)海龟画图的主要步骤

  通常我们绘图时

  第一步,导入海龟库和绘图时可能用到的一些库,例如随机函数库random,numpy库等等,具体要看实际情况。

  使用方法:

  import turtle

  import random

  

  第二步,使用setup()设置画布尺寸

  画布(canvas):

  画布就是我们用于绘图的区域, 我们可以设置它的大小和初始位置

  设置画布大小:

  1. turtle.screensize(canvwidth=None, canvheight=None, bg=None)

  参数分别为画布的宽(单位像素), 高, 背景颜色

  turtle.screensize()默认大小(400, 300)

  例如:turtle.screensize(800, 600, “black”)

  2. turtle.setup(width=数值, height=数值, startx=None, starty=None)

  setup()设置窗体大小及位置。

  参数:

  width, height:为整数时, 表示像素;

  width, height:为小数时, 表示占据电脑屏幕的比例

  turtle.setup(width=0.5, height=0.85, startx=None, starty=None)

  turtle.setup(width=0.6, height=0.6)

  (startx, starty): 这一坐标表示 矩形窗口左上角顶点的位置, 如果为空,则窗口位于屏幕中心

  如:turtle.setup(width=800, height=800, startx=100, starty=100)

  第三步,设置画笔

  使用Pen()设定海龟画图对象,即画笔:turtle.Pen()

  t = turtle.Pen()

  使用t来代替turtle.Pen()。一劳永逸的做法,可简化输入代码。

(2)海龟画图的坐标体系

  代码执行后就建立了画布,屏幕中间可以看见海龟 (箭头arrow)

  在海龟绘图中,海龟的起点即画布中央为 (0,0),移动单位是像素 (pixel),海龟的头部是x轴方向,为0度。

    turtle绘图中, 就是使用位置方向描述海龟(画笔)的状态

  想象绘图区有一只机器海龟,起始位置在 x-y 平面的 (0, 0) 点。先执行 import turtle,再执行 turtle.forward(15),它将(在屏幕上)朝所面对的 x 轴正方向前进 15 像素,随着它的移动画出一条线段。再执行 turtle.right(25),它将原地右转 25 度。

  描述海龟时使用了两个词语:坐标原点(位置),面朝x轴正方向(方向),

  在画图过程中,如果没明确的指定坐标和角度,那此时所有的角度和位置都是相对的(相对于当前海龟的位置和角度)

画月饼常会用到画圆:turtle.circle(radius, extent=None, steps=None)

参数:

  • radius -- 一个数值

  • extent -- 一个数值 (或 None)

  • steps -- 一个整型数 (或 None)

  绘制一个 radius 指定半径的圆。

  圆心在海龟左边 radius 个单位;

  extent 为一个夹角,用来决定绘制圆的一部分。如未指定 extent* 则绘制整个圆。如果 *extent 不是完整圆周,则以当前画笔位置为一个端点绘制圆弧。如果 radius 为正值则朝逆时针方向绘制圆弧,否则朝顺时针方向。

  最终海龟的朝向会依据 extent 的值而改变。

  圆实际是以其内切正多边形来近似表示的,其边的数量由 steps 指定。

  如果未指定边数则会自动确定。此方法也可用来绘制正多边形。

  画一个半径为100的圆形,circle(100),注意画完后圆心位置不在原点。

(3)海龟画图的一些建议

      a、使用海龟绘图可以编写重复执行简单动作的程序画出精细复杂的形状。

from turtle import *

speed(0)

color('blue', '#87CEFA')

begin_fill()

while True:

    forward(200)

    left(170)

    if abs(pos()) < 1:

        break

end_fill()

将文字排成圆形:

import turtle as t

text="祝大家中秋节快乐"

for i in text:

    t.write(i,align="center",font=("黑体",20,"normal"))

    t.right(360/len(text))

    t.penup()   

    t.forward(40)

t.hideturtle()

t.done()

  b、隐藏画笔;设置速度,可以画得更快些;

  c、海龟绘图时的颜色代码可以参考下面链接

色彩颜色对照表系列(1~5)300种颜色,(16进制、RGB、CMYK、HSV、中英文名)

    挑选出自己喜欢的颜色,拷贝相应的颜色代码值放入海龟颜色设置中。

三、海龟画图常用命令

1、初始化

代码命令

作 用

import turtle

导入海龟库

t = turtle.Pen()

从工具箱子获取海龟画笔

turtle.setup()

画布设置(尺寸,距离)

turtle.bgcolor("black")

画布背景色(例如黑色)

screensize( )  

设置画布窗口的宽度、高度和背昱颜色

2、画笔属性

代码命令

作 用

turtle.pensize(width数字值)

画笔粗细,设置画笔线条的粗细为指定大小

turtle.color('画笔颜色')

画笔颜色   字符串"green", "red" 或者 RGB 3元组

turtle.speed(0)

设置画笔移动速度

画笔绘制的速度范围[0,10]整数,数字越大画笔速度越慢。值1~9,0最快t.speed(0)

turtle.hideturtle()

隐藏海龟图标(隐藏画笔箭头)

turtle.showturtle()

显示海龟图标(显示画笔箭头)

3、画笔运动命令

代码命令

作 用

turtle.forward()

fd(distance)         

向前移动,沿着当前方向前进指定距离

bk(distance)

向后移动,沿着当前相反方向后退指定距离

turtle.right(旋转角度)

画笔右转,turtle. right (90)海龟方向向右转90°

turtle.left(旋转角度)

画笔左转,turtle.left(90)海龟方向向左转90°

turtle.penup()

提笔,抬起画笔

turtle.pendown()

落笔,落下画笔

turtle.goto(x,y横,纵)

控制画笔移动到指定位置,海龟移动到(x,y)位置

turtle.setx(x)

海龟的x坐标移动到指定位置,纵坐标不变

turtle.sety(y)

海龟的y坐标移动到指定位置,横坐标不变

turtle.circle(指定半径, 弧度)

画圆,绘制一个指定半径和角度e的圆或弧线

turtle.dot(半径,color)

画一个圆点(实心)绘制一个指定半径和颜色的圆点

turtle.setheading(angle指向角度)

turtle.seth(angle)

设置当前朝向为angle角度。画笔的指向,右是0,逆时针0-360递增

turtle.home()

设置当前画笔位置为原点,朝向东(默认值)

4、 画笔颜色控制命令

代码命令

作 用

turtle.fillcolor('颜色')

设置 填充颜色

turtle.color(color1, color2)

设置 画笔颜色为color1,填充颜色为color2

可以使用颜色名称或十六进制RGB代码

turtle.begin_fill()

开始填充颜色

turtle.end_fill()

填充完成,结束填充

turtle. pencolor(‘颜色’)

设置画笔颜色

turtle. filling()

返回填充的状态,True为填充。False为未填充

5、全局控制命令

代码命令

作 用

turtle.clear()

清空turtle窗口,但是turtle的位置和状态不会改变(当前窗口清空,当前画笔位置不改变)

turtle.reset()

清空turtle窗口,重置turtle状态为起始状态(当前窗口清空,画笔位置等状态为初始时的默认值)

turtle.undo()

撤销上一个turtle动作(撤销画笔的最后一步动作)

turtle.isvisible()

返回当前turtle是否可见

turtle.done()

关闭画笔,结束绘制,但画面保留

              

代码命令

作 用

t.write("文本" ,align="center",font=("黑体",20,"normal"))

写文本,可指定显示字体,字体大小等align(可选):left,right,center;font(可选):字体名称,字体大小,字体类型(normal,bold,italic)

四、中秋月饼图片欣赏

       要画月饼先要留意月饼长什么样,中秋节少不了月饼,现在的月饼除了传统口味的,还出了不少新口味,外观造型上也有创新,一起来看一下吧。

莲蓉月饼

蛋黄莲蓉月饼

白莲双黄

豆沙月饼

绿豆月饼

五仁月饼

水晶月饼

苏式月饼

五仁月饼(大)

冰皮月饼

绿茶月饼

奶油椰蓉

溏心蛋黄

杨枝甘露

韵香乌龙茶

白桃茉莉花

蓝莓黑莓

夏威夷果仁巧克力

芋泥芝士奇亚籽

金沙奶黄

枣泥核桃

臻品奶黄

栗蓉

红豆

奶黄

黑芝麻

南瓜

五、收集的“用代码画月饼”作品系列:

       这次我用python 海龟画的月饼,因时间的关系,除了增加了情景底图,其他的在代码上没有什么独特之处(我的代码就先不贴出来了),月饼的画法主要借鉴了下面几个作品的思路。让我们一起来学一下吧。

1.冰皮月饼

        个人观点:这款月饼画法简洁,纯海龟作图,入门简单,封装调用,只需修改几个参数就可制作出同款月饼。欠缺的是外观的月饼花纹。

from turtle import *

# 隐藏海龟
hideturtle()
# 颜色模式
colormode(255)
'''
函数说明:

pensize:画笔粗细
pencolor:画笔颜色
fillcolor:填充颜色
begin_fill:开始填充
fd:前进
circle:画圆
right:右转
end_fill():结束填充

'''


def MoonCake(bgcolor, mkcolor, wdcolor, words):
    '''
    参数说明:
    
    bgcolor: 背景颜色
    mkcolor: 月饼颜色
    wdcolor: 文字颜色
    words: 文字(4个字)
    '''
    pensize(2)
    pencolor(0, 0, 0)
    fillcolor(bgcolor)

    begin_fill()
    for i in range(12):
        if i == 5:
            p = pos()
        circle(30, 120)
        right(90)
    end_fill()
    
    penup()
    fd(20)
    pendown()

    fillcolor(mkcolor)
    
    begin_fill()
    for i in range(12):
        circle(30, 120)
        right(90)
    end_fill()

    pencolor(wdcolor)

    left(90)
    fd(140)
    left(90)
    fd(140)
    left(90)
    fd(72)
    p = pos()
    wd1 = words[0:2]
    wd2 = words[2:4]
    write(wd1, font=('Arial', 70, 'normal'))
    fd(70)
    write(wd2, font=('Arial', 70, 'normal'))
    left(90)
    fd(140)


# MoonCake((231, 162, 63), (255, 166, 16), (204, 22, 58), '五仁月饼')

MoonCake((97, 154, 195),(186, 204, 217) ,(17, 101, 154), '冰皮月饼')
mainloop()

作者:二哥不像程序员
原文地址:中秋节快到了,别学Python了,进来排队领块月饼吧【纯手工哪种】!_二哥不像程序员的博客-CSDN博客

2、Crossin牌“月饼”

        个人观点:这款月饼画法上用到了numpy和matplotlib库,需要掌握相应的基础知识。

import numpy as np
from numpy import sin, cos, pi
import matplotlib.pyplot as plt
import matplotlib.patches as mpatch
from matplotlib.patches import Arc, Circle, Wedge
from matplotlib.collections import PatchCollection

length = 20
R = 3**0.5*length/(3**0.5*cos(pi/12)-sin(pi/12))
r = 2*sin(pi/12)*R/3**0.5

arc1 = Arc([0, length], width=2*r, height=2*r, angle=0, theta1=30, theta2=150, ec='orange', linewidth=4)
arc2 = Arc([-length/2, length/2*3**0.5], width=2*r, height=2*r, angle=0, theta1=60, theta2=180, ec='orange', linewidth=4)
arc3 = Arc([-length/2*3**0.5, length/2], width=2*r, height=2*r, angle=0, theta1=90, theta2=210, ec='orange', linewidth=4)
arc4 = Arc([-length, 0], width=2*r, height=2*r, angle=0, theta1=120, theta2=240, ec='orange', linewidth=4)
arc5 = Arc([-length/2*3**0.5, -length/2], width=2*r, height=2*r, angle=0, theta1=150, theta2=270, ec='orange', linewidth=4)
arc6 = Arc([-length/2, -length/2*3**0.5], width=2*r, height=2*r, angle=0, theta1=180, theta2=300, ec='orange', linewidth=4)
arc7 = Arc([0, -length], width=2*r, height=2*r, angle=0, theta1=210, theta2=330, ec='orange', linewidth=4)
arc8 = Arc([length/2, -length/2*3**0.5], width=2*r, height=2*r, angle=0, theta1=240, theta2=360, ec='orange', linewidth=4)
arc9 = Arc([length/2*3**0.5, -length/2], width=2*r, height=2*r, angle=0, theta1=270, theta2=390, ec='orange', linewidth=4)
arc10 = Arc([length, 0], width=2*r, height=2*r, angle=0, theta1=300, theta2=420, ec='orange', linewidth=4)
arc11 = Arc([length/2*3**0.5, length/2], width=2*r, height=2*r, angle=0, theta1=330, theta2=450, ec='orange', linewidth=4)
arc12 = Arc([length/2, length/2*3**0.5], width=2*r, height=2*r, angle=0, theta1=0, theta2=120, ec='orange', linewidth=4)

art_list = [arc1, arc2, arc3, arc4, arc5, arc6, arc7, arc8, arc9, arc10, arc11, arc12]

circle = Circle((0,0), R, ec='orange', fc='white', linewidth=4)

wedge1 = Wedge([-2, 2], R-5, 90, 180, ec='orange', fc=r'white', linewidth=4)
wedge2 = Wedge([-5, 5], R-12, 90, 180, ec='orange', fc=r'white', linewidth=4)
wedge3 = Wedge([-2, -2], R-5, 180, 270, ec='orange', fc=r'white', linewidth=4)
wedge4 = Wedge([-5, -5], R-12, 180, 270, ec='orange', fc=r'white', linewidth=4)
wedge5 = Wedge([2, -2], R-5, 270, 360, ec='orange', fc=r'white', linewidth=4)
wedge6 = Wedge([5, -5], R-12, 270, 360, ec='orange', fc=r'white', linewidth=4)
wedge7 = Wedge([2, 2], R-5, 0, 90, ec='orange', fc=r'white', linewidth=4)
wedge8 = Wedge([5, 5], R-12, 0, 90, ec='orange', fc=r'white', linewidth=4)

art_list.extend([circle, wedge1, wedge2, wedge3, wedge4, wedge5, wedge6, wedge7, wedge8])
fig, ax = plt.subplots(figsize=(8,8))
ax.set_aspect('equal')
for a in art_list:
    ax.add_patch(a)

plt.text(-18, -2.5, 'CROSSIN', fontfamily=r'Times New Man', bbox=dict(boxstyle='square', fc="w", ec='orange', linewidth=4),  fontsize=50, color='orange')

plt.ylim([-35, 35])
plt.xlim([-35, 35])

plt.show()

作者:Crossin的编程教室
原文地址:

中秋节到了,送你一个Python做的Crossin牌“月饼”_Crossin的编程教室的博客-CSDN博客

3、福字月饼

        个人观点:这款月饼是python 海龟月饼,有花纹

import turtle
 
def goto(x, y):#定义提笔的位置
    turtle.penup() #将笔提起,移动时无图
    turtle.goto(x, y)
    turtle.pendown() #将笔放下,移动时绘图。
 
 
def yuebing_wai():
    turtle.pensize(20)#画笔调粗点
    turtle.color( "#F8CD32","#FBA92D")#填充颜色,F8CD32是圆圈的边缘颜色,FBA92D是圆圈的填充颜色
    goto(0, -200)#画笔起点位于(0,0)点的下方200向量处
    turtle.begin_fill()#准备开始填充
    turtle.circle(200)#定义半径
    turtle.end_fill()#填充结束
 
 
def yuebing_zhong():
    goto(0, 0)#画笔起点位于(0,0)处
    turtle.color("#F0BE7C")
    for _ in range(20):#_是占位符,表示临时变量,仅用一次,后面无需再用到 
        turtle.right(18)#顺时针移动18度
        turtle.begin_fill()
        turtle.forward(220)#向前移动的距离
        turtle.circle(40, 180)#上一条向前移动220之后,开始画半径40的半圆
        turtle.goto(0, 0)#画完半圆之后回到(0,0)
        turtle.right(360)#顺时针转个360度
        turtle.end_fill()
 
 
def yuebing_nei():#逻辑同上
    turtle.right(360)
    turtle.color('#F5E16F')#内层颜色
    goto(0, -180)
    for _ in range(12):
        turtle.begin_fill()
        turtle.circle(60, 120)
        turtle.left(180)
        turtle.circle(60, 120)
        turtle.end_fill()
 
 
def fu():#
    turtle.right(50)
    goto(-70, -80)#更高坐标尽量使字靠中间
    turtle.color("Gold")#颜色
    turtle.write("福", font=("华文隶书", 120, "bold"))
    turtle.done()
 
 
if __name__ == '__main__':
    turtle.speed(90)
    yuebing_zhong()
    yuebing_wai()
    yuebing_nei()
    fu()
 
 
turtle.done()  

作者:weixin_39912368
原文地址: 

python趣味代码_趣味项目:用Python代码做个月饼送给你!_weixin_39912368的博客-CSDN博客


4、花纹月饼

       个人观点:这款月饼属纯python 海龟绘制,外观精致,有花纹和文字,用函数定义了月饼的不同部分,修改起来不难。

import turtle

t = turtle.Pen()  # 画笔一 用于画图
t.speed(0)


# 花纹颜色 #F29407
# 饼身颜色 #F8B41A

# 画 饼身部分
def outfill_flower(flower_num: "花瓣数量", flower_color: "花瓣颜色"):
    for i in range(flower_num):
        t.left(i * (360 // flower_num))
        t.color(flower_color)
        t.penup()
        t.forward(200)
        t.pendown()
        t.fillcolor(flower_color)
        t.begin_fill()
        t.circle(60)
        t.end_fill()
        t.penup()
        t.home()


# 画 饼身外围 花纹部分
def out_line_flower(flower_num: "花纹数量", flower_color: "花纹颜色"):
    for i in range(flower_num):
        t.pensize(5)
        t.left(i * (360 // 18))
        t.color(flower_color)
        t.penup()
        t.forward(192)
        t.pendown()
        t.circle(60)
        t.penup()
        t.home()


# 画内测的大圆 大圆的填充色比饼身略亮
def big_circle(circle_color: "大圆颜色", circle_fill_color: "大圆填充颜色", circle_size: "大圆半径"):
    t.goto(circle_size, 0)
    t.left(90)
    t.pendown()
    t.pensize(8)
    t.color(circle_color)
    t.fillcolor(circle_fill_color)
    t.begin_fill()
    t.circle(circle_size)
    t.end_fill()
    t.penup()
    t.home()


# 饼上印花文字 文字内容和坐标用字典存储
def write_font(text_content: "文本内容", text_color: "文本颜色", size: "文字大小"):
    t.color(text_color)
    for x in text_content:
        t.penup()
        t.goto(text_content[x])
        t.write(x, align='center', font=('simhei', size, 'bold'))
    t.penup()
    t.home()
    t.color('#F29407')


# 饼身中间矩形条纹部分
def body_center_line(width: "矩形宽度", height: "矩形高度"):
    t.penup()
    t.home()
    t.pensize(4)
    t.pendown()
    t.backward(width / 2)
    t.forward(width)
    t.left(90)
    t.forward(height)
    t.left(90)
    t.forward(width)
    t.left(90)
    t.forward(height * 2)
    t.left(90)
    t.forward(width)
    t.left(90)
    t.forward(height)
    t.penup()
    t.home()


# 矩形条纹两侧的四个花纹 画笔轨迹是一样的 所以只需要传入不同的初始位置和角度即可复用代码
def center_flower(start_point: "落笔位置", start_angle: "落笔朝向", angle_direction_change: "新朝向",
                  rectangle_height: "矩形高度", circle_direction: "花纹弧度"):
    t.penup()
    t.goto(start_point)
    t.pendown()
    t.setheading(start_angle)
    t.forward(10)
    t.setheading(angle_direction_change)
    t.forward(20)
    t.backward(rectangle_height * 2)
    t.forward(rectangle_height * 2)
    t.setheading(start_angle)
    t.circle(circle_direction * 70, 90)
    t.setheading(start_angle + 180)
    t.forward(60)
    t.setheading(angle_direction_change)
    t.forward(30)
    t.penup()
    t.home()


# 饼身上下左右的花纹
def out_flower(begin_x: "落笔横坐标", begin_y: "落笔纵坐标", start_angle: "落笔朝向"):
    t.penup()
    t.goto(begin_x, begin_y)
    t.pendown()
    t.setheading(start_angle)
    t.forward(20)
    t.right(90)
    t.circle(-100, 20)

    t.penup()
    t.goto(begin_x, begin_y)
    t.pendown()
    t.setheading(start_angle)
    t.right(90)
    t.circle(-100, 30)
    t.left(90)
    t.forward(45)
    t.left(95)
    t.circle(190, 50)
    t.left(95)
    t.forward(45)
    t.left(90)
    t.circle(-100, 31)
    t.setheading(start_angle)
    t.forward(20)
    t.left(90)
    t.circle(100, 20)
    t.penup()
    t.home()

# 以下代码开始调用各种功能
if __name__ == "__main__":
	# 设置画布名称
    t.screen.title('中秋快乐')
    # 画 饼身部分
    outfill_flower(18, '#F8B41A')
    # 画 饼身外围 花纹部分
    out_line_flower(18, '#F29407')
    # 画内测的大圆 大圆的填充色比饼身略亮
    # big_circle('#F29407','#F8B41A',200)
    big_circle('#F29407', '#F8B51D', 200)
    # 饼上印花文字 文字内容和坐标用字典存储
    text_content = '花': (-100, 70), '好': (100, 70), '月': (100, -120), '圆': (-98, -125)  # 圆字坐标最后向下微调了一下
    # write_font(text_content,'#F29407',40)
    write_font(text_content, '#FC932B', 40)
    # 饼身中间矩形条纹部分
    body_center_line(12, 80)
    # 矩形条纹两侧的四个花纹
    center_flower((6, 60), 0, 90, 80, -1)
    center_flower((6, -60), 0, -90, 80, 1)
    center_flower((-6, 60), 180, 90, 80, 1)
    center_flower((-6, -60), 180, -90, 80, -1)
    # 饼身上下左右的花纹
    out_flower(6, 110, 90)
    out_flower(-110, 6, 180)
    out_flower(-6, -110, 270)
    out_flower(110, -6, 360)
    # 可以再加点字
    # text_content2 = '天': (-50, 30), '地': (50, 30), '仁': (50, -60), '和': (-50, -60)  # 圆字坐标最后向下微调了一下
    # write_font(text_content2, '#F29407',30)

    # 隐藏画笔
    t.hideturtle()
    # 保持画布显示
    turtle.done()



作者:浪淘三千
原文地址:python画中秋月饼,用turtle海龟库画中秋月饼_浪淘三千的博客-CSDN博客_python画月饼

5、MATLAB绘制一款2.5D月饼

        个人观点:这款月饼是MATLAB绘制的,月饼花纹精致、立体。透视感可略作修改。

function moonCake
% @author:slandarer
ax=gca;
hold(ax,'on');
axis equal
ax.XLim=[-15,15];
ax.YLim=[-15,15];
CSet=[0.92 0.51 0.11;1 0.7 0.09;0

以上是关于Neovim,要尝一口不?的主要内容,如果未能解决你的问题,请参考以下文章

Vim和Neovim安装YouCompleteMe

使用 CMAKE 为 C++ 设置 Neovim

Mac 安装neovim

neovim 使用系统剪切板

Neovim scp不会提示输入密码

win10安装neovim