Reisen1969 / Reisen1969.github.io.back

1 stars 0 forks source link

aarch64 #5

Open Reisen1969 opened 8 months ago

Reisen1969 commented 8 months ago

总结一下最近折腾的事情,方便以后查阅。

所有内容都假设已经安装了必须的构建工具链,如果没有装,可以在报错的时候再根据提示安装。

编译 BusyBox 需要先编译一个 BusyBox 作准备,之后作为 rootfs 加载。

这里 下载适当版本的 BusyBox 源码并解压,然后运行:

cd busybox-1.32.0 mkdir build

make O=build ARCH=arm64 defconfig make O=build ARCH=arm64 menuconfig 这会首先生成默认配置,然后开启一个配置菜单。在「Settings」里面修改下面几项配置:

[] Don't use /usr [] Build static binary (no shared libs) (aarch64-linux-gnu-) Cross compiler prefix 然后保存并退出。运行:

make O=build # -j8 make O=build install cd build/_install 这会使用刚刚保存的配置进行编译,然后安装到 build/_install 目录,此时该目录如下:

$ tree -L 1 . . ├── bin ├── linuxrc -> bin/busybox └── sbin

2 directories, 1 file 接着创建一些空目录:

mkdir -pv {etc,proc,sys,usr/{bin,sbin}} 然后创建一个 init 文件,内容如下:

!/bin/sh

mount -t proc none /proc mount -t sysfs none /sys

echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"

exec /bin/sh 修改 init 文件为可执行:

chmod +x init 此时当前目录(build/_install)内容如下:

$ tree -L 1 . . ├── bin ├── etc ├── init ├── linuxrc -> bin/busybox ├── proc ├── sbin ├── sys └── usr

6 directories, 2 files 把这些目录和文件打包:

find . -print0 | cpio --null -ov --format=newc | gzip > ../initramfs.cpio.gz 生成的 gzip 压缩后的 cpio 映像放在了 build/initramfs.cpio.gz,此时 BusyBox ramdisk 就做好了,保存备用。

编译最小配置的 Linux 内核 在 这里 下载适当版本的内核源码并解压,然后运行:

cd linux-5.8.8 mkdir build

make O=build ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- allnoconfig make O=build ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig 这会首先初始化一个最小的配置(allnoconfig),然后打开配置菜单。在配置菜单中做以下修改:

-> General setup [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

-> General setup -> Configure standard kernel features [*] Enable support for printk

-> Executable file formats / Emulations [] Kernel support for ELF binaries [] Kernel support for scripts starting with #!

-> Device Drivers -> Generic Driver Options [] Maintain a devtmpfs filesystem to mount at /dev [] Automount devtmpfs at /dev, after the kernel mounted the rootfs

-> Device Drivers -> Character devices [*] Enable TTY

-> Device Drivers -> Character devices -> Serial drivers [] ARM AMBA PL010 serial port support [] Support for console on AMBA serial port [] ARM AMBA PL011 serial port support [] Support for console on AMBA serial port

-> File systems -> Pseudo filesystems [] /proc file system support [] sysfs file system support 完成后保存并退出,再运行:

make O=build ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- # -j8 即可编译 Linux 内核,编译出来的两个东西比较有用,一个是 build/vmlinux,另一个是 build/arch/arm64/boot/Image,前者是 ELF 格式的内核,可以用来在 GDB 中加载调试信息,后者是可启动的内核映像文件。

编译 qemu-system-aarch64 这一步是可选的,直接使用包管理器安装 QEMU 也可以。

这里 下载适当版本的 QEMU 源码并解压,然后运行:

cd qemu-5.0.0

mkdir build cd build

../configure --target-list=aarch64-softmmu make # -j8 即可编译 AArch64 目标架构的 QEMU。

启动 Linux 为了清晰起见,回到上面三个源码目录的外层,即当前目录中内容如下:

$ tree -L 1 . . ├── busybox-1.32.0 ├── linux-5.8.8 └── qemu-5.0.0

3 directories, 0 files 然后使用 QEMU 启动刚刚编译的 Linux:

./qemu-5.0.0/build/aarch64-softmmu/qemu-system-aarch64 \ -machine virt -cpu cortex-a53 -smp 1 -m 2G \ -kernel ./linux-5.8.8/build/arch/arm64/boot/Image \ -append "console=ttyAMA0" \ -initrd ./busybox-1.32.0/build/initramfs.cpio.gz \ -nographic 这里使用了 QEMU 的 virt 平台。

Reisen1969 commented 8 months ago

image

Reisen1969 commented 7 months ago

import re

pattern = re.compile(r'(?:(0x[0-9a-fA-F]+)|(\d+.\d+)|(\d+))')

例子

text = "0x1a 3.14 42" matches = pattern.findall(text)

for match in matches: result = next(item for item in match if item) print(result)

Reisen1969 commented 7 months ago

import re

pattern = re.compile(r'(?:(0x[0-9a-fA-F]+)|(\d+.\d+)|(\d+)|-nan%)')

例子

text = "0x1a 3.14 42 -nan%" matches = pattern.findall(text)

for match in matches: result = next(item for item in match if item) print(result)

Reisen1969 commented 7 months ago

import os

root_folder = '/your/root/folder'

for root, dirs, files in os.walk(root_folder):

遍历第一层目录

if root == root_folder:
    for dir_name in dirs:
        dir_path = os.path.join(root, dir_name)
        print("第一层目录:", dir_path)

# 遍历第二层目录
if root != root_folder:
    for dir_name in dirs:
        dir_path = os.path.join(root, dir_name)
        print("第二层目录:", dir_path)
Reisen1969 commented 7 months ago

import importlib.util

指定绝对路径

file_path = '/绝对路径/文件名.py'

创建一个模块规范

spec = importlib.util.spec_from_file_location("模块名", file_path)

根据规范创建一个模块

module = importlib.util.module_from_spec(spec)

将规范绑定到模块

spec.loader.exec_module(module)

现在你可以使用加载的模块

print(module.你的变量名)

Reisen1969 commented 7 months ago

include

include

int main() { std::vector numbers;

int num;
// 从标准输入读取数字,直到到达文件尾
while (std::cin >> num) {
    numbers.push_back(num);
}

// 在这里进行你的程序逻辑,使用 numbers 容器

return 0;

}

Reisen1969 commented 7 months ago

nested_list = [[1, 2, 3], [4, 5], [6, 7, 8]]

使用列表解析将嵌套列表合并成单层列表

flat_list = [item for sublist in nested_list for item in sublist]

print(flat_list)

Reisen1969 commented 7 months ago

import sys

def a(): print("Function A")

def b(): print("Function B")

def c(): print("Function C")

def d(): print("Function D")

def main():

获取命令行参数(不包括脚本名)

args = sys.argv[1:]

# 定义函数映射
function_mapping = {'a': a, 'b': b, 'c': c, 'd': d}

# 按照参数顺序执行相应的函数
for arg in args:
    if arg in function_mapping:
        function_mapping[arg]()

if name == "main": main()

Reisen1969 commented 6 months ago

import multiprocessing from queue import Queue

定义任务队列

task_queue = Queue()

定义任务函数

def task_function(task): func, args = task func(*args)

定义进程执行函数

def process_function(): while True: task = task_queue.get() if task is None: break # 如果任务为None,说明任务队列已完成 task_function(task)

if name == "main":

创建四个进程

num_processes = 4
processes = []

for _ in range(num_processes):
    p = multiprocessing.Process(target=process_function)
    processes.append(p)
    p.start()

# 将任务放入任务队列
tasks = [
    (print, ("Task 1",)),
    (print, ("Task 2",)),
    # 添加更多任务...
    None  # 用于表示任务队列结束的标志
]

for task in tasks:
    task_queue.put(task)

# 等待所有任务完成
for _ in range(num_processes):
    task_queue.put(None)  # 发送任务队列结束的标志

# 等待所有进程结束
for p in processes:
    p.join()
Reisen1969 commented 6 months ago

import threading import queue

定义队列

number_queue = queue.Queue()

向队列中添加数字

for num in range(1, 11): number_queue.put(num)

定义一个锁,用于保证线程安全

lock = threading.Lock()

定义四个线程函数

def thread_function(thread_id): while True: with lock: if not number_queue.empty(): num = number_queue.get() print(f"Thread {thread_id} got number: {num}") else: break # 如果队列为空,线程退出循环

创建四个线程

threads = []

for i in range(4): t = threading.Thread(target=thread_function, args=(i,)) threads.append(t) t.start()

等待所有线程结束

for t in threads: t.join()

Reisen1969 commented 6 months ago

from collections import ChainMap

dict1 = {'a': 1, 'b': 2} dict2 = {'c': 3, 'd': 4} dict3 = {'e': 5, 'f': 6}

merged_dict = dict(ChainMap(dict1, dict2, dict3))

print(merged_dict)

Reisen1969 commented 6 months ago

要将一个ext4文件系统打包成cpio.gz格式并在QEMU中启动,可以按照以下步骤进行操作:

  1. 创建目录并挂载ext4文件系统
sudo mkdir /mnt/ext4
sudo mount -t ext4 /path/to/tmp.ext4 /mnt/ext4

确保替换 /path/to/tmp.ext4 为你的实际ext4文件系统路径。

  1. 创建cpio.gz文件
sudo find /mnt/ext4 | cpio -o -H newc | gzip -9 > /path/to/initramfs.cpio.gz

确保替换 /path/to/initramfs.cpio.gz 为你希望保存initramfs的路径。

  1. 卸载ext4文件系统
sudo umount /mnt/ext4
  1. 使用QEMU启动
qemu-system-x86_64 -kernel /path/to/kernel -initrd /path/to/initramfs.cpio.gz -append "root=/dev/ram0"

确保替换 /path/to/kernel/path/to/initramfs.cpio.gz 为你的实际内核和initramfs路径。这里使用/dev/ram0作为根文件系统。

这样QEMU将启动,加载指定的内核和initramfs。请注意,initramfs是基于内存的,因此在关闭QEMU后,其中的数据会丢失。如果需要持久性存储,可以考虑使用其他文件系统并将其保存在硬盘中。

Reisen1969 commented 6 months ago

要使一个目录对普通用户可访问(无需使用 sudo),你可以通过更改目录的权限和所有者来实现。以下是一些建议的步骤:

  1. 更改目录的拥有者:

    sudo chown -R username:groupname /path/to/your/directory

    替换 usernamegroupname 为你希望的用户和组。这将确保目录属于指定的用户和组。

  2. 更改目录的权限:

    为了让普通用户能够访问目录,你可以使用以下命令:

    sudo chmod -R 755 /path/to/your/directory

    这样设置后,目录的拥有者(通常是你指定的 username)可以读写执行,而其他用户可以读和执行目录。

    如果你希望所有用户都能够对目录进行写操作,你可以使用:

    sudo chmod -R 777 /path/to/your/directory

    请注意,赋予 777 权限可能存在安全风险,只在确实需要这种权限时使用。

  3. 测试普通用户访问:

    确保你的普通用户可以访问目录:

    cd /path/to/your/directory

    如果没有权限错误,说明你已经成功让普通用户访问这个目录。

请谨慎更改目录的权限和所有者,确保在需要的情况下进行,并理解潜在的安全风险。

Reisen1969 commented 6 months ago

要查看普通用户属于哪些用户组,你可以使用以下命令:

groups username

请将 username 替换为你想要查询的普通用户的实际用户名。这将列出用户所属的用户组。

例如,如果要查看用户Alice所属的用户组,可以运行:

groups alice

命令的输出将显示用户所在的用户组列表。如果用户属于多个用户组,它们将以空格分隔。

Reisen1969 commented 6 months ago

在QEMU中设置两个共享文件夹并在Guest系统中挂载它们,你需要使用-virtfs参数,然后在Guest中手动挂载这些共享文件夹。

以下是一个示例,假设你的Guest系统是Linux:

qemu-system-x86_64 -drive file=your_disk_image.img,format=qcow2 -virtfs local,path=/path/on/host1,security_model=none,mount_tag=share1 -virtfs local,path=/path/on/host2,security_model=none,mount_tag=share2 -boot c

在Guest系统中,你可以执行以下步骤来挂载这些共享文件夹:

  1. 创建用于挂载的目录:
sudo mkdir /mnt/share1
sudo mkdir /mnt/share2
  1. 挂载共享文件夹:
sudo mount -t 9p -o trans=virtio,version=9p2000.L,cache=none share1 /mnt/share1
sudo mount -t 9p -o trans=virtio,version=9p2000.L,cache=none share2 /mnt/share2

这里,share1share2 是在QEMU启动命令中定义的 mount_tag

请确保替换 your_disk_image.img/path/on/host1/path/on/host2 为实际的值。如果你的Guest系统不是Linux,挂载步骤可能有所不同。

Reisen1969 commented 6 months ago

find_non_empty_value = lambda my_tuple: next((item for item in my_tuple if item is not None and item != ''), None)

例子

my_tuple = (None, '', 42, 'hello', 0) result = find_non_empty_value(my_tuple) print(result)

Reisen1969 commented 6 months ago

git bisect 是一个用于二分查找引入错误的 Git 命令。以下是一个简单的 git bisect 使用教程:

  1. 开始 bisect:

    git bisect start
  2. 标记一个已知的“好”提交:

    git bisect good <commit-hash>
  3. 标记一个已知的“坏”提交:

    git bisect bad <commit-hash>

    这会告诉 Git 在这两个提交之间进行二分查找。

  4. Git 将自动切换到中间的提交:

    Bisecting: <commit-details>
  5. 测试当前提交是否有错误: 在每个提交上运行你的测试,如果有错误,使用 git bisect bad,否则使用 git bisect good

  6. 重复步骤 4 和步骤 5: Git 会根据你的反馈继续二分查找,直到找到引入错误的提交。

  7. 结束 bisect: 一旦找到了引入错误的提交,结束 bisect:

    git bisect reset

示例:

假设你的项目有一次提交引入了错误,你已知在提交 abc123 之前没有问题,而在提交 def456 之后出现了问题。开始 bisect:

git bisect start
git bisect good abc123
git bisect bad def456

Git 会自动选择中间的提交,并提示你测试。重复这个过程,直到找到引入错误的提交。最后,使用 git bisect reset 结束 bisect。

这是一个简单的演示,实际使用时,你需要根据项目的具体情况运行适当的测试。

Reisen1969 commented 6 months ago

https://blog.csdn.net/shao_1101/article/details/134870586

Reisen1969 commented 6 months ago

gcc -dumpspecs | grep -oP '(?<=*link:\s(ld)\s)\S+'

Reisen1969 commented 6 months ago

你可以使用以下 Python 代码实现匹配第一个冒号前和第一个冒号后的字符:

import re

# 你的输入字符串
input_string = "123:456:789"

# 定义正则表达式
pattern = re.compile(r'^([^:]+):(.*)')

# 进行匹配
match = pattern.match(input_string)

# 获取匹配的结果
if match:
    before_colon = match.group(1)
    after_colon = match.group(2)

    print("第一个冒号前的内容:", before_colon)
    print("第一个冒号后的内容:", after_colon)
else:
    print("未匹配到结果")

在这个例子中,正则表达式 ^([^:]+):(.*) 用于匹配字符串的开始,然后捕获第一个冒号前的内容和第一个冒号后的内容。匹配结果会输出在 before_colonafter_colon 变量中。

Reisen1969 commented 6 months ago

to_excel 是 pandas DataFrame 对象的方法,用于将数据写入 Excel 文件。以下是一些常用的参数及其用途:

  1. excel_writer 指定写入的 Excel 文件名或 ExcelWriter 对象。

    df.to_excel(excel_writer='output.xlsx', index=False)
  2. sheet_name 指定 Excel 工作表的名称。

    df.to_excel(excel_writer='output.xlsx', sheet_name='Sheet1', index=False)
  3. index 决定是否将 DataFrame 的索引写入 Excel 文件。默认为 True。

    df.to_excel(excel_writer='output.xlsx', index=False)
  4. header 决定是否将列名写入 Excel 文件。默认为 True。

    df.to_excel(excel_writer='output.xlsx', header=False, index=False)
  5. startrowstartcol 指定写入 Excel 文件时的起始行和列。

    df.to_excel(excel_writer='output.xlsx', startrow=2, startcol=3, index=False)
  6. na_rep 指定在文件中用于表示缺失数据的字符串。

    df.to_excel(excel_writer='output.xlsx', na_rep='NA', index=False)
  7. merge_cells 决定是否合并单元格,默认为 True。可以设置为 False 禁止合并单元格。

    df.to_excel(excel_writer='output.xlsx', merge_cells=False, index=False)

这只是一些常见参数的示例,你可以根据需要查看 pandas 文档 获取更多详细信息。

Reisen1969 commented 6 months ago

image

Reisen1969 commented 6 months ago

在 MySQL 的启动命令行中设置参数可以使用 --set-variable--variable-name=value 的形式,具体取决于 MySQL 版本。

对于 innodb_use_native_aio 参数,你可以在 mysqld 命令行启动时这样设置:

mysqld --set-variable=innodb_use_native_aio=OFF

或者使用 --innodb-use-native-aio=OFF 形式:

mysqld --innodb-use-native-aio=OFF

请注意,根据 MySQL 版本的不同,某些参数可能已经被废弃或者替代。确保查看 MySQL 版本的文档以获取准确的参数信息。在生产环境中修改这些参数之前,请务必测试并谨慎行事。

Reisen1969 commented 5 months ago

在CMake中添加自定义的GCC选项通常是通过修改CMakeLists.txt文件来实现的。下面是一个简单的示例,演示如何向CMake中添加自定义的GCC选项:

  1. 打开你的MySQL源代码目录中的 CMakeLists.txt 文件。

  2. 在文件中找到适当的位置,通常是在编译选项部分。你可能会找到一些类似于 add_compile_options 的指令。

  3. 在这里,添加你的自定义GCC选项。例如,如果你想添加优化选项 -O3,你可以这样写:

    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")

    如果你想添加其他自定义选项,使用类似的语法即可。

  4. 如果有多个编译器选项,你可以使用 target_compile_options 指令来针对特定的目标(比如mysqld)添加选项:

    target_compile_options(mysqld PRIVATE -O3 -Wall)

    这里,mysqld 是你的MySQL目标的名称,你可能需要根据实际情况调整。

  5. 保存文件并重新运行CMake,然后再次编译你的MySQL代码。

请确保你的修改符合MySQL代码的构建系统,并注意确保选项不会导致不稳定或不安全的行为。

Reisen1969 commented 5 months ago

在CMake中,要进行静态编译程序,你可以使用以下步骤:

  1. 设置编译类型为静态库: 在你的CMakeLists.txt文件中,使用add_executableadd_library时,可以通过STATIC关键字指定使用静态库。例如:

    add_executable(MyExecutable main.cpp)
  2. 指定链接类型为静态库: 使用target_link_libraries来指定链接的库,包括静态库。例如:

    target_link_libraries(MyExecutable PRIVATE your_static_library)
  3. 禁用共享库: 你还需要禁用共享库的生成,以确保静态链接。可以通过设置全局属性或目标属性来实现。例如:

    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")

    或者,针对特定目标:

    set_target_properties(MyExecutable PROPERTIES LINK_SEARCH_START_STATIC 1)
    set_target_properties(MyExecutable PROPERTIES LINK_SEARCH_END_STATIC 1)
  4. 重新生成项目: 在完成上述更改后,重新运行CMake生成项目文件,然后进行编译。

请注意,确保你所链接的所有库都具有相应的静态版本。一些库可能提供动态和静态版本,你需要选择正确的版本。

Reisen1969 commented 5 months ago

要在CMake中设置静态链接程序,你可以使用以下步骤:

  1. 全局设置静态链接: 在你的项目的 CMakeLists.txt 文件中,可以使用以下命令来设置全局的链接选项,使得整个项目都以静态方式链接:

    set(CMAKE_EXE_LINKER_FLAGS "-static")
  2. 目标级别设置静态链接: 如果你只想为特定目标(例如可执行文件)进行静态链接,可以在目标级别使用set_target_properties命令。例如:

    add_executable(YourExecutableName main.cpp)
    set_target_properties(YourExecutableName PROPERTIES LINK_FLAGS "-static")

    对于库:

    add_library(YourLibraryName source.cpp)
    set_target_properties(YourLibraryName PROPERTIES LINK_FLAGS "-static")
  3. 重新生成项目: 在完成上述更改后,重新运行 CMake 生成项目文件,然后进行编译。

这样,你的可执行文件或库就会以静态方式链接。确保你的系统支持静态链接,并且相关的静态库文件是可用的。

Reisen1969 commented 5 months ago

在CMake中静态链接 glibc(GNU C Library)自带的动态库(比如 libc.so)可能会面临一些限制,因为 glibc 通常是设计用于动态链接的。

但你可以采取一些措施来尽可能地实现静态链接:

  1. 查找或生成 glibc 的静态库: 首先,确保你有 glibc 的静态库文件。这可能需要手动构建 glibc 的静态版本,或者你可以尝试查看系统是否提供了这些文件。

  2. 在 CMakeLists.txt 中添加 glibc 的静态库: 使用target_link_libraries命令将 glibc 的静态库链接到你的目标。例如:

    add_executable(YourExecutableName main.cpp)
    target_link_libraries(YourExecutableName PRIVATE /path/to/libc.a)
  3. 禁用动态链接: 你还需要确保禁用对 glibc 的动态链接。可以使用全局或目标级别的set命令来设置链接标志:

    set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static-libc")

    或者,对于目标:

    set_target_properties(YourExecutableName PROPERTIES LINK_FLAGS "-static-libgcc -static-libstdc++ -static-libc")
  4. 重新生成项目: 在完成上述更改后,重新运行 CMake 生成项目文件,然后进行编译。

请注意,glibc 的静态链接可能会引入其他复杂性,包括依赖关系和系统兼容性。确保你的应用程序不会受到这些变化的不利影响。

Reisen1969 commented 5 months ago

include

int main() { int64_t originalValue = 0x1ffdf90; int64_t extendedValue = static_cast(static_cast(originalValue));

std::cout << std::hex << extendedValue << std::endl;

return 0;

}

Reisen1969 commented 4 months ago

当使用映射表优化switch case时,可以考虑使用std::map或类似的数据结构。以下是一个简单的C++示例:

#include <iostream>
#include <map>
#include <functional>

// 定义处理函数类型
using CaseHandler = std::function<void()>;

// 映射表,将case值映射到处理函数
std::map<int, CaseHandler> caseHandlers = {
    {1, [](){ std::cout << "处理情况 1\n"; }},
    {2, [](){ std::cout << "处理情况 2\n"; }},
    {3, [](){ std::cout << "处理情况 3\n"; }},
    // 添加其他映射项...
};

// 主处理函数
void process(int caseValue) {
    // 在映射表中查找相应的处理函数
    auto it = caseHandlers.find(caseValue);

    // 如果找到,则执行对应的处理函数;否则,处理未知情况
    if (it != caseHandlers.end()) {
        it->second();
    } else {
        std::cout << "未知情况\n";
    }
}

int main() {
    // 测试
    process(2);
    process(4); // 未知情况

    return 0;
}

这个例子中,caseHandlers是一个映射表,将case的值映射到相应的处理函数(使用Lambda表达式)。在process函数中,根据输入值查找映射表,执行对应的处理函数。这种方式使得新增或修改情况的处理更加方便,不需要修改主处理函数。

Reisen1969 commented 4 months ago

当两个switch都包含了从2到9的case时,可以将这部分逻辑合并为一个映射表,减少重复代码。以下是优化后的示例:

#include <iostream>
#include <map>
#include <functional>

// 定义处理函数类型
using CaseHandler = std::function<void()>;

// 定义嵌套的映射表
using SwitchMap = std::map<int, CaseHandler>;

// 共享的映射表,包含2到9的处理函数
SwitchMap commonCases = {
    {2, [](){ std::cout << "处理情况 2\n"; }},
    {3, [](){ std::cout << "处理情况 3\n"; }},
    {4, [](){ std::cout << "处理情况 4\n"; }},
    {5, [](){ std::cout << "处理情况 5\n"; }},
    {6, [](){ std::cout << "处理情况 6\n"; }},
    {7, [](){ std::cout << "处理情况 7\n"; }},
    {8, [](){ std::cout << "处理情况 8\n"; }},
    {9, [](){ std::cout << "处理情况 9\n"; }},
};

// 主映射表,将每个switch映射到其对应的嵌套映射表
std::map<int, SwitchMap> switchMaps = {
    {1, {
        {1, [](){ std::cout << "Switch1 处理情况 1\n"; }},
        // 将共享的映射表合并
        commonCases.begin(), commonCases.end()
    }},
    {2, {
        {4, [](){ std::cout << "Switch2 处理情况 4\n"; }},
        // 将共享的映射表合并
        commonCases.begin(), commonCases.end()
    }},
    // 添加其他switch的映射项...
};

// 主处理函数
void process(int switchNumber, int caseValue) {
    // 在主映射表中查找相应的嵌套映射表
    auto switchIt = switchMaps.find(switchNumber);

    // 如果找到,则在嵌套映射表中查找并执行对应的处理函数;否则,处理未知情况
    if (switchIt != switchMaps.end()) {
        auto caseIt = switchIt->second.find(caseValue);
        if (caseIt != switchIt->second.end()) {
            caseIt->second();
        } else {
            std::cout << "未知情况\n";
        }
    } else {
        std::cout << "未知Switch\n";
    }
}

int main() {
    // 测试
    process(1, 2); // Switch1 处理情况 2
    process(2, 5); // Switch2 处理情况 5
    process(3, 7); // 未知Switch

    return 0;
}

在这个示例中,将共享的case部分提取为commonCases,然后在每个switch的映射表中引用这个共享部分。这样可以更好地管理和维护相同的case逻辑。

Reisen1969 commented 4 months ago

include

include

include

// 定义处理函数类型 using CaseHandler = std::function<void()>;

// 定义嵌套的映射表 using SwitchMap = std::map<int, CaseHandler>;

// 生成共享的映射表 SwitchMap generateCommonCases() { return { {2, [](){ std::cout << "处理情况 2\n"; }}, {3, [](){ std::cout << "处理情况 3\n"; }}, {4, [](){ std::cout << "处理情况 4\n"; }}, {5, [](){ std::cout << "处理情况 5\n"; }}, {6, [](){ std::cout << "处理情况 6\n"; }}, {7, [](){ std::cout << "处理情况 7\n"; }}, {8, [](){ std::cout << "处理情况 8\n"; }}, {9, [](){ std::cout << "处理情况 9\n"; }}, }; }

// 主映射表,将每个switch映射到其对应的嵌套映射表 std::map<int, SwitchMap> switchMaps = { {1, { {1, [](){ std::cout << "Switch1 处理情况 1\n"; }}, // 使用生成的共享映射表 generateCommonCases().begin(), generateCommonCases().end() }}, {2, { {4, [](){ std::cout << "Switch2 处理情况 4\n"; }}, // 使用生成的共享映射表 generateCommonCases().begin(), generateCommonCases().end() }}, // 添加其他switch的映射项... };

// 主处理函数 void process(int switchNumber, int caseValue) { // 在主映射表中查找相应的嵌套映射表 auto switchIt = switchMaps.find(switchNumber);

// 如果找到,则在嵌套映射表中查找并执行对应的处理函数;否则,处理未知情况
if (switchIt != switchMaps.end()) {
    auto caseIt = switchIt->second.find(caseValue);
    if (caseIt != switchIt->second.end()) {
        caseIt->second();
    } else {
        std::cout << "未知情况\n";
    }
} else {
    std::cout << "未知Switch\n";
}

}

int main() { // 测试 process(1, 2); // Switch1 处理情况 2 process(2, 5); // Switch2 处理情况 5 process(3, 7); // 未知Switch

return 0;

}

Reisen1969 commented 4 months ago

抱歉出现了问题。以下是另一种可能的写法,使用函数来生成共享的映射表:

#include <iostream>
#include <map>
#include <functional>

// 定义处理函数类型
using CaseHandler = std::function<void()>;

// 定义嵌套的映射表
using SwitchMap = std::map<int, CaseHandler>;

// 生成共享的映射表
SwitchMap generateCommonCases() {
    return {
        {2, [](){ std::cout << "处理情况 2\n"; }},
        {3, [](){ std::cout << "处理情况 3\n"; }},
        {4, [](){ std::cout << "处理情况 4\n"; }},
        {5, [](){ std::cout << "处理情况 5\n"; }},
        {6, [](){ std::cout << "处理情况 6\n"; }},
        {7, [](){ std::cout << "处理情况 7\n"; }},
        {8, [](){ std::cout << "处理情况 8\n"; }},
        {9, [](){ std::cout << "处理情况 9\n"; }},
    };
}

// 主映射表,将每个switch映射到其对应的嵌套映射表
std::map<int, SwitchMap> switchMaps = {
    {1, {
        {1, [](){ std::cout << "Switch1 处理情况 1\n"; }},
        // 使用生成的共享映射表
        generateCommonCases().begin(), generateCommonCases().end()
    }},
    {2, {
        {4, [](){ std::cout << "Switch2 处理情况 4\n"; }},
        // 使用生成的共享映射表
        generateCommonCases().begin(), generateCommonCases().end()
    }},
    // 添加其他switch的映射项...
};

// 主处理函数
void process(int switchNumber, int caseValue) {
    // 在主映射表中查找相应的嵌套映射表
    auto switchIt = switchMaps.find(switchNumber);

    // 如果找到,则在嵌套映射表中查找并执行对应的处理函数;否则,处理未知情况
    if (switchIt != switchMaps.end()) {
        auto caseIt = switchIt->second.find(caseValue);
        if (caseIt != switchIt->second.end()) {
            caseIt->second();
        } else {
            std::cout << "未知情况\n";
        }
    } else {
        std::cout << "未知Switch\n";
    }
}

int main() {
    // 测试
    process(1, 2); // Switch1 处理情况 2
    process(2, 5); // Switch2 处理情况 5
    process(3, 7); // 未知Switch

    return 0;
}

这里将生成共享映射表的逻辑放入了一个函数generateCommonCases中,然后在每个switch的映射表中调用这个函数,避免了重复生成映射表的问题。

Reisen1969 commented 4 months ago

抱歉出现了问题,可能是由于在初始化主映射表时尝试直接使用临时的 generateCommonCases() 结果。这可能导致生命周期问题。下面是修复的示例:

#include <iostream>
#include <map>
#include <functional>

// 定义处理函数类型
using CaseHandler = std::function<void()>;

// 定义嵌套的映射表
using SwitchMap = std::map<int, CaseHandler>;

// 生成共享的映射表
SwitchMap generateCommonCases() {
    return {
        {2, [](){ std::cout << "处理情况 2\n"; }},
        {3, [](){ std::cout << "处理情况 3\n"; }},
        {4, [](){ std::cout << "处理情况 4\n"; }},
        {5, [](){ std::cout << "处理情况 5\n"; }},
        {6, [](){ std::cout << "处理情况 6\n"; }},
        {7, [](){ std::cout << "处理情况 7\n"; }},
        {8, [](){ std::cout << "处理情况 8\n"; }},
        {9, [](){ std::cout << "处理情况 9\n"; }},
    };
}

// 主映射表,将每个switch映射到其对应的嵌套映射表
std::map<int, SwitchMap> initializeSwitchMaps() {
    return {
        {1, {
            {1, [](){ std::cout << "Switch1 处理情况 1\n"; }},
            // 使用生成的共享映射表
            generateCommonCases().begin(), generateCommonCases().end()
        }},
        {2, {
            {4, [](){ std::cout << "Switch2 处理情况 4\n"; }},
            // 使用生成的共享映射表
            generateCommonCases().begin(), generateCommonCases().end()
        }},
        // 添加其他switch的映射项...
    };
}

// 主处理函数
void process(int switchNumber, int caseValue) {
    // 获取初始化的主映射表
    auto switchMaps = initializeSwitchMaps();

    // 在主映射表中查找相应的嵌套映射表
    auto switchIt = switchMaps.find(switchNumber);

    // 如果找到,则在嵌套映射表中查找并执行对应的处理函数;否则,处理未知情况
    if (switchIt != switchMaps.end()) {
        auto caseIt = switchIt->second.find(caseValue);
        if (caseIt != switchIt->second.end()) {
            caseIt->second();
        } else {
            std::cout << "未知情况\n";
        }
    } else {
        std::cout << "未知Switch\n";
    }
}

int main() {
    // 测试
    process(1, 2); // Switch1 处理情况 2
    process(2, 5); // Switch2 处理情况 5
    process(3, 7); // 未知Switch

    return 0;
}

在这个示例中,我将主映射表的初始化移动到了一个独立的函数 initializeSwitchMaps() 中,确保 generateCommonCases() 只被调用一次,避免了可能的生命周期问题。

Reisen1969 commented 3 months ago

include

include

include

int main() { char currentDir[FILENAME_MAX]; if (getcwd(currentDir, sizeof(currentDir)) != NULL) { std::string filePath = std::string(currentDir) + "/text.txt"; std::cout << "File path: " << filePath << std::endl; } else { std::cerr << "Error getting current directory" << std::endl; } return 0; }

Reisen1969 commented 3 months ago

你可以使用<fstream>头文件中的ifstream来读取数组,并使用ofstream来将数组的所有元素写入文件。以下是一个示例:

#include <iostream>
#include <fstream>
#include <vector>

int main() {
    // 读取数组
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // 打开文件以写入
    std::ofstream outFile("output.txt");
    if (outFile.is_open()) {
        // 写入数组的所有元素到文件
        for (int num : numbers) {
            outFile << num << std::endl;
        }
        std::cout << "Array elements written to file successfully." << std::endl;
        // 关闭文件
        outFile.close();
    } else {
        std::cerr << "Error opening file." << std::endl;
    }

    return 0;
}

这段代码会将数组{1, 2, 3, 4, 5}中的所有元素写入名为output.txt的文件中。

Reisen1969 commented 3 months ago

以下是一个示例代码,它将数组的所有数字以十六进制形式写入文件,然后再从文件中读取数字并写回到数组中:

#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip> // For std::hex

int main() {
    // 读取数组
    std::vector<int> numbers = {10, 20, 30, 40, 50};

    // 将数组的所有数字以十六进制形式写入文件
    std::ofstream outFile("output.txt");
    if (outFile.is_open()) {
        for (int num : numbers) {
            outFile << std::hex << num << std::endl;
        }
        std::cout << "Array elements written to file successfully in hexadecimal." << std::endl;
        outFile.close();
    } else {
        std::cerr << "Error opening file for writing." << std::endl;
        return 1;
    }

    // 从文件中读取数字并写回到数组中
    std::ifstream inFile("output.txt");
    if (inFile.is_open()) {
        numbers.clear(); // Clear the array before reading from the file
        int num;
        while (inFile >> std::hex >> num) {
            numbers.push_back(num);
        }
        std::cout << "Array elements read from file and written back to array." << std::endl;
        inFile.close();

        // 输出数组内容以验证
        std::cout << "Array elements: ";
        for (int num : numbers) {
            std::cout << num << " ";
        }
        std::cout << std::endl;
    } else {
        std::cerr << "Error opening file for reading." << std::endl;
        return 1;
    }

    return 0;
}

这段代码首先将数组的所有数字以十六进制形式写入名为output.txt的文件中,然后再从该文件中读取数字并将其写回到数组中。

Reisen1969 commented 2 months ago

include

include

int main() { double value = 3.14159265358979323846; // 任意的double值

// 转换为float类型
float result = static_cast<float>(value);

// 打印结果
std::cout << "Original double value: " << value << std::endl;
std::cout << "Converted float value (rounded toward zero): " << result << std::endl;

return 0;

}

Reisen1969 commented 2 months ago

在C++中,可以使用标准库的std::numeric_limits来获取double和float类型的最大值和最小值,然后将double类型的值转换为float类型,并在转换过程中使用舍入向零的模式。以下是一个示例代码:

#include <iostream>
#include <limits>

int main() {
    double value = 3.14159265358979323846; // 任意的double值

    // 转换为float类型
    float result = static_cast<float>(value);

    // 打印结果
    std::cout << "Original double value: " << value << std::endl;
    std::cout << "Converted float value (rounded toward zero): " << result << std::endl;

    return 0;
}

这段代码将double类型的value转换为float类型的result,并且按照舍入向零的规则进行舍入。

Reisen1969 commented 2 months ago

在C++中,标准库中没有直接提供将double转换为float并使用rounding toward zero的函数。但是,你可以手动实现这个转换过程,如下所示:

#include <iostream>
#include <cmath> // 使用round函数需要包含cmath头文件

float double_to_float_round_toward_zero(double value) {
    if (std::isnan(value) || std::isinf(value)) {
        return static_cast<float>(value); // 处理NaN和Infinity的情况
    }
    if (value == 0.0 || std::abs(value) < std::numeric_limits<float>::min()) {
        return 0.0f; // 处理特殊情况,避免下面的计算出错
    }

    // 计算double值的float表示
    double integral_part;
    double fractional_part = std::modf(value, &integral_part);
    double sign = (value >= 0.0) ? 1.0 : -1.0;
    double float_value = static_cast<float>(integral_part) +
                         static_cast<float>(sign * std::abs(fractional_part));
    return float_value;
}

int main() {
    double value = 3.14159265358979323846; // 任意的double值

    // 转换为float类型(舍入向零)
    float result = double_to_float_round_toward_zero(value);

    // 打印结果
    std::cout << "Original double value: " << value << std::endl;
    std::cout << "Converted float value (rounded toward zero): " << result << std::endl;

    return 0;
}

这个示例代码手动实现了将double转换为float,并且使用了rounding toward zero的舍入模式。

Reisen1969 commented 2 months ago

基本移动

                    ↑
     ← h j k l →
         ↓

word移动

w根据word移动

b根据word反方向移动

W根据WORD移动

B根据WORD反方向移动

e根据word移动到word的末尾

ge反方向的e

同理还有EgE

行移动

0移动到这一行的第一个字符

^ 移动到这一行的第一个非空字符

$ 移动到这一行的最后一个字符

g_ 移动到这一行的最后一个非空字符

段落移动

{ 移动到段落的开头

} 移动到段落的结束

CTRL-D 下一页

CTRL-U 上一页

文件跳转

gg 跳转到文件头部

{line}gg跳转到指定行数

G跳转到文件末尾

% 匹配"({[]})”括号

CTRL-O返回原来的地方

快速查找

f{character} 寻找同一行的单个字符

F{character} 寻找同一行的单个字符(反方向)

t{character} 寻找同一行的单个字符的前一个

T{character} 寻找同一行的单个字符的前一个(反方向)

搜索

/{pattern} 向前搜索 forward

?{pattern} 向后搜索 backwards

输入完毕,摁下ENTER,然后使用n(next)和N(previous)跳转

搜索支持正则表达式

多次使用

数字+命令用法比如:

2w等于2次w

5j等于5次j

3f等于直接跳到f的连续3次

f2/{character} 直接跳到搜索的第2个结果

跳转

gd跳转(go)到光标所在单词的definition

gf跳转(go)到光标所在单词的import file ,(试了下并不能跳转到头文件,不懂怎么用

ctrl O :go back

ctrl I: go forward

操作符

用法:{operator}{count}{motion}

operator :操作符count:次数motion:被操作的文本块

u = CTRL-Z

CTRL-R = CTRL-Z的相反操作

操作符的种类

delete

change

yank

put

g~

> (shift right): Adds indentation

< (shift left): Removes indentation

= (format code): Formats code

Dot重复操作

. 操作符可以重复上一次的改变改变包含:

delete操作符

dw 删除1个word ,d2w 删除2个word daw delete around word

ggdG 删除整个file

dd 删除整行

D 删除光标处--->直到行的末尾

dt{character} 删除光标处--->直到遇上指定的字符,该字符不会被删

d/hello 删除光标处--->直到遇上hello,hello不会被删

change

c操作符等于d+i,删除之后会切换到Insert Mode

yank操作符和put操作符

yank操作符的用法跟dc基本一样,操作是复制

put,粘贴

g~ 操作符

作用:大小写反转,用法跟d基本一样

> < = 操作符

> < 代码缩进= 自动格式化

其他操作符

x :等于dl,等于键盘上的Delete键

X:等于dh,等于键盘上的Backspace键

s:等于ch

r:可以修改一个字符,不需要进入Insert Mode

~:更改一个字符的大小写

插入内容

i 在光标前插入

a 在光标后插入

I 在整行前插入

A 在整行后插入

o 在这一行下面插入新行,并切换到Insert Mode

O 在这一行上面插入新行,并切换到Insert Mode

gi返回到上一次做修改的地方,并进入Insert Mode

在Insert Mode下

<ESC> CTRL-C CTRL-[ 退出Insert Mode

选择内容

进入 Visual mode

Reisen1969 commented 1 month ago

你可以使用C++的字符串处理函数来实现这个替换操作。你可以使用 std::string 类和它的 find()replace() 方法。这是一个简单的示例:

#include <iostream>
#include <string>

int main() {
    std::string str = "This is a ppp test string with ppp in it.";
    std::string target = "ppp";
    std::string replacement = "lkjh";

    size_t pos = str.find(target);
    while (pos != std::string::npos) {
        str.replace(pos, target.length(), replacement);
        pos = str.find(target, pos + replacement.length());
    }

    std::cout << str << std::endl;

    return 0;
}

这段代码将会输出:

This is a lkjh test string with lkjh in it.
Reisen1969 commented 1 month ago

要通过二叉树的前序遍历和中序遍历来求解后序遍历,可以利用递归的方法。下面是一个用 C++ 实现的示例代码:

#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

TreeNode* buildTreeHelper(vector<int>& preorder, vector<int>& inorder, int preorder_start, int preorder_end, int inorder_start, int inorder_end, unordered_map<int, int>& inorder_map) {
    if (preorder_start > preorder_end || inorder_start > inorder_end) {
        return NULL;
    }

    int root_val = preorder[preorder_start];
    TreeNode* root = new TreeNode(root_val);

    int inorder_root_index = inorder_map[root_val];
    int left_subtree_size = inorder_root_index - inorder_start;

    root->left = buildTreeHelper(preorder, inorder, preorder_start + 1, preorder_start + left_subtree_size, inorder_start, inorder_root_index - 1, inorder_map);
    root->right = buildTreeHelper(preorder, inorder, preorder_start + left_subtree_size + 1, preorder_end, inorder_root_index + 1, inorder_end, inorder_map);

    return root;
}

TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    unordered_map<int, int> inorder_map;
    for (int i = 0; i < inorder.size(); ++i) {
        inorder_map[inorder[i]] = i;
    }
    return buildTreeHelper(preorder, inorder, 0, preorder.size() - 1, 0, inorder.size() - 1, inorder_map);
}

void postorderTraversalHelper(TreeNode* root, vector<int>& result) {
    if (root == NULL) {
        return;
    }
    postorderTraversalHelper(root->left, result);
    postorderTraversalHelper(root->right, result);
    result.push_back(root->val);
}

vector<int> postorderTraversal(TreeNode* root) {
    vector<int> result;
    postorderTraversalHelper(root, result);
    return result;
}

int main() {
    vector<int> preorder = {1, 2, 4, 5, 3, 6, 7};
    vector<int> inorder = {4, 2, 5, 1, 6, 3, 7};

    TreeNode* root = buildTree(preorder, inorder);
    vector<int> postorder = postorderTraversal(root);

    cout << "Postorder traversal: ";
    for (int val : postorder) {
        cout << val << " ";
    }
    cout << endl;

    return 0;
}

这段代码首先定义了一个二叉树的结构体 TreeNode,然后实现了 buildTree 函数来构建二叉树,利用了前序遍历和中序遍历的特点,其中利用了一个哈希表 inorder_map 来存储中序遍历中每个节点值对应的索引位置,这样可以快速定位根节点在中序遍历中的位置。接着实现了 postorderTraversal 函数来进行后序遍历,并在 main 函数中进行了测试。

你可以将 preorderinorder 中的数据替换成你自己的二叉树的前序遍历和中序遍历结果,然后运行代码即可得到后序遍历结果。

Reisen1969 commented 1 month ago

在C++中,要判断一个地址是否是4字节对齐或8字节对齐,可以使用指针类型和位操作。具体方法如下:

  1. 4字节对齐:如果地址能被4整除,那么这个地址就是4字节对齐。
  2. 8字节对齐:如果地址能被8整除,那么这个地址就是8字节对齐。

下面是实现这一判断的代码示例:

#include <iostream>

// 判断地址是否4字节对齐
bool isAligned4(void* ptr) {
    return reinterpret_cast<std::uintptr_t>(ptr) % 4 == 0;
}

// 判断地址是否8字节对齐
bool isAligned8(void* ptr) {
    return reinterpret_cast<std::uintptr_t>(ptr) % 8 == 0;
}

int main() {
    int a;
    void* addr = &a;

    if (isAligned4(addr)) {
        std::cout << "地址 " << addr << " 是4字节对齐的。" << std::endl;
    } else {
        std::cout << "地址 " << addr << " 不是4字节对齐的。" << std::endl;
    }

    if (isAligned8(addr)) {
        std::cout << "地址 " << addr << " 是8字节对齐的。" << std::endl;
    } else {
        std::cout << "地址 " << addr << " 不是8字节对齐的。" << std::endl;
    }

    return 0;
}

在这个代码中:

可以在程序中运行这段代码来测试各种变量的地址是否对齐。

Reisen1969 commented 1 month ago

要将一个12-bit的数符号扩展成64-bit的数,可以使用C++进行实现。符号扩展的过程需要确保符号位(即最高位)在扩展后仍然保持正确的符号。

以下是实现这一功能的C++代码示例:

#include <iostream>
#include <cstdint>

int64_t signExtend12Bit(int16_t value) {
    // 12-bit mask to extract the relevant bits
    const int16_t mask = 0x800;

    // Check if the sign bit (12th bit) is set
    if (value & mask) {
        // If the sign bit is set, we need to set all the upper bits to 1
        return static_cast<int64_t>(value | ~0xFFF);
    } else {
        // If the sign bit is not set, we can just return the value
        return static_cast<int64_t>(value);
    }
}

int main() {
    int16_t input = 0x800; // Example input
    int64_t result = signExtend12Bit(input);
    std::cout << "Sign-extended value: " << result << std::endl; // Output: -2048
    return 0;
}

代码说明

  1. 掩码(Mask)和符号位检查:

    const int16_t mask = 0x800;

    掩码 0x800 用于检查12-bit数的最高位(即第12位)。如果该位为1,则该数是负数。

  2. 符号扩展:

    if (value & mask) {
       return static_cast<int64_t>(value | ~0xFFF);
    } else {
       return static_cast<int64_t>(value);
    }
    • 如果符号位(第12位)为1,需要将高位全部设置为1,以保持符号的一致性。通过 value | ~0xFFF 将高位设置为1。
    • 如果符号位为0,则直接返回值即可,因为不需要扩展高位。
  3. 主函数:

    int main() {
       int16_t input = 0x800; // Example input
       int64_t result = signExtend12Bit(input);
       std::cout << "Sign-extended value: " << result << std::endl; // Output: -2048
       return 0;
    }

    主函数中提供一个示例输入 0x800,并调用 signExtend12Bit 函数进行符号扩展,然后输出结果。

运行此代码,将会得到输出:

Sign-extended value: -2048

这表明 0x800(12-bit数)已正确地符号扩展为 -2048(64-bit数)。

Reisen1969 commented 3 weeks ago

winsdk(Windows SDK for Python)模块允许你使用 Python 调用 Windows API,并实现与 Windows 操作系统的交互。下面是一些示例,展示如何使用 winsdk 模块实现不同的功能。

首先,你需要安装 winsdk 模块。如果还没有安装,可以使用以下命令安装:

pip install winsdk

示例 1: 显示消息框

你可以使用 Windows 的 MessageBox 函数来显示一个消息框。以下是如何在 Python 中实现这一点:

import winsdk.windows.ui.popups as wup
import asyncio

async def show_message_box():
    message_dialog = wup.MessageDialog("Hello, World!", "Title")
    await message_dialog.show_async()

asyncio.run(show_message_box())

示例 2: 获取当前电池状态

你可以使用 Windows API 获取系统的电池状态。以下是一个示例,展示如何使用 winsdk 模块来获取电池信息:

import winsdk.windows.system.power as wsp

battery_report = wsp.PowerManager.get_battery_report()
remaining_capacity = battery_report.remaining_capacity_in_milliwatt_hours
full_charge_capacity = battery_report.full_charge_capacity_in_milliwatt_hours
percent_remaining = (remaining_capacity / full_charge_capacity) * 100

print(f"Remaining capacity: {remaining_capacity} mWh")
print(f"Full charge capacity: {full_charge_capacity} mWh")
print(f"Battery percentage remaining: {percent_remaining:.2f}%")

示例 3: 访问文件

使用 winsdk 模块,你可以访问 Windows 的文件系统。以下是一个示例,展示如何打开文件选择对话框并读取所选文件的内容:

import winsdk.windows.storage.pickers as pickers
import winsdk.windows.storage as storage
import asyncio

async def pick_file():
    file_picker = pickers.FileOpenPicker()
    file_picker.suggested_start_location = pickers.PickerLocationId.documents_library
    file_picker.file_type_filter.append("*")

    file = await file_picker.pick_single_file_async()
    if file:
        contents = await storage.FileIO.read_text_async(file)
        print(f"File contents: {contents}")
    else:
        print("No file selected")

asyncio.run(pick_file())

示例 4: 控制系统音量

以下是一个示例,展示如何使用 winsdk 模块控制系统音量:

import winsdk.windows.media as media

# 获取系统音量
volume_manager = media.SystemMediaTransportControls.get_for_current_view()
current_volume = volume_manager.sound_level
print(f"Current volume: {current_volume}")

# 设置系统音量 (在此示例中无法直接设置音量, 需要进一步的接口或模块支持)

示例 5: 检查网络连接状态

你可以使用 Windows 的网络 API 检查网络连接状态。以下是一个示例:

import winsdk.windows.networking.connectivity as wnc

profile = wnc.NetworkInformation.get_internet_connection_profile()
if profile:
    connectivity_level = profile.get_network_connectivity_level()
    print(f"Connectivity level: {connectivity_level}")
else:
    print("No internet connection")

这些示例展示了如何使用 winsdk 模块与 Windows API 交互,完成一些常见的系统任务。根据你的需求,可以进一步扩展这些示例来实现更多功能。

Reisen1969 commented 3 weeks ago

好的,这里是一个完整的示例,展示如何在一个应用程序中使用上述所有的 PySide6 部件。这个示例将包含一个 QMainWindow,并使用 QToolBarQStatusBarQMenuBarQTabWidgetQStackedWidgetQScrollAreaQMessageBox

import sys
from PySide6.QtWidgets import (QApplication, QMainWindow, QToolBar, QStatusBar, QMenuBar, 
                               QTabWidget, QStackedWidget, QScrollArea, QMessageBox, 
                               QLabel, QVBoxLayout, QWidget, QAction, QDialog, QPushButton)
from PySide6.QtGui import QIcon

class CustomDialog(QDialog):
    def __init__(self):
        super(CustomDialog, self).__init__()
        self.setWindowTitle("Custom Dialog")
        layout = QVBoxLayout()
        label = QLabel("This is a custom dialog")
        layout.addWidget(label)
        self.setLayout(layout)

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("Complete Example")
        self.setGeometry(100, 100, 800, 600)

        # 设置中心部件和布局
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout(self.central_widget)

        # 创建标签用于显示工具栏操作的结果
        self.label = QLabel("请选择一个操作", self)
        self.layout.addWidget(self.label)

        # 创建工具栏
        self.toolbar = QToolBar("Main Toolbar", self)
        self.addToolBar(self.toolbar)

        # 创建操作并添加到工具栏
        action_open = QAction(QIcon(), "打开", self)
        action_open.setStatusTip("打开文件")
        action_open.triggered.connect(lambda: self.label.setText("打开操作"))

        action_save = QAction(QIcon(), "保存", self)
        action_save.setStatusTip("保存文件")
        action_save.triggered.connect(lambda: self.label.setText("保存操作"))

        action_exit = QAction(QIcon(), "退出", self)
        action_exit.setStatusTip("退出应用程序")
        action_exit.triggered.connect(self.close)

        self.toolbar.addAction(action_open)
        self.toolbar.addAction(action_save)
        self.toolbar.addSeparator()
        self.toolbar.addAction(action_exit)

        # 创建状态栏
        self.status_bar = QStatusBar(self)
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage("这是状态栏消息")

        # 创建菜单栏
        self.menu_bar = QMenuBar(self)
        self.setMenuBar(self.menu_bar)

        file_menu = self.menu_bar.addMenu("文件")
        file_menu.addAction(action_open)
        file_menu.addAction(action_save)
        file_menu.addSeparator()
        file_menu.addAction(action_exit)

        help_menu = self.menu_bar.addMenu("帮助")
        about_action = QAction("关于", self)
        about_action.triggered.connect(self.show_about_dialog)
        help_menu.addAction(about_action)

        # 创建 TabWidget
        self.tab_widget = QTabWidget(self)
        self.layout.addWidget(self.tab_widget)

        tab1 = QWidget()
        tab1_layout = QVBoxLayout(tab1)
        tab1_label = QLabel("这是第一个标签页")
        tab1_layout.addWidget(tab1_label)

        tab2 = QWidget()
        tab2_layout = QVBoxLayout(tab2)
        tab2_label = QLabel("这是第二个标签页")
        tab2_layout.addWidget(tab2_label)

        self.tab_widget.addTab(tab1, "Tab 1")
        self.tab_widget.addTab(tab2, "Tab 2")

        # 创建 StackedWidget
        self.stacked_widget = QStackedWidget(self)
        self.layout.addWidget(self.stacked_widget)

        page1 = QWidget()
        page1_layout = QVBoxLayout(page1)
        page1_label = QLabel("这是第一个页面")
        switch_to_page2_btn = QPushButton("切换到第二个页面")
        switch_to_page2_btn.clicked.connect(lambda: self.stacked_widget.setCurrentWidget(page2))
        page1_layout.addWidget(page1_label)
        page1_layout.addWidget(switch_to_page2_btn)

        page2 = QWidget()
        page2_layout = QVBoxLayout(page2)
        page2_label = QLabel("这是第二个页面")
        switch_to_page1_btn = QPushButton("切换到第一个页面")
        switch_to_page1_btn.clicked.connect(lambda: self.stacked_widget.setCurrentWidget(page1))
        page2_layout.addWidget(page2_label)
        page2_layout.addWidget(switch_to_page1_btn)

        self.stacked_widget.addWidget(page1)
        self.stacked_widget.addWidget(page2)

        # 创建 ScrollArea
        self.scroll_area = QScrollArea(self)
        self.scroll_content = QWidget()
        self.scroll_area.setWidget(self.scroll_content)
        self.scroll_area.setWidgetResizable(True)
        self.layout.addWidget(self.scroll_area)

        scroll_layout = QVBoxLayout(self.scroll_content)
        for i in range(20):
            scroll_layout.addWidget(QLabel(f"标签 {i}"))

        # 创建一个按钮用于显示消息框
        show_msg_box_btn = QPushButton("显示消息框", self)
        show_msg_box_btn.clicked.connect(self.show_message_box)
        self.layout.addWidget(show_msg_box_btn)

        # 创建一个按钮用于显示自定义对话框
        show_custom_dialog_btn = QPushButton("显示自定义对话框", self)
        show_custom_dialog_btn.clicked.connect(self.show_custom_dialog)
        self.layout.addWidget(show_custom_dialog_btn)

    def show_message_box(self):
        msg_box = QMessageBox(self)
        msg_box.setText("这是一个消息框")
        msg_box.exec()

    def show_custom_dialog(self):
        dialog = CustomDialog()
        dialog.exec()

    def show_about_dialog(self):
        about_msg_box = QMessageBox(self)
        about_msg_box.setWindowTitle("关于")
        about_msg_box.setText("这是一个关于对话框")
        about_msg_box.exec()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

代码解释

  1. 导入模块

    from PySide6.QtWidgets import (QApplication, QMainWindow, QToolBar, QStatusBar, QMenuBar, 
                                   QTabWidget, QStackedWidget, QScrollArea, QMessageBox, 
                                   QLabel, QVBoxLayout, QWidget, QAction, QDialog, QPushButton)
    from PySide6.QtGui import QIcon
  2. 自定义对话框 CustomDialog

    class CustomDialog(QDialog):
        def __init__(self):
            super(CustomDialog, self).__init__()
            self.setWindowTitle("Custom Dialog")
            layout = QVBoxLayout()
            label = QLabel("This is a custom dialog")
            layout.addWidget(label)
            self.setLayout(layout)
  3. 主窗口 MainWindow

    class MainWindow(QMainWindow):
        def __init__(self):
            super(MainWindow, self).__init__()
            self.setWindowTitle("Complete Example")
            self.setGeometry(100, 100, 800, 600)
            ...
  4. 设置中心部件和布局

        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout(self.central_widget)
  5. 创建工具栏、状态栏和菜单栏

        self.toolbar = QToolBar("Main Toolbar", self)
        self.addToolBar(self.toolbar)
    
        self.status_bar = QStatusBar(self)
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage("这是状态栏消息")
    
        self.menu_bar = QMenuBar(self)
        self.setMenuBar(self.menu_bar)
    
        file_menu = self.menu_bar.addMenu("文件")
        ...
    
        help_menu = self.menu_bar.addMenu("帮助")
        about_action = QAction("关于", self)
        about_action.triggered.connect(self.show_about_dialog)
        help_menu.addAction(about_action)
  6. 创建 QTabWidgetQStackedWidget

        self.tab_widget = QTabWidget(self)
        self.layout.addWidget(self.tab_widget)
        ...
    
        self.stacked_widget = QStackedWidget(self)
        self.layout.addWidget(self.stacked_widget)
        ...
  7. 创建 QScrollArea

        self.scroll_area = QScrollArea(self)
        self.scroll_content = QWidget()
        self.scroll_area.setWidget(self.scroll_content)
        self.scroll_area.setWidgetResizable(True)
        self.layout.addWidget(self.scroll_area)
    
        scroll_layout = QVBoxLayout(self.scroll_content)
        for i in range(20):
            scroll_layout.addWidget(QLabel(f"标签 {i}"))
  8. 创建按钮用于显示消息框和自定义对话框

    
        show_msg_box_btn = QPushButton("显示消息框", self)
        show_msg_box_btn.clicked.connect(self.show_message_box)
        self.layout.addWidget(show_msg_box_btn)
    
        show_custom_dialog_btn = QPushButton("显示自定义对话框
Reisen1969 commented 3 weeks ago

好的,这里是一个完整的示例,展示如何在一个应用程序中使用上述所有的 PySide6 部件。这个示例将包含一个 QMainWindow,并使用 QToolBarQStatusBarQMenuBarQTabWidgetQStackedWidgetQScrollAreaQMessageBox

import sys
from PySide6.QtWidgets import (QApplication, QMainWindow, QToolBar, QStatusBar, QMenuBar, 
                               QTabWidget, QStackedWidget, QScrollArea, QMessageBox, 
                               QLabel, QVBoxLayout, QWidget, QAction, QDialog, QPushButton)
from PySide6.QtGui import QIcon

class CustomDialog(QDialog):
    def __init__(self):
        super(CustomDialog, self).__init__()
        self.setWindowTitle("Custom Dialog")
        layout = QVBoxLayout()
        label = QLabel("This is a custom dialog")
        layout.addWidget(label)
        self.setLayout(layout)

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("Complete Example")
        self.setGeometry(100, 100, 800, 600)

        # 设置中心部件和布局
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout(self.central_widget)

        # 创建标签用于显示工具栏操作的结果
        self.label = QLabel("请选择一个操作", self)
        self.layout.addWidget(self.label)

        # 创建工具栏
        self.toolbar = QToolBar("Main Toolbar", self)
        self.addToolBar(self.toolbar)

        # 创建操作并添加到工具栏
        action_open = QAction(QIcon(), "打开", self)
        action_open.setStatusTip("打开文件")
        action_open.triggered.connect(lambda: self.label.setText("打开操作"))

        action_save = QAction(QIcon(), "保存", self)
        action_save.setStatusTip("保存文件")
        action_save.triggered.connect(lambda: self.label.setText("保存操作"))

        action_exit = QAction(QIcon(), "退出", self)
        action_exit.setStatusTip("退出应用程序")
        action_exit.triggered.connect(self.close)

        self.toolbar.addAction(action_open)
        self.toolbar.addAction(action_save)
        self.toolbar.addSeparator()
        self.toolbar.addAction(action_exit)

        # 创建状态栏
        self.status_bar = QStatusBar(self)
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage("这是状态栏消息")

        # 创建菜单栏
        self.menu_bar = QMenuBar(self)
        self.setMenuBar(self.menu_bar)

        file_menu = self.menu_bar.addMenu("文件")
        file_menu.addAction(action_open)
        file_menu.addAction(action_save)
        file_menu.addSeparator()
        file_menu.addAction(action_exit)

        help_menu = self.menu_bar.addMenu("帮助")
        about_action = QAction("关于", self)
        about_action.triggered.connect(self.show_about_dialog)
        help_menu.addAction(about_action)

        # 创建 TabWidget
        self.tab_widget = QTabWidget(self)
        self.layout.addWidget(self.tab_widget)

        tab1 = QWidget()
        tab1_layout = QVBoxLayout(tab1)
        tab1_label = QLabel("这是第一个标签页")
        tab1_layout.addWidget(tab1_label)

        tab2 = QWidget()
        tab2_layout = QVBoxLayout(tab2)
        tab2_label = QLabel("这是第二个标签页")
        tab2_layout.addWidget(tab2_label)

        self.tab_widget.addTab(tab1, "Tab 1")
        self.tab_widget.addTab(tab2, "Tab 2")

        # 创建 StackedWidget
        self.stacked_widget = QStackedWidget(self)
        self.layout.addWidget(self.stacked_widget)

        page1 = QWidget()
        page1_layout = QVBoxLayout(page1)
        page1_label = QLabel("这是第一个页面")
        switch_to_page2_btn = QPushButton("切换到第二个页面")
        switch_to_page2_btn.clicked.connect(lambda: self.stacked_widget.setCurrentWidget(page2))
        page1_layout.addWidget(page1_label)
        page1_layout.addWidget(switch_to_page2_btn)

        page2 = QWidget()
        page2_layout = QVBoxLayout(page2)
        page2_label = QLabel("这是第二个页面")
        switch_to_page1_btn = QPushButton("切换到第一个页面")
        switch_to_page1_btn.clicked.connect(lambda: self.stacked_widget.setCurrentWidget(page1))
        page2_layout.addWidget(page2_label)
        page2_layout.addWidget(switch_to_page1_btn)

        self.stacked_widget.addWidget(page1)
        self.stacked_widget.addWidget(page2)

        # 创建 ScrollArea
        self.scroll_area = QScrollArea(self)
        self.scroll_content = QWidget()
        self.scroll_area.setWidget(self.scroll_content)
        self.scroll_area.setWidgetResizable(True)
        self.layout.addWidget(self.scroll_area)

        scroll_layout = QVBoxLayout(self.scroll_content)
        for i in range(20):
            scroll_layout.addWidget(QLabel(f"标签 {i}"))

        # 创建一个按钮用于显示消息框
        show_msg_box_btn = QPushButton("显示消息框", self)
        show_msg_box_btn.clicked.connect(self.show_message_box)
        self.layout.addWidget(show_msg_box_btn)

        # 创建一个按钮用于显示自定义对话框
        show_custom_dialog_btn = QPushButton("显示自定义对话框", self)
        show_custom_dialog_btn.clicked.connect(self.show_custom_dialog)
        self.layout.addWidget(show_custom_dialog_btn)

    def show_message_box(self):
        msg_box = QMessageBox(self)
        msg_box.setText("这是一个消息框")
        msg_box.exec()

    def show_custom_dialog(self):
        dialog = CustomDialog()
        dialog.exec()

    def show_about_dialog(self):
        about_msg_box = QMessageBox(self)
        about_msg_box.setWindowTitle("关于")
        about_msg_box.setText("这是一个关于对话框")
        about_msg_box.exec()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

代码解释

  1. 导入模块

    from PySide6.QtWidgets import (QApplication, QMainWindow, QToolBar, QStatusBar, QMenuBar, 
                                   QTabWidget, QStackedWidget, QScrollArea, QMessageBox, 
                                   QLabel, QVBoxLayout, QWidget, QAction, QDialog, QPushButton)
    from PySide6.QtGui import QIcon
  2. 自定义对话框 CustomDialog

    class CustomDialog(QDialog):
        def __init__(self):
            super(CustomDialog, self).__init__()
            self.setWindowTitle("Custom Dialog")
            layout = QVBoxLayout()
            label = QLabel("This is a custom dialog")
            layout.addWidget(label)
            self.setLayout(layout)
  3. 主窗口 MainWindow

    class MainWindow(QMainWindow):
        def __init__(self):
            super(MainWindow, self).__init__()
            self.setWindowTitle("Complete Example")
            self.setGeometry(100, 100, 800, 600)
            ...
  4. 设置中心部件和布局

        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout(self.central_widget)
  5. 创建工具栏、状态栏和菜单栏

        self.toolbar = QToolBar("Main Toolbar", self)
        self.addToolBar(self.toolbar)
    
        self.status_bar = QStatusBar(self)
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage("这是状态栏消息")
    
        self.menu_bar = QMenuBar(self)
        self.setMenuBar(self.menu_bar)
    
        file_menu = self.menu_bar.addMenu("文件")
        ...
    
        help_menu = self.menu_bar.addMenu("帮助")
        about_action = QAction("关于", self)
        about_action.triggered.connect(self.show_about_dialog)
        help_menu.addAction(about_action)
  6. 创建 QTabWidgetQStackedWidget

        self.tab_widget = QTabWidget(self)
        self.layout.addWidget(self.tab_widget)
        ...
    
        self.stacked_widget = QStackedWidget(self)
        self.layout.addWidget(self.stacked_widget)
        ...
  7. 创建 QScrollArea

        self.scroll_area = QScrollArea(self)
        self.scroll_content = QWidget()
        self.scroll_area.setWidget(self.scroll_content)
        self.scroll_area.setWidgetResizable(True)
        self.layout.addWidget(self.scroll_area)
    
        scroll_layout = QVBoxLayout(self.scroll_content)
        for i in range(20):
            scroll_layout.addWidget(QLabel(f"标签 {i}"))
  8. 创建按钮用于显示消息框和自定义对话框

    
        show_msg_box_btn = QPushButton("显示消息框", self)
        show_msg_box_btn.clicked.connect(self.show_message_box)
        self.layout.addWidget(show_msg_box_btn)
    
        show_custom_dialog_btn = QPushButton("显示自定义对话框