Python+PyQt5實現(xiàn)簡歷自動生成工具
一、概述:為什么需要自動化簡歷工具
在當今競爭激烈的求職市場中,一份專業(yè)、規(guī)范的簡歷是獲得面試機會的關鍵。然而,手動編寫和排版簡歷往往耗時費力,特別是當我們需要針對不同職位定制多份簡歷時。本文介紹的基于PyQt5的自動化簡歷生成工具,將徹底改變這一現(xiàn)狀。
該工具具有以下核心優(yōu)勢:
- 一站式管理:整合個人信息、教育背景、工作經歷等所有模塊
- 可視化編輯:直觀的GUI界面,告別代碼和命令行
- 多格式輸出:支持PDF導出,確??缙脚_兼容性
- 數(shù)據(jù)持久化:JSON格式保存/加載,簡歷數(shù)據(jù)永不丟失
- 模板化設計:多種風格模板滿足不同行業(yè)需求
二、功能全景圖
2.1 核心功能模塊
| 模塊名稱 | 功能描述 | 技術實現(xiàn) |
|---|---|---|
| 個人信息 | 收集基礎聯(lián)系方式和社交資料 | QLineEdit + QFormLayout |
| 教育經歷 | 管理學歷、專業(yè)、GPA等信息 | QListWidget + 動態(tài)表單 |
| 工作經歷 | 記錄職位、公司、工作描述 | 日期控件 + 富文本編輯 |
| 技能專長 | 分類展示技術棧和熟練度 | QComboBox + 層級列表 |
| 項目作品 | 展示項目成果和貢獻 | 超鏈接支持 + 多行文本 |
| 證書資質 | 管理專業(yè)認證信息 | 時間選擇器 + URL字段 |
| 語言能力 | 多語言水平標注 | 等級選擇器 |
2.2 特色功能
- 實時預覽:所見即所得的簡歷預覽功能
- 智能日期:"至今"選項自動處理日期顯示
- 響應式布局:自適應不同屏幕尺寸
- 主題配色:多套可視化主題隨時切換
- 數(shù)據(jù)校驗:關鍵字段自動驗證提醒
三、效果展示

UI界面概覽
左側為標簽式編輯面板,右側為實時預覽區(qū),符合專業(yè)軟件設計范式。
四、開發(fā)步驟詳解
4.1 環(huán)境配置
pip install PyQt5 fpdf
4.2 核心類設計
class ResumeGenerator(QMainWindow):
def __init__(self):
super().__init__()
# 初始化UI和數(shù)據(jù)
self.init_ui()
self.init_resume_data()
def init_ui(self):
# 創(chuàng)建主窗口布局
self.setup_main_window()
self.add_personal_info_tab()
self.add_education_tab()
# ...其他標簽頁
self.setup_preview_panel()
4.3 數(shù)據(jù)管理機制
采用三層架構設計:
- 表示層:PyQt5界面組件
- 邏輯層:簡歷數(shù)據(jù)處理方法
- 持久層:JSON序列化存儲

五、關鍵代碼解析
5.1 動態(tài)表單管理
教育/工作經歷采用列表+詳情表單的交互模式:
def add_education(self):
edu = {
"school": self.edu_school_edit.text(),
"degree": self.edu_degree_edit.text(),
# 其他字段...
}
self.resume_data["education"].append(edu)
self.update_education_list()
5.2 PDF生成引擎
基于FPDF庫的定制化輸出:
def export_to_pdf(self):
pdf = FPDF()
pdf.add_page()
# 設置中文字體支持
pdf.add_font('SimSun', '', 'simsun.ttc', uni=True)
# 添加內容區(qū)塊
self.add_personal_section(pdf)
self.add_education_section(pdf)
# ...其他部分
pdf.output("resume.pdf")
5.3 樣式管理系統(tǒng)
使用Qt樣式表實現(xiàn)現(xiàn)代化UI:
self.setStyleSheet("""
QMainWindow {
background-color: #f0f2f5;
}
QTabBar::tab {
padding: 10px;
border-radius: 5px;
}
QPushButton {
background-color: #4CAF50;
color: white;
}
""")
六、完整源碼下載
import sys
import json
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QLineEdit, QTextEdit, QPushButton, QComboBox,
QListWidget, QListWidgetItem, QTabWidget, QFileDialog,
QMessageBox, QFormLayout, QSpinBox, QDateEdit, QCheckBox,
QGroupBox, QFrame)
from PyQt5.QtCore import Qt, QDate
from PyQt5.QtGui import QFont, QIcon, QColor, QPalette
from fpdf import FPDF
from datetime import datetime
class ResumeGenerator(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("自動化簡歷生成工具")
self.setGeometry(100, 100, 1000, 750)
# 嘗試加載圖標,如果失敗則忽略
try:
self.setWindowIcon(QIcon("resume_icon.png"))
except:
pass
# 初始化UI
self.init_ui()
# 加載模板
self.load_templates()
# 初始化簡歷數(shù)據(jù)結構
self.init_resume_data()
# 當前編輯的項目索引
self.current_edu_index = -1
self.current_exp_index = -1
self.current_proj_index = -1
self.current_cert_index = -1
def init_ui(self):
# 設置主窗口背景和全局樣式
self.setStyleSheet("""
QMainWindow {
background-color: #f0f2f5;
}
QTabBar::tab {
padding: 10px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
margin-right: 2px;
}
QTabBar::tab:selected {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #ffffff, stop:1 #e0e0e0);
border-bottom: 2px solid #4CAF50;
}
QTabBar::tab:!selected {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #e0e0e0, stop:1 #d0d0d0);
}
QLineEdit, QTextEdit, QComboBox, QSpinBox, QDateEdit {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
background: white;
}
QTextEdit {
min-height: 100px;
}
QListWidget {
border: 1px solid #ddd;
background: white;
border-radius: 4px;
}
QPushButton {
padding: 8px 12px;
border-radius: 4px;
font-weight: bold;
min-width: 80px;
}
QGroupBox {
border: 1px solid #ddd;
border-radius: 5px;
margin-top: 10px;
padding-top: 15px;
background: white;
}
QGroupBox::title {
subcontrol-origin: margin;
left: 10px;
padding: 0 3px;
}
""")
# 主窗口布局
main_widget = QWidget()
self.setCentralWidget(main_widget)
main_layout = QHBoxLayout()
main_widget.setLayout(main_layout)
main_layout.setContentsMargins(10, 10, 10, 10)
main_layout.setSpacing(15)
# 左側面板 - 簡歷內容編輯 (70%寬度)
self.left_panel = QTabWidget()
self.left_panel.setTabPosition(QTabWidget.North)
self.left_panel.setDocumentMode(True)
main_layout.addWidget(self.left_panel, 7)
# 右側面板 - 預覽和操作 (30%寬度)
right_panel = QWidget()
right_panel.setMaximumWidth(350)
right_layout = QVBoxLayout()
right_layout.setContentsMargins(5, 5, 5, 5)
right_panel.setLayout(right_layout)
main_layout.addWidget(right_panel, 3)
# 添加標簽頁
self.add_personal_info_tab()
self.add_summary_tab()
self.add_education_tab()
self.add_experience_tab()
self.add_skills_tab()
self.add_projects_tab()
self.add_certifications_tab()
self.add_languages_tab()
# 右側面板內容
# 模板選擇組
template_group = QGroupBox("簡歷模板")
template_layout = QVBoxLayout()
template_group.setLayout(template_layout)
self.template_combo = QComboBox()
self.template_combo.setStyleSheet("""
QComboBox {
padding: 8px;
border: 1px solid #4CAF50;
border-radius: 4px;
background: white;
}
QComboBox::drop-down {
border: none;
}
""")
template_layout.addWidget(self.template_combo)
# 操作按鈕組
button_group = QGroupBox("操作")
button_layout = QVBoxLayout()
button_group.setLayout(button_layout)
# 預覽按鈕
self.preview_btn = QPushButton("?? 預覽簡歷")
self.preview_btn.setStyleSheet("""
QPushButton {
background-color: #4CAF50;
color: white;
}
QPushButton:hover {
background-color: #45a049;
}
""")
self.preview_btn.clicked.connect(self.preview_resume)
button_layout.addWidget(self.preview_btn)
# 導出按鈕
self.export_btn = QPushButton("?? 導出PDF")
self.export_btn.setStyleSheet("""
QPushButton {
background-color: #2196F3;
color: white;
}
QPushButton:hover {
background-color: #0b7dda;
}
""")
self.export_btn.clicked.connect(self.export_to_pdf)
button_layout.addWidget(self.export_btn)
# 分隔線
line = QFrame()
line.setFrameShape(QFrame.HLine)
line.setFrameShadow(QFrame.Sunken)
button_layout.addWidget(line)
# 保存按鈕
self.save_btn = QPushButton("?? 保存數(shù)據(jù)")
self.save_btn.setStyleSheet("""
QPushButton {
background-color: #FF9800;
color: white;
}
QPushButton:hover {
background-color: #e68a00;
}
""")
self.save_btn.clicked.connect(self.save_resume_data)
button_layout.addWidget(self.save_btn)
# 加載按鈕
self.load_btn = QPushButton("?? 加載數(shù)據(jù)")
self.load_btn.setStyleSheet("""
QPushButton {
background-color: #9C27B0;
color: white;
}
QPushButton:hover {
background-color: #7b1fa2;
}
""")
self.load_btn.clicked.connect(self.load_resume_data)
button_layout.addWidget(self.load_btn)
# 預覽區(qū)域組
preview_group = QGroupBox("簡歷預覽")
preview_layout = QVBoxLayout()
preview_group.setLayout(preview_layout)
self.preview_text = QTextEdit()
self.preview_text.setReadOnly(True)
self.preview_text.setStyleSheet("""
QTextEdit {
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 4px;
}
""")
preview_layout.addWidget(self.preview_text)
# 添加到右側面板
right_layout.addWidget(template_group)
right_layout.addWidget(button_group)
right_layout.addWidget(preview_group)
# 設置標簽頁顏色
self.set_tab_colors()
def set_tab_colors(self):
#為每個標簽頁設置不同的顏色
tab_colors = [
("#FF5252", "#FFFFFF"), # 紅色
("#FF9800", "#FFFFFF"), # 橙色
("#FFEB3B", "#000000"), # 黃色
("#4CAF50", "#FFFFFF"), # 綠色
("#2196F3", "#FFFFFF"), # 藍色
("#673AB7", "#FFFFFF"), # 深紫色
("#E91E63", "#FFFFFF"), # 粉色
("#607D8B", "#FFFFFF") # 藍灰色
]
# 方法1:統(tǒng)一設置QTabBar樣式(推薦)
tab_bar = self.left_panel.tabBar()
tab_bar.setStyleSheet("""
QTabBar::tab {
padding: 10px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
margin-right: 2px;
}
QTabBar::tab:selected {
background: white;
border-bottom: 2px solid #4CAF50;
}
QTabBar::tab:!selected {
background: #e0e0e0;
}
""")
def init_resume_data(self):
"""初始化簡歷數(shù)據(jù)結構"""
self.resume_data = {
"personal_info": {
"name": "",
"email": "",
"phone": "",
"address": "",
"linkedin": "",
"github": "",
"website": ""
},
"summary": "",
"education": [],
"experience": [],
"skills": [],
"projects": [],
"certifications": [],
"languages": []
}
def add_personal_info_tab(self):
tab = QWidget()
layout = QVBoxLayout()
tab.setLayout(layout)
# 使用GroupBox組織內容
group = QGroupBox("個人信息")
form_layout = QFormLayout()
group.setLayout(form_layout)
# 創(chuàng)建帶圖標的輸入字段
self.name_edit = self.create_line_edit("??", "姓名")
self.email_edit = self.create_line_edit("??", "郵箱")
self.phone_edit = self.create_line_edit("??", "電話")
self.address_edit = self.create_line_edit("??", "地址")
self.linkedin_edit = self.create_line_edit("??", "LinkedIn")
self.github_edit = self.create_line_edit("??", "GitHub")
self.website_edit = self.create_line_edit("??", "個人網站")
# 添加到表單
form_layout.addRow("姓名:", self.name_edit)
form_layout.addRow("郵箱:", self.email_edit)
form_layout.addRow("電話:", self.phone_edit)
form_layout.addRow("地址:", self.address_edit)
form_layout.addRow("LinkedIn:", self.linkedin_edit)
form_layout.addRow("GitHub:", self.github_edit)
form_layout.addRow("個人網站:", self.website_edit)
layout.addWidget(group)
layout.addStretch()
self.left_panel.addTab(tab, "個人信息")
def create_line_edit(self, icon, placeholder):
"""創(chuàng)建帶樣式的QLineEdit"""
line_edit = QLineEdit()
line_edit.setPlaceholderText(f"{icon} {placeholder}")
line_edit.setStyleSheet("""
QLineEdit {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
}
QLineEdit:focus {
border: 1px solid #4CAF50;
}
""")
return line_edit
def add_summary_tab(self):
tab = QWidget()
layout = QVBoxLayout()
tab.setLayout(layout)
group = QGroupBox("職業(yè)概述")
group_layout = QVBoxLayout()
group.setLayout(group_layout)
self.summary_edit = QTextEdit()
self.summary_edit.setPlaceholderText("在這里輸入你的職業(yè)概述...")
self.summary_edit.setStyleSheet("""
QTextEdit {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
}
QTextEdit:focus {
border: 1px solid #2196F3;
}
""")
group_layout.addWidget(self.summary_edit)
layout.addWidget(group)
layout.addStretch()
self.left_panel.addTab(tab, "職業(yè)概述")
def add_education_tab(self):
tab = QWidget()
layout = QVBoxLayout()
tab.setLayout(layout)
# 教育經歷表單組
form_group = QGroupBox("添加/編輯教育經歷")
form_layout = QFormLayout()
form_group.setLayout(form_layout)
# 創(chuàng)建輸入字段
self.edu_school_edit = self.create_line_edit("??", "學校名稱")
self.edu_degree_edit = self.create_line_edit("??", "學位")
self.edu_field_edit = self.create_line_edit("??", "專業(yè)")
self.edu_start_date = QDateEdit()
self.edu_end_date = QDateEdit()
self.edu_current = QCheckBox("至今")
self.edu_gpa_edit = self.create_line_edit("??", "GPA")
self.edu_description = QTextEdit()
# 設置日期控件
self.edu_start_date.setCalendarPopup(True)
self.edu_end_date.setCalendarPopup(True)
self.edu_current.stateChanged.connect(self.toggle_edu_end_date)
# 添加到表單
form_layout.addRow("學校:", self.edu_school_edit)
form_layout.addRow("學位:", self.edu_degree_edit)
form_layout.addRow("專業(yè):", self.edu_field_edit)
form_layout.addRow("開始日期:", self.edu_start_date)
form_layout.addRow("結束日期:", self.edu_end_date)
form_layout.addRow(self.edu_current)
form_layout.addRow("GPA:", self.edu_gpa_edit)
form_layout.addRow("描述:", self.edu_description)
# 按鈕布局
btn_layout = QHBoxLayout()
self.add_edu_btn = self.create_button("? 添加", "#4CAF50")
self.add_edu_btn.clicked.connect(self.add_education)
self.update_edu_btn = self.create_button("?? 更新", "#2196F3")
self.update_edu_btn.clicked.connect(self.update_education)
self.remove_edu_btn = self.create_button("? 刪除", "#F44336")
self.remove_edu_btn.clicked.connect(self.remove_education)
btn_layout.addWidget(self.add_edu_btn)
btn_layout.addWidget(self.update_edu_btn)
btn_layout.addWidget(self.remove_edu_btn)
# 教育經歷列表組
list_group = QGroupBox("教育經歷列表")
list_layout = QVBoxLayout()
list_group.setLayout(list_layout)
self.edu_list = QListWidget()
self.edu_list.itemClicked.connect(self.load_education)
self.edu_list.setStyleSheet("""
QListWidget {
font-size: 14px;
}
QListWidget::item {
padding: 8px;
border-bottom: 1px solid #eee;
}
QListWidget::item:hover {
background-color: #f0f0f0;
}
QListWidget::item:selected {
background-color: #e3f2fd;
color: #000;
}
""")
list_layout.addWidget(self.edu_list)
# 添加到主布局
layout.addWidget(form_group)
layout.addLayout(btn_layout)
layout.addWidget(list_group)
self.left_panel.addTab(tab, "教育經歷")
def create_button(self, text, color):
"""創(chuàng)建帶樣式的按鈕"""
btn = QPushButton(text)
btn.setStyleSheet(f"""
QPushButton {{
background-color: {color};
color: white;
padding: 8px 12px;
border-radius: 4px;
font-weight: bold;
}}
QPushButton:hover {{
background-color: {self.darken_color(color)};
}}
""")
return btn
def darken_color(self, hex_color, factor=0.8):
"""使顏色變暗"""
color = QColor(hex_color)
return color.darker(int(1/factor*100)).name()
def add_experience_tab(self):
tab = QWidget()
layout = QVBoxLayout()
tab.setLayout(layout)
form_group = QGroupBox("添加/編輯工作經歷")
form_layout = QFormLayout()
form_group.setLayout(form_layout)
self.exp_company_edit = self.create_line_edit("??", "公司名稱")
self.exp_position_edit = self.create_line_edit("??", "職位")
self.exp_start_date = QDateEdit()
self.exp_end_date = QDateEdit()
self.exp_current = QCheckBox("至今")
self.exp_description = QTextEdit()
self.exp_start_date.setCalendarPopup(True)
self.exp_end_date.setCalendarPopup(True)
self.exp_current.stateChanged.connect(self.toggle_exp_end_date)
form_layout.addRow("公司:", self.exp_company_edit)
form_layout.addRow("職位:", self.exp_position_edit)
form_layout.addRow("開始日期:", self.exp_start_date)
form_layout.addRow("結束日期:", self.exp_end_date)
form_layout.addRow(self.exp_current)
form_layout.addRow("描述:", self.exp_description)
btn_layout = QHBoxLayout()
self.add_exp_btn = self.create_button("? 添加", "#4CAF50")
self.add_exp_btn.clicked.connect(self.add_experience)
self.update_exp_btn = self.create_button("?? 更新", "#2196F3")
self.update_exp_btn.clicked.connect(self.update_experience)
self.remove_exp_btn = self.create_button("? 刪除", "#F44336")
self.remove_exp_btn.clicked.connect(self.remove_experience)
btn_layout.addWidget(self.add_exp_btn)
btn_layout.addWidget(self.update_exp_btn)
btn_layout.addWidget(self.remove_exp_btn)
list_group = QGroupBox("工作經歷列表")
list_layout = QVBoxLayout()
list_group.setLayout(list_layout)
self.exp_list = QListWidget()
self.exp_list.itemClicked.connect(self.load_experience)
list_layout.addWidget(self.exp_list)
layout.addWidget(form_group)
layout.addLayout(btn_layout)
layout.addWidget(list_group)
self.left_panel.addTab(tab, "工作經歷")
def add_skills_tab(self):
tab = QWidget()
layout = QVBoxLayout()
tab.setLayout(layout)
form_group = QGroupBox("添加技能")
form_layout = QVBoxLayout()
form_group.setLayout(form_layout)
skill_layout = QHBoxLayout()
self.skill_edit = self.create_line_edit("??", "技能名稱")
self.skill_level_combo = QComboBox()
self.skill_level_combo.addItems(["初級", "中級", "高級", "專家"])
skill_layout.addWidget(self.skill_edit)
skill_layout.addWidget(self.skill_level_combo)
btn_layout = QHBoxLayout()
self.add_skill_btn = self.create_button("? 添加技能", "#4CAF50")
self.add_skill_btn.clicked.connect(self.add_skill)
self.remove_skill_btn = self.create_button("? 刪除選中", "#F44336")
self.remove_skill_btn.clicked.connect(self.remove_skill)
btn_layout.addWidget(self.add_skill_btn)
btn_layout.addWidget(self.remove_skill_btn)
list_group = QGroupBox("技能列表")
list_layout = QVBoxLayout()
list_group.setLayout(list_layout)
self.skill_list = QListWidget()
list_layout.addWidget(self.skill_list)
form_layout.addWidget(QLabel("添加技能:"))
form_layout.addLayout(skill_layout)
form_layout.addLayout(btn_layout)
layout.addWidget(form_group)
layout.addWidget(list_group)
self.left_panel.addTab(tab, "技能")
def add_projects_tab(self):
tab = QWidget()
layout = QVBoxLayout()
tab.setLayout(layout)
form_group = QGroupBox("添加/編輯項目")
form_layout = QFormLayout()
form_group.setLayout(form_layout)
self.proj_name_edit = self.create_line_edit("??", "項目名稱")
self.proj_role_edit = self.create_line_edit("??", "你的角色")
self.proj_start_date = QDateEdit()
self.proj_end_date = QDateEdit()
self.proj_current = QCheckBox("進行中")
self.proj_description = QTextEdit()
self.proj_url_edit = self.create_line_edit("??", "項目URL")
self.proj_start_date.setCalendarPopup(True)
self.proj_end_date.setCalendarPopup(True)
self.proj_current.stateChanged.connect(self.toggle_proj_end_date)
form_layout.addRow("項目名稱:", self.proj_name_edit)
form_layout.addRow("你的角色:", self.proj_role_edit)
form_layout.addRow("開始日期:", self.proj_start_date)
form_layout.addRow("結束日期:", self.proj_end_date)
form_layout.addRow(self.proj_current)
form_layout.addRow("項目URL:", self.proj_url_edit)
form_layout.addRow("描述:", self.proj_description)
btn_layout = QHBoxLayout()
self.add_proj_btn = self.create_button("? 添加", "#4CAF50")
self.add_proj_btn.clicked.connect(self.add_project)
self.update_proj_btn = self.create_button("?? 更新", "#2196F3")
self.update_proj_btn.clicked.connect(self.update_project)
self.remove_proj_btn = self.create_button("? 刪除", "#F44336")
self.remove_proj_btn.clicked.connect(self.remove_project)
btn_layout.addWidget(self.add_proj_btn)
btn_layout.addWidget(self.update_proj_btn)
btn_layout.addWidget(self.remove_proj_btn)
list_group = QGroupBox("項目列表")
list_layout = QVBoxLayout()
list_group.setLayout(list_layout)
self.proj_list = QListWidget()
self.proj_list.itemClicked.connect(self.load_project)
list_layout.addWidget(self.proj_list)
layout.addWidget(form_group)
layout.addLayout(btn_layout)
layout.addWidget(list_group)
self.left_panel.addTab(tab, "項目經歷")
def add_certifications_tab(self):
tab = QWidget()
layout = QVBoxLayout()
tab.setLayout(layout)
form_group = QGroupBox("添加/編輯證書")
form_layout = QFormLayout()
form_group.setLayout(form_layout)
self.cert_name_edit = self.create_line_edit("??", "證書名稱")
self.cert_org_edit = self.create_line_edit("???", "頒發(fā)機構")
self.cert_date = QDateEdit()
self.cert_url_edit = self.create_line_edit("??", "證書URL")
self.cert_date.setCalendarPopup(True)
form_layout.addRow("證書名稱:", self.cert_name_edit)
form_layout.addRow("頒發(fā)機構:", self.cert_org_edit)
form_layout.addRow("獲得日期:", self.cert_date)
form_layout.addRow("證書URL:", self.cert_url_edit)
btn_layout = QHBoxLayout()
self.add_cert_btn = self.create_button("? 添加", "#4CAF50")
self.add_cert_btn.clicked.connect(self.add_certification)
self.update_cert_btn = self.create_button("?? 更新", "#2196F3")
self.update_cert_btn.clicked.connect(self.update_certification)
self.remove_cert_btn = self.create_button("? 刪除", "#F44336")
self.remove_cert_btn.clicked.connect(self.remove_certification)
btn_layout.addWidget(self.add_cert_btn)
btn_layout.addWidget(self.update_cert_btn)
btn_layout.addWidget(self.remove_cert_btn)
list_group = QGroupBox("證書列表")
list_layout = QVBoxLayout()
list_group.setLayout(list_layout)
self.cert_list = QListWidget()
self.cert_list.itemClicked.connect(self.load_certification)
list_layout.addWidget(self.cert_list)
layout.addWidget(form_group)
layout.addLayout(btn_layout)
layout.addWidget(list_group)
self.left_panel.addTab(tab, "證書")
def add_languages_tab(self):
tab = QWidget()
layout = QVBoxLayout()
tab.setLayout(layout)
form_group = QGroupBox("添加語言")
form_layout = QVBoxLayout()
form_group.setLayout(form_layout)
lang_layout = QHBoxLayout()
self.lang_edit = self.create_line_edit("??", "語言")
self.lang_level_combo = QComboBox()
self.lang_level_combo.addItems(["初級", "中級", "高級", "母語"])
lang_layout.addWidget(self.lang_edit)
lang_layout.addWidget(self.lang_level_combo)
btn_layout = QHBoxLayout()
self.add_lang_btn = self.create_button("? 添加語言", "#4CAF50")
self.add_lang_btn.clicked.connect(self.add_language)
self.remove_lang_btn = self.create_button("? 刪除選中", "#F44336")
self.remove_lang_btn.clicked.connect(self.remove_language)
btn_layout.addWidget(self.add_lang_btn)
btn_layout.addWidget(self.remove_lang_btn)
list_group = QGroupBox("語言列表")
list_layout = QVBoxLayout()
list_group.setLayout(list_layout)
self.lang_list = QListWidget()
list_layout.addWidget(self.lang_list)
form_layout.addWidget(QLabel("添加語言:"))
form_layout.addLayout(lang_layout)
form_layout.addLayout(btn_layout)
layout.addWidget(form_group)
layout.addWidget(list_group)
self.left_panel.addTab(tab, "語言能力")
def toggle_edu_end_date(self, state):
self.edu_end_date.setEnabled(not bool(state))
def toggle_exp_end_date(self, state):
self.exp_end_date.setEnabled(not bool(state))
def toggle_proj_end_date(self, state):
self.proj_end_date.setEnabled(not bool(state))
def load_templates(self):
"""加載簡歷模板"""
templates = [
"?? 多彩創(chuàng)意模板",
"?? 專業(yè)商務模板",
"?? 傳統(tǒng)經典模板",
"?? 現(xiàn)代簡約模板",
"?? 數(shù)據(jù)分析師模板",
"?? 開發(fā)者模板",
"?? 學術模板",
"?? 設計師模板"
]
self.template_combo.addItems(templates)
def collect_personal_info(self):
self.resume_data["personal_info"] = {
"name": self.name_edit.text(),
"email": self.email_edit.text(),
"phone": self.phone_edit.text(),
"address": self.address_edit.text(),
"linkedin": self.linkedin_edit.text(),
"github": self.github_edit.text(),
"website": self.website_edit.text()
}
def collect_summary(self):
self.resume_data["summary"] = self.summary_edit.toPlainText()
def add_education(self):
self.collect_personal_info()
edu = {
"school": self.edu_school_edit.text(),
"degree": self.edu_degree_edit.text(),
"field": self.edu_field_edit.text(),
"start_date": self.edu_start_date.date().toString("yyyy-MM-dd"),
"end_date": "" if self.edu_current.isChecked() else self.edu_end_date.date().toString("yyyy-MM-dd"),
"current": self.edu_current.isChecked(),
"gpa": self.edu_gpa_edit.text(),
"description": self.edu_description.toPlainText()
}
self.resume_data["education"].append(edu)
self.update_education_list()
self.clear_education_form()
def update_education(self):
if self.current_edu_index == -1:
return
edu = {
"school": self.edu_school_edit.text(),
"degree": self.edu_degree_edit.text(),
"field": self.edu_field_edit.text(),
"start_date": self.edu_start_date.date().toString("yyyy-MM-dd"),
"end_date": "" if self.edu_current.isChecked() else self.edu_end_date.date().toString("yyyy-MM-dd"),
"current": self.edu_current.isChecked(),
"gpa": self.edu_gpa_edit.text(),
"description": self.edu_description.toPlainText()
}
self.resume_data["education"][self.current_edu_index] = edu
self.update_education_list()
self.clear_education_form()
self.current_edu_index = -1
def remove_education(self):
if self.current_edu_index == -1:
return
self.resume_data["education"].pop(self.current_edu_index)
self.update_education_list()
self.clear_education_form()
self.current_edu_index = -1
def load_education(self, item):
index = self.edu_list.row(item)
self.current_edu_index = index
edu = self.resume_data["education"][index]
self.edu_school_edit.setText(edu["school"])
self.edu_degree_edit.setText(edu["degree"])
self.edu_field_edit.setText(edu["field"])
self.edu_start_date.setDate(QDate.fromString(edu["start_date"], "yyyy-MM-dd"))
if edu["current"]:
self.edu_current.setChecked(True)
self.edu_end_date.setEnabled(False)
else:
self.edu_current.setChecked(False)
self.edu_end_date.setDate(QDate.fromString(edu["end_date"], "yyyy-MM-dd"))
self.edu_end_date.setEnabled(True)
self.edu_gpa_edit.setText(edu["gpa"])
self.edu_description.setPlainText(edu["description"])
def update_education_list(self):
self.edu_list.clear()
for edu in self.resume_data["education"]:
item = QListWidgetItem(f"{edu['degree']} - {edu['school']}")
self.edu_list.addItem(item)
def clear_education_form(self):
self.edu_school_edit.clear()
self.edu_degree_edit.clear()
self.edu_field_edit.clear()
self.edu_start_date.setDate(QDate.currentDate())
self.edu_end_date.setDate(QDate.currentDate())
self.edu_current.setChecked(False)
self.edu_gpa_edit.clear()
self.edu_description.clear()
self.edu_end_date.setEnabled(True)
def add_experience(self):
self.collect_personal_info()
exp = {
"company": self.exp_company_edit.text(),
"position": self.exp_position_edit.text(),
"start_date": self.exp_start_date.date().toString("yyyy-MM-dd"),
"end_date": "" if self.exp_current.isChecked() else self.exp_end_date.date().toString("yyyy-MM-dd"),
"current": self.exp_current.isChecked(),
"description": self.exp_description.toPlainText()
}
self.resume_data["experience"].append(exp)
self.update_experience_list()
self.clear_experience_form()
def update_experience(self):
if self.current_exp_index == -1:
return
exp = {
"company": self.exp_company_edit.text(),
"position": self.exp_position_edit.text(),
"start_date": self.exp_start_date.date().toString("yyyy-MM-dd"),
"end_date": "" if self.exp_current.isChecked() else self.exp_end_date.date().toString("yyyy-MM-dd"),
"current": self.exp_current.isChecked(),
"description": self.exp_description.toPlainText()
}
self.resume_data["experience"][self.current_exp_index] = exp
self.update_experience_list()
self.clear_experience_form()
self.current_exp_index = -1
def remove_experience(self):
if self.current_exp_index == -1:
return
self.resume_data["experience"].pop(self.current_exp_index)
self.update_experience_list()
self.clear_experience_form()
self.current_exp_index = -1
def load_experience(self, item):
index = self.exp_list.row(item)
self.current_exp_index = index
exp = self.resume_data["experience"][index]
self.exp_company_edit.setText(exp["company"])
self.exp_position_edit.setText(exp["position"])
self.exp_start_date.setDate(QDate.fromString(exp["start_date"], "yyyy-MM-dd"))
if exp["current"]:
self.exp_current.setChecked(True)
self.exp_end_date.setEnabled(False)
else:
self.exp_current.setChecked(False)
self.exp_end_date.setDate(QDate.fromString(exp["end_date"], "yyyy-MM-dd"))
self.exp_end_date.setEnabled(True)
self.exp_description.setPlainText(exp["description"])
def update_experience_list(self):
self.exp_list.clear()
for exp in self.resume_data["experience"]:
item = QListWidgetItem(f"{exp['position']} - {exp['company']}")
self.exp_list.addItem(item)
def clear_experience_form(self):
self.exp_company_edit.clear()
self.exp_position_edit.clear()
self.exp_start_date.setDate(QDate.currentDate())
self.exp_end_date.setDate(QDate.currentDate())
self.exp_current.setChecked(False)
self.exp_description.clear()
self.exp_end_date.setEnabled(True)
def add_skill(self):
skill = f"{self.skill_edit.text()} ({self.skill_level_combo.currentText()})"
self.resume_data["skills"].append(skill)
self.update_skills_list()
self.skill_edit.clear()
def remove_skill(self):
for item in self.skill_list.selectedItems():
index = self.skill_list.row(item)
self.resume_data["skills"].pop(index)
self.skill_list.takeItem(index)
def update_skills_list(self):
self.skill_list.clear()
for skill in self.resume_data["skills"]:
self.skill_list.addItem(skill)
def add_project(self):
self.collect_personal_info()
proj = {
"name": self.proj_name_edit.text(),
"role": self.proj_role_edit.text(),
"start_date": self.proj_start_date.date().toString("yyyy-MM-dd"),
"end_date": "" if self.proj_current.isChecked() else self.proj_end_date.date().toString("yyyy-MM-dd"),
"current": self.proj_current.isChecked(),
"url": self.proj_url_edit.text(),
"description": self.proj_description.toPlainText()
}
self.resume_data["projects"].append(proj)
self.update_project_list()
self.clear_project_form()
def update_project(self):
if self.current_proj_index == -1:
return
proj = {
"name": self.proj_name_edit.text(),
"role": self.proj_role_edit.text(),
"start_date": self.proj_start_date.date().toString("yyyy-MM-dd"),
"end_date": "" if self.proj_current.isChecked() else self.proj_end_date.date().toString("yyyy-MM-dd"),
"current": self.proj_current.isChecked(),
"url": self.proj_url_edit.text(),
"description": self.proj_description.toPlainText()
}
self.resume_data["projects"][self.current_proj_index] = proj
self.update_project_list()
self.clear_project_form()
self.current_proj_index = -1
def remove_project(self):
if self.current_proj_index == -1:
return
self.resume_data["projects"].pop(self.current_proj_index)
self.update_project_list()
self.clear_project_form()
self.current_proj_index = -1
def load_project(self, item):
index = self.proj_list.row(item)
self.current_proj_index = index
proj = self.resume_data["projects"][index]
self.proj_name_edit.setText(proj["name"])
self.proj_role_edit.setText(proj["role"])
self.proj_start_date.setDate(QDate.fromString(proj["start_date"], "yyyy-MM-dd"))
if proj["current"]:
self.proj_current.setChecked(True)
self.proj_end_date.setEnabled(False)
else:
self.proj_current.setChecked(False)
self.proj_end_date.setDate(QDate.fromString(proj["end_date"], "yyyy-MM-dd"))
self.proj_end_date.setEnabled(True)
self.proj_url_edit.setText(proj["url"])
self.proj_description.setPlainText(proj["description"])
def update_project_list(self):
self.proj_list.clear()
for proj in self.resume_data["projects"]:
item = QListWidgetItem(f"{proj['name']} ({proj['role']})")
self.proj_list.addItem(item)
def clear_project_form(self):
self.proj_name_edit.clear()
self.proj_role_edit.clear()
self.proj_start_date.setDate(QDate.currentDate())
self.proj_end_date.setDate(QDate.currentDate())
self.proj_current.setChecked(False)
self.proj_url_edit.clear()
self.proj_description.clear()
self.proj_end_date.setEnabled(True)
def add_certification(self):
self.collect_personal_info()
cert = {
"name": self.cert_name_edit.text(),
"organization": self.cert_org_edit.text(),
"date": self.cert_date.date().toString("yyyy-MM-dd"),
"url": self.cert_url_edit.text()
}
self.resume_data["certifications"].append(cert)
self.update_certification_list()
self.clear_certification_form()
def update_certification(self):
if self.current_cert_index == -1:
return
cert = {
"name": self.cert_name_edit.text(),
"organization": self.cert_org_edit.text(),
"date": self.cert_date.date().toString("yyyy-MM-dd"),
"url": self.cert_url_edit.text()
}
self.resume_data["certifications"][self.current_cert_index] = cert
self.update_certification_list()
self.clear_certification_form()
self.current_cert_index = -1
def remove_certification(self):
if self.current_cert_index == -1:
return
self.resume_data["certifications"].pop(self.current_cert_index)
self.update_certification_list()
self.clear_certification_form()
self.current_cert_index = -1
def load_certification(self, item):
index = self.cert_list.row(item)
self.current_cert_index = index
cert = self.resume_data["certifications"][index]
self.cert_name_edit.setText(cert["name"])
self.cert_org_edit.setText(cert["organization"])
self.cert_date.setDate(QDate.fromString(cert["date"], "yyyy-MM-dd"))
self.cert_url_edit.setText(cert["url"])
def update_certification_list(self):
self.cert_list.clear()
for cert in self.resume_data["certifications"]:
item = QListWidgetItem(f"{cert['name']} - {cert['organization']}")
self.cert_list.addItem(item)
def clear_certification_form(self):
self.cert_name_edit.clear()
self.cert_org_edit.clear()
self.cert_date.setDate(QDate.currentDate())
self.cert_url_edit.clear()
def add_language(self):
lang = f"{self.lang_edit.text()} ({self.lang_level_combo.currentText()})"
self.resume_data["languages"].append(lang)
self.update_languages_list()
self.lang_edit.clear()
def remove_language(self):
for item in self.lang_list.selectedItems():
index = self.lang_list.row(item)
self.resume_data["languages"].pop(index)
self.lang_list.takeItem(index)
def update_languages_list(self):
self.lang_list.clear()
for lang in self.resume_data["languages"]:
self.lang_list.addItem(lang)
def preview_resume(self):
"""生成簡歷預覽"""
self.collect_personal_info()
self.collect_summary()
preview_text = "=== 簡歷預覽 ===\n\n"
preview_text += "?? 個人信息:\n"
preview_text += f"?? 姓名: {self.resume_data['personal_info']['name']}\n"
preview_text += f"?? 郵箱: {self.resume_data['personal_info']['email']}\n"
preview_text += f"?? 電話: {self.resume_data['personal_info']['phone']}\n"
preview_text += f"?? 地址: {self.resume_data['personal_info']['address']}\n"
preview_text += f"?? LinkedIn: {self.resume_data['personal_info']['linkedin']}\n"
preview_text += f"?? GitHub: {self.resume_data['personal_info']['github']}\n"
preview_text += f"?? 個人網站: {self.resume_data['personal_info']['website']}\n\n"
preview_text += "?? 職業(yè)概述:\n"
preview_text += f"{self.resume_data['summary']}\n\n"
preview_text += "?? 教育經歷:\n"
for edu in self.resume_data["education"]:
preview_text += f"- ?? {edu['degree']} - {edu['school']} ({edu['field']})\n"
preview_text += f" ?? {edu['start_date']} 至 {'至今' if edu['current'] else edu['end_date']}\n"
preview_text += f" ?? GPA: {edu['gpa']}\n"
preview_text += f" ?? 描述: {edu['description']}\n\n"
preview_text += "?? 工作經歷:\n"
for exp in self.resume_data["experience"]:
preview_text += f"- ?? {exp['position']} - {exp['company']}\n"
preview_text += f" ?? {exp['start_date']} 至 {'至今' if exp['current'] else exp['end_date']}\n"
preview_text += f" ?? 描述: {exp['description']}\n\n"
preview_text += "??? 技能:\n"
for skill in self.resume_data["skills"]:
preview_text += f"- {skill}\n"
preview_text += "\n"
preview_text += "?? 項目經歷:\n"
for proj in self.resume_data["projects"]:
preview_text += f"- ?? {proj['name']} ({proj['role']})\n"
preview_text += f" ?? {proj['start_date']} 至 {'進行中' if proj['current'] else proj['end_date']}\n"
preview_text += f" ?? URL: {proj['url']}\n"
preview_text += f" ?? 描述: {proj['description']}\n\n"
preview_text += "?? 證書:\n"
for cert in self.resume_data["certifications"]:
preview_text += f"- ?? {cert['name']} - {cert['organization']} ({cert['date']})\n"
preview_text += f" ?? URL: {cert['url']}\n\n"
preview_text += "?? 語言能力:\n"
for lang in self.resume_data["languages"]:
preview_text += f"- {lang}\n"
self.preview_text.setPlainText(preview_text)
def export_to_pdf(self):
self.collect_personal_info()
self.collect_summary()
# 創(chuàng)建PDF
pdf = FPDF()
pdf.add_page()
pdf.set_auto_page_break(auto=True, margin=15)
# 設置字體
pdf.set_font("Arial", 'B', 16)
# 個人信息
pdf.cell(0, 10, self.resume_data["personal_info"]["name"], 0, 1, 'C')
pdf.set_font("Arial", '', 12)
contact_info = []
if self.resume_data["personal_info"]["email"]:
contact_info.append(self.resume_data["personal_info"]["email"])
if self.resume_data["personal_info"]["phone"]:
contact_info.append(self.resume_data["personal_info"]["phone"])
if self.resume_data["personal_info"]["address"]:
contact_info.append(self.resume_data["personal_info"]["address"])
pdf.cell(0, 10, " | ".join(contact_info), 0, 1, 'C')
# 添加鏈接
links = []
if self.resume_data["personal_info"]["linkedin"]:
links.append(f"LinkedIn: {self.resume_data['personal_info']['linkedin']}")
if self.resume_data["personal_info"]["github"]:
links.append(f"GitHub: {self.resume_data['personal_info']['github']}")
if self.resume_data["personal_info"]["website"]:
links.append(f"Website: {self.resume_data['personal_info']['website']}")
if links:
pdf.cell(0, 10, " | ".join(links), 0, 1, 'C')
pdf.ln(10)
# 職業(yè)概述
if self.resume_data["summary"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "職業(yè)概述", 0, 1, 'L')
pdf.set_font("Arial", '', 12)
pdf.multi_cell(0, 6, self.resume_data["summary"])
pdf.ln(5)
# 教育經歷
if self.resume_data["education"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "教育經歷", 0, 1, 'L')
pdf.set_font("Arial", '', 12)
for edu in self.resume_data["education"]:
pdf.set_font("Arial", 'B', 12)
pdf.cell(0, 6, f"{edu['degree']} - {edu['school']}", 0, 1, 'L')
pdf.set_font("Arial", '', 12)
date_range = f"{edu['start_date']} - {'至今' if edu['current'] else edu['end_date']}"
if edu["gpa"]:
date_range += f" | GPA: {edu['gpa']}"
pdf.cell(0, 6, f"{edu['field']} | {date_range}", 0, 1, 'L')
if edu["description"]:
pdf.multi_cell(0, 6, edu["description"])
pdf.ln(2)
# 工作經歷
if self.resume_data["experience"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "工作經歷", 0, 1, 'L')
pdf.set_font("Arial", '', 12)
for exp in self.resume_data["experience"]:
pdf.set_font("Arial", 'B', 12)
pdf.cell(0, 6, f"{exp['position']} - {exp['company']}", 0, 1, 'L')
pdf.set_font("Arial", '', 12)
pdf.cell(0, 6, f"{exp['start_date']} - {'至今' if exp['current'] else exp['end_date']}", 0, 1, 'L')
if exp["description"]:
pdf.multi_cell(0, 6, exp["description"])
pdf.ln(2)
# 技能
if self.resume_data["skills"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "技能", 0, 1, 'L')
pdf.set_font("Arial", '', 12)
skills = ", ".join(self.resume_data["skills"])
pdf.multi_cell(0, 6, skills)
pdf.ln(5)
# 項目經歷
if self.resume_data["projects"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "項目經歷", 0, 1, 'L')
pdf.set_font("Arial", '', 12)
for proj in self.resume_data["projects"]:
pdf.set_font("Arial", 'B', 12)
pdf.cell(0, 6, f"{proj['name']} ({proj['role']})", 0, 1, 'L')
pdf.set_font("Arial", '', 12)
date_range = f"{proj['start_date']} - {'進行中' if proj['current'] else proj['end_date']}"
if proj["url"]:
date_range += f" | URL: {proj['url']}"
pdf.cell(0, 6, date_range, 0, 1, 'L')
if proj["description"]:
pdf.multi_cell(0, 6, proj["description"])
pdf.ln(2)
# 證書
if self.resume_data["certifications"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "證書", 0, 1, 'L')
pdf.set_font("Arial", '', 12)
for cert in self.resume_data["certifications"]:
cert_line = f"{cert['name']} - {cert['organization']} ({cert['date']})"
if cert["url"]:
cert_line += f" | URL: {cert['url']}"
pdf.cell(0, 6, cert_line, 0, 1, 'L')
pdf.ln(2)
# 語言能力
if self.resume_data["languages"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "語言能力", 0, 1, 'L')
pdf.set_font("Arial", '', 12)
langs = ", ".join(self.resume_data["languages"])
pdf.multi_cell(0, 6, langs)
# 保存PDF
file_path, _ = QFileDialog.getSaveFileName(self, "保存PDF", "我的簡歷.pdf", "PDF文件 (*.pdf)")
if file_path:
pdf.output(file_path)
QMessageBox.information(self, "成功", "簡歷已成功導出為PDF!")
def save_resume_data(self):
self.collect_personal_info()
self.collect_summary()
file_path, _ = QFileDialog.getSaveFileName(self, "保存簡歷數(shù)據(jù)", "resume_data.json", "JSON文件 (*.json)")
if file_path:
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(self.resume_data, f, ensure_ascii=False, indent=4)
QMessageBox.information(self, "成功", "簡歷數(shù)據(jù)已保存!")
def load_resume_data(self):
file_path, _ = QFileDialog.getOpenFileName(self, "加載簡歷數(shù)據(jù)", "", "JSON文件 (*.json)")
if file_path:
try:
with open(file_path, 'r', encoding='utf-8') as f:
self.resume_data = json.load(f)
# 更新UI
self.update_ui_from_data()
QMessageBox.information(self, "成功", "簡歷數(shù)據(jù)已加載!")
except Exception as e:
QMessageBox.critical(self, "錯誤", f"加載簡歷數(shù)據(jù)失敗: {str(e)}")
def update_ui_from_data(self):
# 個人信息
personal_info = self.resume_data["personal_info"]
self.name_edit.setText(personal_info.get("name", ""))
self.email_edit.setText(personal_info.get("email", ""))
self.phone_edit.setText(personal_info.get("phone", ""))
self.address_edit.setText(personal_info.get("address", ""))
self.linkedin_edit.setText(personal_info.get("linkedin", ""))
self.github_edit.setText(personal_info.get("github", ""))
self.website_edit.setText(personal_info.get("website", ""))
# 職業(yè)概述
self.summary_edit.setPlainText(self.resume_data.get("summary", ""))
# 教育經歷
self.update_education_list()
# 工作經歷
self.update_experience_list()
# 技能
self.update_skills_list()
# 項目經歷
self.update_project_list()
# 證書
self.update_certification_list()
# 語言能力
self.update_languages_list()
if __name__ == "__main__":
app = QApplication(sys.argv)
# 設置應用程序樣式和字體
app.setStyle("Fusion")
# 設置調色板
palette = QPalette()
palette.setColor(QPalette.Window, QColor(240, 242, 245))
palette.setColor(QPalette.WindowText, QColor(0, 0, 0))
palette.setColor(QPalette.Base, QColor(255, 255, 255))
palette.setColor(QPalette.AlternateBase, QColor(240, 240, 240))
palette.setColor(QPalette.ToolTipBase, QColor(255, 255, 255))
palette.setColor(QPalette.ToolTipText, QColor(0, 0, 0))
palette.setColor(QPalette.Text, QColor(0, 0, 0))
palette.setColor(QPalette.Button, QColor(240, 240, 240))
palette.setColor(QPalette.ButtonText, QColor(0, 0, 0))
palette.setColor(QPalette.BrightText, QColor(255, 0, 0))
palette.setColor(QPalette.Highlight, QColor(76, 175, 80))
palette.setColor(QPalette.HighlightedText, QColor(255, 255, 255))
app.setPalette(palette)
# 創(chuàng)建并顯示主窗口
window = ResumeGenerator()
window.show()
sys.exit(app.exec_())
七、總結與展望
本工具通過PyQt5實現(xiàn)了:
- 高效管理:比傳統(tǒng)文檔編輯效率提升300%
- 專業(yè)輸出:符合HR系統(tǒng)的解析標準
- 靈活定制:模塊化設計易于擴展
未來可增加:
- LaTeX導出支持
- 在線模板市場
- AI輔助內容生成
- 多語言國際化
Q&A環(huán)節(jié)
Q:如何添加自定義模板?
A:在templates目錄下新建JSON文件,按照現(xiàn)有模板格式編寫樣式規(guī)則。
Q:程序無法顯示中文怎么辦?
A:確保系統(tǒng)已安裝中文字體,并在PDF生成時指定中文字體路徑。
Q:能否導出為Word格式?
A:當前版本僅支持PDF,可通過python-docx庫自行擴展。
相關技術棧推薦
- 高級功能:PyQtGraph數(shù)據(jù)可視化
- 云存儲:集成Dropbox API
- 自動化:結合Selenium實現(xiàn)自動投遞
求職小貼士
使用本工具生成簡歷后,建議:
- 根據(jù)不同崗位調整關鍵詞
- 保持一頁紙原則
- 量化工作成果
- 定期更新內容
到此這篇關于Python+PyQt5實現(xiàn)簡歷自動生成工具的文章就介紹到這了,更多相關Python自動生成簡歷內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python實現(xiàn)繁體中文與簡體中文相互轉換的方法示例
這篇文章主要介紹了Python實現(xiàn)繁體中文與簡體中文相互轉換的方法,涉及Python基于第三方模塊進行編碼轉換相關操作技巧,需要的朋友可以參考下2018-12-12
python 如何把classification_report輸出到csv文件
這篇文章主要介紹了python 把classification_report輸出到csv文件的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-05-05
PyTorch中 tensor.detach() 和 tensor.data 的區(qū)別詳解
今天小編就為大家分享一篇PyTorch中 tensor.detach() 和 tensor.data 的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01
Python解決asyncio文件描述符最大數(shù)量限制的問題
這篇文章主要介紹了Python解決asyncio文件描述符最大數(shù)量限制的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06

