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

UI界面概覽
左側(cè)為標(biāo)簽式編輯面板,右側(cè)為實(shí)時(shí)預(yù)覽區(qū),符合專業(yè)軟件設(shè)計(jì)范式。
四、開(kāi)發(fā)步驟詳解
4.1 環(huán)境配置
pip install PyQt5 fpdf
4.2 核心類設(shè)計(jì)
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()
# ...其他標(biāo)簽頁(yè)
self.setup_preview_panel()
4.3 數(shù)據(jù)管理機(jī)制
采用三層架構(gòu)設(shè)計(jì):
- 表示層:PyQt5界面組件
- 邏輯層:簡(jiǎn)歷數(shù)據(jù)處理方法
- 持久層:JSON序列化存儲(chǔ)

五、關(guān)鍵代碼解析
5.1 動(dòng)態(tài)表單管理
教育/工作經(jīng)歷采用列表+詳情表單的交互模式:
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庫(kù)的定制化輸出:
def export_to_pdf(self):
pdf = FPDF()
pdf.add_page()
# 設(shè)置中文字體支持
pdf.add_font('SimSun', '', 'simsun.ttc', uni=True)
# 添加內(nèi)容區(qū)塊
self.add_personal_section(pdf)
self.add_education_section(pdf)
# ...其他部分
pdf.output("resume.pdf")
5.3 樣式管理系統(tǒng)
使用Qt樣式表實(shí)現(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("自動(dòng)化簡(jiǎn)歷生成工具")
self.setGeometry(100, 100, 1000, 750)
# 嘗試加載圖標(biāo),如果失敗則忽略
try:
self.setWindowIcon(QIcon("resume_icon.png"))
except:
pass
# 初始化UI
self.init_ui()
# 加載模板
self.load_templates()
# 初始化簡(jiǎn)歷數(shù)據(jù)結(jié)構(gòu)
self.init_resume_data()
# 當(dāng)前編輯的項(xiàng)目索引
self.current_edu_index = -1
self.current_exp_index = -1
self.current_proj_index = -1
self.current_cert_index = -1
def init_ui(self):
# 設(shè)置主窗口背景和全局樣式
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)
# 左側(cè)面板 - 簡(jiǎn)歷內(nèi)容編輯 (70%寬度)
self.left_panel = QTabWidget()
self.left_panel.setTabPosition(QTabWidget.North)
self.left_panel.setDocumentMode(True)
main_layout.addWidget(self.left_panel, 7)
# 右側(cè)面板 - 預(yù)覽和操作 (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)
# 添加標(biāo)簽頁(yè)
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()
# 右側(cè)面板內(nèi)容
# 模板選擇組
template_group = QGroupBox("簡(jiǎn)歷模板")
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)
# 預(yù)覽按鈕
self.preview_btn = QPushButton("?? 預(yù)覽簡(jiǎn)歷")
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)
# 導(dǎo)出按鈕
self.export_btn = QPushButton("?? 導(dǎo)出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)
# 預(yù)覽區(qū)域組
preview_group = QGroupBox("簡(jiǎn)歷預(yù)覽")
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)
# 添加到右側(cè)面板
right_layout.addWidget(template_group)
right_layout.addWidget(button_group)
right_layout.addWidget(preview_group)
# 設(shè)置標(biāo)簽頁(yè)顏色
self.set_tab_colors()
def set_tab_colors(self):
#為每個(gè)標(biāo)簽頁(yè)設(shè)置不同的顏色
tab_colors = [
("#FF5252", "#FFFFFF"), # 紅色
("#FF9800", "#FFFFFF"), # 橙色
("#FFEB3B", "#000000"), # 黃色
("#4CAF50", "#FFFFFF"), # 綠色
("#2196F3", "#FFFFFF"), # 藍(lán)色
("#673AB7", "#FFFFFF"), # 深紫色
("#E91E63", "#FFFFFF"), # 粉色
("#607D8B", "#FFFFFF") # 藍(lán)灰色
]
# 方法1:統(tǒng)一設(shè)置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):
"""初始化簡(jiǎn)歷數(shù)據(jù)結(jié)構(gòu)"""
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組織內(nèi)容
group = QGroupBox("個(gè)人信息")
form_layout = QFormLayout()
group.setLayout(form_layout)
# 創(chuàng)建帶圖標(biāo)的輸入字段
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("??", "個(gè)人網(wǎng)站")
# 添加到表單
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("個(gè)人網(wǎng)站:", self.website_edit)
layout.addWidget(group)
layout.addStretch()
self.left_panel.addTab(tab, "個(gè)人信息")
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)
# 教育經(jīng)歷表單組
form_group = QGroupBox("添加/編輯教育經(jīng)歷")
form_layout = QFormLayout()
form_group.setLayout(form_layout)
# 創(chuàng)建輸入字段
self.edu_school_edit = self.create_line_edit("??", "學(xué)校名稱")
self.edu_degree_edit = self.create_line_edit("??", "學(xué)位")
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()
# 設(shè)置日期控件
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("學(xué)校:", self.edu_school_edit)
form_layout.addRow("學(xué)位:", self.edu_degree_edit)
form_layout.addRow("專業(yè):", self.edu_field_edit)
form_layout.addRow("開(kāi)始日期:", self.edu_start_date)
form_layout.addRow("結(jié)束日期:", 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)
# 教育經(jīng)歷列表組
list_group = QGroupBox("教育經(jīng)歷列表")
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, "教育經(jīng)歷")
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("添加/編輯工作經(jīng)歷")
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("開(kāi)始日期:", self.exp_start_date)
form_layout.addRow("結(jié)束日期:", 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("工作經(jīng)歷列表")
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, "工作經(jīng)歷")
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(["初級(jí)", "中級(jí)", "高級(jí)", "專家"])
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("添加/編輯項(xiàng)目")
form_layout = QFormLayout()
form_group.setLayout(form_layout)
self.proj_name_edit = self.create_line_edit("??", "項(xiàng)目名稱")
self.proj_role_edit = self.create_line_edit("??", "你的角色")
self.proj_start_date = QDateEdit()
self.proj_end_date = QDateEdit()
self.proj_current = QCheckBox("進(jìn)行中")
self.proj_description = QTextEdit()
self.proj_url_edit = self.create_line_edit("??", "項(xiàng)目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("項(xiàng)目名稱:", self.proj_name_edit)
form_layout.addRow("你的角色:", self.proj_role_edit)
form_layout.addRow("開(kāi)始日期:", self.proj_start_date)
form_layout.addRow("結(jié)束日期:", self.proj_end_date)
form_layout.addRow(self.proj_current)
form_layout.addRow("項(xiàng)目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("項(xiàng)目列表")
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, "項(xiàng)目經(jīng)歷")
def add_certifications_tab(self):
tab = QWidget()
layout = QVBoxLayout()
tab.setLayout(layout)
form_group = QGroupBox("添加/編輯證書(shū)")
form_layout = QFormLayout()
form_group.setLayout(form_layout)
self.cert_name_edit = self.create_line_edit("??", "證書(shū)名稱")
self.cert_org_edit = self.create_line_edit("???", "頒發(fā)機(jī)構(gòu)")
self.cert_date = QDateEdit()
self.cert_url_edit = self.create_line_edit("??", "證書(shū)URL")
self.cert_date.setCalendarPopup(True)
form_layout.addRow("證書(shū)名稱:", self.cert_name_edit)
form_layout.addRow("頒發(fā)機(jī)構(gòu):", self.cert_org_edit)
form_layout.addRow("獲得日期:", self.cert_date)
form_layout.addRow("證書(shū)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("證書(shū)列表")
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, "證書(shū)")
def add_languages_tab(self):
tab = QWidget()
layout = QVBoxLayout()
tab.setLayout(layout)
form_group = QGroupBox("添加語(yǔ)言")
form_layout = QVBoxLayout()
form_group.setLayout(form_layout)
lang_layout = QHBoxLayout()
self.lang_edit = self.create_line_edit("??", "語(yǔ)言")
self.lang_level_combo = QComboBox()
self.lang_level_combo.addItems(["初級(jí)", "中級(jí)", "高級(jí)", "母語(yǔ)"])
lang_layout.addWidget(self.lang_edit)
lang_layout.addWidget(self.lang_level_combo)
btn_layout = QHBoxLayout()
self.add_lang_btn = self.create_button("? 添加語(yǔ)言", "#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("語(yǔ)言列表")
list_layout = QVBoxLayout()
list_group.setLayout(list_layout)
self.lang_list = QListWidget()
list_layout.addWidget(self.lang_list)
form_layout.addWidget(QLabel("添加語(yǔ)言:"))
form_layout.addLayout(lang_layout)
form_layout.addLayout(btn_layout)
layout.addWidget(form_group)
layout.addWidget(list_group)
self.left_panel.addTab(tab, "語(yǔ)言能力")
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):
"""加載簡(jiǎn)歷模板"""
templates = [
"?? 多彩創(chuàng)意模板",
"?? 專業(yè)商務(wù)模板",
"?? 傳統(tǒng)經(jīng)典模板",
"?? 現(xiàn)代簡(jiǎn)約模板",
"?? 數(shù)據(jù)分析師模板",
"?? 開(kāi)發(fā)者模板",
"?? 學(xué)術(shù)模板",
"?? 設(shè)計(jì)師模板"
]
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):
"""生成簡(jiǎn)歷預(yù)覽"""
self.collect_personal_info()
self.collect_summary()
preview_text = "=== 簡(jiǎn)歷預(yù)覽 ===\n\n"
preview_text += "?? 個(gè)人信息:\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"?? 個(gè)人網(wǎng)站: {self.resume_data['personal_info']['website']}\n\n"
preview_text += "?? 職業(yè)概述:\n"
preview_text += f"{self.resume_data['summary']}\n\n"
preview_text += "?? 教育經(jīng)歷:\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 += "?? 工作經(jīng)歷:\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 += "?? 項(xiàng)目經(jīng)歷:\n"
for proj in self.resume_data["projects"]:
preview_text += f"- ?? {proj['name']} ({proj['role']})\n"
preview_text += f" ?? {proj['start_date']} 至 {'進(jìn)行中' if proj['current'] else proj['end_date']}\n"
preview_text += f" ?? URL: {proj['url']}\n"
preview_text += f" ?? 描述: {proj['description']}\n\n"
preview_text += "?? 證書(shū):\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 += "?? 語(yǔ)言能力:\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)
# 設(shè)置字體
pdf.set_font("Arial", 'B', 16)
# 個(gè)人信息
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)
# 教育經(jīng)歷
if self.resume_data["education"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "教育經(jīng)歷", 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)
# 工作經(jīng)歷
if self.resume_data["experience"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "工作經(jīng)歷", 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)
# 項(xiàng)目經(jīng)歷
if self.resume_data["projects"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "項(xiàng)目經(jīng)歷", 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']} - {'進(jìn)行中' 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)
# 證書(shū)
if self.resume_data["certifications"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "證書(shū)", 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)
# 語(yǔ)言能力
if self.resume_data["languages"]:
pdf.set_font("Arial", 'B', 14)
pdf.cell(0, 10, "語(yǔ)言能力", 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", "我的簡(jiǎn)歷.pdf", "PDF文件 (*.pdf)")
if file_path:
pdf.output(file_path)
QMessageBox.information(self, "成功", "簡(jiǎn)歷已成功導(dǎo)出為PDF!")
def save_resume_data(self):
self.collect_personal_info()
self.collect_summary()
file_path, _ = QFileDialog.getSaveFileName(self, "保存簡(jiǎn)歷數(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, "成功", "簡(jiǎn)歷數(shù)據(jù)已保存!")
def load_resume_data(self):
file_path, _ = QFileDialog.getOpenFileName(self, "加載簡(jiǎn)歷數(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, "成功", "簡(jiǎn)歷數(shù)據(jù)已加載!")
except Exception as e:
QMessageBox.critical(self, "錯(cuò)誤", f"加載簡(jiǎn)歷數(shù)據(jù)失敗: {str(e)}")
def update_ui_from_data(self):
# 個(gè)人信息
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", ""))
# 教育經(jīng)歷
self.update_education_list()
# 工作經(jīng)歷
self.update_experience_list()
# 技能
self.update_skills_list()
# 項(xiàng)目經(jīng)歷
self.update_project_list()
# 證書(shū)
self.update_certification_list()
# 語(yǔ)言能力
self.update_languages_list()
if __name__ == "__main__":
app = QApplication(sys.argv)
# 設(shè)置應(yīng)用程序樣式和字體
app.setStyle("Fusion")
# 設(shè)置調(diào)色板
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_())
七、總結(jié)與展望
本工具通過(guò)PyQt5實(shí)現(xiàn)了:
- 高效管理:比傳統(tǒng)文檔編輯效率提升300%
- 專業(yè)輸出:符合HR系統(tǒng)的解析標(biāo)準(zhǔn)
- 靈活定制:模塊化設(shè)計(jì)易于擴(kuò)展
未來(lái)可增加:
- LaTeX導(dǎo)出支持
- 在線模板市場(chǎng)
- AI輔助內(nèi)容生成
- 多語(yǔ)言國(guó)際化
Q&A環(huán)節(jié)
Q:如何添加自定義模板?
A:在templates目錄下新建JSON文件,按照現(xiàn)有模板格式編寫樣式規(guī)則。
Q:程序無(wú)法顯示中文怎么辦?
A:確保系統(tǒng)已安裝中文字體,并在PDF生成時(shí)指定中文字體路徑。
Q:能否導(dǎo)出為Word格式?
A:當(dāng)前版本僅支持PDF,可通過(guò)python-docx庫(kù)自行擴(kuò)展。
相關(guān)技術(shù)棧推薦
- 高級(jí)功能:PyQtGraph數(shù)據(jù)可視化
- 云存儲(chǔ):集成Dropbox API
- 自動(dòng)化:結(jié)合Selenium實(shí)現(xiàn)自動(dòng)投遞
求職小貼士
使用本工具生成簡(jiǎn)歷后,建議:
- 根據(jù)不同崗位調(diào)整關(guān)鍵詞
- 保持一頁(yè)紙?jiān)瓌t
- 量化工作成果
- 定期更新內(nèi)容
到此這篇關(guān)于Python+PyQt5實(shí)現(xiàn)簡(jiǎn)歷自動(dòng)生成工具的文章就介紹到這了,更多相關(guān)Python自動(dòng)生成簡(jiǎn)歷內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- python簡(jiǎn)單實(shí)現(xiàn)刷新智聯(lián)簡(jiǎn)歷
- 使用C# CefSharp Python采集某網(wǎng)站簡(jiǎn)歷并且自動(dòng)發(fā)送邀請(qǐng)短信的方法
- python+selenium實(shí)現(xiàn)簡(jiǎn)歷自動(dòng)刷新的示例代碼
- Python實(shí)現(xiàn)提取PDF簡(jiǎn)歷信息并存入Excel
- Python Word文件自動(dòng)化實(shí)戰(zhàn)之簡(jiǎn)歷篩選
- 利用Python實(shí)現(xiàn)自動(dòng)生成數(shù)據(jù)日?qǐng)?bào)
- Python辦公自動(dòng)化之?dāng)?shù)據(jù)可視化與報(bào)表生成
- python使用MkDocs自動(dòng)生成文檔的操作方法
相關(guān)文章
python?包實(shí)現(xiàn)?time?時(shí)間管理操作
這篇文章主要介紹了python包實(shí)現(xiàn)time時(shí)間管理操作,文章通過(guò)獲取當(dāng)前時(shí)間戳,即當(dāng)前系統(tǒng)內(nèi)表示時(shí)間的一個(gè)浮點(diǎn)數(shù),下文更多相關(guān)內(nèi)容需要的小伙伴可以參考一下2022-04-04
Python實(shí)現(xiàn)繁體中文與簡(jiǎn)體中文相互轉(zhuǎn)換的方法示例
這篇文章主要介紹了Python實(shí)現(xiàn)繁體中文與簡(jiǎn)體中文相互轉(zhuǎn)換的方法,涉及Python基于第三方模塊進(jìn)行編碼轉(zhuǎn)換相關(guān)操作技巧,需要的朋友可以參考下2018-12-12
python框架django中結(jié)合vue進(jìn)行前后端分離
本篇將基于Python+Django結(jié)合Vue.js前端框架,為大家介紹如何基于這三者的技術(shù)棧來(lái)實(shí)現(xiàn)一個(gè)前端后離的Web開(kāi)發(fā)項(xiàng)目。文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
python 如何把classification_report輸出到csv文件
這篇文章主要介紹了python 把classification_report輸出到csv文件的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05
PyTorch中 tensor.detach() 和 tensor.data 的區(qū)別詳解
今天小編就為大家分享一篇PyTorch中 tensor.detach() 和 tensor.data 的區(qū)別詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01
pytorch實(shí)現(xiàn)查看當(dāng)前學(xué)習(xí)率
這篇文章主要介紹了pytorch實(shí)現(xiàn)查看當(dāng)前學(xué)習(xí)率,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06
Python解決asyncio文件描述符最大數(shù)量限制的問(wèn)題
這篇文章主要介紹了Python解決asyncio文件描述符最大數(shù)量限制的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06

