├── docs
├── logo.png
├── リテラチュア.mp3
├── tags.md
├── tutorials
│ ├── images
│ │ ├── 0-1.dark.png
│ │ └── 0-1.light.png
│ ├── chapter_01
│ │ ├── images
│ │ │ ├── 2-1.dark.png
│ │ │ ├── 2-1.light.png
│ │ │ ├── 2-1-win10.dark.png
│ │ │ └── 2-1-win10.light.png
│ │ ├── index.md
│ │ ├── 2.md
│ │ ├── 1.md
│ │ └── 3.md
│ ├── chapter_02
│ │ ├── images
│ │ │ ├── 1-1.dark.png
│ │ │ └── 1-1.light.png
│ │ ├── index.md
│ │ ├── 1.md
│ │ └── 2.md
│ ├── chapter_03
│ │ ├── images
│ │ │ ├── 1-1.dark.png
│ │ │ ├── 1-1.light.png
│ │ │ ├── 1-2.dark.png
│ │ │ ├── 1-2.light.png
│ │ │ ├── 1-3.dark.png
│ │ │ ├── 1-3.light.png
│ │ │ ├── 1-4.dark.png
│ │ │ ├── 1-4.light.png
│ │ │ ├── 1-5.dark.png
│ │ │ ├── 1-5.light.png
│ │ │ ├── 1-6.dark.png
│ │ │ ├── 1-6.light.png
│ │ │ ├── 2-1.dark.png
│ │ │ ├── 2-1.light.png
│ │ │ ├── 2-10.dark.png
│ │ │ ├── 2-11.dark.png
│ │ │ ├── 2-2.dark.png
│ │ │ ├── 2-2.light.png
│ │ │ ├── 2-3.dark.png
│ │ │ ├── 2-3.light.png
│ │ │ ├── 2-4.dark.png
│ │ │ ├── 2-4.light.png
│ │ │ ├── 2-5.dark.png
│ │ │ ├── 2-5.light.png
│ │ │ ├── 2-6.dark.png
│ │ │ ├── 2-6.light.png
│ │ │ ├── 2-7.dark.png
│ │ │ ├── 2-7.light.png
│ │ │ ├── 2-8.dark.png
│ │ │ ├── 2-8.light.png
│ │ │ ├── 2-9.dark.png
│ │ │ ├── 2-9.light.png
│ │ │ ├── 3-1.dark.png
│ │ │ ├── 3-1.light.png
│ │ │ ├── 3-2.dark.png
│ │ │ ├── 3-2.light.png
│ │ │ ├── 3-3.dark.png
│ │ │ ├── 3-3.light.png
│ │ │ ├── 2-10.light.png
│ │ │ ├── 2-11.light.png
│ │ │ ├── 1-3-win10.dark.png
│ │ │ ├── 1-4-win10.dark.png
│ │ │ ├── 1-5-win10.dark.png
│ │ │ ├── 1-6-win10.dark.png
│ │ │ ├── 2-1-win10.dark.png
│ │ │ ├── 2-2-win10.dark.png
│ │ │ ├── 2-3-win10.dark.png
│ │ │ ├── 2-4-win10.dark.png
│ │ │ ├── 2-5-win10.dark.png
│ │ │ ├── 2-6-win10.dark.png
│ │ │ ├── 2-7-win10.dark.png
│ │ │ ├── 3-1-win10.dark.png
│ │ │ ├── 3-2-win10.dark.png
│ │ │ ├── 3-3-win10.dark.png
│ │ │ ├── 1-3-win10.light.png
│ │ │ ├── 1-4-win10.light.png
│ │ │ ├── 1-5-win10.light.png
│ │ │ ├── 1-6-win10.light.png
│ │ │ ├── 2-1-win10.light.png
│ │ │ ├── 2-10-win10.dark.png
│ │ │ ├── 2-10-win10.light.png
│ │ │ ├── 2-11-win10.dark.png
│ │ │ ├── 2-11-win10.light.png
│ │ │ ├── 2-2-win10.light.png
│ │ │ ├── 2-3-win10.light.png
│ │ │ ├── 2-4-win10.light.png
│ │ │ ├── 2-5-win10.light.png
│ │ │ ├── 2-6-win10.light.png
│ │ │ ├── 2-7-win10.light.png
│ │ │ ├── 3-1-win10.light.png
│ │ │ ├── 3-2-win10.light.png
│ │ │ └── 3-3-win10.light.png
│ │ ├── index.md
│ │ ├── 3.md
│ │ ├── 1.md
│ │ └── 2.md
│ ├── chapter_04
│ │ ├── images
│ │ │ ├── 1-1.dark.gif
│ │ │ ├── 1-1.light.gif
│ │ │ ├── 1-2.dark.gif
│ │ │ ├── 1-2.light.gif
│ │ │ ├── 1-3.dark.gif
│ │ │ ├── 1-3.light.gif
│ │ │ ├── 1-4.dark.gif
│ │ │ ├── 1-4.light.gif
│ │ │ ├── 1-5.dark.gif
│ │ │ ├── 1-5.light.gif
│ │ │ ├── 1-6.dark.gif
│ │ │ ├── 1-6.light.gif
│ │ │ ├── 1-7.dark.gif
│ │ │ ├── 1-7.light.gif
│ │ │ ├── 1-8.dark.gif
│ │ │ ├── 1-8.light.gif
│ │ │ ├── 1-9.dark.gif
│ │ │ ├── 1-9.light.gif
│ │ │ ├── 2-1.dark.png
│ │ │ ├── 2-1.light.png
│ │ │ ├── 2-2.dark.png
│ │ │ ├── 2-2.light.png
│ │ │ ├── 2-3.dark.png
│ │ │ ├── 2-3.light.png
│ │ │ ├── 2-4.dark.gif
│ │ │ └── 2-4.light.gif
│ │ ├── index.md
│ │ ├── 3.md
│ │ ├── 2.md
│ │ └── 1.md
│ ├── chapter_05
│ │ ├── images
│ │ │ ├── 1-1.dark.png
│ │ │ ├── 1-1.light.png
│ │ │ ├── 2-1.dark.png
│ │ │ └── 2-1.light.png
│ │ ├── index.md
│ │ ├── 2.md
│ │ └── 1.md
│ ├── chapter_06
│ │ ├── index.md
│ │ └── 1.md
│ └── index.md
├── practices
│ └── index.md
├── overrides
│ ├── main.html
│ ├── statistics_template.html
│ └── partials
│ │ ├── comments.html
│ │ ├── content.html
│ │ └── header.html
└── index.md
├── requirements.txt
├── LICENSE.txt
├── README.md
├── scripts
└── gen_doc_pages.py
├── .gitignore
└── mkdocs.yml
/docs/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/logo.png
--------------------------------------------------------------------------------
/docs/リテラチュア.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/リテラチュア.mp3
--------------------------------------------------------------------------------
/docs/tags.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | icon: material/tag
4 | ---
5 |
6 | # 标签索引
7 |
8 |
--------------------------------------------------------------------------------
/docs/tutorials/images/0-1.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/images/0-1.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/images/0-1.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/images/0-1.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_01/images/2-1.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_01/images/2-1.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_01/images/2-1.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_01/images/2-1.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_02/images/1-1.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_02/images/1-1.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_02/images/1-1.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_02/images/1-1.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-1.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-1.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-1.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-1.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-2.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-2.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-2.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-2.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-3.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-3.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-3.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-3.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-4.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-4.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-4.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-4.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-5.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-5.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-5.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-5.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-6.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-6.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-6.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-6.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-1.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-1.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-1.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-1.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-11.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-11.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-2.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-2.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-2.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-2.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-3.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-3.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-3.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-3.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-4.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-4.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-4.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-4.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-5.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-5.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-5.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-5.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-6.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-6.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-6.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-6.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-7.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-7.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-7.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-7.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-8.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-8.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-8.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-8.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-9.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-9.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-9.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-9.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-1.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-1.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-1.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-1.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-2.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-2.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-2.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-2.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-3.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-3.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-3.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-3.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-1.dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-1.dark.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-1.light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-1.light.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-2.dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-2.dark.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-2.light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-2.light.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-3.dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-3.dark.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-3.light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-3.light.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-4.dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-4.dark.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-4.light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-4.light.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-5.dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-5.dark.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-5.light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-5.light.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-6.dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-6.dark.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-6.light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-6.light.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-7.dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-7.dark.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-7.light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-7.light.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-8.dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-8.dark.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-8.light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-8.light.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-9.dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-9.dark.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/1-9.light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/1-9.light.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/2-1.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/2-1.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/2-1.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/2-1.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/2-2.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/2-2.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/2-2.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/2-2.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/2-3.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/2-3.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/2-3.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/2-3.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/2-4.dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/2-4.dark.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/images/2-4.light.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_04/images/2-4.light.gif
--------------------------------------------------------------------------------
/docs/tutorials/chapter_05/images/1-1.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_05/images/1-1.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_05/images/1-1.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_05/images/1-1.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_05/images/2-1.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_05/images/2-1.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_05/images/2-1.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_05/images/2-1.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-11.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-11.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_01/images/2-1-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_01/images/2-1-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-3-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-3-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-4-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-4-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-5-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-5-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-6-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-6-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-1-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-1-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-2-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-2-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-3-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-3-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-4-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-4-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-5-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-5-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-6-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-6-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-7-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-7-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-1-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-1-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-2-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-2-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-3-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-3-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_01/images/2-1-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_01/images/2-1-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-3-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-3-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-4-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-4-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-5-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-5-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/1-6-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/1-6-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-1-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-1-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-10-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-10-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-10-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-10-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-11-win10.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-11-win10.dark.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-11-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-11-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-2-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-2-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-3-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-3-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-4-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-4-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-5-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-5-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-6-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-6-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/2-7-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/2-7-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-1-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-1-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-2-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-2-win10.light.png
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/images/3-3-win10.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xiaokang2022/maliang-docs/HEAD/docs/tutorials/chapter_03/images/3-3-win10.light.png
--------------------------------------------------------------------------------
/docs/practices/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | icon: material/pencil-circle
4 | ---
5 |
6 | # 实战教学
7 |
8 | !!! tip "很遗憾呢"
9 |
10 | 肥肠抱歉!还没有更新噢~
11 |
12 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_02/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | ---
4 |
5 | # 第二章:容器控件
6 |
7 | 
8 | 
9 |
10 | !!! abstract "章节概述"
11 |
12 | 本章会详细介绍容器控件的使用方式和需要注意的地方。
13 |
14 | `maliang` 中的容器控件包括 `Tk`、`Toplevel`、`Canvas`。
15 |
16 | ## 本章内容
17 |
18 | * [2.1 窗口容器控件](1.md)
19 | * [2.1 画布容器控件](2.md)
20 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_05/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | ---
4 |
5 | # 第五章:颜色
6 |
7 | 
8 | 
9 |
10 | !!! abstract "章节概述"
11 |
12 | 这一章会讲解如何用 `maliang` 构建出绚丽的颜色效果。
13 |
14 | 只会使用默认配色可不是一个好习惯,学会使用各种处理颜色的工具才能写好 GUI 程序。
15 |
16 | ## 本章内容
17 |
18 | * [5.1 颜色格式及其转换](1.md)
19 | * [5.2 颜色处理](2.md)
20 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | ---
4 |
5 | # 第三章:基本控件
6 |
7 | 
8 | 
9 |
10 | !!! abstract "章节概述"
11 |
12 | 本章会详细说明如何使用 `maliang` 中所有的基本控件。
13 |
14 | 所有控件被分为三类:信息类控件、功能类控件和文本类控件。
15 |
16 | ## 本章内容
17 |
18 | * [3.1 信息类控件](1.md)
19 | * [3.2 功能类控件](2.md)
20 | * [3.3 文本类控件](3.md)
21 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | ---
4 |
5 | # 第四章:动画
6 |
7 | 
8 | 
9 |
10 | !!! abstract "章节概述"
11 |
12 | 本章会详细说明如何使用 `maliang` 来做出一些基本的动画。
13 |
14 | 既然 `tkinter` 没有动画,就让 `maliang` 来弥补吧!
15 |
16 | ## 本章内容
17 |
18 | * [4.1 基础动画](1.md)
19 | * [4.2 控制函数](2.md)
20 | * [4.3 自定义动画](3.md)
21 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_06/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | status: new
4 | ---
5 |
6 | # 第六章:主题
7 |
8 | !!! abstract "章节概述"
9 |
10 | 这一章会讲解如何用 `maliang` 自动适配明暗主题以及调用系统相关主题。
11 |
12 | 或许你在前面的章节就已经发现了,只要点击网页顶栏的图标 :material-theme-light-dark: 就会出现神奇的事情:
13 | 不仅网页的颜色主题切换了,连部分展示的图片的颜色主题也切换了!!
14 |
15 | 是的,本文档针对颜色主题做了特殊适配,如果你想提前查看预制的明暗颜色主题的效果,就可以通过这种方式。
16 |
17 | ## 本章内容
18 |
19 | * [6.1 切换颜色主题](1.md)
20 | * 6.2 切换样式主题
21 | * 6.3 设置特殊主题
22 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_01/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | ---
4 |
5 | # 第一章:安装与初识
6 |
7 | 
8 | 
9 |
10 | !!! abstract "章节概述"
11 |
12 | 本章不会深入介绍如何使用 `maliang` 来构建一个图形化的程序,但会介绍如何安装 `maliang` 并通过简单的示例来展示构建一个图形化程序的过程。
13 |
14 | 同时会简要地介绍一下 `maliang` 的框架,方便各位理解 `maliang`。
15 |
16 | ## 本章内容
17 |
18 | * [1.1 环境搭建](1.md)
19 | * [1.2 实现一个简单的界面](2.md)
20 | * [1.3 框架概述](3.md)
21 |
--------------------------------------------------------------------------------
/docs/overrides/main.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 | {% if config.theme.language == "zh" %}
6 |
7 | {% include ".icons/material/file-download.svg" %}
8 |
9 | {% else %}
10 |
11 | {% include ".icons/material/file-download.svg" %}
12 |
13 | {% endif %}
14 |
15 | {{ super() }}
16 | {% endblock content %}
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # core
2 | mkdocs
3 | mkdocs-material
4 |
5 | # markdown
6 | markdown
7 | pymdown-extensions
8 | pygments
9 |
10 | # git
11 | mkdocs-git-committers-plugin-2
12 | mkdocs-git-revision-date-localized-plugin
13 | mkdocs-git-authors-plugin
14 |
15 | # mkdocs plugins
16 | mkdocs-glightbox
17 | mkdocs-redirects
18 | mkdocs-statistics-plugin
19 | mkdocs-minify-plugin
20 | mkdocs-macros-plugin
21 | mkdocs-rss-plugin
22 | mkdocs-print-site-plugin
23 | mkdocs-markmap
24 | mkdocs_puml
25 | markdown-exec
26 |
27 | # search
28 | jieba
29 |
30 | # versioning
31 | mike
32 |
33 | # code documentation
34 | mkdocstrings
35 | mkdocstrings-python
36 | mkdocs-autorefs
37 | mkdocs-gen-files
38 | mkdocs-literate-nav
39 | ruff
40 |
41 | # official griffe extensions
42 | griffe-autodocstringstyle
43 | griffe-inherited-docstrings
44 | griffe-public-redundant-aliases
45 | griffe-public-wildcard-imports
46 | griffe-pydantic
47 | griffe-runtime-objects
48 | griffe-sphinx
49 | griffe-typingdoc
50 | griffe-warnings-deprecated
51 |
52 | # package to be documented
53 | maliang
54 | maliang[ext]
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | statistics: True
3 | comments: true
4 | icon: material/home
5 | ---
6 |
7 | # maliang `3.1.x`
8 |
9 | !!! tip "温馨提示"
10 |
11 | 这里是 `maliang 3.1.x` 系列版本的教程和文档网站,请走错的朋友在网页左上角切换版本哈……😅
12 |
13 | - [X] 您可以通过按下快捷键 ++left++ 和 ++right++ 来快速跳转到上一页和下一页!🎉
14 | - [X] 您可以通过点击页面顶部搜索栏或按下快捷键 / 来快速查找想要的内容!✨
15 | - [X] 您可以通过点击页面顶部主题按钮来切换网站主题,不同主题带来不同的心情!🎨
16 | - [X] 您可以在阅读教程和查阅文档的时候,点击顶部的音乐播放器享受一下作者精选的纯音乐,自动循环播放!🎈
17 | - [X] 您可以在大部分的页面底部找到评论区,登录 GitHub 账号之后就可以公开发表您的想法!👀
18 |
19 | 最后,祝您阅读愉快!❤️
20 |
21 | !!! info ""
22 |
23 |
24 | ```python exec
25 | import time
26 |
27 | print(f"本站最后更新(构建)时间:`#!py {time.strftime("%Y-%m-%d %H:%M:%S %z", time.localtime())}`")
28 | ```
29 |
30 |
31 |
32 | [:fontawesome-solid-circle-arrow-left: 返回主站](https://Xiaokang2022.github.io/maliang/){ .md-button title="点我闪现返回主站!" }
33 | [:fontawesome-solid-paper-plane: 最新内容](./tutorials/chapter_05/index.md){ .md-button title="点我飞到最近更新的内容!" }
34 |
35 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Xiaokang2022
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/docs/overrides/statistics_template.html:
--------------------------------------------------------------------------------
1 |
2 | {% if config.theme.language=='zh' %}
3 | :octicons-pencil-16: 字数 {{ words }} 个 {% if code_lines != 0 %}:octicons-code-16: 代码 {{ code_lines }} 行 {% endif %}{% if page_images %}{% if images != 0 %}:octicons-image-16: 图片 {{ images }} 张 {% endif %}{% endif %}{% if page_read_time %}:octicons-clock-16: {% if read_time == 0 %}阅读时间不到 1 分钟 {% else %}阅读时间 {{ read_time }} 分钟 {% endif %}{% endif %}:octicons-graph-16: 访问量
4 | {% elif config.theme.language=='en' %}
5 | :octicons-pencil-16: {{ words }} word{% if words > 1 %}s{% endif %} {% if code_lines != 0 %}:octicons-code-16: {{ code_lines }} line{% if code_lines > 1 %}s{% endif %} of code {% endif %}{% if page_images %}{% if images != 0 %}:octicons-image-16: {{ images }} image{% if images > 1 %}s{% endif %} {% endif %}{% endif %}{% if page_read_time %}:octicons-clock-16: {% if read_time == 0 %}less than 1 min read {% else %} {{ read_time }} min read {% endif %}{% endif %}:octicons-graph-16: views
6 | {% endif %}
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # maliang-docs
2 |
3 | Official documentation website of the package [`maliang`](https://github.com/Xiaokang2022/maliang)
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | > [!TIP]
15 | > **Homepage:** https://xiaokang2022.github.io/maliang-docs/
16 | > **Mirror:** https://maliang-docs.netlify.app/
17 |
--------------------------------------------------------------------------------
/docs/overrides/partials/comments.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {% if page.meta.comments %}
5 |
10 |
11 |
12 |
46 | {% endif %}
--------------------------------------------------------------------------------
/docs/overrides/partials/content.html:
--------------------------------------------------------------------------------
1 | {#-
2 | This file was automatically generated - do not edit
3 | -#}
4 | {% if "material/tags" in config.plugins and tags %}
5 | {% include "partials/tags.html" %}
6 | {% endif %}
7 | {% include "partials/actions.html" %}
8 | {% if "\x3ch1" not in page.content %}
9 | {{ page.title | d(config.site_name, true)}}
10 | {% endif %}
11 | {{ page.content }}
12 | {% include "partials/source-file.html" %}
13 |
14 |
15 |
69 |
70 | {% include "partials/feedback.html" %}
71 | {% include "partials/comments.html" %}
--------------------------------------------------------------------------------
/docs/tutorials/chapter_01/2.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 入门
5 | ---
6 |
7 | # §1.2 实现一个简单的界面
8 |
9 | 本节不对 `maliang` 的具体使用做详细讲解,这里只是给大家提供一个简单程序体验一下 `maliang`。
10 |
11 | 以最简单的登录窗口为例,说明一下使用 `maliang` 搭建图形界面的流程是怎样的。
12 |
13 | ## 一、登录窗口
14 |
15 | ### 1.1 构建窗口
16 |
17 | 运行以下命令以构建一个标题为 “登录” 并且居中窗口
18 |
19 | ```python
20 | import maliang
21 |
22 | root = maliang.Tk(title="登录")
23 | root.center()
24 | root.mainloop()
25 | ```
26 |
27 | `maliang` 是支持暗色模式的,如果您装有 `darkdetect` 可选依赖包,则 `maliang` 不仅仅会将界面渲染成暗色,窗口也会更改为暗色模式。
28 |
29 | !!! warning "特别注意:窗口的暗色模式可能不生效"
30 |
31 | 窗口本身的暗色模式在部分操作系统上可能不会生效(如部分 Linux 系统),但窗口内部的控件等的暗色模式是可以修改的。关于窗口的暗色模式,模式的检测与第三方包 有关,模式的支持与操作系统及相关第三方包有关,下面是对应关系:
32 |
33 | * Windows: https://github.com/Akascape/py-window-styles
34 | * Linux: 暂不支持手动修改
35 | * macOS: 暂不支持手动修改
36 |
37 | ### 1.2 创建画布
38 |
39 | `maliang` 的宗旨就是,一切都是通过画布“画”出来的,你可以把画布当作网页的页面,每一页就是一个画布实例。使用 `Canvas` 来创建画布。
40 |
41 | ```python hl_lines="6-7"
42 | import maliang
43 |
44 | root = maliang.Tk(title="登录")
45 | root.center()
46 |
47 | cv = maliang.Canvas(auto_zoom=True, keep_ratio="min", free_anchor=True)
48 | cv.place(width=1280, height=720, x=640, y=360, anchor="center")
49 |
50 | root.mainloop()
51 | ```
52 |
53 | ### 1.3 创建控件
54 |
55 | 创建一些控件来实现登录窗口。
56 |
57 | ```python hl_lines="9 11-14 16-17"
58 | import maliang
59 |
60 | root = maliang.Tk(title="登录")
61 | root.center()
62 |
63 | cv = maliang.Canvas(auto_zoom=True, keep_ratio="min", free_anchor=True)
64 | cv.place(width=1280, height=720, x=640, y=360, anchor="center")
65 |
66 | maliang.Text(cv, (640, 200), text="账 号 登 录", fontsize=48, anchor="center")
67 |
68 | maliang.Text(cv, (450, 300), text="账号", anchor="nw")
69 | maliang.InputBox(cv, (450, 340), (380, 50), placeholder="点击输入账号")
70 | maliang.Text(cv, (450, 400), text="密码", anchor="nw")
71 | maliang.InputBox(cv, (450, 440), (380, 50), show="●", placeholder="点击输入密码")
72 |
73 | maliang.Button(cv, (450, 540), (180, 50), text="注 册")
74 | maliang.Button(cv, (650, 540), (180, 50), text="登 录")
75 |
76 | root.mainloop()
77 | ```
78 |
79 | 这样就完成了一个没有功能的登录界面。你可以在此时尝试着更改操作系统颜色模式,看看该窗口的颜色模式会不会跟随改变。(1)
80 | { .annotate }
81 |
82 | 1. 💡你也可以在页面顶栏试着切换网站的主题(点击图标 :material-theme-light-dark: 来切换),看看不同主题下程序运行的效果
83 |
84 | 
85 | 
86 |
87 | /// figure-caption
88 | 教程环境下的运行结果
89 | ///
90 |
91 | !!! tip "温馨提示:界面外观与系统有关"
92 |
93 | 对于不同的操作系统,`maliang` 构建出来的界面的外观不一定相同,若没有强制指定 `maliang` 的系统变量,`maliang` 会自动获取当前系统类型,并根据类型绘制不同的界面外观。如在 Windows10 和 Windows11 中的界面就不相同,Windows10 的界面更符合 Windows10 风格(如下):
94 |
95 | 
96 | 
97 |
--------------------------------------------------------------------------------
/docs/tutorials/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | icon: material/book
4 | ---
5 |
6 | # 官方教程
7 |
8 | !!! warning "特别注意:教程版本要求"
9 |
10 | 目前此教程对应的环境如下(文档构建时自动更新):
11 |
12 | ```python exec
13 | import platform
14 | import sys
15 |
16 | import maliang
17 |
18 | print(f"* maliang: `{maliang.__version__}`")
19 | print(f"* Python: `{sys.version[:6]}`")
20 | print(f"* OS: `{platform.system()}`")
21 | ```
22 |
23 | 若您需要的教程不是该版本,请在网页左上切换版本!
24 |
25 | !!! success "特别提供:相关教程及文档链接"
26 |
27 | * Tcl / Tk 8.6 官方文档:https://www.tcl.tk/man/tcl8.6/contents.htm
28 | * Tcl / Tk 9.0 官方文档:https://www.tcl.tk/man/tcl9.0/
29 | * 个人不完整 Tk 参考教程:https://xiaokang2022.blog.csdn.net/category_11600888.html
30 | * 个人推荐的 Tk 参考教程:https://blog.csdn.net/qq_41556318/category_9283243.html
31 |
32 | ## 一、阅前须知
33 |
34 | ### 1.1 主题说明*
35 |
36 | 此网站主题默认跟随系统,可手动调节为暗色主题或者亮色主题,这不仅会影响网站的颜色外观,更会**影响部分在不同主题下的图片**,因为 `maliang` 涉及亮色和暗色主题,所以部分效果预览图也会同步受网站主题而切换。
37 |
38 | 例如,下面的 “[*图1 在 VSCode 中查看类的文档字符串*](#13-前置需求)” 就受网站主题影响,大家可以试着在页面顶部切换网站主题颜色,看看这张图片有什么变化。
39 |
40 | 此外,本站的所有图片都可以通过点击来放大。
41 |
42 | ### 1.2 图像说明*
43 |
44 | 图形分为两种,一种是由图片文件直接展示的,还有一种是由 Markdown 的 Mermaid 语法代码块生成的。某些时候这些图没有完全生成,而是呈现出一种源代码的状态,此时可以尝试刷新网页重新让它们生成。
45 |
46 | 另外,它们的颜色也与主题有关。
47 |
48 | ### 1.3 前置需求
49 |
50 | 推荐在阅读此教程的同时搭配 Visual Studio Code(以下简称 VSCode)进行开发,使用 PyCharm 或者 Visual Studio 也可以,但我个人更推荐使用 VSCode。
51 |
52 | `maliang 3`(以下简称 `maliang`) 专门对 VSCode 做了文档字符串的优化,可以十分方便地在 VSCode 内看到每个函数、类甚至是常量的详细信息,包括它们的类型、默认值和使用方法。**只需要将鼠标移动到想要查看的函数或者类上面即可**,PyCharm 和 Visual Studio 也有类似的功能,但渲染效果不如 VSCode 的那么好。虽然可以直接查看文档字符串,但 `maliang` 在开发的时候为了力求符合 [PEP 8](https://peps.python.org/pep-0008/) 的规则,所以文档字符串均是英文的。阅读起来不方便的朋友们可以在本站查阅教程来进行辅助开发。
53 |
54 | 
55 | 
56 |
57 | /// figure-caption
58 | 在 VSCode 中查看类的文档字符串
59 | ///
60 |
61 | ## 二、想说的一些事情
62 |
63 | ### 2.1 关于该项目名字的由来
64 |
65 | 实际上,该项目的旧版本并不叫 `maliang`,而是 `tkintertools`。这是因为在以前本项目还没有做得这么大的时候,本项目只是一个用来辅助 tkinter 进行开发的工具,所以取名为 `tkinter` 和 tools 的结合,但这个名称将止步于 3.0.0 版本,在这个版本发布前,经过社区投票,我决定更改这个项目的名称,并最终取名为 `maliang`。
66 |
67 | 至于为什么要起这个名字,实际和本项目的最终目标有一定联系,不知大家小时候有没有用画板画程序界面的这种想法?有些人不仅想过,还实际做过,比如我。小时候看着花花绿绿的电脑屏幕,不会编程的我只能用 “画图.exe” 在上面画一些自己幻想的程序,觉得非常好玩。是的,这很好玩,但这并不是真的界面,只是一副可能算不上画的画罢了。但“神笔马良”的故事大家都知道,马良有一支神笔,能让画出来的东西变成真的!要是有这么一个项目,真的能让画出来的界面变成真的,岂不美哉?
68 |
69 | 是的,你想的没错,**通过画画来构建图形界面就是这个项目的终极目标**。因此,该项目被重命名为了 `maliang`。这个时候就有人要问了,你这怎么只有“马良”,你的“神笔”呢?别急!“神笔”也是有的,本项目只是一个 UI 框架,但还需一个配套的可视化开发软件,而这个软件就是“神笔”,目前“神笔”项目还处于初期阶段,只能实现控件的拖拽,但随着不断的开发,它的功能将越来越强大。
70 |
71 | “神笔”项目也是开源的,项目链接为:
72 |
73 | ### 2.2 养成看教程和文档的好习惯
74 |
75 | 教程和文档是最好的资源,实时更新和维护,尽可能保证准确性,养成看教程和文档的好习惯会让你的开发事半功倍。
76 |
77 | ~~所以不要有事没事儿就问我这问我那,以及在评论区问东问西(bushi~~
78 |
--------------------------------------------------------------------------------
/scripts/gen_doc_pages.py:
--------------------------------------------------------------------------------
1 | """Generate the document pages."""
2 |
3 | import inspect
4 | import pathlib
5 | import typing
6 |
7 | import maliang
8 | import maliang.media
9 | import maliang.mpl
10 | import maliang.table
11 | import maliang.three
12 | import mkdocs_gen_files
13 |
14 | DIR: typing.Final[str] = "documents"
15 | MOD_SYMBOL: typing.Final[str] = ''
16 | PKG_SYMBOL: typing.Final[str] = ''
17 |
18 | nav = mkdocs_gen_files.Nav()
19 | src = pathlib.Path(inspect.getfile(maliang)).parent
20 |
21 |
22 | def get_data(values: str, /) -> tuple[str, str]:
23 | """Returns the repo and version of a parts."""
24 | if "media" in values:
25 | return "maliang-media", maliang.media.__version__
26 | if "mpl" in values:
27 | return "maliang-mpl", maliang.mpl.__version__
28 | if "three" in values:
29 | return "maliang-three", maliang.three.__version__
30 | if "table" in values:
31 | return "maliang-table", maliang.table.__version__
32 | return "maliang", maliang.__version__
33 |
34 |
35 | with mkdocs_gen_files.open(f"{DIR}/summary.md", "w") as nav_file:
36 | for path in sorted(src.rglob("*.py")):
37 | module_path = maliang.__name__ / path.relative_to(src).with_suffix("")
38 | doc_path = path.relative_to(src).with_suffix(".md")
39 | full_doc_path = DIR / doc_path
40 | parts = tuple(module_path.parts)
41 | file = "/".join(parts) + ".py"
42 |
43 | symbol = MOD_SYMBOL
44 |
45 | if parts[-1] == "__init__":
46 | parts = parts[:-1]
47 | doc_path = doc_path.with_name("index.md")
48 | full_doc_path = full_doc_path.with_name("index.md")
49 | symbol = PKG_SYMBOL
50 | elif parts[-1] == "__main__":
51 | continue
52 |
53 | with mkdocs_gen_files.open(full_doc_path, "w") as fd:
54 | identifier = ".".join(parts)
55 | if full_doc_path == pathlib.Path(f"{DIR}/index.md"):
56 | fd.write(f"---\ntitle: {identifier}\ncomments: true\nicon: material/file-document\n---\n\n")
57 | else:
58 | fd.write(f"---\ntitle: {identifier}\n---\n\n")
59 | fd.write(f"# {symbol} {identifier}\n\n")
60 | repo, tag = get_data(file)
61 | fd.write(f":octicons-mark-github-16: 源代码:[`{file}`](https://github.com/Xiaokang2022/{repo}/blob/{tag}/{file}){{ target='_blank' }} \n\n")
62 | fd.write(f"::: {identifier}\n")
63 |
64 | if full_doc_path == pathlib.Path(f"{DIR}/index.md"):
65 | nav_file.write("* [](index.md)\n")
66 | else:
67 | space = " " if symbol == MOD_SYMBOL else ""
68 | nav_file.write(f"{space}* [{symbol} {parts[-1]}]({str(doc_path).replace("\\", "/")})\n")
69 |
--------------------------------------------------------------------------------
/docs/overrides/partials/header.html:
--------------------------------------------------------------------------------
1 | {#-
2 | This file was automatically generated - do not edit
3 | -#}
4 | {% set class = "md-header" %}
5 | {% if "navigation.tabs.sticky" in features %}
6 | {% set class = class ~ " md-header--shadow md-header--lifted" %}
7 | {% elif "navigation.tabs" not in features %}
8 | {% set class = class ~ " md-header--shadow" %}
9 | {% endif %}
10 |
11 |
65 | {% if "navigation.tabs.sticky" in features %}
66 | {% if "navigation.tabs" in features %}
67 | {% include "partials/tabs.html" %}
68 | {% endif %}
69 | {% endif %}
70 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
110 | .pdm.toml
111 | .pdm-python
112 | .pdm-build/
113 |
114 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
115 | __pypackages__/
116 |
117 | # Celery stuff
118 | celerybeat-schedule
119 | celerybeat.pid
120 |
121 | # SageMath parsed files
122 | *.sage.py
123 |
124 | # Environments
125 | .env
126 | .venv
127 | env/
128 | venv/
129 | ENV/
130 | env.bak/
131 | venv.bak/
132 |
133 | # Spyder project settings
134 | .spyderproject
135 | .spyproject
136 |
137 | # Rope project settings
138 | .ropeproject
139 |
140 | # mkdocs documentation
141 | /site
142 |
143 | # mypy
144 | .mypy_cache/
145 | .dmypy.json
146 | dmypy.json
147 |
148 | # Pyre type checker
149 | .pyre/
150 |
151 | # pytype static type analyzer
152 | .pytype/
153 |
154 | # Cython debug symbols
155 | cython_debug/
156 |
157 | # PyCharm
158 | .idea/
159 |
160 | # VSCode
161 | .vscode/
--------------------------------------------------------------------------------
/docs/tutorials/chapter_01/1.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 入门
5 | - 安装
6 | - 环境搭建
7 | ---
8 |
9 | # §1.1 环境搭建
10 |
11 | ## 一、环境要求
12 |
13 | 
14 | 
15 | 
16 | 
17 | 
18 |
19 | `maliang` 运行要求 Python 版本大于等于 `3.10`,操作系统没有过多要求(Windows、macOS、Linux 均可)。(1)
20 | {.annotate}
21 |
22 | 1. 💡但实际上我更推荐使用 Windows 操作系统
23 |
24 | **推荐使用 Python 3.11 及以上版本**。
25 |
26 | ## 二、安装 `maliang`
27 |
28 | ### 2.1 纯净安装
29 |
30 | `maliang` 目前的依赖包只有 Python 官方的 ,安装时会自动安装依赖:
31 |
32 | ```shell linenums="0"
33 | pip install maliang
34 | ```
35 |
36 | ### 2.2 完整安装
37 |
38 | 若想获取 `maliang` 的完整功能,用如下命令进行安装:
39 |
40 | ```shell
41 | pip install maliang[opt]
42 | pip install maliang[ext]
43 | ```
44 |
45 | 上述命令的第一条是安装 `maliang` 及其全部的可选依赖包,第二条命令是安装 `maliang` 的官方扩展包。
46 |
47 | 所有的可选依赖包信息如下:
48 |
49 | - : 提供操作系统主题检测
50 | - : 提供更多类型图片的使用及优化图片缩放速度
51 | - : 提供一些 Windows 系统的窗口效果
52 | - : 提供更多 Windows 系统窗口的配置选项
53 | - : 提供更多 Windows 系统窗口的配置选项
54 |
55 | 所有的官方扩展包信息如下:
56 |
57 | - : 提供 `matplotlib` 包的相关支持
58 | - : 提供媒体文件的相关支持
59 | - : 提供简单 3D 绘图的相关支持
60 | - : 提供表格控件的相关支持
61 |
62 | 如果您只想安装上述的部分包,可以单独使用 pip 进行安装。
63 |
64 | ### 2.3 推荐安装
65 |
66 | 以下是安装命令:
67 |
68 | ```shell linenums="0"
69 | pip install maliang[opt]
70 | ```
71 |
72 | `maliang` 目前所必须安装的依赖包只有上面提到的一个,它只是用来强化类型提示的,但为了您的良好体验,建议安装推荐的可选依赖包,即用 pip 安装时加上上述命令的 "opt" 字段。
73 |
74 | ### 2.4 升级安装
75 |
76 | 如果您之前安装过 `maliang`,但并不是最新版本,您可以通过以下命令进行升级:
77 |
78 | ```shell linenums="0"
79 | pip install --upgrade maliang
80 | ```
81 |
82 | 当然,如果需要同步升级可选包或者扩展包,你可能需要下面的命令:
83 |
84 | ```shell
85 | pip install --upgrade maliang[opt]
86 | pip install --upgrade maliang[ext]
87 | ```
88 |
89 | ### 2.5 检验安装
90 |
91 | 运行以下代码来检验 `maliang` 是否安装成功:
92 |
93 | ```shell linenums="0"
94 | pip show maliang
95 | ```
96 |
97 | 若运行无误,则可以在终端输出中看到当前 `maliang` 的版本。
98 |
99 | ## 三、体验最新功能
100 |
101 | 有些功能可能并未存在于当前最新版的 `maliang` 中,这就需要下载安装最新提交的版本,其安装方式并不是直接同 PyPI 上下载,而是克隆存储库后再下载的。
102 |
103 | !!! warning "特别注意:最新版本可能构建失败"
104 |
105 | 最新版本是实时在源代码仓库中构建的,但并不能保证检查和测试完全通过,其实时状态如下(注意测试覆盖率可能并非 100%):
106 |
107 | [](https://github.com/Xiaokang2022/maliang/actions)
108 | [](https://codecov.io/gh/Xiaokang2022/maliang)
109 |
110 | 下面是安装命令:
111 |
112 | ```shell
113 | git clone https://github.com/Xiaokang2022/maliang.git
114 | cd maliang
115 | pip install . #(1)!
116 | ```
117 |
118 | 1. 当然,你也可以这样写
119 |
120 | ```shell linenums="0"
121 | pip install .[opt]
122 | ```
123 |
124 | 或者
125 |
126 | ```shell linenums="0"
127 | pip install .[ext]
128 | ```
129 |
130 | 另附:如果无法访问 GitHub,可使用镜像源同名仓库的地址:(1)
131 | { .annotate }
132 |
133 | 1. 镜像源数据一般会在 24 小时内同步,可能更新不及时,一切以 GitHub 的数据为准!
134 |
135 | - Gitee(首选镜像源):
136 |
137 | ```shell
138 | git clone https://gitee.com/Xiaokang2022/maliang.git
139 | cd maliang
140 | pip install .
141 | ```
142 |
143 | - GitCode:
144 |
145 | ```shell
146 | git clone https://gitcode.com/Xiaokang2022/maliang.git
147 | cd maliang
148 | pip install .
149 | ```
150 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/3.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 控件
5 | - 文本
6 | ---
7 |
8 | # §3.3 文本类控件
9 |
10 | ## 一、文本类控件简述
11 |
12 | ### 1.1 什么是文本类控件
13 |
14 | 文本类控件就是功能主要与文本有关的一类控件,最典型的就是输入框控件了。由于涉及文本的相关功能多且复杂,因此 `maliang` 目前对文本类控件的支持还不是很好,某些功能还没有完全实现。
15 |
16 | 目前 `maliang` 内置的文本类控件有 `InputBox`、`SpinBox` 和 `ComboBox`。但这三个都是对于单行文本进行操作的控件,关于多行文本的控件,将在未来加入 `maliang`。
17 |
18 | ### 1.2 它们是如何运作的
19 |
20 | 其实,`maliang` 的文本类控件不像前面章节讲的那些控件一样,文本类控件实现起来非常复杂,为了遵循 `maliang` 一切都是绘制出来的宗旨以及实现某些特殊的功能,`maliang` 不得不做了妥协,借用 `tkinter` 中相对底层的 API 来“重绘”文本类控件,而不是直接使用 `tkinter` 的文本控件。
21 |
22 | 文本类控件需要实现大量功能,如复制、剪切、粘贴、文本选中、光标显示、文本显示、换行处理、字符替换等等,其中最复杂的莫过于文本的显示和选中了。我们知道一个输入框应该是有一定范围的,超出这个范围的字符是不会显示的,但 `maliang` 中的一切都是用画布绘制的,只能绘制,无法擦除,导致 `maliang` 无法像其它 UI 框架那样直接限制文本的范围来呈现出一种文本被切割的样子,`maliang` 只能通过控制字符显示的数量来达到类似的效果。而不同字符的宽度并不相同,更别说还要根据字体来计算,这就极大地增加了实现文本显示以及文本选中的功能的难度。
23 |
24 | ### 1.3 目前存在的缺陷
25 |
26 | 目前 `maliang` 对于文本类控件还是实现了一定的基本功能,但仍存在一些问题,如文本选中不完善,无法选中“框外隐藏”的文本,这一功能同时导致了全选功能只能选中显示出来的文本,而非真正的全选。不过在未来会实现这个功能的,目前只是暂时未实现而已。
27 |
28 | ## 二、文本类控件详述
29 |
30 | ### 2.1 [`InputBox`][maliang.standard.widgets.InputBox]
31 |
32 | `InputBox` 就是输入框控件,是 `tkinter` 的控件 `Entry` 的平替,但相对 `Entry` 又有增强。我们可以通过设定其各个初始化参数来达到相应的要求,如通过设置参数 `align` 来设定文本的靠左、居中和靠右,设置参数 `show` 来替换原来显示的字符,设置参数 `placeholder` 来设定一个提示文本等。
33 |
34 | 下面是一个简单的示例,其设定一个提示文本,在控件内容为空且处于 `#!python "normal"` 状态时,会以灰色显示这个提示文本:
35 |
36 | ```python hl_lines="7"
37 | import maliang
38 |
39 | root = maliang.Tk()
40 | cv = maliang.Canvas(auto_zoom=True)
41 | cv.place(width=1280, height=720)
42 |
43 | maliang.InputBox(cv, (20, 20), placeholder="InputBox")
44 |
45 | root.mainloop()
46 | ```
47 |
48 | 效果如下:
49 |
50 | === ":fontawesome-brands-microsoft: Windows11 风格"
51 |
52 |
53 | 
54 | 
55 | 图1 输入框控件
56 |
57 |
58 | === ":fontawesome-brands-windows: Windows10 风格"
59 |
60 |
61 | 
62 | 
63 | 图1 输入框控件
64 |
65 |
66 | ### 2.2 [`SpinBox`][maliang.standard.widgets.SpinBox]
67 |
68 | 从名称上就知道,这个控件对标的就是 `tkinter` 的 `SpinBox` 控件,功能类似的,不再赘述。
69 |
70 | 下面是一个简单的示例:
71 |
72 | ```python hl_lines="7"
73 | import maliang
74 |
75 | root = maliang.Tk()
76 | cv = maliang.Canvas(auto_zoom=True)
77 | cv.place(width=1280, height=720)
78 |
79 | maliang.SpinBox(cv, (20, 20))
80 |
81 | root.mainloop()
82 | ```
83 |
84 | 效果如下:
85 |
86 | === ":fontawesome-brands-microsoft: Windows11 风格"
87 |
88 |
89 | 
90 | 
91 | 图2 值输入控件
92 |
93 |
94 | === ":fontawesome-brands-windows: Windows10 风格"
95 |
96 |
97 | 
98 | 
99 | 图2 值输入控件
100 |
101 |
102 | ### 2.3 [`ComboBox`][maliang.standard.widgets.ComboBox]
103 |
104 | 下拉框控件算是选项按钮(`OptionButton`)的文本可编辑版本,也就是说,它可以通过下拉选项列表来选择一个内容之外,还可以直接编辑里面的内容。
105 |
106 | 下面是一个简单的示例:
107 |
108 | ```python hl_lines="7-8"
109 | import maliang
110 |
111 | root = maliang.Tk()
112 | cv = maliang.Canvas(auto_zoom=True)
113 | cv.place(width=1280, height=720)
114 |
115 | maliang.ComboBox(cv, (20, 20), text=("Option1", "Option2", "Option3"))
116 | maliang.ComboBox(cv, (200, 20), text=("Option1", "Option2", "Option3"))
117 |
118 | root.mainloop()
119 | ```
120 |
121 | 效果如下:
122 |
123 | === ":fontawesome-brands-microsoft: Windows11 风格"
124 |
125 |
126 | 
127 | 
128 | 图3 下拉框控件
129 |
130 |
131 | === ":fontawesome-brands-windows: Windows10 风格"
132 |
133 |
134 | 
135 | 
136 | 图3 下拉框控件
137 |
138 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_06/1.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 主题
5 | - 颜色主题
6 | - 适配系统
7 | status: new
8 | ---
9 |
10 | # §6.1 切换颜色主题
11 |
12 | ## 一、切换颜色主题的方式
13 |
14 | `maliang` 支持两种切换颜色主题的方式,手动调用的方式来切换主题和根据系统的主题自动进行适配。
15 |
16 | ### 1.1 手动切换颜色主题
17 |
18 | 目前 `maliang` 内置的主题有两套,一套亮色主题 `#!py "light"` 和一套暗色主题 `#!py "dark"`,用户可以通过自定义的方式添加更多主题,名称也不一定要按照什么约定,只要不覆盖内置的主题名称即可。除了内置的两套主题外,还有一个特殊的主题名称不可使用,即后文将提到的 `#!py "system"`。
19 |
20 | /// failure | 不推荐自定义主题:不要没苦硬吃
21 |
22 | 虽然说用户可以通过自定义的方式添加更多主题,但这里我并不推荐这样做。因为这样做的工作量非常大,且难以移植!曾经的 `maliang` 在某个版本的时候可以通过导入 JSON 格式的主题配置文件来自定义主题,但随着后续主题功能的重构升级,这个功能目前已被移除。目前只能通过编写 Python 文件的“样式”类来实现自定义主题,这样做非常麻烦,而且一旦后续版本升级 API 发生某些变动,将导致主题不可用!
23 |
24 | 所以,这里不推荐自定义主题。那可以怎么办呢?等!等我后续更新……看看什么时候有空把 JSON 格式的主题配置文件加回来。
25 |
26 | ///
27 |
28 | 下面是一个简单的示例,它可以强制指定窗口的主题:
29 |
30 | ```python hl_lines="2 4"
31 | import maliang
32 | from maliang import theme
33 |
34 | theme.set_color_mode("light")
35 |
36 | root = maliang.Tk(title="登录")
37 |
38 | canvas = maliang.Canvas(auto_zoom=True, keep_ratio="min", free_anchor=True)
39 | canvas.place(width=1280, height=720, x=640, y=360, anchor="center")
40 |
41 | maliang.Text(canvas, (640, 200), text="账 号 登 录", fontsize=48, anchor="center")
42 |
43 | maliang.Text(canvas, (450, 300), text="账号", anchor="nw")
44 | maliang.InputBox(canvas, (450, 340), (380, 50), placeholder="点击输入账号")
45 | maliang.Text(canvas, (450, 400), text="密码", anchor="nw")
46 | maliang.InputBox(canvas, (450, 440), (380, 50), show="●", placeholder="点击输入密码")
47 |
48 | maliang.Button(canvas, (450, 540), (180, 50), text="注 册")
49 | maliang.Button(canvas, (650, 540), (180, 50), text="登 录")
50 |
51 | root.center()
52 | root.mainloop()
53 | ```
54 |
55 | 同理,你也可以将 `#!py "light"` 更改为 `#!py "dark"` 来强制指定颜色主题为暗色。
56 |
57 | 设置颜色主题的代码并不一定要放在最前面,你也可以将其放到中间。
58 |
59 | ### 1.2 自动适配颜色主题
60 |
61 | 自动适配颜色主题的功能默认是开启的,如果你安装了所需要的可选包。`maliang` 通过调用第三方包 来检测系统主题并跟随系统主题的切换进行切换。但其本质上和上面手动切换的方式一样,只不过这个切换操作是由 `maliang` 自动完成的。
62 |
63 | 但为了防止和手动切换颜色主题的功能产生冲突,当 `maliang` 的主题名称不是 `#!py "system"` 时,自动适配颜色主题的功能不会生效,也就是说,如果通过某种方式手动改变了应用程序的主题,那么自动适配的功能会失效,只有重新将主题设为 `#!py "system"` 才会重新生效。
64 |
65 | 下面是一个示例程序,运行后出现一个分段按钮,你尝试选择不同的主题后查看窗口的变化,并时不时地修改系统的主题,再看看窗口会发生什么变化:
66 |
67 | ```python hl_lines="5-6 13"
68 | import maliang
69 | from maliang import theme
70 |
71 |
72 | def _set_color_mode(index: int) -> None:
73 | theme.set_color_mode(["light", "system", "dark"][index])
74 |
75 |
76 | root = maliang.Tk()
77 | canvas = maliang.Canvas()
78 | canvas.pack(fill="both", expand=True)
79 |
80 | maliang.SegmentedButton(canvas, (20, 20), text=("light", "system", "dark"), default=1, command=_set_color_mode)
81 |
82 | root.mainloop()
83 | ```
84 |
85 | 想必你现在应该已经理解它的逻辑了。
86 |
87 | ## 二、为主题切换绑定关联函数
88 |
89 | `maliang` 还提供了在主题切换时触发已注册的函数的功能。
90 |
91 | ### 2.1 获取当前程序的颜色主题
92 |
93 | 这个很简单,直接调用函数 [`get_color_mode`][maliang.theme.get_color_mode] 就行:
94 |
95 | ```python
96 | from maliang import theme
97 |
98 | print(theme.get_color_mode())
99 | ```
100 |
101 | 在程序的任意时刻都可以调用。
102 |
103 | ### 2.2 绑定关联函数
104 |
105 | 可以通过函数 [`register_event`][maliang.theme.register_event] 来绑定关联函数,通过函数 [`remove_event`][maliang.theme.remove_event] 来去除已经绑定的关联函数。
106 |
107 | 下面是一个简单的示例:
108 |
109 | ```python hl_lines="9"
110 | import maliang
111 | from maliang import theme
112 |
113 | theme.register_event(lambda mode: print(f"Color mode changed to: {mode}"))
114 |
115 | root = maliang.Tk()
116 | root.mainloop()
117 | ```
118 |
119 | 运行上面的代码,然后调整系统的明暗主题,看看终端会有什么内容输出。
120 |
121 | /// question | 猜你想问:诶为啥我运行上面的程序后调整系统主题时终端没有任何输出?
122 |
123 | 您再仔细看看 [前面讲的内容](#12-自动适配颜色主题) 呢?(或者查看下面的隐藏提示
124 |
125 | ```txt { .blur linenums="0" .yaml .no-copy}
126 | 不是你真的安装第三方包 https://github.com/albertosottile/darkdetect 了吗???
127 | ```
128 |
129 | ///
130 |
131 | 可以绑定多个关联函数,只要多次调用即可。如果需要去除原来绑定的函数,则需要传入函数对象到函数 [`remove_event`][maliang.theme.remove_event],像下面这样:
132 |
133 | ```python hl_lines="7"
134 | import maliang
135 | from maliang import theme
136 |
137 | f = lambda mode: print(f"Color mode changed to: {mode}")
138 |
139 | theme.register_event(f)
140 | theme.remove_event(f)
141 |
142 | root = maliang.Tk()
143 | root.mainloop()
144 | ```
145 |
146 | 上面的函数 `f` 就不会生效,因为刚绑定就被去除了。
147 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_01/3.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 额外内容
5 | ---
6 |
7 | # §1.3 框架概述
8 |
9 | ## 一、起因
10 |
11 | ### 1.1 为什么要写 `maliang`
12 |
13 | Python 在图形化程序的开发上除了可以选择内置的 `tkinter` 之外,实际还有很多优秀的第三方包来支持,如 `PySide`、`PyQT`、`wxpython` 等等,但为什么我还要开发 `maliang` 呢?
14 |
15 | 实际上,最开始写 `maliang` 的目的并非是要构建什么框架,而只是作为一个辅助工具,辅助我自己开发图形化的程序,这在前面也已经讲过了,但随着量的逐渐增加,`maliang` 也变得像个样子了,于是我的目标不再只是将其作为一个辅助工具,而是作为一个简易的 UI 框架,在帮我实现某些功能的同时,开源出来,让大家一起使用,一起开发。
16 |
17 | ### 1.2 为什么选择 `tkinter` 作为底层
18 |
19 | 你其实可以想一下,Python 已是当今世界上最流行的编程语言了,既然它如此流行,为什么还会选择 `tkinter` 作为内置的图形化接口呢?
20 |
21 | 很多人都说 `tkinter` 丑陋、落后以及性能低下,Python 官方将其内置只是因为它的语法简单。诶嘿,这“语法简单”就很关键了!众所周知,Python 的简单易用就是其出色的特点之一,因此选择同样简单的图形库就非常合理了。当然,这些其实都只是大家的猜测,官方不一定是这样想的。
22 |
23 | 个人认为,`tkinter` 的底层,Tk/Tcl 涉及到很多的东西,官方无法将其弃置,所以才会一直选用它。首先,Tk/Tcl 非常小,在 UI 框架里面属于极其轻量级的,此外它跨平台、开源、免费、易用、兼容性非常好,很多库和小工具都与其做了对接。比如使用量最大的开源轻量级数据库 SQLite 就有对 Tcl 的对接,而正好 Python 有个内置库 `sqlite3` 实现了 SQLite 的接口。
24 |
25 | 此外,Python 还有多个内置库都使用了 `tkinter`,如以教育方面著名内置库 `turtle` 就是以 `tkinter` 为底层的,还有内置库 `idlelib` 实现了 Python 打开即用的集成开发环境 IDLE,其底层也是 `tkinter`。
26 |
27 | 这些还是内置库的,第三方库也有不少做了与 `tkinter` 的对接,如 `matplotlib`、`pillow` 等。
28 |
29 | 所以,为什么选择 `tkinter` 作为 `maliang` 的底层,原因就很简单了。
30 |
31 | ## 二、设计目标
32 |
33 | ### 2.1 目标由来
34 |
35 | 说完起因了,就该说说 `maliang` 的预期目标了。既然要开发一个 UI 框架,就难免不和其它成熟的 UI 框架去做比较,既然要比较,那就必须要有优势才行。
36 |
37 | 截至 `tkintertools 2`(`maliang` 的前代版本),目标都不是以 UI 框架去定义的,从 `maliang` 开始,才真正地向着一个 UI 框架走。`maliang` 起初是一个辅助工具,因此它就应该从以前版本的开始,具备一些弥补 `tkinter` 缺点的功能,于是目标很简单,把 `tkinter` 很难做的功能给实现出来,并将其封装好,提供简单易用的接口给用户使用。
38 |
39 | 这一目标和一开源 UI 框架 https://github.com/TomSchimansky/CustomTkinter 很像。从名字上来看,`customtkinter` 可以高度自定义你的 `tkinter` 程序,`maliang` 的目标也是如此,但这还不够。因为再怎么样,`customtkinter` 的控件都无法脱离 `tkinter` 的真实控件,这就导致控件数量十分有限,那么该怎么解决这个问题呢?
40 |
41 | ### 2.2 主体思路
42 |
43 | 其实,无论任何控件,其归根结底,都是在计算机屏幕上绘制出来的,那些 UI 效果无非就是对绘制出来的图形和颜色加以控制罢了。试想完全把整个窗口当成一个画布,而 UI 就是在上面画画而已。于是,`maliang` 的开发主体思路就定下来了,就是用 `tkinter.Canvas` 对象来当做窗口,而用户要做的就是在上面“画” UI!
44 |
45 | 由于一切都是通过画布绘制的,因此理论上可以实现任何控件,限制各位开发者的不再是底层和平台,而是大家的想象力!
46 |
47 | ## 三、基本框架
48 |
49 | ### 3.1 控件构建框架
50 |
51 | `maliang` 的构建控件基本框架如下图所示:
52 |
53 | ```mermaid
54 | flowchart LR
55 |
56 | app{{APP}}
57 | tk(Tk)
58 | tp1(Toplevel 1)
59 | tp2(Toplevel 2)
60 | cv1(Canvas 1)
61 | cv2(Canvas 2)
62 | wid1([Widget 1])
63 | wid2([Widget 2])
64 | wid3([Widget 3])
65 | cp1([Element 1])
66 | cp2([Element 2])
67 | it1[Item 1]
68 | it2[Item 2]
69 | _1(More...)
70 | _2([More...])
71 | _3([More...])
72 | _4[More...]
73 | _5(More...)
74 |
75 | app --> tp1; app --> tp2; app --> tk; app --> _5;
76 | tk --> cv1; tk --> cv2; tk --> _1;
77 | cv2 --> wid1; cv2 --> wid2; cv2 --> _2;
78 | wid2 --> cp1; wid2 --> cp2; wid2 --> _3; wid2 --> wid3;
79 | cp2 --> it1; cp2 --> it2; cp2 --> _4;
80 | ```
81 |
82 | 其中圆角矩形包起来的是从 `tkinter` 中继承而来的对象,半圆矩形的是 `maliang` 中定义的对象,矩形的是一个特殊对象,即画布元素,在 Python 中体现为一个 `#!python int` 类型。
83 |
84 | 这里的控件(`Widget`)基本可以认为是 `tkinter.Widget`,但此处的元素(`Element`)或许需要我解释一下。简单说就是,控件的外观是由这些元素及控件组成的,而元素又是可以细分的,即:
85 |
86 | ```mermaid
87 | flowchart TB
88 |
89 | 1[Element]
90 | 2([Text])
91 | 3([Image])
92 | 4([Shape])
93 | 5[Feature]
94 | 6[Widget]
95 | 7[Widget]
96 | 8[Style]
97 |
98 | 1 --> 2; 1 --> 3; 1 --> 4;
99 | 7 --> 6; 7 --> 5; 7 --> 8; 7 --> 1;
100 | ```
101 |
102 | 特别说明,这里的 `Feature` 是功能基类,是用来控制控件的功能的,`Style` 是样式基类,是用来控制控件的样式的。此外,这里的 `Text`、`Image` 和 `Shape` 都是基类,它们下面还有很多细分的类。
103 |
104 | ### 3.2 细节处理
105 |
106 | 上面都是在类级别的框架,在元素抽象基类下还可以细分,如 `Shape`,可以像下面这样构成:
107 |
108 | ```mermaid
109 | flowchart TB
110 |
111 | 1([Shape])
112 | 2[line]
113 | 3[oval]
114 | 4[rectangle]
115 | 5[polygon]
116 | 6[More...]
117 |
118 | 1 --> 2; 1 --> 3; 1 --> 4; 1 --> 5; 1 --> 6;
119 | ```
120 |
121 | 上述的这些 `line`、`oval` 并不是类,而是画布的特殊对象(Item),以 `#!python int` 的形式的存在(上文提到过)。
122 |
123 | ### 3.3 整体框架
124 |
125 | 上述两部分讲的都是控件的构建的框架,在 `maliang` 源代码中属于包 `core`(核心部分)和 `standard`(标准件) 的内容。除此之外,还有其它的一些包,如:
126 |
127 | * `animation`: 管理动画和控制器函数;
128 | * `color`: 颜色处理;
129 | * `theme`: 主题控制以及样式数据的解析和处理;
130 | * `toolbox`: 提供一些实用的工具类和函数;
131 |
132 | 以及三个扩展包(需要通过额外的方式安装):
133 |
134 | * `mpl`: 实现和处理 `matplotlib` 相关的接口;
135 | * `media`: 实现对带音频视频的播放;
136 | * `three`: 实现简单的 3D 绘图;
137 |
138 | 总之,`maliang` 的整体功能极为丰富。
139 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/3.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 动画
5 | - 自定义
6 | ---
7 |
8 | # §4.3 自定义动画
9 |
10 | ## 一、动画基类
11 |
12 | ### 1.1 参数及方法
13 |
14 | 关于动画基类 [`Animation`][maliang.animation.animations.Animation],在 [§4.1 基础动画](./1.md#二动画类) 中提过一嘴,实现动画的核心就在于这个类。这里说明一下它的相关参数。
15 |
16 | * `ms`: 动画时长,单位是毫秒
17 | * `callback`: 回调函数,每帧都将调用这个函数,传入当前时间占比
18 | * `controller`: 控制函数
19 | * `end`: 终止函数,动画一轮结束时会调用这个函数
20 | * `repeat`: 重复次数,小于零表示无限次,默认为 `#!python 0`
21 | * `fps`: 动画帧率,默认为 `#!python 30`
22 | * `derivation`: 表示是否对控制函数求导,默认为 `False`
23 |
24 | 此外,动画基类还有两个方法,即 `start` 和 `stop`。但是注意,调用 `stop` 之后这个动画就被彻底终止了,并不是暂停,如果重新调用 `start` 也只是从头开始运行动画。
25 |
26 | 下面有一个简单的示例,展示了相关参数的用法:
27 |
28 | ```python hl_lines="11"
29 | import time
30 |
31 | import maliang
32 | import maliang.animation as animation
33 |
34 | root = maliang.Tk()
35 |
36 | callback = lambda x: print(x, time.time() - t)
37 | end = lambda: print("Done!")
38 |
39 | an = animation.Animation(1000, callback, controller=animation.linear, end=end)
40 |
41 | t = time.time()
42 | an.start()
43 | root.mainloop()
44 | ```
45 |
46 | 运行上述示例,可以看见每帧都输出了当前时间占比和实际时长,结束时调用 `end` 函数。
47 |
48 | 关于最后一个参数,稍微有些复杂,将在下一部分进行说明。
49 |
50 | ### 1.2 控制动画的速度
51 |
52 | 众所周知,位移函数求导之后就是速度函数,正如前面章节 [§4.2 控制函数](./2.md#13-内置的控制函数),有时候位置并不好直接修改,但速度比较好控制,这个时候就需要将 `derivation` 设为 `True` 了。此时每帧传给回调函数的参数将不在每帧的时间占比了,而是这一帧的时间占比,**所有帧的总和为 1**(1),也就是函数图像与横纵轴截出来的面积为 1。
53 | { .annotate }
54 |
55 | 1. 所以并不是直接的求导,而是求导之后再除以总帧数
56 |
57 | 那这有什么用呢?当你的回调函数并非直接操控位置时可以尝试使用这个,典型的就是 `Canvas` 的 `move` 方法和 `moveto` 方法。`move` 使用的是相对坐标,对于单帧而言相当于速度,`moveto` 使用的是绝对坐标,对于单帧而言就是位置。当我们无法使用 `moveto` 方法的时候,`move` 方法配合 `derivation` 参数就起作用了(如 `MoveWidget`)。
58 |
59 | ## 二、自定义动画类
60 |
61 | 所谓自定义动画类,实际上就是通过继承动画基类并具化为自己需要的类。可以把内置的那些基础动画类作为参考,实现属于自己需要的动画类。当然,若是需求比较简单,那还是直接调用动画基类就好。
62 |
63 | 下面看一下内置基础动画类 `MoveWidget` 的源代码:
64 |
65 | ```python { .blur hl_lines="1 4-15 27-39" }
66 | class MoveWidget(Animation):
67 | """Animation of moving ``virtual.Widget``."""
68 |
69 | def __init__(
70 | self,
71 | widget: virtual.Widget | Sequence[virtual.Widget],
72 | offset: tuple[float, float],
73 | duration: int,
74 | *,
75 | controller: Callable[[float], float] = controllers.linear,
76 | end: Callable[[], Any] | None = None,
77 | fps: int = 30,
78 | repeat: int = 0,
79 | repeat_delay: int = 0,
80 | ) -> None:
81 | """
82 | Args:
83 | widget: the ``virtual.Widget`` to be moved.
84 | offset: relative offset of the coordinates.
85 | duration: duration of the animation, in milliseconds.
86 | controller: a function that controls the animation process.
87 | end: end function, which is called once at the end of the animation.
88 | fps: frame rate of the animation.
89 | repeat: number of repetitions of the animation.
90 | repeat_delay: length of the delay before the animation repeats.
91 | """
92 | if isinstance(widget, Sequence):
93 | def command(p: float) -> None:
94 | dx, dy = offset[0]*p, offset[1]*p
95 | for w in widget:
96 | w.move(dx, dy)
97 | else:
98 | def command(p: float) -> None:
99 | widget.move(offset[0]*p, offset[1]*p)
100 |
101 | super().__init__(
102 | duration, command, controller=controller, end=end, fps=fps,
103 | repeat=repeat, repeat_delay=repeat_delay, derivation=True,
104 | )
105 | ```
106 |
107 | 看起来很多,实际核心内容就一点点。当然,我们自己定义属于自己的动画类时并不需要像上面这样写得如此繁琐。
108 |
109 | 比如,我们写一个这样的动画类:
110 |
111 | ```python hl_lines="12 13"
112 | import math
113 |
114 | import maliang
115 | import maliang.animation as animation
116 |
117 |
118 | class MyAnimation(animation.Animation):
119 | """My customized animation class"""
120 |
121 | def __init__(self, ms: int, window: maliang.Tk, *args, **kwargs) -> None:
122 | """Let the window gradually change from transparent to clear"""
123 | controller = animation.generate(math.sin, 0, math.pi, map_y=False)
124 | super().__init__(ms, window.alpha, controller=controller, *args, **kwargs)
125 |
126 |
127 | root = maliang.Tk()
128 | MyAnimation(2000, root, repeat=-1, fps=60).start(delay=1000)
129 | root.mainloop()
130 | ```
131 |
132 | 运行上述代码,你窗口不停的从透明到清晰,再清晰到透明地变化。
133 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_05/2.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 颜色
5 | - 颜色处理
6 | ---
7 |
8 | # §5.2 颜色处理
9 |
10 | ## 一、处理函数
11 |
12 | `maliang` 只支持两种颜色空间的处理,分别是 RGB 和 HSL,且对这两种颜色空间支持的相关处理函数都差不多。处理 RGB 的函数位于子包 [`color.rgb`][maliang.color.rgb] 中,处理 HSL 的函数为位于子包 [`color.hsl`][maliang.color.hsl]。
13 |
14 | ### 1.1 获取相反色
15 |
16 | 以 RGB 颜色为例,这里说的相反色是指颜色某个指标的最大值减去当前值所得的结果,比如 `#!python (50, 100, 150)` 的相反色就是 `#!python (255-50, 255-100, 255-150)`,即 `#!python (205, 155, 105)`,HSL 颜色同理。
17 |
18 | 要获取一个颜色的相反色,对于 RGB 颜色,可以使用函数 [`rgb.contrast`][maliang.color.rgb.contrast],对于 HSL 颜色,可以使用函数 [`hsl.contrast`][maliang.color.hsl.contrast]。两者参数类似。
19 |
20 | 下面是一个简单的示例(运行结果为文档构建时计算得到):
21 |
22 | ```python exec source="material-block" result="console"
23 | import maliang.color.hsl
24 | import maliang.color.rgb
25 |
26 | print(maliang.color.rgb.contrast((50, 100, 150)))
27 | print(maliang.color.hsl.contrast((1, 0.3, 0.6)))
28 | ```
29 |
30 | ### 1.2 过渡一个颜色
31 |
32 | 这里说的过渡一个颜色是指,将一个颜色以另外一个颜色为目标,以一定的比例向其靠拢得到的颜色。显然,当过渡比例为 100% 时,得到的返回值就是目标颜色,0% 时为原来的颜色。对于 RGB,过渡一个颜色要调用的函数为 [`rgb.transition`][maliang.color.rgb.transition],对于 HSL 是 [`hsl.transition`][maliang.color.hsl.transition]。
33 |
34 | 下面是一个简单的示例(运行结果为文档构建时计算得到):
35 |
36 | ```python exec source="material-block" result="console"
37 | import maliang.color.hsl
38 | import maliang.color.rgb
39 |
40 | print(maliang.color.rgb.transition((50, 100, 150), (0, 0, 0), 0.3))
41 | print(maliang.color.hsl.transition((2, 0.3, 0.6), (0, 0, 0), 0.5))
42 | ```
43 |
44 | ### 1.3 混合多个颜色
45 |
46 | 混合颜色就是按权重(默认值表示等权重)分配三个颜色通道的值得到新的颜色。对于 RGB,混合颜色的函数为 [`rgb.blend`][maliang.color.rgb.blend],而 HSL 则是 [`hsl.blend`][maliang.color.hsl.blend]。
47 |
48 | 下面是一个简单的示例(运行结果为文档构建时计算得到):
49 |
50 | ```python exec source="material-block" result="console"
51 | import maliang.color.hsl
52 | import maliang.color.rgb
53 |
54 | # same weight
55 | print(maliang.color.rgb.blend((50, 100, 150), (0, 0, 0), (100, 100, 100)))
56 | print(maliang.color.hsl.blend((2, 0.3, 0.6), (0, 0, 0), (4, 0.4, 0.9)))
57 |
58 | # diff weight
59 | print(maliang.color.rgb.blend((50, 100, 150), (0, 0, 0), (100, 100, 100), weights=(1, 2, 3)))
60 | print(maliang.color.hsl.blend((2, 0.3, 0.6), (0, 0, 0), (4, 0.4, 0.9), weights=(0.1, 0.3, 0.6)))
61 | ```
62 |
63 | ### 1.4 获取一组渐变色
64 |
65 | 其实可以通过设置一系列的值多次调用前面提到的函数 `transition` 就可以得到一组渐变色,但我并不推荐你使用这种方式获取渐变色,因为内部处理时由于循环可能会导致某些步骤被重复执行导致性能相对低下。对于 RGB 应该使用 [`rgb.gradient`][maliang.color.rgb.gradient] 来获取渐变色,而 HSL 则是 [`hsl.gradient`][maliang.color.hsl.gradient]。
66 |
67 | 与上面的函数 `transition` 类似,函数 `gradient` 也有一个控制到目标颜色比例的参数 `rate`。这个参数的默认值是 `#!python 1`,表示渐变色的终点就是目标颜色,如果不是 `#!python 1`,那么就是以此参数的值用函数 `transition` 计算出的颜色作为渐变色的终点。不过,有趣的是,函数 `gradient` 有一个名为 `contoller` 的参数可以控制渐变色每次渐变的比例。它要传入的对象是前面第四章提到的控制函数,默认值是 [`controllers.linear`][maliang.animation.controllers.linear],也就是线性的,等差的。但我们可以通过设置其它的控制函数得到其它的渐变效果。
68 |
69 | 该函数的返回值是一个列表,里面是一组 RGB 颜色或者 HSL 颜色,数量由参数 `count` 控制。返回的列表中一般不会包括目标颜色,除非目标颜色与初始颜色相近。
70 |
71 | 下面是一个简单的示例(运行结果为文档构建时计算得到):
72 |
73 | ```python exec source="material-block" result="console"
74 | import math
75 |
76 | import maliang.color.hsl
77 | import maliang.color.rgb
78 |
79 | print(maliang.color.rgb.gradient((0, 0, 0), (100, 100, 100), 5))
80 | print(maliang.color.hsl.gradient((0, 0, 0), (math.pi, 0.5, 0.5), 5))
81 | ```
82 |
83 | !!! warning "特别注意:控制函数选取需谨慎"
84 |
85 | 默认的控制函数用的是线性的,它的曲线最大值都不会超过 `#!python 1`,所以计算得到的颜色字符串永远都是有意义(除非你传入的初始参数就存在问题)。但有些控制函数,或者自定义的控制函数就可能产生一些问题,比如内置的控制函数 [`controllers.rebound`][maliang.animation.controllers.rebound] 就可能会造成产生的颜色字符串无意义。因为这个控制函数的图像中有一部分是超出 `#!python 1` 的,见 [第四章第二节图三](../chapter_04/2.md#13-内置的控制函数-回弹函数rebound)。
86 |
87 | ## 二、一些示例
88 |
89 | 下面给出一些示例以供参考。
90 |
91 | ### 2.1 渐变圆
92 |
93 | 这个示例简单使用了 RGB 和 HSL 的渐变色函数,代码如下:
94 |
95 | ```python hl_lines="12-13 15-16"
96 | import math
97 |
98 | import maliang
99 | import maliang.color
100 | import maliang.color.hsl
101 | import maliang.color.rgb
102 |
103 | root = maliang.Tk()
104 | canvas = maliang.Canvas()
105 | canvas.place(width=1280, height=720)
106 |
107 | for i, v in enumerate(maliang.color.rgb.gradient((0, 0, 0), (255, 255, 255), 360)):
108 | canvas.create_arc(100, 100, 500, 500, start=i, extent=1, fill=maliang.color.rgb_to_hex(v), outline="")
109 |
110 | for i, v in enumerate(maliang.color.hsl.gradient((0, 0.5, 1), (math.tau, 0.5, 1), 360)):
111 | canvas.create_arc(100+600, 100, 500+600, 500, start=i, extent=1, fill=maliang.color.hsl_to_hex(v), outline="")
112 |
113 | root.mainloop()
114 | ```
115 |
116 | 效果如下:
117 |
118 | 
119 | 
120 |
121 | /// figure-caption
122 | 渐变圆
123 | ///
124 |
125 | ### 2.2 呼吸灯效果
126 |
127 | 代码和效果就省略了,具体见 [第四章第一节 2.6](../chapter_04/1.md#26-gradientitem),现在想必你已经知道那个动画类是怎么实现的了吧?
128 |
129 | !!! question "猜你想问:为什么这里省略了代码和效果?"
130 |
131 | ```python { .blur linenums="0" .yaml .no-copy }
132 | 这个问题看起来十分复杂,实际上非常复杂,但简单来说就是,因为我懒 :)
133 | 求求不要再催更我啦 :(
134 | ```
135 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/2.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 动画
5 | - 控制函数
6 | - 自定义
7 | ---
8 |
9 | # §4.2 控制函数
10 |
11 | ## 一、控制函数
12 |
13 | ### 1.1 什么是控制函数
14 |
15 | 控制函数可以理解为一个普通的数学函数,一个 `#!python float` 类型的输入,一个 `#!python float` 类型的输出,输入代表的是当前动画在时间层面上的进度,范围是 `#!python 0` 到 `#!python 1`,输出代表的是当前动画在图像层面上的进度,范围不限,依据动画情况而定。
16 |
17 | 表示成数学函数为如下:
18 |
19 | $$
20 | y=f(x), x\in[0, 1]
21 | $$
22 |
23 | 当动画是对象在画布上的移动时,输出值的范围一般没有限定,可以负数,表示反向移动,也可以大于 `#!python 1`,表示超出预定的移动距离。但对于颜色渐变这种类型的动画,输出值就有限定了。如果输出值为负数可能会得到意想不到的结果(大概率报错),如果输出值大于 `#!python 1`,则也极有可能得到错误的结果(错误的 RGB 码)。
24 |
25 | 因此,一般情况下约定输出值的范围在 `#!python 0` 到 `#!python 1` 之间,如果确需超出此范围,应考虑是否修改动画的参数。
26 |
27 | ### 1.2 控制函数对动画类的作用
28 |
29 | 动画类实际就是按照给出的帧率以及动画时间来调用关联函数的,而每次调用传给关联函数的值又是经过控制函数计算得出的,而控制函数的结果又是通过传入当前动画时间占比得到的,这个流程图画出来大致如下:
30 |
31 | ```mermaid
32 | flowchart LR
33 |
34 | 1(总动画量)
35 | 2(关联函数)
36 | 3(帧率)
37 | 4(动画时间)
38 | 5(动画)
39 | 6(每帧时间占比 x)
40 | 7(每帧动画占比 y)
41 |
42 | subgraph 动画类单帧运算过程
43 | 6 --控制函数--> 7
44 | end
45 |
46 | 3 --> 6
47 | 4 --> 6
48 | 1 --> 2
49 | 2 --> 5
50 | 7 --> 2
51 | ```
52 |
53 | 当然,上述只是简化的流程,实际参数和处理过程比上面的流程图要更复杂。
54 |
55 | ### 1.3 内置的控制函数
56 |
57 | 前面的 [§4.1 基础动画](./1.md#12-控制函数) 已经提过内置的 3 个控制函数了,这里将对它们做详细的讲解,并给出函数图像。
58 |
59 | === "线性函数:`linear`"
60 |
61 | 
62 | 
63 |
64 | /// figure-caption
65 | 线性函数
66 | ///
67 |
68 | === "平滑函数:`smooth`"
69 |
70 | 
71 | 
72 |
73 | /// figure-caption
74 | 平滑函数
75 | ///
76 |
77 | === "回弹函数:`rebound`"
78 |
79 | 
80 | 
81 |
82 | /// figure-caption
83 | 回弹函数
84 | ///
85 |
86 | 从之前的内容来看,不难知道回弹函数在某些情况下是会触发报错的,因为其后半部分图像超出了 `#!python 1`,这就导致类似于颜色渐变这种动画可能报错。
87 |
88 | !!! success "快速理解:看函数的斜率"
89 |
90 | 从控制函数图像其实可以发现,**控制函数的斜率就是动画的速度**,这一点非常关键。x 值就是实际的时间占比,y 值就是实际的运动占比,时间只可能在 0 ~ 1 之间,而动画可以超出限定的范围(尽管不推荐这样做)。
91 |
92 | 综上,控制函数是通过控制运动轨迹来控制整个运动的。
93 |
94 | 上述控制函数是通过控制运动轨迹来控制运动的,那如果我想要的运动轨迹比较复杂,不好写出这个控制函数,但其速度变化曲线,也就是控制函数的导数很容易写出来时,该怎么办呢?关于这一问题将在下一章节进行说明。
95 |
96 | ## 二、自定义控制函数
97 |
98 | ### 2.1 控制函数生成器
99 |
100 | 实际上,`maliang` 的动画子包还带有一个控制函数生成器([`generate`][maliang.animation.controllers.generate]),它是一个便捷函数,我们可以通过它来快速得到我们需要的控制函数。控制函数生成器本质上也是一个函数,根据给定的参数来返回新的函数。
101 |
102 | 每个控制函数都需要明确几个数据:
103 |
104 | * `base`: 基本函数,满足输入值为一个浮点数,返回值也是一个浮点数即可;
105 | * `start`: 上述基本函数截取区间的起始值;
106 | * `end`: 上述基本函数截取区间的终止值;
107 |
108 | 同时,对于控制函数生成器,还有一点要明确,即参数 `map_y` 的值,其默认为 `True`。当 `map_y` 为 `True` 时会自动将整个控制函数的值域映射到 `[起始值, 1]` 上,以保证运动的最终结果和设定的选项一致。此处的起始值表示 $f(start)$。
109 |
110 | !!! tip "温馨提示:有时候不需要 `map_y` 为 `True`"
111 |
112 | 如果你需要往返运动效果的控制函数,那么请将参数 `map_y` 设为 `False`。一旦你没有这样做,假设你的最终值为 0,那么将导致映射时其它值被映射到 $+\infty$,使得动画不可见了。
113 |
114 | 这里将内置控制函数 `rebound` 作为示例,讲讲它是怎么生成的。首先,下面是它的函数实现:
115 |
116 | ```python
117 | def rebound(t: float, /) -> float:
118 | """Before the end, displacement will bounce off a bit."""
119 | return generate(math.sin, 0, (math.pi+1) / 2)(t)
120 | ```
121 |
122 | 可以看见,它实际上就是取正弦函数 0 到 $\frac{\pi+1}{2}$ 范围内,并约束最终值为 1 的函数。它听起来有点复杂,实际数学表达式如下:
123 |
124 | $$
125 | y=\frac{\sin\frac{\pi+1}{2}x}{\sin\frac{\pi+1}{2}}, x\in[0, 1]
126 | $$
127 |
128 | 确实比较复杂,但用控制函数生成器写出来却十分简洁。
129 |
130 | ### 2.2 完全自定义
131 |
132 | 所谓完全自定义,实际就是不借助控制函数生成器,直接定义的控制函数,一般是控制函数足够简单,或者是有特殊需求的情况下才会使用。典型的如内置控制函数 `linear`,下面是它的函数实现:
133 |
134 | ```python
135 | def linear(t: float, /) -> float:
136 | """Speed remains the same."""
137 | return t
138 | ```
139 |
140 | 由于它非常简单,所以没必要使用控制函数生成器。
141 |
142 | 又比如内置控制函数 `smooth`,下面是它的函数实现:
143 |
144 | ```python
145 | def smooth(t: float, /) -> float:
146 | """Speed is slow first, then fast and then slow. (slow -> fast -> slow)"""
147 | return (1 - math.cos(t*math.pi)) / 2
148 | ```
149 |
150 | 它看起来并不是那么简单,但把它转化成控制函数生成器的写法是这样的:
151 |
152 | ```python hl_lines="6"
153 | def smooth(t: float, /) -> float:
154 | """Speed is slow first, then fast and then slow. (slow -> fast -> slow)"""
155 | return generate(lambda x: 1 - math.cos(x), 0, math.pi)(t)
156 | ```
157 |
158 | 这个用控制函数生成器反而又显得复杂了,所以也是直接采用完全自定义的。完全自定义还有助于实现分段函数这样的控制函数。总之,借助控制函数,我们可以实现许多有趣的动画。
159 |
160 | ## 三、使用多个控制函数
161 |
162 | 或许你会有同时控制一个对象在水平方向和竖直方向运动的需求,但很遗憾,`maliang` 的动画类并不支持使用多个控制函数。但是呢,这并不限制我们使用多个动画类来实现类似的需求呀!
163 |
164 | 下面是一个简单的示例,演示了如何让一个小球同时在水平和竖直方向上运动:
165 |
166 | ```python hl_lines="14-15"
167 | import math
168 |
169 | import maliang
170 | import maliang.animation as animation
171 |
172 | root = maliang.Tk()
173 | cv = maliang.Canvas()
174 | cv.place(width=1280, height=720)
175 |
176 | ball = cv.create_oval(640-40, 360-40, 640+40, 360+40, fill="royalblue", outline="")
177 |
178 | controller = animation.generate(math.sin, 0, math.tau, map_y=False)
179 |
180 | x = animation.MoveItem(cv, ball, (500, 0), 2000, fps=60, repeat=-1, controller=controller)
181 | y = animation.MoveItem(cv, ball, (0, 300), 1000, fps=60, repeat=-1, controller=controller)
182 |
183 | x.start()
184 | y.start()
185 |
186 | root.mainloop()
187 | ```
188 |
189 | 这是它的效果:
190 |
191 | 
192 | 
193 |
194 | /// figure-caption
195 | 多个动画
196 | ///
197 |
198 | 是不是非常有趣?当然,这只是使用了两个控制函数,当你学习了 `maliang` 的 3D 扩展包,使用三个控制函数来控制 3D 对象的运动时,将显得更加有趣了!
199 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_02/1.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 控件
5 | - 容器控件
6 | - 窗口
7 | ---
8 |
9 | # §2.1 窗口容器控件
10 |
11 | ## 一、容器控件
12 |
13 | ### 1.1 分类
14 |
15 | 容器控件一般分两类,一种是有实际窗口的控件,包括 `Tk`、`Toplevel`。另外一种则没有实际的窗口,是处于窗口之内的容器,如 `Canvas`。
16 |
17 | ### 1.2 主窗口
18 |
19 | 每个 `tkinter` 程序在运行期间一般只允许存在一个且必须存在一个主窗口(弹窗除外),即只有一个 `Tk` 类的实例。
20 |
21 | 主窗口也叫根窗口,所以我们常常能在 `tkinter` 程序的源代码中见到 “root” 字样,其含义就是根窗口的意思。你可以把图形化程序的搭建理解为一颗树,从根部搭起,后面的控件、组件都连着前面的,也就是有“子与父”的关系存在,没有父一般就没有子。
22 |
23 | ```mermaid
24 | flowchart TB
25 |
26 | 1("Tk(root)")
27 | 2(Canvas 1)
28 | 3(Canvas 2)
29 | 4(Widget)
30 | 5(...)
31 |
32 | 1 --> 2; 3 --> 4;
33 | 1 --> 3; 3 --> 5;
34 | ```
35 |
36 | ### 1.3 子窗口
37 |
38 | 子窗口,或者叫顶级窗口(`Toplevel`),多用于额外的窗口,或者是自定义弹窗。
39 |
40 | 为什么叫顶级窗口呢,因为它和 `Tk` 一样有实际的窗口,处在“控件树”最顶端的位置,但其实际又属于 `Tk` 的“孩子”,根窗口一旦关闭,子窗口也会随之关闭,反之却不会。
41 |
42 | ## 二、窗口容器控件
43 |
44 | ### 2.1 [`Tk`][maliang.core.containers.Tk]
45 |
46 | #### 2.1.1 循环刷新的主窗口
47 |
48 | 通过 `Tk` 来生成一个主窗口,生成该对象后,需要让其进入消息事件循环,而这个循环显然是一直运行的,直到主窗口对象生命周期的结束。
49 |
50 | 通过如下代码可以生成主窗口:
51 |
52 | ```python
53 | import maliang
54 |
55 | root = maliang.Tk()
56 | root.mainloop()
57 |
58 | print("Done!")
59 | ```
60 |
61 | 但我们运行上述代码可以发现,`#!python "Done!"` 并没有被直接打印出来,而是当我们关闭窗口之后,这个 `#!python "Done!"` 才被打印出来。这也说明,`root.mainloop()` 是一个类似于循环的操作,会让主窗口一直做一件事,也就是刷新窗口,直到窗口被关闭,这个循环才结束。
62 |
63 | 我们可以用下面近似等价的代码试验一下效果是不是一样的:
64 |
65 | ```python
66 | import time
67 |
68 | import maliang
69 |
70 | root = maliang.Tk()
71 | start = time.time()
72 |
73 | while time.time() < start + 3:
74 | root.update()
75 |
76 | print("Done!")
77 | ```
78 |
79 | 运行之后不难发现,当窗口打开 3 秒后会自动关闭,之后终端才输出 `#!python "Done!"`。因此,写在 `root.mainloop()` 之后的代码一般是无效的。所以,这也从侧面说明,主窗口有且只有一个。
80 |
81 | #### 2.1.2 修改主窗口的属性
82 |
83 | 通过上面简单代码,我们已经可以创建出一个简单的窗口了,下面将讲述 `Tk` 有哪些内容可以修改,以及可以实现哪些效果。
84 |
85 | 首先,通过前面的章节 [§1.3 框架概述](../chapter_01/3.md/#31-控件构建框架),我们不难知道,`Tk` 是继承自 `tkinter.Tk` 的,因此 `tkinter.Tk` 的许多属性和方法是可以直接拿来用的,此处就不多讲了。这里专门讲一下 `Tk` 不同的地方吧。
86 |
87 | 通过查阅[文档][maliang.core.containers.Tk],我们可以通过初始参数设定主窗口的大小、位置、标题和图标。如下面代码可以创建一个大小为 1600×900(单位:像素),位置在距离屏幕左上角 100, 50,标题为 “My Window” 的窗口:
88 |
89 | ```python
90 | import maliang
91 |
92 | size = 1600, 900
93 | position = 100, 50
94 | title = "My Window"
95 |
96 | maliang.Tk(size, position, title=title).mainloop()
97 | ```
98 |
99 | 如果你不想计算窗口的位置,还可以通过 `Tk` 的方法 `center` 来居中窗口。
100 |
101 | ```python hl_lines="7"
102 | import maliang
103 |
104 | size = 1600, 900
105 | title = "My Window"
106 |
107 | root = maliang.Tk(size, title=title)
108 | root.center()
109 | root.mainloop()
110 | ```
111 |
112 | #### 2.1.3 使用部分简化的语法
113 |
114 | `tkinter.Tk` 有些很实用的功能可以使用,如全屏、置顶等,但它们使用调用起来比较麻烦,如使窗口置顶你需要这样写:
115 |
116 | ```python
117 | root = tkinter.Tk()
118 | root.attributes("-topmost", True)
119 | ```
120 |
121 | 这不仅难记,而且容易出错,故 `Tk` 对这些功能做了一定的简化,如置顶只需要这样写:
122 |
123 | ```python
124 | root = maliang.Tk()
125 | root.topmost(True)
126 | ```
127 |
128 | 与上面的类似的方法都写在这里了,具体参数和使用说明可以查阅[文档][maliang.core.containers.Tk]:
129 |
130 | * 通用:
131 | * [`alpha`][maliang.core.containers.Tk.alpha]: 调节窗口透明度
132 | * [`fullscreen`][maliang.core.containers.Tk.fullscreen]: 设置窗口为全屏
133 | * [`topmost`][maliang.core.containers.Tk.topmost]: 设置窗口置顶
134 | * 仅 Windows:
135 | * [`toolwindow`][maliang.core.containers.Tk.toolwindow]: 设置窗口为工具窗口
136 | * [`transparentcolor`][maliang.core.containers.Tk.transparentcolor]: 设置窗口的透明颜色
137 | * 仅 macOS:
138 | * [`modified`][maliang.core.containers.Tk.modified]: 设置窗口的编辑状态
139 | * [`transparent`][maliang.core.containers.Tk.transparent]: 设置窗口是否启用透明功能
140 |
141 | !!! warning "特别注意:部分功能不是跨平台的"
142 |
143 | 并不是所有的功能都是跨平台的,如设置透明颜色的功能在部分 Linux 操作系统上可能就无法生效甚至报错!
144 |
145 | 因为并不是所有的操作系统都支持上述的这些方法,所以在使用的时候请特别注意。如果不确定哪些功能在哪些操作系统上会导致错误,请查阅 `tkinter` 相关[文档](https://tcl.tk/man/tcl8.6/)。
146 |
147 | #### 2.1.4 创建后调整大小位置
148 |
149 | 可以使用方法 [`geometry`][maliang.core.containers.Tk.geometry] 来调整窗口的位置和大小。
150 |
151 | 如果需要原生 `tkinter` 调整窗口位置和大小方法,可调用或者重载 `wm_geometry` 方法来使用,不过并不建议这样做,这样可能会导致缩放上的一些问题。
152 |
153 | #### 2.1.5 窗口关闭时调用函数
154 |
155 | 有时候,我们需要在窗口关闭的时候执行一些功能,比如询问用户文件是否需要保存等,这时可以使用 `at_exit` 方法。下面是一个简单的示例:
156 |
157 | ```python hl_lines="12"
158 | import tkinter.messagebox as messagebox
159 |
160 | import maliang
161 |
162 |
163 | def ask() -> None:
164 | if messagebox.askyesno(message="是否关闭窗口?"):
165 | root.destroy()
166 |
167 |
168 | root = maliang.Tk()
169 | root.at_exit(ask, ensure_destroy=False)
170 | root.mainloop()
171 | ```
172 |
173 | 当窗口关闭的时候,程序会询问用户“是否关闭窗口”,若选择“是”则会关闭窗口,反之不会。
174 |
175 | ### 2.2 [`Toplevel`][maliang.core.containers.Toplevel]
176 |
177 | #### 2.2.1 继承而来的子窗口类
178 |
179 | `Toplevel` 是同时继承于 `tkinter.Toplevel` 和 `Tk` 的,所以 `Tk` 具有的方法,`Toplevel` 也有。
180 |
181 | 唯一不同的地方在于其初始化参数,详细说明可查阅[文档][maliang.core.containers.Toplevel]。
182 |
183 | #### 2.2.2 居中窗口的小技巧
184 |
185 | 其实在仔细查阅了方法 [`center`][maliang.core.containers.Tk.center] 的参数之后,不难发现,它有一个名为 `master` 的参数,当它的值为 `None` 的时候,居中的参考对象是屏幕,当它的值是根窗口的时候,就会以根窗口为参考对象而居中。
186 |
187 | ```python hl_lines="5"
188 | import maliang
189 |
190 | root = maliang.Tk()
191 | tl = maliang.Toplevel()
192 | tl.center(refer=root)
193 | root.mainloop()
194 | ```
195 |
196 | 运行上面的代码,无论根窗口在哪里,子窗口始终会在其中间出现。
197 |
198 | 
199 | 
200 |
201 | /// figure-caption
202 | 窗口居中
203 | ///
204 |
205 | !!! warning "特别注意:居中并不是一定准确的"
206 |
207 | 居中并不保证完全使窗口居中,因为这个窗口的范围判定并不一定和所看的外观一致。如 Windows7 风格的窗口在以 Windows10/11 窗口为参考对象居中时,看起来可能就不像是居中的。这可能与 `tkinter` 底层有关,`tkinter` 的 API 对 Windows7 风格的窗口给出结果貌似并不准确。
208 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_02/2.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 控件
5 | - 容器控件
6 | - 画布
7 | - 缩放
8 | ---
9 |
10 | # §2.1 画布容器控件
11 |
12 | ## 一、以画布为底
13 |
14 | ### 1.1 为什么以画布为底
15 |
16 | `maliang` 和 `tkinter` 程序不同,`tkinter` 程序是直接以窗口为底板,在上面放置控件的,但由于 `maliang` 的控件都是虚拟的,需要以画布为底板,在上面呈现出来。所以,在显示任何 `maliang` 控件之前,都需要一个画布来作为它们的容器。
17 |
18 | ### 1.2 将画布当作页面
19 |
20 | 我们可以把画布当作网页的一个个页面,每个画布都独立运作,这样层次就比较清晰,多个场景的切换也比较方便。
21 |
22 | ## 二、画布
23 |
24 | ### 2.1 [`Canvas`][maliang.core.containers.Canvas]
25 |
26 | 查阅文档可知,`Canvas` 继承自 `tkinter.Canvas`,它是在 `tkinter.Canvas` 的基础之上“魔改”而来的,增加了很多功能。
27 |
28 | #### 2.1.1 初始化参数的说明
29 |
30 | 直接查看文档可能还是不容易理解 `Canvas` 的初始化参数,这里做一个详细解释。
31 |
32 | * `master`: 父控件;
33 | * `expand`: 这个可以取的值有 4 个,但实际含义就是**画布本身**的缩放的规则,`#!python "x"` 表示横向要缩放,`#!python "y"` 表示纵向要缩放,两个都有就表示横纵都缩放,空字符串则表示不缩放;
34 | * `auto_zoom`: 布尔值,标志是否自动缩放画布里面的东西;
35 | * `keep_ratio`: 可取值有 `#!python "min"`,`#!python "max"` 和 `None` 标志缩放保持比例的规则,`#!python "min"` 表示跟随最小的缩放比,`#!python "max"` 表示跟随最大的缩放比,`None` 表示缩放不保持比例;
36 | * `free_anchor`: 布尔值,标志画布的锚点是否为动态的;
37 | * `auto_update`: 布尔值,标志着画布的样式是否自动根据主题而更新
38 |
39 | 这里着重讲一下后面两个参数。
40 |
41 | 保持画布横纵比例意味着画布里面的东西永远不会变形,这对于某些场景极为重要,比如播放视频,或者小游戏的画面。有两种模式,`#!python "min"` 像播放视频那样,保证画面始终在父控件之中,而不会溢出画面,而 `#!python "max"` 则是保证画面一定被铺满,就算某些部分会被父控件遮挡。
42 |
43 | `free_anchor` 则涉及到画布缩放,且只对 Place 布局有效。它会使锚点位置的是动态缩放的,而不是一直位于某个地方。比如锚点位于画布左上角,初始位置在 `#!python (100, 100)`,假设缩放倍率为 2,那么当 `free_anchor` 的值为 `True` 时,锚点的位置会变成 `#!python (200, 200)`,反之则没有任何变化。
44 |
45 | `auto_update` 为 `True` 时,`maliang` 的样式管理机制会自动根据窗口的主题修改画布的主题,也就是说,当它的值为 `True` 的时候,你无法修改画布的主题,就算通过某种手段修改了,当窗口主题发生变化时,画布的主题还是会自动更新。相对应地,如果你想自定义画布的样式,如背景颜色等,你可能需要将这个参数设为 `False`,此时画布的一切样式都会回归 `tkinter` 的默认值。当然,此时你可以自定义画布的主题:
46 |
47 | ```python
48 | import maliang
49 |
50 | root = maliang.Tk()
51 | cv = maliang.Canvas(auto_update=False, bg="lightyellow")
52 | cv.pack()
53 |
54 | root.mainloop()
55 | ```
56 |
57 | 上述代码可以让你的画布不受窗口主题变化的影响,但同样的,画布的外观细节都需要你自己设置。
58 |
59 | #### 2.1.2 隐藏/显示来切换页面
60 |
61 | 页面切换的方式有很多,你可以通过 `tkinter` 提供的方式,也可以通过 `maliang` 提供的方式。
62 |
63 | 当你使用 Place 布局时,在 `tkinter` 里面可以通过 `place_forget` 方法来将画布暂时隐藏掉。对于 Pack 和 Grid 布局也是类似的,可以使用 `pack_forget` 和 `grid_forget` 隐藏画布。但是当你想重新显示画布的时候,你必须再次使用对应的布局方法。而这个时候,你需要对当前窗口的缩放做出一定的处理。
64 |
65 | 如果窗口这个时候已经放大了,但你还是使用之前的方式去显示画布,就会导致画布看起来变小了。
66 |
67 | 下面是一个不正确 的示例:
68 |
69 | ```python
70 | import maliang
71 |
72 | root = maliang.Tk()
73 | root.center()
74 |
75 | cv = maliang.Canvas(bg="orange", auto_update=False)
76 | cv.place(width=1280, height=720)
77 | cv.place_forget()
78 |
79 | root.after(3000, lambda: cv.place(width=1280, height=720))
80 | root.mainloop()
81 | ```
82 |
83 | 在上述程序开始运行后,用户可以快速缩放窗口,然后等待 3 秒,看看画布是否处于正确的大小。
84 |
85 | 很显然,上面的示例就会导致画布没有同步缩放。应该修改为如下代码:
86 |
87 | ```python hl_lines="11-14 17"
88 | import maliang
89 |
90 | root = maliang.Tk()
91 | root.center()
92 |
93 | cv = maliang.Canvas(bg="orange", auto_update=False)
94 | cv.place(width=1280, height=720)
95 | cv.place_forget()
96 |
97 |
98 | def func() -> None:
99 | cv.place(width=1280, height=720)
100 | cv.update()#(1)!
101 | cv.zoom()#(2)!
102 |
103 |
104 | root.after(3000, func)
105 | root.mainloop()
106 | ```
107 |
108 | 1. 更新画布,防止执行下一行的操作时画布的数据还没及时更新。
109 | 2. 根据父控件和画布本身的数据重新调整画布的缩放。
110 |
111 | 此方法虽然可以,不过需要特别提醒的是,此方法仅对 Place 布局有效。
112 |
113 | !!! tip "温馨提示:运行时动态创建控件需要调用控件的方法 `zoom` 来保证正确缩放"
114 |
115 | 由于画布缩放后大小不一定和原来的一致,在缩放后创建新的控件就会导致新控件与其它控件的大小比例不协调,于是就需要缩放一下新创建的控件来保证比例协调。
116 |
117 | 通过调用控件的方法 `zoom` 来保证正确缩放,参数使用默认值即为自动适配画布的缩放比例。由于该操作有一定的性能开销,所以 `maliang` 并没有让所有的控件在创建时都自动调用该方法,开发者需要自己确定调用的时机以保证正确缩放。
118 |
119 | #### 2.1.3 动画移动来切换页面
120 |
121 | 当然除了上面说的这种方式之外,还有一种比较取巧的办法。那就是在程序开始的时候就把所有的画布一次性创建好,然后通过 Place 布局的方式将它们放置在看不到的位置,需要的时候就把他们移动到可见范围内,反之就移开。正好,`maliang` 提供了比较好的动画机制,可以试着用这种方式解决这个问题:
122 |
123 | ```python hl_lines="10 11"
124 | import maliang
125 | import maliang.animation as animation
126 |
127 | root = maliang.Tk()
128 | cv1 = maliang.Canvas(bg="orange", auto_update=False)
129 | cv1.place(width=1280, height=720, x=0)
130 | cv2 = maliang.Canvas(bg="lightgreen", auto_update=False)
131 | cv2.place(width=1280, height=720, x=-1280)
132 |
133 | animation.MoveTkWidget(cv1, (1280, 0), 1000, controller=animation.smooth, fps=60).start(delay=1000)
134 | animation.MoveTkWidget(cv2, (1280, 0), 1000, controller=animation.smooth, fps=60).start(delay=1000)
135 |
136 | root.mainloop()
137 | ```
138 |
139 | 上述代码在运行 1 秒后,两个画布会有移动的动画。
140 |
141 | !!! warning "特别注意:可能造成性能问题"
142 |
143 | 对于上述第二种方式,在画布的数量较多时缩放窗口可能会产生性能问题。因为缩放机制会对当前所有“可见”的控件进行缩放(未第一次放置或者调用了类似 `*_forget` 方法的画布不可见),而这里的可见是指在程序层面可见的,故这种方式可能导致缩放时产生明显卡顿。
144 |
145 | ### 2.2 混合 `tkinter` 控件
146 |
147 | 画布可以承载 `maliang` 的虚拟控件,但它本身也是 `tkinter` 的控件,因此也可以包含 `tkinter` 的控件,这是完全可以的。
148 |
149 | 不过为了兼容性考虑,推荐在 `Canvas` 里的 `tkinter` 控件使用 `Place` 布局方式,这样在缩放时,其缩放模式会和 `maliang` 的虚拟控件保持一致。使用其它的布局方式也是可以,但无法保证缩放时能得到正确的结果。
150 |
151 | ```python
152 | import tkinter.ttk as ttk
153 |
154 | import maliang
155 | import maliang.theme as theme
156 |
157 | theme.set_color_mode("light")
158 |
159 | root = maliang.Tk(title="登录")
160 | root.center()
161 |
162 | cv = maliang.Canvas(auto_zoom=True)
163 | cv.place(width=1280, height=720)
164 |
165 | ttk.Label(cv, text="账 号 登 录", font=(maliang.Font.family, -48), anchor="center").place(width=400, height=100, x=440, y=150)
166 |
167 | ttk.Label(cv, text="账号").place(x=450, y=300)
168 | ttk.Entry(cv, font=(maliang.Font.family, -20)).place(width=380, height=50, x=450, y=340)
169 | ttk.Label(cv, text="密码").place(x=450, y=400)
170 | ttk.Entry(cv, font=(maliang.Font.family, -20), show="●").place(width=380, height=50, x=450, y=440)
171 |
172 | ttk.Button(cv, text="注 册").place(width=180, height=50, x=450, y=540)
173 | ttk.Button(cv, text="登 录").place(width=180, height=50, x=650, y=540)
174 |
175 | root.mainloop()
176 | ```
177 |
178 | 上面代码就是在 `Canvas` 里混合了 `tkinter` 控件的示例。
179 |
180 | 运行这段代码,你可能会对这个效果很熟悉。其实在前面的章节 [§1.2 实现一个简单的界面](../chapter_01/2.md#13-创建控件) 的示例代码中我们已经用 `maliang` 实现了类似的效果,这里只是用 `tkinter.ttk` 再次实现了它,但不同的是,这里是 `maliang` 混合 `tkinter.ttk` 做的,其不仅具有 `tkinter.ttk` 的样式,还拥有了 `maliang` 的功能。(1)
181 | { .annotate }
182 |
183 | 1. 💡你可以试着缩放窗口,看看与原生的 `tkinter.ttk` 程序相比,有什么不同之处
184 |
185 | ### 2.4 嵌套画布
186 |
187 | 既然画布本身是 `tkinter` 控件,那自然画布可以嵌套在画布之中,当然,`Canvas` 和 `Canvas` 自身之间也是可以任意嵌套的。
188 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_05/1.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 颜色
5 | - 颜色转换
6 | ---
7 |
8 | # §5.1 颜色格式及其转换
9 |
10 | ## 一、颜色格式
11 |
12 | ### 1.1 `tkinter` 的颜色
13 |
14 | `tkinter` 仅支持颜色名称字符串和像 #RGB 格式的十六进制颜色字符串(如 #RGB 和 #RRGGBB),此处的 R 表示红色的比例(Red),G 表示绿色的比例(Green),B 表示蓝色的比例(Blue)。
15 |
16 | 下面举例一些 `tkinter` 能够识别的颜色字符串:
17 |
18 | * `#!python "royalblue"`
19 | * `#!python "pink"`
20 | * `#!python "#123"`
21 | * `#!python "#FF6600"`
22 |
23 | 关于 RGB 颜色格式的其它详细信息,这里不想再额外说明,如果想知道,请自行在别处搜索。
24 |
25 | !!! tip "温馨提示:空字符串在 `tkinter` 中表示没有颜色"
26 |
27 | 空字符串 `#!python ""` 在 `tkinter` 中也是可以解析的,表示没有颜色,你也可以将其视为完全透明。在某些情况下这会很有用,比如在 Canvas 中,有些 Item 的边框是有默认颜色的(一般是黑色),如果不想让它们显示出来,就将对应的参数设置为空字符串,这样就变成“透明”了。
28 |
29 | ### 1.2 `maliang` 的颜色
30 |
31 | `maliang` 并没有在接口上对 `tkinter` 做什么修改,只是增加了一些用于颜色的函数方便开发而已。也就是说,`maliang` 所有涉及到颜色的地方也是用和 `tkinter` 一样的颜色字符串的方式来传入颜色的。
32 |
33 | !!! question "猜你想问:Python 已内置了模块 `colorsys` 来提供颜色相关的函数,为什么 `maliang` 还专门对此有新的内容?"
34 |
35 | 很简单,`colorsys` 提供的功能很有限,很多轮子都没有,需要自己造。而 `maliang` 的子包 `maliang.color` 提供了更多处理颜色的功能。不过要注意的是,`colorsys` 提供的接口与 `maliang` 的不一样,不能混用!
36 |
37 | 虽然在格式上来说,都是颜色字符串,但实际上 `maliang` 还实验性地支持 #RRGGBBAA 格式的颜色字符串,但这个功能实现的是“伪 RGBA”,只能完成非常有限的功能。
38 |
39 | 首先,RGBA 中的 A 表示的是透明度(Alpha),与 R、G 和 B 一样,范围是 0~F,F 表示不透明,0 表示完全透明。但是 `maliang` 提供的 RGBA 并没有真正意义上实现透明度功能,它只是相对于 Canvas 的背景色做了一定处理的颜色而已。限于技术原因,没办法以低性能开销地方式实现真正的透明度功能。下文会对此作详细的介绍。
40 |
41 | ## 二、颜色间转换
42 |
43 | ### 2.1 颜色“标识符”
44 |
45 | 这里所说的“标识符”是 `maliang` 对一种涉及到的颜色格式的称呼,并非一个类或者常量。`maliang` 支持处理的颜色“标识符”有下面六种:
46 |
47 | 1. `rgb`: RGB 三元组,例如 `#!python (12, 34, 56)`
48 | 2. `hsl`: HSL 三元组,例如 `#!python (math.pi, 0.5, 0.5)`
49 | 3. `hex`: 十六进制颜色字符串,例如 `#!python "#ABCDEF"` 或者 `#!python "#12345678"`
50 | 4. `name`: 颜色名称字符串,例如 `#!python "royalblue"`
51 | 5. `rgba`: RGBA 四元组,例如 `#!python (12, 34, 56, 78)`
52 | 6. `str`: hex(不含八位长度 RGBA 格式的 hex)或 name
53 |
54 | 其中三位长度与六位长度的 `hex` 格式和 `name` 格式可以直接被 `tkinter` 识别。因此一般情况下,转换后的最终的结果都是这两种格式。虽然这两种可以被直接识别,但并不利于处理,常用的实际上是 `rgb` 或者其它的格式。这里注意一下,八位长度的 `hex` 格式的颜色字符串(如 `#!python "#12345678"`)是 `maliang` 中的“伪 RGBA” 格式,这种是不能被 `tkinter` 直接识别的,但可以被 `maliang` 所识别。
55 |
56 | 关于“伪 RGBA”,假设 Canvas 的背景色是白色,设置的“伪 RGBA”值为 `#!python "#FF000078"`,那么实际呈现的颜色为 `#!python "#780000"`,读者见下面的示例:
57 |
58 | ```python hl_lines="7-10 12-13"
59 | import maliang
60 |
61 | root = maliang.Tk()
62 | canvas = maliang.Canvas()
63 | canvas.place(width=1280, height=720)
64 |
65 | maliang.Label(canvas, (20, 20), text="Label RGBA 0%").style.set(bg="#FF000000")
66 | maliang.Label(canvas, (20, 80), text="Label RGBA 50%").style.set(bg="#FF00007F")
67 | maliang.Label(canvas, (20, 140), text="Label RGBA 100%").style.set(bg="#FF0000FF")
68 | maliang.Label(canvas, (20, 200), text="Label RGB").style.set(bg="#FF0000")
69 |
70 | maliang.Label(canvas, (300, 100), text="Label RGBA").style.set(bg="#FF00007F")
71 | maliang.Label(canvas, (320, 120), text="Label RGBA").style.set(bg="#FF00007F")
72 |
73 | root.mainloop()
74 | ```
75 |
76 | 其效果如下:
77 |
78 | 
79 | 
80 |
81 | /// figure-caption
82 | “伪 RGBA”
83 | ///
84 |
85 | 很明显,Alpha 设置的值越小,就越透明(和 [`Tk.alpha`][maliang.core.containers.Tk.alpha] 类似)。但多个控件叠加的时候效果并不会像预期的那样,这也是这项功能被称为“伪 RGBA” 的原因。
86 |
87 | !!! question "猜你想问:既然是“伪 RGBA”,那我提前计算出这个 RGBA 的值再设置到控件的样式上不是一样的效果吗?"
88 |
89 | 其实不一样的,写成 RGBA 的格式会好一些。虽然这是“伪 RGBA”,但首先它不需要我们手动去计算,可以减少开发时间;此外,也是最重要的一点,它是动态响应系统主题的!你可以尝试运行上面的代码,然后切换系统的主题,看看这个假的是半透明会不会跟着变化。
90 |
91 | 当然,能看到变化的前提是,你当前的环境支持跟随系统主题切换程序主题。
92 |
93 | ### 2.2 格式间转换
94 |
95 | 虽然上面涉及到的颜色格式很多,但记住它们在 `maliang` 的“标识符”就能很容易使用这些转换函数了,下面是它们之间的转换函数:
96 |
97 | | | rgb | hsl | hex | name | rgba |
98 | | :---: | :------------------------------------------------: | :----------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: | :------------------------------------------------: |
99 | | rgb | \ | [`rgb_to_hsl`][maliang.color.convert.rgb_to_hsl] | [`rgb_to_hex`][maliang.color.convert.rgb_to_hex] | [`rgb_to_name`][maliang.color.convert.rgb_to_name] | |
100 | | hsl | [`hsl_to_rgb`][maliang.color.convert.hsl_to_rgb] | \ | [`hsl_to_hex`][maliang.color.convert.hsl_to_hex] | | |
101 | | hex | [`hex_to_rgb`][maliang.color.convert.hex_to_rgb] | [`hex_to_hsl`][maliang.color.convert.hex_to_hsl] | \ | [`hex_to_name`][maliang.color.convert.hex_to_name] | [`hex_to_rgba`][maliang.color.convert.hex_to_rgba] |
102 | | name | [`name_to_rgb`][maliang.color.convert.name_to_rgb] | | [`name_to_hex`][maliang.color.convert.name_to_hex] | \ | |
103 | | rgba | | | [`rgba_to_hex`][maliang.color.convert.rgba_to_hex] | | \ |
104 | | str | [`str_to_rgb`][maliang.color.convert.str_to_rgb] | | | | |
105 |
106 | 具体转换函数的使用方式,可以点击上表中对应函数的文档链接来查看。
107 |
108 | !!! Tip "温馨提示:颜色转换函数可以使用简化名称来调用"
109 |
110 | 尽管各种颜色格式已经使用“标识符”来简化了,但转换函数的名称仍然比较长,所以 `maliang` 还为每个转换函数提供了简化的别名,具体来说就是将转换函数中的 "\_to\_" 给简化为 "2"。举个例子,`str_to_rgb` 等价于 `str2rgb`。
111 |
112 | 下面是一个简单使用颜色转换函数的例子(运行结果为文档构建时计算得到):
113 |
114 | ```python exec source="material-block" result="console"
115 | import maliang.color.convert
116 |
117 | print(maliang.color.convert.str_to_rgb("red"))
118 | print(maliang.color.convert.str2rgb("Red"))
119 | print(maliang.color.convert.str_to_rgb("#FF0000"))
120 | print(maliang.color.convert.str2rgb("#F00"))
121 | ```
122 |
123 | 很显然,上面四个的结果是一致的。这里需要注意的一点就是,颜色名称字符串是不区分大小写的。
124 |
125 | 如果想知道有哪些颜色名称字符串可以被 `tkinter` 直接识别,可以在 [`colortable.MAPPING_TABLE`][maliang.color.colortable.MAPPING_TABLE] 中找到。它是一个常量字典,记录了所有 `tkinter` 可以识别的颜色名称字符串及其对应的 RGB 三元组的值。
126 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/1.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 控件
5 | - 信息展示
6 | - 文本
7 | - 图片
8 | ---
9 |
10 | # §3.1 信息类控件
11 |
12 | !!! tip "温馨提示:切换网站主题可切换效果图的主题"
13 |
14 | 本小节的图片大量涉及主题,你可以通过切换网站主题来查看在不同主题下程序运行的效果图,后面的章节也是一样的。网站的主题共有三种模式,分别对应 `maliang` 的主题三种模式。鼠标移至网站主题切换按钮下可查看当前主题。
15 |
16 | ## 一、信息类控件简述
17 |
18 | ### 1.1 什么是信息类控件
19 |
20 | 信息类控件就是指那些应该用于展示信息,而不具有额外功能的控件,如标签控件。
21 |
22 | 目前 `maliang` 内置的信息类控件有 `Text`、`Image`、`Label`、`ProgressBar`、`Tooltip` 和 `Spinner`。
23 |
24 | ### 1.2 注意事项
25 |
26 | 信息类控件的本意就是展示信息的,其不应该包含其他额外的功能,如果需要控件有其他的功能,应该考虑使用其他对应的控件或者自定义一个符合自己需要的控件。
27 |
28 | 关于自定义控件,后续章节中会详细讲述。
29 |
30 | ## 二、信息类控件详述
31 |
32 | ### 2.1 [`Text`][maliang.standard.widgets.Text]
33 |
34 | `Text` 是文本控件,它的用途是展示一些文本。这些文本可以随着画布的缩放而缩放,随程序的亮色与暗色而改变。
35 |
36 | 我们可以使用其 `get` 和 `set` 方法来获取和设置控件所展示的文本内容。
37 |
38 | 下面这段代码会在坐标为 `#!python (10, 10)` 的位置放置一个锚点为西北的文本,该文本的颜色会自动适应主题,同时可以响应画布的缩放。
39 |
40 | ```python hl_lines="7"
41 | import maliang
42 |
43 | root = maliang.Tk()
44 | cv = maliang.Canvas(auto_zoom=True)
45 | cv.place(width=1280, height=720)
46 |
47 | maliang.Text(cv, (10, 10), text="Hello tkintertools!", anchor="nw")
48 |
49 | root.mainloop()
50 | ```
51 |
52 | 效果如下:(1)
53 | { .annotate }
54 |
55 | 1. 💡你可以通过更改网站主题来查看效果图在不同主题下的样子
56 |
57 |
58 | 
59 | 
60 | 图1 文本控件
61 |
62 |
63 | ### 2.2 [`Image`][maliang.standard.widgets.Image]
64 |
65 | `Image` 是图片控件,用于展示图片,其可以响应画布的缩放,在没有安装 `pillow` 可选包的时候,仅支持 `tkinter` 原生图片格式(PNG 等),安装 `pillow` 之后可以支持更多的格式而无需更改任何代码。
66 |
67 | !!! warning "特别注意:缺少 `pillow` 可能导致性能低下"
68 |
69 | 在没有安装 `pillow` 的情况下,图片也是可以缩放的,但缩放的效率极低,极有可能导致窗口缩放时产生严重的卡顿,建议有图片缩放需求的朋友安装一下 `pillow`。
70 |
71 | 如果您已经按照 [§1.1 安装 tkintertools](../chapter_01/1.md#23-推荐安装) 中的推荐方式安装,则不需要关心这则说明。
72 |
73 | 与上面提到的 `Text` 控件类似,我们也可以用 `get`和 `set` 方法来获取和设置 `Image` 控件的内容。
74 |
75 | 下面的代码是一个简单的示例:
76 |
77 | ```python hl_lines="7"
78 | import maliang
79 |
80 | root = maliang.Tk()
81 | cv = maliang.Canvas(auto_zoom=True)
82 | cv.place(width=1280, height=720)
83 |
84 | maliang.Image(cv, (100, 100), image=maliang.PhotoImage(file="./logo.png"), anchor="center")
85 |
86 | root.mainloop()
87 | ```
88 |
89 | 效果如下:
90 |
91 |
92 | 
93 | 
94 | 图2 图片控件
95 |
96 |
97 | 示例中的图片文件是**旧版** `maliang` 的 Logo,可以在[此处](https://xiaokang2022.github.io/tkintertools/logo.png)获取。
98 |
99 | `maliang` 的 `Image` 相比于 `tkinter` 的图片展示会稍微方便一些,对于 `tkinter` 展示图片的方法,其 `PhotoImage` 类有一个问题,其必须是全局变量(保持引用)才可以展示图片,详情见[官方文档](https://docs.python.org/zh-cn/3/library/tkinter.html#images),而 `maliang` 的 `Image` 会对此进行一定的处理,使得某些情况不会出现“空白图片”的问题。
100 |
101 | ### 2.3 [`Label`][maliang.standard.widgets.Label]
102 |
103 | `maliang` 的 `Label` 稍稍不同于 `tkinter` 的 `Label`,同样是展示信息,但 `tkinter` 的 `Label` 的功能更多的是用上面讲到的 `Text` 来替代的。这里的 `Label` 更像是标签真正的意义,也就是用它来展示一个类似于分类标签的东西,比如 GitHub Issue 的标签那样。
104 |
105 | 下面的代码是一个示例:
106 |
107 | ```python hl_lines="7"
108 | import maliang
109 |
110 | root = maliang.Tk()
111 | cv = maliang.Canvas(auto_zoom=True)
112 | cv.place(width=1280, height=720)
113 |
114 | maliang.Label(cv, (10, 10), text="Label")
115 |
116 | root.mainloop()
117 | ```
118 |
119 | 效果如下:
120 |
121 | === ":fontawesome-brands-microsoft: Windows11 风格"
122 |
123 |
124 | 
125 | 
126 | 图3 标签控件
127 |
128 |
129 | === ":fontawesome-brands-windows: Windows10 风格"
130 |
131 |
132 | 
133 | 
134 | 图3 标签控件
135 |
136 |
137 | !!! tip "温馨提示:部分控件外观与系统相关"
138 |
139 | 部分控件在不同的操作系统下有不同的外观,这是为了使控件更符合操作系统的 UI 风格,一般情况下,都会使用 Windows11 风格的。当然,你也可以强制指定一种风格,在后续章节中会提到这个的。
140 |
141 | ### 2.4 [`ProgressBar`][maliang.standard.widgets.ProgressBar]
142 |
143 | `ProgressBar` 是进度条控件,相比于 `tkinter` 的进度条,`maliang` 的进度条在外观上有了很大的改善,但功能还不是完整的,缺少了无进度模式。
144 |
145 | 与前面提到的控件类似,我们可以使用 `get` 和 `set` 方法来获取和设置进度条的值,当设置的值小于 `#!python 0` 时被视为 `#!python 0`,大于 `#!python 1` 时被视为 `#!python 1`。
146 |
147 | 下面是一个简单的示例:
148 |
149 | ```python hl_lines="7"
150 | import maliang
151 |
152 | root = maliang.Tk()
153 | cv = maliang.Canvas(auto_zoom=True)
154 | cv.place(width=1280, height=720)
155 |
156 | maliang.ProgressBar(cv, (10, 10)).set(0.5)
157 |
158 | root.mainloop()
159 | ```
160 |
161 | 效果如下:
162 |
163 | === ":fontawesome-brands-microsoft: Windows11 风格"
164 |
165 |
166 | 
167 | 
168 | 图4 进度条控件
169 |
170 |
171 | === ":fontawesome-brands-windows: Windows10 风格"
172 |
173 |
174 | 
175 | 
176 | 图4 进度条控件
177 |
178 |
179 | ### 2.5 [`Tooltip`][maliang.standard.widgets.Tooltip]
180 |
181 | `Tooltip` 是工具提示框控件,简称提示框控件。它的作用就是在鼠标移至关联控件上面时显示出来以起到相应的提示作用。
182 |
183 | !!! warning "特别注意:提示框无法跨画布显示"
184 |
185 | 由于 `maliang` 的设计理念就是尽可能基于画布实现一切功能,所以提示框控件也是由画布绘制而成,无法跨出画布进行显示。
186 |
187 | 下面是一个简单的示例:
188 |
189 | ```python hl_lines="10"
190 | import maliang
191 |
192 | root = maliang.Tk()
193 | cv = maliang.Canvas(auto_zoom=True)
194 | cv.place(width=1280, height=720)
195 |
196 | pb = maliang.ProgressBar(cv, (10, 10))
197 | pb.set(0.5)
198 |
199 | maliang.Tooltip(pb, text="Loading... 50.0%")
200 |
201 | root.mainloop()
202 | ```
203 |
204 | 效果如下:
205 |
206 | === ":fontawesome-brands-microsoft: Windows11 风格"
207 |
208 |
209 | 
210 | 
211 | 图5 提示框控件
212 |
213 |
214 | === ":fontawesome-brands-windows: Windows10 风格"
215 |
216 |
217 | 
218 | 
219 | 图5 提示框控件
220 |
221 |
222 | ### 2.6 [`Spinner`][maliang.standard.widgets.Spinner]
223 |
224 | `Spinner` 是环形进度条,类似于 `ProgressBar`,但它是环形的,且目前相比于 `ProgressBar` 它有两个模式:确定模式和不定模式。
225 |
226 | * 确定模式(`#!python "determinate"`): 进度由用户控制,精确指定,表示加载进度确定的内容
227 | * 不定模式(`#!python "indeterminate"`): 进度自动呈规律变化,表示正在加载但加载进度无法确定的内容
228 |
229 | 很显然,目前 `ProgressBar` 只有“确定模式”,而 `Spinner` 目前两种都支持。~~那为什么另外一个没有“不定模式”呢?因为我懒(bushi)~~
230 |
231 | 下面是个简单的示例:
232 |
233 | ```python hl_lines="7-8"
234 | import maliang
235 |
236 | root = maliang.Tk()
237 | cv = maliang.Canvas(auto_zoom=True)
238 | cv.place(width=1280, height=720)
239 |
240 | maliang.Spinner(cv, (20, 20)).set(0.67)
241 | maliang.Spinner(cv, (100, 20), mode="indeterminate")
242 |
243 | root.mainloop()
244 | ```
245 |
246 | 效果如下:
247 |
248 | === ":fontawesome-brands-microsoft: Windows11 风格"
249 |
250 |
251 | 
252 | 
253 | 图6 环形进度条控件
254 |
255 |
256 | === ":fontawesome-brands-windows: Windows10 风格"
257 |
258 |
259 | 
260 | 
261 | 图6 环形进度条控件
262 |
263 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_04/1.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 动画
5 | - 原生动画
6 | - 控制函数
7 | ---
8 |
9 | # §4.1 基础动画
10 |
11 | ## 一、动画简述
12 |
13 | ### 1.1 动画的实现方式
14 |
15 | 在 `maliang` 中,有两种实现动画的方式,一种是使用 `maliang` 封装好的动画类,另外一种是使用 `tkinter` 原生的方式。很显然,这里推荐使用 `maliang` 封装好的动画类。
16 |
17 | #### 1.1.1 `maliang` 方式
18 |
19 | 使用 `maliang` 封装的好的动画类既可以极大地简化实现动画的操作,还可以获得一个较好的动画效果。首先,`maliang` 有一个动画基类,这个动画基类的功能比较强大,可以通过继承它来实现各种各样的动画子类。
20 |
21 | 此外,`maliang` 还实现了对动画过程的细微控制,而不是一个简单的开始和结束。说简单点,就是可以通过一个控制函数来控制动画运动的过程。比如说,一个小球从左移动到右这一动画,我们可以通过使用[控制函数](#12-控制函数)来实现小球平滑移动这一效果,又或者是回弹的效果,而不是简单的平移。
22 |
23 | 除了上述说的平滑移动,还有其它很多的方式,只要你设置了合适的控制函数,动画就能按照控制函数那样去运动!
24 |
25 | #### 1.1.2 `tkinter` 原生方式
26 |
27 | 当然,说到底 `maliang` 封装的动画类也是基于 `tkinter` 原生动画方式实现的,但要直接使用 `tkinter` 原生的方式来做出一些动画有一定难度,且不好操控。
28 |
29 | 下面是一个简单的示例,该示例可以将画布上的一个小球向右平移:
30 |
31 | ```python hl_lines="10-13 16"
32 | import maliang
33 |
34 | root = maliang.Tk()
35 | cv = maliang.Canvas()
36 | cv.place(width=1280, height=720)
37 |
38 | ball = cv.create_oval(100, 100, 200, 200, fill="orange", outline="")
39 |
40 |
41 | def animation(t: int = 0) -> None:
42 | if t < 100:
43 | cv.move(ball, 10, 0)
44 | cv.after(10, animation, t+1)
45 |
46 |
47 | root.after(1000, animation)
48 | root.mainloop()
49 | ```
50 |
51 | 效果如下:(1)
52 | { .annotate }
53 |
54 | 1. 注:gif 图限制了帧率为 30 ,实际效果会更流畅一些,后面的同理。
55 |
56 | 
57 | 
58 |
59 | /// figure-caption
60 | `tkinter` 原生动画
61 | ///
62 |
63 | 虽然使用 `tkinter` 原生的方式能实现一定的动画效果,但要再想深入实现某些功能就比较复杂了。由于 `tkinter` 实现动画的方式并不属于本教程的范畴,这里就不深入讲解了。
64 |
65 | ### 1.2 控制函数
66 |
67 | 从前面讲述的内容来看,想必你已经大致了解什么是控制函数了。本小节并不会对控制函数做一个详细的说明,这部分会出现在后续章节中。但此处仍指出 `maliang` 内置的 5 个控制函数:
68 |
69 | * [`linear`][maliang.animation.controllers.linear]: 平移运动,动画类控制函数的默认值都是它
70 | * [`smooth`][maliang.animation.controllers.smooth]: 平滑运动
71 | * [`rebound`][maliang.animation.controllers.rebound]: 回弹运动
72 | * [`ease_in`][maliang.animation.controllers.ease_in]: 缓入运动
73 | * [`ease_out`][maliang.animation.controllers.ease_out]: 缓出运动
74 |
75 | 下面是它们的效果,红绿蓝分别对应上述的前三种控制函数:
76 |
77 | 
78 | 
79 |
80 | /// figure-caption
81 | `maliang` 动画
82 | ///
83 |
84 | 下面是上述效果的实现代码:
85 |
86 | ```python hl_lines="12-14"
87 | import maliang
88 | import maliang.animation as animation
89 |
90 | root = maliang.Tk()
91 | cv = maliang.Canvas()
92 | cv.place(width=1280, height=720)
93 |
94 | ball_1 = cv.create_oval(100, 100, 200, 200, fill="red", outline="")
95 | ball_2 = cv.create_oval(100, 100+200, 200, 200+200, fill="green", outline="")
96 | ball_3 = cv.create_oval(100, 100+400, 200, 200+400, fill="royalblue", outline="")
97 |
98 | animation.MoveItem(cv, ball_1, (840, 0), 1000, fps=60, controller=animation.linear).start(delay=1000)
99 | animation.MoveItem(cv, ball_2, (840, 0), 1000, fps=60, controller=animation.smooth).start(delay=1000)
100 | animation.MoveItem(cv, ball_3, (840, 0), 1000, fps=60, controller=animation.rebound).start(delay=1000)
101 |
102 | root.mainloop()
103 | ```
104 |
105 | 此外,还可以自定义控制函数,这部分会在后续内容中详细讲解。
106 |
107 | ## 二、动画类
108 |
109 | 这里说的动画类是动画基类的各个子类,关于动画基类的讲解在后续章节中。
110 |
111 | 每个动画子类都是对于某一特定动画的具体实现,使用时应该根据需求选取,若没有满足需要的动画子类,也可以基于动画基类继承后实现属于自己的动画子类,即自定义动画类。关于自定义动画类的内容将在后续章节中详述。
112 |
113 | ### 2.1 [`MoveTkWidget`][maliang.animation.animations.MoveTkWidget]
114 |
115 | `MoveTkWidget` 用来移动 `tkinter` 中的原生控件(如 `tkinter` 的 `Label`)及其继承的子类(如 `maliang` 的 `Canvas`)。
116 |
117 | 下面是一个简单的示例,利用该类移动 `tkinter` 的 `Label` 控件:
118 |
119 | ```python hl_lines="11"
120 | import tkinter
121 |
122 | import maliang
123 | import maliang.animation as animation
124 |
125 | root = maliang.Tk()
126 |
127 | label = tkinter.Label(root, text="TkLabel")
128 | label.place(x=100, y=100)
129 |
130 | animation.MoveTkWidget(label, (1000, 0), 1000, fps=60).start(delay=1000)
131 |
132 | root.mainloop()
133 | ```
134 |
135 | 效果如下:
136 |
137 | 
138 | 
139 |
140 | /// figure-caption
141 | 移动 `tkinter` 原生控件
142 | ///
143 |
144 | ### 2.2 [`MoveWidget`][maliang.animation.animations.MoveWidget]
145 |
146 | `MoveWidget` 用来移动 `maliang` 中的控件。
147 |
148 | 使用方式和上面的类似,下面是一个简单的示例:
149 |
150 | ```python hl_lines="10"
151 | import maliang
152 | import maliang.animation as animation
153 |
154 | root = maliang.Tk()
155 | cv = maliang.Canvas()
156 | cv.place(width=1280, height=720)
157 |
158 | label = maliang.Label(cv, (100, 100), text="Label")
159 |
160 | animation.MoveWidget(label, (1000, 0), 1000, fps=60).start(delay=1000)
161 |
162 | root.mainloop()
163 | ```
164 |
165 | 效果如下:
166 |
167 | 
168 | 
169 |
170 | /// figure-caption
171 | 移动控件
172 | ///
173 |
174 | ### 2.3 [`MoveElement`][maliang.animation.animations.MoveElement]
175 |
176 | `MoveElement` 用来移动 `maliang` 中的元素。这里说的元素与上面说的控件有很大的区别,前面章节并没有详细地指出这个问题,这个问题将在后续关于自定义控件和元素的部分详细说明。
177 |
178 | 下面是一个简单示例:
179 |
180 | ```python hl_lines="10"
181 | import maliang
182 | import maliang.animation as animation
183 |
184 | root = maliang.Tk()
185 | cv = maliang.Canvas(root)
186 | cv.place(width=1280, height=720)
187 |
188 | label = maliang.Label(cv, (100, 100), text="Label")
189 |
190 | animation.MoveElement(label.elements[0], (1000, 0), 1000, fps=60).start(delay=1000)
191 |
192 | root.mainloop()
193 | ```
194 |
195 | 效果如下:
196 |
197 | 
198 | 
199 |
200 | /// figure-caption
201 | 移动元素
202 | ///
203 |
204 | 可以看见,控件的形状和其它部分离了,但这里只是为了演示这个作用和效果,实际中一般并不会这样做。(~~没事干嘛把形状分离??~~)
205 |
206 | ### 2.4 [`MoveItem`][maliang.animation.animations.MoveItem]
207 |
208 | `MoveItem` 用来移动画布中的基本项。
209 |
210 | 与其它不同的是,操作 item 必须指明其所属的画布,不然无法对 item 进行操作(1)。下面是一个简单的示例:
211 | { .annotate }
212 |
213 | 1. 因为 item 实际只是一个 `#!python int` 类型的对象,自身无法存储其所属画布的相关信息
214 |
215 | ```python hl_lines="10"
216 | import maliang
217 | import maliang.animation as animation
218 |
219 | root = maliang.Tk()
220 | cv = maliang.Canvas()
221 | cv.place(width=1280, height=720)
222 |
223 | item = cv.create_rectangle(100, 100, 200, 200, fill="gray", outline="")
224 |
225 | animation.MoveItem(cv, item, (1000, 0), 1000, fps=60).start(delay=1000)
226 |
227 | root.mainloop()
228 | ```
229 |
230 | 效果如下:
231 |
232 | 
233 | 
234 |
235 | /// figure-caption
236 | 移动画布基本项
237 | ///
238 |
239 | ### 2.5 [`GradientTkWidget`][maliang.animation.animations.GradientTkWidget]
240 |
241 | `GradientTkWidget` 用来使 `tkinter` 中的原生控件的相关颜色渐变。
242 |
243 | 下面是一个简单的示例:
244 |
245 | ```python hl_lines="11"
246 | import tkinter
247 |
248 | import maliang
249 | import maliang.animation as animation
250 |
251 | root = maliang.Tk()
252 |
253 | label = tkinter.Label(root, text="TkLabel")
254 | label.place(x=200, y=200)
255 |
256 | animation.GradientTkWidget(label, "bg",("red", "green"), 2000, repeat=-1).start()
257 |
258 | root.mainloop()
259 | ```
260 |
261 | 效果如下:
262 |
263 | 
264 | 
265 |
266 | /// figure-caption
267 | `tkinter` 控件的渐变颜色
268 | ///
269 |
270 | 这个示例使用了 `repeat` 参数来让这个动画循环进行,`repeat` 是循环的次数,当次数小于 `#!python 0` 时会无限循环,直到动画类或者程序被终止。
271 |
272 | ### 2.6 [`GradientItem`][maliang.animation.animations.GradientItem]
273 |
274 | `GradientItem` 用来使画布中元素的相关颜色渐变。
275 |
276 | 前面的渐变动画使用了循环,但每次循环之间没有过渡,看起来十分不自然。我们可以给动画类设定一个控制函数来让渐变颜色的起始值和终止值相同,以保证过渡自然。下面是一个简单的示例:
277 |
278 | ```python hl_lines="12"
279 | import math
280 |
281 | import maliang
282 | import maliang.animation as animation
283 |
284 | root = maliang.Tk()
285 | cv = maliang.Canvas()
286 | cv.place(width=1280, height=720)
287 |
288 | item = cv.create_rectangle(100, 100, 200, 200, outline="")
289 |
290 | animation.GradientItem(cv, item, "fill", ("yellow", "purple"), 2000, repeat=-1, controller=lambda x: math.sin(x*math.pi)).start()
291 |
292 | root.mainloop()
293 | ```
294 |
295 | 效果与呼吸灯类似:
296 |
297 | 
298 | 
299 |
300 | /// figure-caption
301 | 画布元素的渐变颜色
302 | ///
303 |
304 | ### 2.7 [`ScaleFontSize`][maliang.animation.animations.ScaleFontSize]
305 |
306 | `ScaleFontSize` 用来缩放**组件** `Text` 的字体大小,注意不是控件 `Text` 的字体大小。
307 |
308 | 为了让字体的缩放看着更有张力,我们可以试着使用前面提到的 `rebound` 控制函数,下面是一个简单的示例:
309 |
310 | ```python hl_lines="10"
311 | import maliang
312 | import maliang.animation as animation
313 |
314 | root = maliang.Tk()
315 | cv = maliang.Canvas()
316 | cv.place(width=1280, height=720)
317 |
318 | text = maliang.Text(cv, (100, 100), text="Text", anchor="center")
319 |
320 | animation.ScaleFontSize(text.texts[0], (20, 48), 500, controller=animation.rebound).start(delay=1000)
321 |
322 | root.mainloop()
323 | ```
324 |
325 | 运行上述代码后,字体放大后会再回弹缩小,效果如下:
326 |
327 | 
328 | 
329 |
330 | /// figure-caption
331 | `tkinter` 控件的渐变颜色
332 | ///
333 |
334 | !!! warning "特别注意:慎用 `ScaleFontSize` 类"
335 |
336 | 该类没有对窗口和画布的缩放做适配,在窗口或者画布缩放之后,该类可能会产生意想不到的效果,该效果一般不符合预期要求。
337 |
--------------------------------------------------------------------------------
/docs/tutorials/chapter_03/2.md:
--------------------------------------------------------------------------------
1 | ---
2 | comments: true
3 | tags:
4 | - 控件
5 | - 功能
6 | ---
7 |
8 | # §3.2 功能类控件
9 |
10 | ## 一、功能类控件简述
11 |
12 | ### 1.1 什么是功能类控件
13 |
14 | 从名字上就可以看出,它们是自带了一定功能的控件,相比于信息类控件,它们除了可以展示一定的信息之外,还可以通关相关互动改变相应的信息。
15 |
16 | 目前 `maliang` 内置的功能类控件有 `Button`、`Switch`、`ToggleButton`、`CheckBox`、`RadioBox`、`UnderlineButton`、`HighlightButton`、`IconButton`、`Slider`、`SegmentedButton` 和 `OptionButton`。
17 |
18 | 虽然看起来很多,但在后续章节中学习了自定义控件后,我们将会了解到实际上其中有很多的类都是大同小异的。
19 |
20 | ### 1.2 与信息类控件的差异
21 |
22 | 功能类控件与信息类控件最大的差异就是,其功能类 `Feature` 的复杂程度不同,有些信息类控件,如 `Text` 和 `Image`,甚至都没有功能类,也就是说,它们不具备任何交互。可以说,功能类控件的核心就是其功能类。
23 |
24 | !!! question "猜你想问:什么是功能类 `Feature` ?"
25 |
26 | 在前面的选读章节 [§1.3 框架概述](../chapter_01/3.md#31-控件构建框架) 中有提到,`maliang` 的一个控件由五大基础部分组成,即 `Shape`、`Image`、`Text`、`Style` 和 `Feature`。它们分别负责图形部分、图像部分、文本部分、样式部分和功能部分。
27 |
28 | ## 二、功能类控件详述
29 |
30 | 下面的都是经典的基本控件,在各大 UI 框架都能见到它们的身影,而这里是 `maliang` 对它们的一个简单实现。
31 |
32 | ### 2.1 [`Button`][maliang.standard.widgets.Button]
33 |
34 | `Button` 是按钮控件,可以用于执行某些函数。
35 |
36 | 下面是一个简单的示例,创建了一个文本内容为 `#!python "Button"`,且在点击后会在终端输出 `#!python "Click"` 的按钮:
37 |
38 | ```python hl_lines="7"
39 | import maliang
40 |
41 | root = maliang.Tk()
42 | cv = maliang.Canvas(auto_zoom=True)
43 | cv.place(width=1280, height=720)
44 |
45 | maliang.Button(cv, (20, 20), text="Button", command=lambda: print("Click"))
46 |
47 | root.mainloop()
48 | ```
49 |
50 | 效果如下:
51 |
52 | === ":fontawesome-brands-microsoft: Windows11 风格"
53 |
54 |
55 | 
56 | 
57 | 图1 按钮控件
58 |
59 |
60 | === ":fontawesome-brands-windows: Windows10 风格"
61 |
62 |
63 | 
64 | 
65 | 图1 按钮控件
66 |
67 |
68 | ### 2.2 [`Switch`][maliang.standard.widgets.Switch]
69 |
70 | `Switch` 是开关控件,既可以直观地看到状态,又可以直接操作来改变状态。我们可以使用其 `get` 和 `set` 方法来获取和设置其状态。
71 |
72 | 下面的示例创建了两个开关控件,并给它们绑定了函数 `#!python print`,当它被点击时会在终端输出当前的状态:
73 |
74 | ```python hl_lines="7-8"
75 | import maliang
76 |
77 | root = maliang.Tk()
78 | cv = maliang.Canvas(auto_zoom=True)
79 | cv.place(width=1280, height=720)
80 |
81 | maliang.Switch(cv, (20, 20), command=print)
82 | maliang.Switch(cv, (120, 20), command=print, default=True)
83 |
84 | root.mainloop()
85 | ```
86 |
87 | 效果如下:
88 |
89 | === ":fontawesome-brands-microsoft: Windows11 风格"
90 |
91 |
92 | 
93 | 
94 | 图2 开关控件
95 |
96 |
97 | === ":fontawesome-brands-windows: Windows10 风格"
98 |
99 |
100 | 
101 | 
102 | 图2 开关控件
103 |
104 |
105 | !!! warning "特别注意:`default` 参数和 `set` 方法"
106 |
107 | 我们查阅文档可以注意到,开关控件包含一个名为 `default` 的初始化参数,可以设定其初始状态。于是我们可以使用两种方式来设置开关控件的初始状态,其一是利用 `default` 参数,其二是利用 `set` 方法。
108 |
109 | 若没有指定 `set` 方法的 `callback` 参数,那么这两种方式并没有差异。当 `callback` 被设置为 `True`,那么调用 `set` 方法的同时将调用控件绑定的关联函数,不管当前状态与设置的是否相同。反之,则只会改变控件的外观和状态,且仅在修改的状态与当前不同时执行。
110 |
111 | 后面有许多控件也有类似的设定,就不再赘述。
112 |
113 | ### 2.3 [`ToggleButton`][maliang.standard.widgets.ToggleButton]
114 |
115 | `ToggleButton` 被称为开关按钮控件,它本质和上面的开关控件一样,只是外观不同罢了。
116 |
117 | 下面是一个简单的示例:
118 |
119 | ```python hl_lines="7-8"
120 | import maliang
121 |
122 | root = maliang.Tk()
123 | cv = maliang.Canvas(auto_zoom=True)
124 | cv.place(width=1280, height=720)
125 |
126 | maliang.ToggleButton(cv, (20, 20), text="ToggleButton", command=print)
127 | maliang.ToggleButton(cv, (20, 120), text="ToggleButton", command=print, default=True)
128 |
129 | root.mainloop()
130 | ```
131 |
132 | 效果如下:
133 |
134 | === ":fontawesome-brands-microsoft: Windows11 风格"
135 |
136 |
137 | 
138 | 
139 | 图3 开关按钮控件
140 |
141 |
142 | === ":fontawesome-brands-windows: Windows10 风格"
143 |
144 |
145 | 
146 | 
147 | 图3 开关按钮控件
148 |
149 |
150 | ### 2.4 [`CheckBox`][maliang.standard.widgets.CheckBox]
151 |
152 | `CheckBox` 是复选框控件,但 `maliang` 的复选框控件可能和其它 UI 框架里面的复选框控件不同,其它的 UI 框架的复选框一般都是带文本的,但 `maliang` 的复选框真的就只有一个框。这样用户可以灵活放置复选框对应文本的位置。
153 |
154 | 下面的示例是复选框配上文本控件的效果:
155 |
156 | ```python hl_lines="7-10"
157 | import maliang
158 |
159 | root = maliang.Tk()
160 | cv = maliang.Canvas(auto_zoom=True)
161 | cv.place(width=1280, height=720)
162 |
163 | maliang.CheckBox(cv, (20, 20), command=print)
164 | maliang.Text(cv, (60, 35), text="CheckBox", anchor="w")
165 | maliang.CheckBox(cv, (20, 120), command=print, default=True)
166 | maliang.Text(cv, (60, 135), text="CheckBox", anchor="w")
167 |
168 | root.mainloop()
169 | ```
170 |
171 | 效果如下:
172 |
173 | === ":fontawesome-brands-microsoft: Windows11 风格"
174 |
175 |
176 | 
177 | 
178 | 图4 复选框控件
179 |
180 |
181 | === ":fontawesome-brands-windows: Windows10 风格"
182 |
183 |
184 | 
185 | 
186 | 图4 复选框控件
187 |
188 |
189 | ### 2.5 [`RadioBox`][maliang.standard.widgets.RadioBox]
190 |
191 | 与复选框控件对应的就是 `RadioBox` 单选框控件,与复选框控件类似,但是它的目前情况有些尴尬,因为无法判断哪些单选框是绑定在一起的,所以需要用户自己去绑定相关函数来完成单选框的功能。目前单选框只提供了一个外观,说简单点就是存在一定问题,有待优化。
192 |
193 | 下面是一个简单的示例:
194 |
195 | ```python hl_lines="7-10"
196 | import maliang
197 |
198 | root = maliang.Tk()
199 | cv = maliang.Canvas(auto_zoom=True)
200 | cv.place(width=1280, height=720)
201 |
202 | rb1 = maliang.RadioBox(cv, (20, 20), command=print)
203 | maliang.Text(cv, (60, 35), text="RadioBox", anchor="w")
204 | rb2 = maliang.RadioBox(cv, (20, 120), command=print, default=True)
205 | maliang.Text(cv, (60, 135), text="RadioBox", anchor="w")
206 |
207 | maliang.RadioBox.group(rb1, rb2)#(1)!
208 |
209 | root.mainloop()
210 | ```
211 |
212 | 1. 实际上你也可以这样写:
213 |
214 | ```python linenums="0"
215 | rb1.group(rb2)
216 | ```
217 |
218 | 效果如下:
219 |
220 | === ":fontawesome-brands-microsoft: Windows11 风格"
221 |
222 |
223 | 
224 | 
225 | 图5 单选框控件
226 |
227 |
228 | === ":fontawesome-brands-windows: Windows10 风格"
229 |
230 |
231 | 
232 | 
233 | 图5 单选框控件
234 |
235 |
236 | 如果觉得单选框这个不好操作,可以尝试选择使用功能类似的[分段按钮控件](#27-segmentedbutton)。
237 |
238 | ### 2.6 [`Slider`][maliang.standard.widgets.Slider]
239 |
240 | `Slider` 滑动条控件,用于直观的调整处在某个范围的数据,并实时地看到反馈。
241 |
242 | 下面这个示例就可以在调节的同时在终端看到当前滑动条的值:
243 |
244 | ```python hl_lines="7"
245 | import maliang
246 |
247 | root = maliang.Tk()
248 | cv = maliang.Canvas(auto_zoom=True)
249 | cv.place(width=1280, height=720)
250 |
251 | maliang.Slider(cv, (20, 20), default=0.5, command=print)
252 |
253 | root.mainloop()
254 | ```
255 |
256 | 效果如下:
257 |
258 | === ":fontawesome-brands-microsoft: Windows11 风格"
259 |
260 |
261 | 
262 | 
263 | 图6 滑动条控件
264 |
265 |
266 | === ":fontawesome-brands-windows: Windows10 风格"
267 |
268 |
269 | 
270 | 
271 | 图6 滑动条控件
272 |
273 |
274 | ### 2.7 [`SegmentedButton`][maliang.standard.widgets.SegmentedButton]
275 |
276 | 分段按钮控件,某些情况下可以作为单选框控件的平替。作用和单选框控件类似,只是外观不大相同,这里就不再赘述。
277 |
278 | 下面是一个简单的示例:
279 |
280 | ```python hl_lines="7"
281 | import maliang
282 |
283 | root = maliang.Tk()
284 | cv = maliang.Canvas(auto_zoom=True)
285 | cv.place(width=1280, height=720)
286 |
287 | maliang.SegmentedButton(cv, (20, 20), text=("Option 1", "Option 2", "Option 3"))
288 |
289 | root.mainloop()
290 | ```
291 |
292 | 效果如下:
293 |
294 | === ":fontawesome-brands-microsoft: Windows11 风格"
295 |
296 |
297 | 
298 | 
299 | 图7 分段按钮控件
300 |
301 |
302 | === ":fontawesome-brands-windows: Windows10 风格"
303 |
304 |
305 | 
306 | 
307 | 图7 分段按钮控件
308 |
309 |
310 | 除了上面的示例代码演示的效果之外,我们还可以尝试设置分段按钮控件的其它参数,如将参数 `layout` 设置为 `#!python "vertical"`,你就可以得到一个纵向布局的分段按钮控件。
311 |
312 | ### 2.8 [`OptionButton`][maliang.standard.widgets.OptionButton]
313 |
314 | 选项按钮控件,相当于折叠版的 `SegmentedButton`。它和 `SegmentedButton` 一样,只不过它的内容只有在点击按钮时才会展示出来,选择内容之后又会消失。
315 |
316 | 下面是一个简单的示例:
317 |
318 | ```python hl_lines="7-8"
319 | import maliang
320 |
321 | root = maliang.Tk()
322 | cv = maliang.Canvas(auto_zoom=True)
323 | cv.place(width=1280, height=720)
324 |
325 | maliang.OptionButton(cv, (20, 100), text=("Option 1", "Option 2", "Option 3"))
326 | maliang.OptionButton(cv, (200, 100), text=("Option 1", "Option 2", "Option 3"))
327 |
328 | root.mainloop()
329 | ```
330 |
331 | 效果如下:
332 |
333 | === ":fontawesome-brands-microsoft: Windows11 风格"
334 |
335 |
336 | 
337 | 
338 | 图8 选项按钮控件
339 |
340 |
341 | === ":fontawesome-brands-windows: Windows10 风格"
342 |
343 |
344 | 
345 | 
346 | 图8 选项按钮控件
347 |
348 |
349 | ## 三、典型自定义控件
350 |
351 | 下面的这些控件属于对 `Button` 的一个二次修改得到的,属于简单自定义控件,比较典型,这里单独拿出来说明。
352 |
353 | 不过这里不会详述它们是怎么自定义出来的,只是在这里做一个分类,把它们当作和其它控件一样普通的控件就行。关于自定义控件,后续章节会做详细讲解。
354 |
355 | !!! warning "特别注意:可能的变动"
356 |
357 | 下面的这三个控件不属于基本的控件,在 `maliang` 正式版后可能会被移动到 `maliang` 控件扩展包!`maliang` 自身应只包括标准的基本控件,而非主流的控件应被单独成为一个包,以免过多不常用的控件的代码及其样式数据占用了空间。
358 |
359 | ### 3.1 [`UnderlineButton`][maliang.standard.widgets.UnderlineButton]
360 |
361 | 此控件是为了实现网页链接那样的效果而做的,一般搭配文本控件来使用。
362 |
363 | 下面是一个简单的示例:
364 |
365 | ```python hl_lines="7"
366 | import maliang
367 |
368 | root = maliang.Tk()
369 | cv = maliang.Canvas(auto_zoom=True)
370 | cv.place(width=1280, height=720)
371 |
372 | maliang.UnderlineButton(cv, (20, 20), text="UnderlineButton", anchor="nw")
373 |
374 | root.mainloop()
375 | ```
376 |
377 | 效果如下:
378 |
379 |
380 | 
381 | 
382 | 图9 下划线按钮控件
383 |
384 |
385 | ### 3.2 [`HighlightButton`][maliang.standard.widgets.HighlightButton]
386 |
387 | 此控件单纯只是自定义控件的一个演示,存在一定的问题,不过具有一定的参考意义。
388 |
389 | 下面是一个简单的示例:
390 |
391 | ```python hl_lines="7"
392 | import maliang
393 |
394 | root = maliang.Tk()
395 | cv = maliang.Canvas(auto_zoom=True)
396 | cv.place(width=1280, height=720)
397 |
398 | maliang.HighlightButton(cv, (20, 20), text="HighlightButton", anchor="nw")
399 |
400 | root.mainloop()
401 | ```
402 |
403 | 效果如下:
404 |
405 |
406 | 
407 | 
408 | 图10 高亮按钮控件
409 |
410 |
411 | ### 3.3 [`IconButton`][maliang.standard.widgets.IconButton]
412 |
413 | `IconButton` 是图标按钮控件,它本质上是一个便捷类,可以十分方便地将图标和文本融合到一个按钮里面。
414 |
415 | 下面是一个简单的示例,这个示例中使用到的图片仍是**旧版** `maliang` 的 Logo,你也可以使用自己的图片文件:
416 |
417 | ```python hl_lines="7"
418 | import maliang
419 |
420 | root = maliang.Tk()
421 | cv = maliang.Canvas(auto_zoom=True)
422 | cv.place(width=1280, height=720)
423 |
424 | maliang.IconButton(cv, (20, 20), text="IconButton", image=maliang.PhotoImage(file="./logo.png").resize(32, 32))
425 |
426 | root.mainloop()
427 | ```
428 |
429 | 效果如下:
430 |
431 | === ":fontawesome-brands-microsoft: Windows11 风格"
432 |
433 |
434 | 
435 | 
436 | 图11 图标按钮控件
437 |
438 |
439 | === ":fontawesome-brands-windows: Windows10 风格"
440 |
441 |
442 | 
443 | 
444 | 图11 图标按钮控件
445 |
446 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: maliang # 站点名称
2 | site_url: https://Xiaokang2022.github.io/maliang-docs/ # 站点链接
3 | repo_url: https://github.com/Xiaokang2022/maliang # 仓库地址
4 | repo_name: Xiaokang2022/maliang # 仓库名称
5 | edit_uri: https://github.com/Xiaokang2022/maliang-docs/edit/main/docs/ # 编辑地址
6 | edit_uri_template: "" # 编辑地址模板(默认值)
7 | site_description: maliang 的官方文档网站 # 站点描述
8 | site_author: Xiaokang2022 # 站点作者
9 | copyright: 修改 Cookie 设置 Copyright © 2024 Xiaokang2022 # 版权信息和 Cookie 设置
10 | remote_branch: gh-pages # GitHub Pages 远程分支名称(默认值)
11 | remote_name: origin # 远程名称(默认值)
12 | docs_dir: docs/ # 文档目录(默认值)
13 | site_dir: site # 网站目录(默认值)
14 | dev_addr: 127.0.0.1:8080 # 预览模式地址(默认值)
15 | use_directory_urls: true # URL 使用目录名还是文件名(默认值)
16 | strict: false # 警告级别(默认值),出现警告就终止程序
17 |
18 | markdown_extensions:
19 | ###### Python Markdown 配置(markdown 基础语法)
20 |
21 | # 被 pymdownx.extra 完全替代且【冲突】
22 | # - abbr # 定义缩写
23 | # - attr_list # Markdown 元素可添加 HTML 和 CSS 属性
24 | # - def_list # 定义列表
25 | # - footnotes # 脚注
26 | # - md_in_html # Markdown 元素可内嵌在 HTML 中
27 | # - tables # 表格
28 |
29 | # - fenced_code # 代码块,被 pymdownx.superfences 完全替代且【冲突】
30 | # - codehilite # 代码高亮,被 pymdownx.highlight 完全替代且优化
31 |
32 | # - nl2br # 换行符会直接换行
33 |
34 | - admonition # 提示框
35 | - meta # 元数据
36 | - sane_lists # 理智列表,避免原版 Markdown 列表错误渲染
37 | - smarty # 优化部分字符串为特殊符号
38 | - wikilinks # 快捷链接
39 |
40 | - toc: # 目录
41 | marker: "" # 目录替换文本,空字符串则不替换,缺省为 [TOC]
42 | # title: "" # 目录标题,material 主题会自动根据语言计算
43 | anchorlink: false # 锚点链接(默认值),给标题自身锚定链接
44 | permalink: ¶ # 锚点符号
45 | permalink_title: "" # 锚点链接提示词,空字符表示没有
46 | permalink_leading: false # 前置锚点链接(默认值),将锚点放到标题前面
47 | baselevel: 1 # 最高级别(默认值),往下顺延
48 | separator: "-" # 分隔符(默认值),替换空格字符
49 | toc_depth: 4 # 目录显示级别
50 | slugify:
51 | !!python/object/apply:pymdownx.slugs.slugify # 锚点链接 URL 格式(小写)
52 | kwds:
53 | case: lower
54 |
55 | ###### PyMdown Extensions 配置(markdown 扩展语法)
56 |
57 | # - pymdownx.b64 # 普通网站用不到,详见 PyMdown 文档
58 | # - pymdownx.pathconverter # 普通网站用不到,详见 PyMdown 文档
59 | # - pymdownx.progressbar # 进度条(暂不支持)
60 | # - pymdownx.striphtml # 去除 HTML 中不需要的注释和 / 或标记属性,与插件 minify 有交叉但没有完全覆盖【别启用,大坑】
61 |
62 | - pymdownx.extra # 见上面 Python Markdown 配置说明
63 |
64 | - pymdownx.blocks.definition # 支持更高级的定义块语法(可能与 def_list 混淆)
65 | - pymdownx.blocks.details # 支持更高级的提示框布局(可能与 pymdownx.details 混淆)
66 | - pymdownx.blocks.html # 支持一些更高级的 Markdown 内嵌 HTML 语法(pymdownx.blocks 默认开启)
67 | - pymdownx.blocks.tab: # 支持更高级的标签块写法(可能与 pymdownx.tabbed 混淆)
68 | alternate_style: True
69 | combine_header_slug: True
70 | slugify:
71 | !!python/object/apply:pymdownx.slugs.slugify { kwds: { case: lower } }
72 | - pymdownx.blocks.admonition: # 支持更高级提示框语法(可能与 admonition 混淆)
73 | types:
74 | - new
75 | - settings
76 | - note
77 | - abstract
78 | - info
79 | - tip
80 | - success
81 | - question
82 | - warning
83 | - failure
84 | - danger
85 | - bug
86 | - example
87 | - quote
88 | - pymdownx.blocks.caption: # 支持更高级标题语法
89 | types:
90 | - name: figure-caption
91 | prefix: "图 {} "
92 | - name: table-caption
93 | prefix: "表 {} "
94 |
95 | - pymdownx.betterem # 斜体与粗体优化,更好的嵌套使用
96 | - pymdownx.caret # 文本下划线及上标
97 | - pymdownx.critic # 支持 Critic Markup 语法
98 | - pymdownx.details # 支持提示框的折叠
99 | - pymdownx.fancylists # 高级列表
100 | - pymdownx.inlinehilite # 行内代码高亮
101 | - pymdownx.keys # 按键高亮优化,增加图标
102 | - pymdownx.mark # 文本高亮
103 | - pymdownx.saneheaders # 理智标题,“#”和标题间必须有空格
104 | - pymdownx.smartsymbols # 智能符号优化,比上面的 smarty 支持更多
105 | - pymdownx.tilde # 文本删除线及下标
106 |
107 | - pymdownx.arithmatex: # 数学表达式
108 | generic: true
109 |
110 | - pymdownx.emoji: # Emoji 表情
111 | emoji_index: !!python/name:material.extensions.emoji.twemoji
112 | emoji_generator: !!python/name:material.extensions.emoji.to_svg
113 |
114 | - pymdownx.escapeall: # 转义一切
115 | hardbreak: true # 转义换行符会变成间断
116 | nbsp: true # 空格转义会变成无间隔空格
117 |
118 | - pymdownx.highlight: # 代码高亮
119 | use_pygments: true # 使用 Pygments 而不是 JavaScript 来渲染高亮
120 | linenums: true # 显示行号(默认值)
121 | anchor_linenums: true # 用锚链接包装代码行号,便于超链接和共享(就是行号可以像锚点一样被点击)
122 | line_spans: __span # 这对于高亮功能正常工作至关重要
123 | pygments_lang_class: true # 对于自定义注释标记的运行至关重要
124 | default_lang: python # 默认解析的语言
125 | # pygments_style: one-dark # 代码高亮风格,见 https://pygments.org/styles/
126 | # noclasses: true # 使用 pygments_style 必须开启
127 | # auto_title: true # 自动为所有代码块添加一个标题
128 |
129 | - pymdownx.magiclink: # 魔术链接,自动识别链接
130 | user: "Xiaokang2022" # 可缺省的用户名
131 | repo: "maliang" # 可缺省的仓库名
132 | hide_protocol: true # 隐藏链接协议头
133 | repo_url_shorthand: true # 识别仓库提交等链接
134 | repo_url_shortener: true # 仓库提交等链接简短显示
135 | social_url_shorthand: true # 识别社交账号等链接
136 | social_url_shortener: true # 社交账号等链接简短显示
137 | normalize_issue_symbols: true # 规范化 Issue、PR 等链接的表示为 #
138 |
139 | - pymdownx.snippets: # 外部片段插入
140 | url_download: true # 远程文件下载
141 | url_timeout: 10.0 # 超时时长(默认值)
142 | url_max_size: 33554432 # 文件大小限制(默认值),32MiB
143 |
144 | - pymdownx.superfences: # 各种嵌套
145 | disable_indented_code_blocks: false # 禁用缩进代码块(默认值)
146 | preserve_tabs: true # 嵌套块格式化表格(实验性)
147 | custom_fences:
148 | - name: mermaid # 允许 mermaid 图表语法
149 | class: mermaid
150 | format: !!python/name:pymdownx.superfences.fence_code_format
151 | - name: markmap # 允许 markmap 图表语法
152 | class: language-markmap
153 | format: !!python/name:pymdownx.superfences.fence_code_format
154 |
155 | - pymdownx.tabbed: # 选项卡
156 | alternate_style: true # 实验性样式
157 | combine_header_slug: true # 选项卡 URL 带上父标题的前缀
158 | separator: "-" # 分隔符(默认值),替换空格字符
159 | slugify: !!python/object/apply:pymdownx.slugs.slugify {}
160 |
161 | - pymdownx.tasklist: # 任务列表
162 | custom_checkbox: true # 允许修改复选框样式(默认已修改)
163 |
164 | theme: # 此项各个设定因主题而异
165 | name: material # 主题名称
166 | custom_dir: docs/overrides # 覆盖目录
167 | language: zh # 主题语言
168 | features:
169 | # Setting up navigation
170 | - navigation.instant # 页面不会重复加载(已加载页面不会再次加载)
171 | - navigation.instant.prefetch # 鼠标移到的链接会提前加载
172 | - navigation.instant.progress # 加载速度慢时,在页面顶部显示加载进度(400ms 以上加载时间才会显示它)
173 | # - navigation.instant.preview # 为全局标题启用即时预览,添加属性 data-preview 到标题可单独启用
174 | - navigation.tracking # 锚点跟踪
175 | - navigation.tabs # 页面顶部导航栏
176 | # - navigation.tabs.sticky # 导航栏标题栏位置固定
177 | # - navigation.sections # 左侧边栏节点是否保持展开
178 | # - navigation.expand # 左侧边栏节点默认全部展开(与 navigation.prune 不兼容)
179 | - navigation.path # 导航栏面包屑导航
180 | # - navigation.prune # 左侧栏节点至多展开一个,以此来减小站点的构建大小(对于页数100+的网站很有用,与 navigation.expand 不兼容)
181 | - navigation.indexes # 左侧边栏大节点是否可以被导向到 index.md,可以不写,但不能没有
182 | - toc.follow # 锚点跟随,侧边栏自动滚动,使锚点总是可见
183 | # - toc.integrate # 右边侧栏是否集成到左侧边栏(与 navigation.indexes 不兼容)
184 | - navigation.top # 回到顶部的按钮
185 |
186 | # Setting up site search
187 | - search.suggest # 搜索栏内容建议
188 | - search.highlight # 搜索栏内容高亮
189 | - search.share # 搜索栏分享按钮
190 |
191 | # Setting up the header
192 | # - header.autohide # 顶栏自动隐藏
193 | - announce.dismiss # 公告栏可以被关闭
194 |
195 | # Setting up the footer
196 | - navigation.footer # 页面底下换页的支持
197 |
198 | # Adding a git repository
199 | - content.action.edit # 允许页面被编辑(会出现编辑按钮)
200 | - content.action.view # 允许查看页面的源代码(会出现查看源代码按钮)
201 |
202 | # Code blocks
203 | - content.code.copy # 例如:``` python { .yaml .copy } 默认开启,{ .yaml .no-copy } 关闭
204 | - content.code.select # 选择按钮
205 | - content.code.annotate # 允许内联代码注释
206 |
207 | # Content tabs
208 | - content.tabs.link # 同样的标签,整个网站的同步切换,如 C -> C++,则其它类似的全部标签都同步切换
209 |
210 | # Footnotes
211 | - content.tooltips # 提示框(以前有的样式变好看了,此外还支持更高级的提示框语法)
212 | palette: # 界面整体样式
213 | - media: "(prefers-color-scheme)" # 系统主题
214 | toggle:
215 | icon: material/theme-light-dark
216 | name: 系统主题
217 | - media: "(prefers-color-scheme: light)" # 亮色主题
218 | scheme: default
219 | primary: white
220 | accent: light blue
221 | toggle:
222 | icon: material/weather-sunny
223 | name: 明亮主题
224 | - media: "(prefers-color-scheme: dark)" # 暗色主题
225 | scheme: slate
226 | primary: black
227 | accent: yellow
228 | toggle:
229 | icon: material/weather-night
230 | name: 暗黑主题
231 | font: false # 避免从谷歌加载字体导致网页加载变慢(具体参数可以在自定义 CSS 中指定)
232 | logo: logo.png # 页面左上角徽标
233 | favicon: logo.png # 网页的图标
234 | icon: # 图标重载,替换掉默认的图标
235 | repo: fontawesome/brands/github # 右上角仓库图标
236 | edit: material/file-edit # 页面编辑的图标
237 | view: material/file-eye # 页面查看源代码的图标
238 | tag:
239 | default: material/tag
240 |
241 | extra: # 额外设定
242 | alternate:
243 | - name: 简体中文
244 | link: .
245 | lang: zh
246 | generator: false # 页面底部不显示生成信息
247 | status: # 元信息状态标识
248 | new: 最近添加
249 | deprecated: 已废弃
250 | homepage: . # 左上角徽标链接的地址
251 | tags:
252 | _:
253 | social: # 社交联系方式(页面右下角内容)
254 | - icon: fontawesome/brands/github
255 | link: https://github.com/Xiaokang2022/maliang/
256 | name: GitHub
257 | - icon: fontawesome/brands/python
258 | link: https://pypi.org/project/maliang/
259 | name: PyPI
260 | - icon: fontawesome/brands/bilibili
261 | link: https://space.bilibili.com/498105668
262 | name: 哔哩哔哩
263 | - icon: fontawesome/solid/paper-plane
264 | link: mailto:2951256653@qq.com
265 | name: 联系作者
266 | version:
267 | provider: mike
268 | alias: true
269 | consent:
270 | actions:
271 | - accept
272 | - reject
273 | - manage
274 | title: Cookie 设置
275 | description: >-
276 | 我们使用 cookies 来识别您的重复访问和偏好,以及衡量我们文档的有效性和用户是否找
277 | 到他们正在搜索的内容。
278 | 在您的同意下,您将帮助我们改进我们的文档。
279 | (您稍后仍可以在网页左下角重新修改 cookies 设置)
280 | analytics: # 谷歌统计
281 | provider: google
282 | property: G-C5GHN09YHC
283 | feedback:
284 | title: 该页面对你有帮助吗?
285 | ratings:
286 | - icon: material/emoticon-happy-outline
287 | name: 有帮助
288 | data: 1
289 | note: 感谢您的反馈!
290 | - icon: material/emoticon-neutral-outline
291 | name: 一般般
292 | data: 0
293 | note: 感谢您的反馈!
294 | - icon: material/emoticon-sad-outline
295 | name: 有待改进
296 | data: -1
297 | note: 感谢您的反馈!
298 |
299 | extra_javascript:
300 | - https://xiaokang2022.github.io/s/click-colorful.js # 鼠标点击效果
301 | - https://xiaokang2022.github.io/js/shortcuts.js # 绑定左右键换页的键盘快捷键
302 | - https://xiaokang2022.github.io/js/katex.js # 数学表达式
303 | - https://xiaokang2022.github.io/js/tablesort.js # 表格排序功能
304 | - https://unpkg.com/katex@latest/dist/katex.min.js # 数学表达式
305 | - https://unpkg.com/katex@latest/dist/contrib/auto-render.min.js # 自动渲染数学表达式
306 | - https://unpkg.com/tablesort@latest/dist/tablesort.min.js # 表格排序功能运行环境(默认文本类型)
307 | - https://unpkg.com/tablesort@latest/dist/sorts/tablesort.date.min.js # 表格排序功能(日期类型)
308 | - https://unpkg.com/tablesort@latest/dist/sorts/tablesort.dotsep.min.js # 表格排序功能(点分割类型)
309 | - https://unpkg.com/tablesort@latest/dist/sorts/tablesort.filesize.min.js # 表格排序功能(文件大小类型)
310 | - https://unpkg.com/tablesort@latest/dist/sorts/tablesort.monthname.min.js # 表格排序功能(月份名称类型)
311 | - https://unpkg.com/tablesort@latest/dist/sorts/tablesort.number.min.js # 表格排序功能(数字类型)
312 | - https://unpkg.com/d3@latest/dist/d3.min.js # markmap 运行环境
313 | - https://unpkg.com/markmap-lib@latest/dist/browser/index.iife.js # markmap 运行环境
314 | - https://unpkg.com/markmap-view@latest/dist/browser/index.js # markmap 运行环境
315 |
316 | extra_css:
317 | - https://xiaokang2022.github.io/css/extra.css
318 | - https://unpkg.com/katex@latest/dist/katex.min.css # 数学表达式
319 | - https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css # 图标字体库
320 | - https://cdnjs.cloudflare.com/ajax/libs/lxgw-wenkai-screen-webfont/1.7.0/style.min.css # 设置字体(霞鹜文楷)
321 |
322 | plugins:
323 | # 内置插件
324 | - search:
325 | - meta:
326 | - tags:
327 | # - blog:
328 | # blog_toc: true
329 | # post_readtime: false
330 | # pagination_keep_content: true
331 | # pagination_format: "$link_first $link_previous ~2~ $link_next $link_last"
332 | # 第三方插件
333 | - mike:
334 | - macros:
335 | - markdown-exec:
336 | - statistics:
337 | page_template: overrides/statistics_template.html
338 | - markmap:
339 | d3_version: ""
340 | lib_version: ""
341 | view_version: ""
342 | - rss:
343 | match_path: blog/posts/.*
344 | date_from_meta:
345 | as_creation: date.created
346 | as_update: date.updated
347 | categories:
348 | - categories
349 | - tags
350 | comments_path: "#__comments"
351 | - glightbox:
352 | background: none
353 | auto_themed: true
354 | - plantuml:
355 | puml_url: https://www.plantuml.com/plantuml/
356 | theme:
357 | light: material/blue-light
358 | dark: material/amber-dark
359 | - git-revision-date-localized:
360 | enable_creation_date: true
361 | type: timeago
362 | - git-authors: # 通过本地 git 存储库获取贡献者
363 | add_co_authors: true
364 | sort_authors_by: contribution
365 | - git-committers: # 通过云端 git 存储库获取贡献者
366 | repository: Xiaokang2022/Xiaokang2022.github.io
367 | branch: main
368 | token: !ENV GH_TOKEN # 需要自行在终端中设置临时环境变量,强烈不建议显式地在此处设置 token
369 | exclude_committers:
370 | - web-flow
371 | - autorefs:
372 | resolve_closest: true
373 | - literate-nav:
374 | nav_file: summary.md
375 | - gen-files:
376 | scripts:
377 | - scripts/gen_doc_pages.py
378 | - mkdocstrings:
379 | handlers:
380 | python:
381 | inventories: # 无法联网的话必须删除这个
382 | - https://docs.python.org/3/objects.inv
383 | - https://pillow.readthedocs.io/en/stable/objects.inv
384 | options:
385 | # General
386 | backlinks: tree
387 | show_inheritance_diagram: true
388 | show_source: false
389 |
390 | # Headings
391 | parameter_headings: true
392 | show_root_full_path: false
393 | show_symbol_type_heading: true
394 | show_symbol_type_toc: true
395 |
396 | # Members
397 | members_order: source
398 | filters: public
399 | summary: true
400 |
401 | # Docstrings
402 | docstring_style: auto
403 | docstring_section_style: spacy
404 | merge_init_into_class: true
405 | relative_crossrefs: true
406 | scoped_crossrefs: true
407 | show_if_no_docstring: true
408 |
409 | # Signatures
410 | line_length: 80
411 | modernize_annotations: true
412 | overloads_only: true
413 | show_signature_annotations: true
414 | show_signature_type_parameters: true
415 | separate_signature: true
416 | signature_crossrefs: true
417 |
418 | # Extensions
419 | extensions:
420 | # Built-in
421 | - dataclasses
422 | - unpack_typeddict
423 | # Official
424 | - griffe_autodocstringstyle
425 | - griffe_inherited_docstrings
426 | - griffe_public_redundant_aliases
427 | - griffe_public_wildcard_imports
428 | - griffe_pydantic:
429 | schema: true
430 | - griffe_runtime_objects
431 | - griffe_sphinx
432 | - griffe_typingdoc
433 | - griffe_warnings_deprecated
434 | - minify:
435 | minify_html: true
436 | htmlmin_opts:
437 | remove_comments: true
438 | - print-site:
439 | print_page_title: Documentation
440 | print_page_basename: downloads
441 | enumerate_headings: false
442 | enumerate_figures: false
443 |
444 | nav:
445 | - 站点主页:
446 | - index.md
447 | - 标签索引: tags.md
448 |
449 | - 官方教程:
450 | - tutorials/index.md
451 | - 第一章:安装与初识:
452 | - tutorials/chapter_01/index.md
453 | - 1.1 环境搭建: tutorials/chapter_01/1.md
454 | - 1.2 实现一个简单的界面: tutorials/chapter_01/2.md
455 | - 1.3 框架概述: tutorials/chapter_01/3.md
456 | - 第二章:容器控件:
457 | - tutorials/chapter_02/index.md
458 | - 2.1 窗口容器控件: tutorials/chapter_02/1.md
459 | - 2.2 画布容器控件: tutorials/chapter_02/2.md
460 | - 第三章:基本控件:
461 | - tutorials/chapter_03/index.md
462 | - 3.1 信息类控件: tutorials/chapter_03/1.md
463 | - 3.2 功能类控件: tutorials/chapter_03/2.md
464 | - 3.3 文本类控件: tutorials/chapter_03/3.md
465 | - 第四章:动画:
466 | - tutorials/chapter_04/index.md
467 | - 4.1 基础动画: tutorials/chapter_04/1.md
468 | - 4.2 控制函数: tutorials/chapter_04/2.md
469 | - 4.3 自定义动画: tutorials/chapter_04/3.md
470 | - 第五章:颜色:
471 | - tutorials/chapter_05/index.md
472 | - 5.1 颜色格式及其转换: tutorials/chapter_05/1.md
473 | - 5.2 颜色处理: tutorials/chapter_05/2.md
474 | - 第六章:主题:
475 | - tutorials/chapter_06/index.md
476 | - 6.1 切换颜色主题: tutorials/chapter_06/1.md
477 | # - 6.2 切换样式主题: tutorials/chapter_06/2.md
478 | # - 6.3 设置特殊主题: tutorials/chapter_06/3.md
479 | # - 第八章:自定义开发:
480 | # - 8.1 自定义容器控件: tutorials/1-1.md
481 | # - 8.2 自定义基础控件: tutorials/1-1.md
482 | # - 8.3 自定义组件: tutorials/1-1.md
483 | # - 8.4 自定义控制器: tutorials/1-1.md
484 | # - 8.5 自定义动画: tutorials/1-1.md
485 | # - 第四章:界面布局:
486 | # - 4.1 Place: tutorials/1-1.md
487 | # - 4.2 Pack 和 Grid: tutorials/1-1.md
488 | # - 4.3 混合布局: tutorials/1-1.md
489 | # - 第五章:图像:
490 | # - 5.1 图像基础操作: tutorials/1-1.md
491 | # - 5.2 高级操作: tutorials/1-1.md
492 | # - 第九章:杂项:
493 | # - 9.1 混合 tkinter 开发: tutorials/1-1.md
494 | # - 9.2 matplotlib 扩展包: tutorials/1-1.md
495 | # - 9.3 3D 扩展包: tutorials/1-1.md
496 | # - 9.4 Demos & Projects: tutorials/1-1.md
497 |
498 | - 参考文档: documents/ # mkdocstrings 自动生成
499 |
500 | - 实战教学:
501 | - practices/index.md
502 |
--------------------------------------------------------------------------------