Open Reisen1969 opened 8 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)
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)
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)
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.你的变量名)
int main() {
std::vector
int num;
// 从标准输入读取数字,直到到达文件尾
while (std::cin >> num) {
numbers.push_back(num);
}
// 在这里进行你的程序逻辑,使用 numbers 容器
return 0;
}
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)
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()
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()
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()
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)
要将一个ext4文件系统打包成cpio.gz格式并在QEMU中启动,可以按照以下步骤进行操作:
sudo mkdir /mnt/ext4
sudo mount -t ext4 /path/to/tmp.ext4 /mnt/ext4
确保替换 /path/to/tmp.ext4
为你的实际ext4文件系统路径。
sudo find /mnt/ext4 | cpio -o -H newc | gzip -9 > /path/to/initramfs.cpio.gz
确保替换 /path/to/initramfs.cpio.gz
为你希望保存initramfs的路径。
sudo umount /mnt/ext4
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后,其中的数据会丢失。如果需要持久性存储,可以考虑使用其他文件系统并将其保存在硬盘中。
要使一个目录对普通用户可访问(无需使用 sudo
),你可以通过更改目录的权限和所有者来实现。以下是一些建议的步骤:
更改目录的拥有者:
sudo chown -R username:groupname /path/to/your/directory
替换 username
和 groupname
为你希望的用户和组。这将确保目录属于指定的用户和组。
更改目录的权限:
为了让普通用户能够访问目录,你可以使用以下命令:
sudo chmod -R 755 /path/to/your/directory
这样设置后,目录的拥有者(通常是你指定的 username
)可以读写执行,而其他用户可以读和执行目录。
如果你希望所有用户都能够对目录进行写操作,你可以使用:
sudo chmod -R 777 /path/to/your/directory
请注意,赋予 777 权限可能存在安全风险,只在确实需要这种权限时使用。
测试普通用户访问:
确保你的普通用户可以访问目录:
cd /path/to/your/directory
如果没有权限错误,说明你已经成功让普通用户访问这个目录。
请谨慎更改目录的权限和所有者,确保在需要的情况下进行,并理解潜在的安全风险。
要查看普通用户属于哪些用户组,你可以使用以下命令:
groups username
请将 username
替换为你想要查询的普通用户的实际用户名。这将列出用户所属的用户组。
例如,如果要查看用户Alice所属的用户组,可以运行:
groups alice
命令的输出将显示用户所在的用户组列表。如果用户属于多个用户组,它们将以空格分隔。
在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系统中,你可以执行以下步骤来挂载这些共享文件夹:
sudo mkdir /mnt/share1
sudo mkdir /mnt/share2
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
这里,share1
和 share2
是在QEMU启动命令中定义的 mount_tag
。
请确保替换 your_disk_image.img
,/path/on/host1
,/path/on/host2
为实际的值。如果你的Guest系统不是Linux,挂载步骤可能有所不同。
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)
git bisect
是一个用于二分查找引入错误的 Git 命令。以下是一个简单的 git bisect
使用教程:
开始 bisect:
git bisect start
标记一个已知的“好”提交:
git bisect good <commit-hash>
标记一个已知的“坏”提交:
git bisect bad <commit-hash>
这会告诉 Git 在这两个提交之间进行二分查找。
Git 将自动切换到中间的提交:
Bisecting: <commit-details>
测试当前提交是否有错误:
在每个提交上运行你的测试,如果有错误,使用 git bisect bad
,否则使用 git bisect good
。
重复步骤 4 和步骤 5: Git 会根据你的反馈继续二分查找,直到找到引入错误的提交。
结束 bisect: 一旦找到了引入错误的提交,结束 bisect:
git bisect reset
示例:
假设你的项目有一次提交引入了错误,你已知在提交 abc123
之前没有问题,而在提交 def456
之后出现了问题。开始 bisect:
git bisect start
git bisect good abc123
git bisect bad def456
Git 会自动选择中间的提交,并提示你测试。重复这个过程,直到找到引入错误的提交。最后,使用 git bisect reset
结束 bisect。
这是一个简单的演示,实际使用时,你需要根据项目的具体情况运行适当的测试。
gcc -dumpspecs | grep -oP '(?<=*link:\s(ld)\s)\S+'
你可以使用以下 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_colon
和 after_colon
变量中。
to_excel
是 pandas DataFrame 对象的方法,用于将数据写入 Excel 文件。以下是一些常用的参数及其用途:
excel_writer
: 指定写入的 Excel 文件名或 ExcelWriter 对象。
df.to_excel(excel_writer='output.xlsx', index=False)
sheet_name
: 指定 Excel 工作表的名称。
df.to_excel(excel_writer='output.xlsx', sheet_name='Sheet1', index=False)
index
: 决定是否将 DataFrame 的索引写入 Excel 文件。默认为 True。
df.to_excel(excel_writer='output.xlsx', index=False)
header
: 决定是否将列名写入 Excel 文件。默认为 True。
df.to_excel(excel_writer='output.xlsx', header=False, index=False)
startrow
和 startcol
: 指定写入 Excel 文件时的起始行和列。
df.to_excel(excel_writer='output.xlsx', startrow=2, startcol=3, index=False)
na_rep
: 指定在文件中用于表示缺失数据的字符串。
df.to_excel(excel_writer='output.xlsx', na_rep='NA', index=False)
merge_cells
: 决定是否合并单元格,默认为 True。可以设置为 False 禁止合并单元格。
df.to_excel(excel_writer='output.xlsx', merge_cells=False, index=False)
这只是一些常见参数的示例,你可以根据需要查看 pandas 文档 获取更多详细信息。
在 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 版本的文档以获取准确的参数信息。在生产环境中修改这些参数之前,请务必测试并谨慎行事。
在CMake中添加自定义的GCC选项通常是通过修改CMakeLists.txt文件来实现的。下面是一个简单的示例,演示如何向CMake中添加自定义的GCC选项:
打开你的MySQL源代码目录中的 CMakeLists.txt
文件。
在文件中找到适当的位置,通常是在编译选项部分。你可能会找到一些类似于 add_compile_options
的指令。
在这里,添加你的自定义GCC选项。例如,如果你想添加优化选项 -O3
,你可以这样写:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
如果你想添加其他自定义选项,使用类似的语法即可。
如果有多个编译器选项,你可以使用 target_compile_options
指令来针对特定的目标(比如mysqld
)添加选项:
target_compile_options(mysqld PRIVATE -O3 -Wall)
这里,mysqld
是你的MySQL目标的名称,你可能需要根据实际情况调整。
保存文件并重新运行CMake,然后再次编译你的MySQL代码。
请确保你的修改符合MySQL代码的构建系统,并注意确保选项不会导致不稳定或不安全的行为。
在CMake中,要进行静态编译程序,你可以使用以下步骤:
设置编译类型为静态库:
在你的CMakeLists.txt文件中,使用add_executable
或add_library
时,可以通过STATIC
关键字指定使用静态库。例如:
add_executable(MyExecutable main.cpp)
指定链接类型为静态库:
使用target_link_libraries
来指定链接的库,包括静态库。例如:
target_link_libraries(MyExecutable PRIVATE your_static_library)
禁用共享库: 你还需要禁用共享库的生成,以确保静态链接。可以通过设置全局属性或目标属性来实现。例如:
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)
重新生成项目: 在完成上述更改后,重新运行CMake生成项目文件,然后进行编译。
请注意,确保你所链接的所有库都具有相应的静态版本。一些库可能提供动态和静态版本,你需要选择正确的版本。
要在CMake中设置静态链接程序,你可以使用以下步骤:
全局设置静态链接: 在你的项目的 CMakeLists.txt 文件中,可以使用以下命令来设置全局的链接选项,使得整个项目都以静态方式链接:
set(CMAKE_EXE_LINKER_FLAGS "-static")
目标级别设置静态链接:
如果你只想为特定目标(例如可执行文件)进行静态链接,可以在目标级别使用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")
重新生成项目: 在完成上述更改后,重新运行 CMake 生成项目文件,然后进行编译。
这样,你的可执行文件或库就会以静态方式链接。确保你的系统支持静态链接,并且相关的静态库文件是可用的。
在CMake中静态链接 glibc(GNU C Library)自带的动态库(比如 libc.so
)可能会面临一些限制,因为 glibc 通常是设计用于动态链接的。
但你可以采取一些措施来尽可能地实现静态链接:
查找或生成 glibc 的静态库: 首先,确保你有 glibc 的静态库文件。这可能需要手动构建 glibc 的静态版本,或者你可以尝试查看系统是否提供了这些文件。
在 CMakeLists.txt 中添加 glibc 的静态库:
使用target_link_libraries
命令将 glibc 的静态库链接到你的目标。例如:
add_executable(YourExecutableName main.cpp)
target_link_libraries(YourExecutableName PRIVATE /path/to/libc.a)
禁用动态链接:
你还需要确保禁用对 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")
重新生成项目: 在完成上述更改后,重新运行 CMake 生成项目文件,然后进行编译。
请注意,glibc 的静态链接可能会引入其他复杂性,包括依赖关系和系统兼容性。确保你的应用程序不会受到这些变化的不利影响。
int main() {
int64_t originalValue = 0x1ffdf90;
int64_t extendedValue = static_cast
std::cout << std::hex << extendedValue << std::endl;
return 0;
}
当使用映射表优化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
函数中,根据输入值查找映射表,执行对应的处理函数。这种方式使得新增或修改情况的处理更加方便,不需要修改主处理函数。
当两个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
逻辑。
// 定义处理函数类型 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;
}
抱歉出现了问题。以下是另一种可能的写法,使用函数来生成共享的映射表:
#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
的映射表中调用这个函数,避免了重复生成映射表的问题。
抱歉出现了问题,可能是由于在初始化主映射表时尝试直接使用临时的 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()
只被调用一次,避免了可能的生命周期问题。
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; }
你可以使用<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
的文件中。
以下是一个示例代码,它将数组的所有数字以十六进制形式写入文件,然后再从文件中读取数字并写回到数组中:
#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
的文件中,然后再从该文件中读取数字并将其写回到数组中。
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;
}
在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
,并且按照舍入向零的规则进行舍入。
在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的舍入模式。
↑
← h j k l →
↓
w
根据word移动
b
根据word反方向移动
W
根据WORD移动
B
根据WORD反方向移动
e
根据word移动到word的末尾
ge
反方向的e
同理还有E
和gE
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
跳转(g
o)到光标所在单词的d
efinition
gf
跳转(g
o)到光标所在单词的import f
ile ,(试了下并不能跳转到头文件,不懂怎么用
ctrl O :go back
ctrl I: go forward
用法:{operator}{count}{motion}
operator :操作符count:次数motion:被操作的文本块
u
= CTRL-Z
CTRL-R
= CTRL-Z
的相反操作
d
elete
c
hange
y
ank
p
ut
g~
>
(shift right): Adds indentation
<
(shift left): Removes indentation
=
(format code): Formats code
.
操作符可以重复上一次的改变改变包含:
d
elete 操作i
nsert 操作c
hange 操作dw
删除1个word ,d2w
删除2个word daw
delete around word
ggdG
删除整个file
dd
删除整行
D
删除光标处--->直到行的末尾
dt{character}
删除光标处--->直到遇上指定的字符,该字符不会被删
d/hello
删除光标处--->直到遇上hello,hello不会被删
c
操作符等于d
+i
,删除之后会切换到Insert Mode
y
ank操作符的用法跟d和c基本一样,操作是复制
p
ut,粘贴
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
CTRL-H
删除输入的最后一个字符CTRL-W
删除输入的最后一个wordCTRL-U
删除输入的最后一行<ESC>
CTRL-C
CTRL-[
退出Insert Mode
进入 Visual mode
v
字符 visual modeV
行 visual modeCTRL-V
块 visual mode你可以使用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.
要通过二叉树的前序遍历和中序遍历来求解后序遍历,可以利用递归的方法。下面是一个用 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
函数中进行了测试。
你可以将 preorder
和 inorder
中的数据替换成你自己的二叉树的前序遍历和中序遍历结果,然后运行代码即可得到后序遍历结果。
在C++中,要判断一个地址是否是4字节对齐或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;
}
在这个代码中:
reinterpret_cast<std::uintptr_t>(ptr)
将指针转换为无符号整数类型,以便进行模运算。isAligned4
和 isAligned8
分别用于检查地址是否是4字节和8字节对齐。main
函数中,我们用一个整数变量 a
的地址来进行测试。可以在程序中运行这段代码来测试各种变量的地址是否对齐。
要将一个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;
}
掩码(Mask)和符号位检查:
const int16_t mask = 0x800;
掩码 0x800
用于检查12-bit数的最高位(即第12位)。如果该位为1,则该数是负数。
符号扩展:
if (value & mask) {
return static_cast<int64_t>(value | ~0xFFF);
} else {
return static_cast<int64_t>(value);
}
value | ~0xFFF
将高位设置为1。主函数:
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数)。
winsdk
(Windows SDK for Python)模块允许你使用 Python 调用 Windows API,并实现与 Windows 操作系统的交互。下面是一些示例,展示如何使用 winsdk
模块实现不同的功能。
首先,你需要安装 winsdk
模块。如果还没有安装,可以使用以下命令安装:
pip install winsdk
你可以使用 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())
你可以使用 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}%")
使用 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())
以下是一个示例,展示如何使用 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}")
# 设置系统音量 (在此示例中无法直接设置音量, 需要进一步的接口或模块支持)
你可以使用 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 交互,完成一些常见的系统任务。根据你的需求,可以进一步扩展这些示例来实现更多功能。
好的,这里是一个完整的示例,展示如何在一个应用程序中使用上述所有的 PySide6 部件。这个示例将包含一个 QMainWindow
,并使用 QToolBar
、QStatusBar
、QMenuBar
、QTabWidget
、QStackedWidget
、QScrollArea
和 QMessageBox
。
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())
导入模块:
from PySide6.QtWidgets import (QApplication, QMainWindow, QToolBar, QStatusBar, QMenuBar,
QTabWidget, QStackedWidget, QScrollArea, QMessageBox,
QLabel, QVBoxLayout, QWidget, QAction, QDialog, QPushButton)
from PySide6.QtGui import QIcon
自定义对话框 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)
主窗口 MainWindow
:
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.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)
创建 QTabWidget
和 QStackedWidget
:
self.tab_widget = QTabWidget(self)
self.layout.addWidget(self.tab_widget)
...
self.stacked_widget = QStackedWidget(self)
self.layout.addWidget(self.stacked_widget)
...
创建 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}"))
创建按钮用于显示消息框和自定义对话框:
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("显示自定义对话框
好的,这里是一个完整的示例,展示如何在一个应用程序中使用上述所有的 PySide6 部件。这个示例将包含一个 QMainWindow
,并使用 QToolBar
、QStatusBar
、QMenuBar
、QTabWidget
、QStackedWidget
、QScrollArea
和 QMessageBox
。
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())
导入模块:
from PySide6.QtWidgets import (QApplication, QMainWindow, QToolBar, QStatusBar, QMenuBar,
QTabWidget, QStackedWidget, QScrollArea, QMessageBox,
QLabel, QVBoxLayout, QWidget, QAction, QDialog, QPushButton)
from PySide6.QtGui import QIcon
自定义对话框 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)
主窗口 MainWindow
:
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.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)
创建 QTabWidget
和 QStackedWidget
:
self.tab_widget = QTabWidget(self)
self.layout.addWidget(self.tab_widget)
...
self.stacked_widget = QStackedWidget(self)
self.layout.addWidget(self.stacked_widget)
...
创建 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}"))
创建按钮用于显示消息框和自定义对话框:
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("显示自定义对话框
总结一下最近折腾的事情,方便以后查阅。
所有内容都假设已经安装了必须的构建工具链,如果没有装,可以在报错的时候再根据提示安装。
编译 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 平台。