python: DDD+ORM+pyQt6 using MySql
sql:
create table School #創建表 ( `SchoolId` char(5) NOT NULL comment'主鍵primary key,學校編號', #採取手工輸入,也可以設計為自動添加自增長 為5位元,數位,字元,或數位和字元組合,在文本保存資料時,用程式碼進行限制 #`SchoolId` int(11) NOT NULL AUTO_INCREMENT comment'學校編號', #設計為自增長 `SchoolName` nvarchar(500) NOT NULL DEFAULT '' comment' 學校名稱', `SchoolTelNo` varchar(8) NULL DEFAULT '' comment'電話號碼', PRIMARY KEY (`SchoolId`) #主鍵 )ENGINE=MyISAM COMMENT='學校表 School Table' DEFAULT CHARSET=utf8; 、 create table Teacher #創建表 ( `TeacherId` char(5) NOT NULL comment'主鍵primary key,學生編號', `TeacherFirstName` nvarchar(100) NOT NULL DEFAULT '' comment' 名', `TeacherLastName` nvarchar(20) NOT NULL DEFAULT '' comment' 姓', `TeacherGender` char(2) NOT NULL DEFAULT '' comment'性別', `TeacherTelNo` varchar(8) NULL DEFAULT '' comment'電話號碼', `TeacherSchoolId` char(5) NOT NULL DEFAULT '' comment'外鍵 foreign key 學校ID', PRIMARY KEY (`TeacherId`), #主鍵 CONSTRAINT TeacherSchool_ibfk_1 FOREIGN KEY(TeacherSchoolId) REFERENCES School(SchoolId) #外鍵 )ENGINE=MyISAM COMMENT='老師表Teacher Table' DEFAULT CHARSET=utf8;
数据处理各层,就用前面的就可以了。只是呈现器(MVP)改成pyQt6就可以了。
项目结构:
# encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/3/29 22:51 # User : geovindu # Product : PyCharm # Project : pymysqlDDDQt # File : school.py # explain : 学习 import sys from PyQt6.QtWidgets import QApplication, QTabWidget from presentation.controllers.school import SchoolController from presentation.views.school import SchoolView class SchoolPresenter: def __init__(self, view, controller: SchoolController): self.view = view self.controller = controller self.current_page = 1 self.page_size = 10 self.search_query = "" self.setup_connections() self.update_table() def setup_connections(self): self.view.search_button.clicked.connect(self.on_search) self.view.add_button.clicked.connect(self.on_add) self.view.edit_button.clicked.connect(self.on_edit) self.view.delete_button.clicked.connect(self.on_delete) self.view.prev_button.clicked.connect(self.on_prev_page) self.view.next_button.clicked.connect(self.on_next_page) def update_table(self): try: schools = self.controller.get_all_schools( self.current_page, self.page_size, self.search_query) print(schools) self.view.set_table_data(schools) total_records = self.controller.get_total_schools(self.search_query) print(total_records) total_pages = (total_records + self.page_size - 1) // self.page_size self.view.set_pagination_info(self.current_page, total_pages, total_records) except Exception as e: print(f"更新学校表格数据时出错: {e}") def on_search(self): self.search_query = self.view.get_search_query() self.current_page = 1 self.update_table() def on_add(self): try: school = self.view.show_add_dialog() if school: self.controller.add_school(school) self.update_table() self.view.show_message("School added successfully.") except Exception as e: print(f"添加学校时出错: {e}") def on_edit(self): try: row = self.view.get_selected_row() if row != -1: school_id = self.view.table.item(row, 0).text() school = self.controller.get_all_schools( self.current_page, self.page_size, self.search_query)[row] edited_school = self.view.show_edit_dialog(school) if edited_school: edited_school.SchoolId = school_id self.controller.update_school(edited_school) self.update_table() self.view.show_message("School updated successfully.") else: self.view.show_message("Please select a school to edit.") except Exception as e: print(f"编辑学校时出错: {e}") def on_delete(self): try: row = self.view.get_selected_row() if row != -1: school_id = self.view.table.item(row, 0).text() self.controller.delete_school(school_id) self.update_table() self.view.show_message("School deleted successfully.") else: self.view.show_message("Please select a school to delete.") except Exception as e: print(f"删除学校时出错: {e}") def on_prev_page(self): if self.current_page > 1: self.current_page -= 1 self.update_table() def on_next_page(self): total_schools = self.controller.get_total_schools(self.search_query) total_pages = (total_schools + self.page_size - 1) // self.page_size if self.current_page < total_pages: self.current_page += 1 self.update_table() # encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/3/29 22:51 # User : geovindu # Product : PyCharm # Project : pymysqlDDDQt # File : teacher.py # explain : 学习 from presentation.controllers.teacher import TeacherController from presentation.views.teacher import TeacherView from presentation.controllers.school import SchoolController class TeacherPresenter: def __init__(self, view, controller:TeacherController,scontroller: SchoolController): self.view = view self.controller = controller self.scontroller = scontroller self.school_map = None self.current_page = 1 self.page_size = 10 self.search_query = "" self.setup_connections() self.update_table() def setup_connections(self): self.view.search_button.clicked.connect(self.on_search) self.view.add_button.clicked.connect(self.on_add) self.view.edit_button.clicked.connect(self.on_edit) self.view.delete_button.clicked.connect(self.on_delete) self.view.prev_button.clicked.connect(self.on_prev_page) self.view.next_button.clicked.connect(self.on_next_page) # 学校选择 schools = self.scontroller.get_schoolall() print("schools:") print(schools) # 这个有错语 self.school_map = schools # {s.school_name: s.school_id for s in schools} def update_table(self): try: teachers = self.controller.get_all_teachers( self.current_page, self.page_size, self.search_query) self.view.set_table_data(teachers) total_records = self.controller.get_total_teachers(self.search_query) total_pages = (total_records + self.page_size - 1) // self.page_size self.view.set_pagination_info(self.current_page, total_pages, total_records) except Exception as e: print(f"更新教师表格数据时出错: {e}") def on_search(self): self.search_query = self.view.get_search_query() self.current_page = 1 self.update_table() def on_add(self): try: teacher = self.view.show_add_dialog(self.school_map) if teacher: self.controller.add_teacher(teacher) self.update_table() self.view.show_message("Teacher added successfully.") except Exception as e: print(f"添加教师时出错: {e}") def on_edit(self): try: row = self.view.get_selected_row() if row != -1: teacher_id = self.view.table.item(row, 0).text() teacher = self.controller.get_all_teachers( self.current_page, self.page_size, self.search_query)[row] # edited_teacher = self.view.show_edit_dialog(teacher,self.school_map) if edited_teacher: edited_teacher.TeacherId = teacher_id self.controller.update_teacher(edited_teacher) self.update_table() self.view.show_message("Teacher updated successfully.") else: self.view.show_message("Please select a teacher to edit.") except Exception as e: print(f"编辑教师时出错: {e}") def on_delete(self): try: row = self.view.get_selected_row() if row != -1: teacher_id = self.view.table.item(row, 0).text() self.controller.delete_teacher(teacher_id) self.update_table() self.view.show_message("Teacher deleted successfully.") else: self.view.show_message("Please select a teacher to delete.") except Exception as e: print(f"删除教师时出错: {e}") def on_prev_page(self): if self.current_page > 1: self.current_page -= 1 self.update_table() def on_next_page(self): total_teachers = self.controller.get_total_teachers(self.search_query) total_pages = (total_teachers + self.page_size - 1) // self.page_size if self.current_page < total_pages: self.current_page += 1 self.update_table()
# encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/3/29 21:34 # User : geovindu # Product : PyCharm # Project : pymysqlDDDQt # File : school.py # explain : 学习 from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, QPushButton, QLabel, QLineEdit, QDialog, QFormLayout, QDialogButtonBox, QMessageBox, QMdiArea, QMdiSubWindow ) from domain.entities.school import School class SchoolView(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.mdi_area = QMdiArea() self.sub_window = QMdiSubWindow() self.main_widget = QWidget() self.table = QTableWidget() self.table.setColumnCount(3) self.table.setHorizontalHeaderLabels( ['SchoolId', 'SchoolName', 'SchoolTelNo']) self.search_input = QLineEdit() self.search_button = QPushButton("Search") self.add_button = QPushButton("Add") self.edit_button = QPushButton("Edit") self.delete_button = QPushButton("Delete") self.prev_button = QPushButton("Prev") self.next_button = QPushButton("Next") self.pagination_label = QLabel() search_layout = QHBoxLayout() search_layout.addWidget(self.search_input) search_layout.addWidget(self.search_button) button_layout = QHBoxLayout() button_layout.addWidget(self.add_button) button_layout.addWidget(self.edit_button) button_layout.addWidget(self.delete_button) button_layout.addWidget(self.prev_button) button_layout.addWidget(self.next_button) button_layout.addWidget(self.pagination_label) layout = QVBoxLayout() layout.addLayout(search_layout) layout.addWidget(self.table) layout.addLayout(button_layout) self.main_widget.setLayout(layout) self.sub_window.setWidget(self.main_widget) self.mdi_area.addSubWindow(self.sub_window) main_layout = QVBoxLayout() main_layout.addWidget(self.mdi_area) self.setLayout(main_layout) def set_table_data(self, schools): self.table.setRowCount(len(schools)) for row, school in enumerate(schools): self.table.setItem(row, 0, QTableWidgetItem(school.school_id)) self.table.setItem(row, 1, QTableWidgetItem(school.school_name)) self.table.setItem(row, 2, QTableWidgetItem(school.school_tel_no)) def get_selected_row(self): selected_items = self.table.selectedItems() if selected_items: return selected_items[0].row() return -1 def get_search_query(self): return self.search_input.text() def show_add_dialog(self): dialog = QDialog(self) dialog.setWindowTitle("Add School") layout = QFormLayout() id_input = QLineEdit() name_input = QLineEdit() tel_input = QLineEdit() layout.addRow("School ID:", id_input) layout.addRow("School Name:", name_input) layout.addRow("School Tel No:", tel_input) button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) button_box.accepted.connect(dialog.accept) button_box.rejected.connect(dialog.reject) layout.addWidget(button_box) dialog.setLayout(layout) if dialog.exec() == QDialog.DialogCode.Accepted: school_id = id_input.text() name = name_input.text() tel_no = tel_input.text() return School(SchoolId=school_id, SchoolName=name, SchoolTelNo=tel_no) return None def show_edit_dialog(self, school): dialog = QDialog(self) dialog.setWindowTitle("Edit School") layout = QFormLayout() id_input = QLineEdit(school.school_id) name_input = QLineEdit(school.school_name) tel_input = QLineEdit(school.school_tel_no) layout.addRow("School ID:", id_input) layout.addRow("School Name:", name_input) layout.addRow("School Tel No:", tel_input) button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) button_box.accepted.connect(dialog.accept) button_box.rejected.connect(dialog.reject) layout.addWidget(button_box) dialog.setLayout(layout) if dialog.exec() == QDialog.DialogCode.Accepted: school.SchoolId = id_input.text() school.SchoolName = name_input.text() school.SchoolTelNo = tel_input.text() return school return None def show_message(self, message): QMessageBox.information(self, 'Message', message) def set_pagination_info(self, current_page, total_pages, total_records): info_text = f"当前页: {current_page} / 总页数: {total_pages} 总记录数: {total_records}" self.pagination_label.setText(info_text) # encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/3/29 21:34 # User : geovindu # Product : PyCharm # Project : pymysqlDDDQt # File : teacher.py # explain : 学习 from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, QPushButton, QLabel, QLineEdit, QDialog, QFormLayout, QDialogButtonBox, QMessageBox, QMdiArea, QMdiSubWindow, QComboBox ) from domain.entities.teacher import Teacher from application.services.school import SchoolService from domain.repositories.school import SchoolRepository class TeacherView(QWidget): def __init__(self): super().__init__() self.initUI() #respository = SchoolRepository() #self.respository=respository #self.school_service = SchoolService(respository) def initUI(self): self.mdi_area = QMdiArea() self.sub_window = QMdiSubWindow() self.main_widget = QWidget() self.table = QTableWidget() self.table.setColumnCount(6) self.table.setHorizontalHeaderLabels([ 'TeacherId', 'TeacherFirstName', 'TeacherLastName', 'TeacherGender', 'TeacherTelNo', 'TeacherSchoolId' ]) self.search_input = QLineEdit() self.search_button = QPushButton("Search") self.add_button = QPushButton("Add") self.edit_button = QPushButton("Edit") self.delete_button = QPushButton("Delete") self.prev_button = QPushButton("Prev") self.next_button = QPushButton("Next") self.pagination_label = QLabel() search_layout = QHBoxLayout() search_layout.addWidget(self.search_input) search_layout.addWidget(self.search_button) button_layout = QHBoxLayout() button_layout.addWidget(self.add_button) button_layout.addWidget(self.edit_button) button_layout.addWidget(self.delete_button) button_layout.addWidget(self.prev_button) button_layout.addWidget(self.next_button) button_layout.addWidget(self.pagination_label) layout = QVBoxLayout() layout.addLayout(search_layout) layout.addWidget(self.table) layout.addLayout(button_layout) self.main_widget.setLayout(layout) self.sub_window.setWidget(self.main_widget) self.mdi_area.addSubWindow(self.sub_window) main_layout = QVBoxLayout() main_layout.addWidget(self.mdi_area) self.setLayout(main_layout) def set_table_data(self, teachers): self.table.setRowCount(len(teachers)) for row, teacher in enumerate(teachers): self.table.setItem(row, 0, QTableWidgetItem(teacher.teacher_id)) self.table.setItem(row, 1, QTableWidgetItem( teacher.first_name)) self.table.setItem(row, 2, QTableWidgetItem( teacher.last_name)) self.table.setItem(row, 3, QTableWidgetItem(teacher.gender)) self.table.setItem(row, 4, QTableWidgetItem(teacher.tel_no)) self.table.setItem(row, 5, QTableWidgetItem( teacher.school_id)) def get_selected_row(self): selected_items = self.table.selectedItems() if selected_items: return selected_items[0].row() return -1 def get_search_query(self): return self.search_input.text() def show_add_dialog(self,school_map): dialog = QDialog(self) dialog.setWindowTitle("Add Teacher") layout = QFormLayout() id_input = QLineEdit() first_name_input = QLineEdit() last_name_input = QLineEdit() gender_input = QLineEdit() tel_input = QLineEdit() school_combo = QComboBox() # 获取所有学校信息 schools =school_map # self.school_service.get_schoolall() print("获取所有学校信息") print(schools) for school in school_map: school_combo.addItem(f"{school.school_id} - {school.school_name}", school.school_id) layout.addRow("Teacher ID:", id_input) layout.addRow("First Name:", first_name_input) layout.addRow("Last Name:", last_name_input) layout.addRow("Gender:", gender_input) layout.addRow("Tel No:", tel_input) layout.addRow("School:", school_combo) button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) button_box.accepted.connect(dialog.accept) button_box.rejected.connect(dialog.reject) layout.addWidget(button_box) dialog.setLayout(layout) if dialog.exec() == QDialog.DialogCode.Accepted: teacher_id = id_input.text() first_name = first_name_input.text() last_name = last_name_input.text() gender = gender_input.text() tel_no = tel_input.text() school_id = school_combo.currentData() return Teacher(TeacherId=teacher_id, TeacherFirstName=first_name, TeacherLastName=last_name, TeacherGender=gender, TeacherTelNo=tel_no, TeacherSchoolId=school_id) return None def show_edit_dialog(self, teacher,school_map): dialog = QDialog(self) dialog.setWindowTitle("Edit Teacher") layout = QFormLayout() id_input = QLineEdit(teacher.teacher_id) first_name_input = QLineEdit(teacher.first_name) last_name_input = QLineEdit(teacher.last_name) gender_input = QLineEdit(teacher.gender) tel_input = QLineEdit(teacher.tel_no) school_combo = QComboBox() # 获取所有学校信息 schools = school_map # self.school_service.get_schoolall() for school in schools: school_combo.addItem(f"{school.school_id} - {school.school_name}", school.school_id) if school.school_id == teacher.school_id: school_combo.setCurrentIndex(school_combo.count() - 1) layout.addRow("Teacher ID:", id_input) layout.addRow("First Name:", first_name_input) layout.addRow("Last Name:", last_name_input) layout.addRow("Gender:", gender_input) layout.addRow("Tel No:", tel_input) layout.addRow("School:", school_combo) button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) button_box.accepted.connect(dialog.accept) button_box.rejected.connect(dialog.reject) layout.addWidget(button_box) dialog.setLayout(layout) if dialog.exec() == QDialog.DialogCode.Accepted: teacher.TeacherId = id_input.text() teacher.TeacherFirstName = first_name_input.text() teacher.TeacherLastName = last_name_input.text() teacher.TeacherGender = gender_input.text() teacher.TeacherTelNo = tel_input.text() teacher.TeacherSchoolId = school_combo.currentData() return teacher return None def show_message(self, message): QMessageBox.information(self, 'Message', message) def set_pagination_info(self, current_page, total_pages, total_records): info_text = f"当前页: {current_page} / 总页数: {total_pages} 总记录数: {total_records}" self.pagination_label.setText(info_text)
效果:
加入登录窗口
# encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司 ® # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: python.exe -m pip install --upgrade pip # pip install sqlalchemy ORM DDD MVC pip install pymysql # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # OS : windows 10 # python.exe -m pip install --upgrade pip # pip install pymysql pip install SQLAlchemy # pip3 install pyqt6 # pip install pyside6 # pip install pyqt6-tools # database : mysql 9.0 sql server 2019, postgreSQL 17.0 oracle 21c Neo4j # Datetime : 2025/3/20 20:32 # User : geovindu # Product : PyCharm # Project : pyMySqlDDDOrmDemo # File : main.py # explain : 学习 ''' create table School #創建表 ( `SchoolId` char(5) NOT NULL comment'主鍵primary key,學校編號', #採取手工輸入,也可以設計為自動添加自增長 為5位元,數位,字元,或數位和字元組合,在文本保存資料時,用程式碼進行限制 #`SchoolId` int(11) NOT NULL AUTO_INCREMENT comment'學校編號', #設計為自增長 `SchoolName` nvarchar(500) NOT NULL DEFAULT '' comment' 學校名稱', `SchoolTelNo` varchar(8) NULL DEFAULT '' comment'電話號碼', PRIMARY KEY (`SchoolId`) #主鍵 )ENGINE=MyISAM COMMENT='學校表 School Table' DEFAULT CHARSET=utf8; 、 create table Teacher #創建表 ( `TeacherId` char(5) NOT NULL comment'主鍵primary key,學生編號', `TeacherFirstName` nvarchar(100) NOT NULL DEFAULT '' comment' 名', `TeacherLastName` nvarchar(20) NOT NULL DEFAULT '' comment' 姓', `TeacherGender` char(2) NOT NULL DEFAULT '' comment'性別', `TeacherTelNo` varchar(8) NULL DEFAULT '' comment'電話號碼', `TeacherSchoolId` char(5) NOT NULL DEFAULT '' comment'外鍵 foreign key 學校ID', PRIMARY KEY (`TeacherId`), #主鍵 CONSTRAINT TeacherSchool_ibfk_1 FOREIGN KEY(TeacherSchoolId) REFERENCES School(SchoolId) #外鍵 )ENGINE=MyISAM COMMENT='老師表Teacher Table' DEFAULT CHARSET=utf8; CREATE TABLE Userlist ( `Id` int(11) NOT NULL AUTO_INCREMENT COMMENT '', `UserName` nvarchar(500) NOT NULL DEFAULT '' COMMENT '名称', `Password` varchar(18) NULL DEFAULT '' COMMENT '密码', `email` varchar(50) NULL DEFAULT '' COMMENT '邮件', PRIMARY KEY (`Id`) ) COMMENT='用户表' DEFAULT CHARSET=utf8; ''' import sys from PyQt6.QtWidgets import QApplication, QTabWidget, QWidget, QVBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox,QMenuBar, QMenu, QMainWindow,QStackedWidget from PyQt6.QtGui import QIcon from PyQt6.QtGui import QAction from PyQt6.QtSql import QSqlDatabase, QSqlQuery from presentation.controllers.school import SchoolController from presentation.views.school import SchoolView from presentation.controllers.teacher import TeacherController from presentation.views.teacher import TeacherView from presentation.Presenter.school import SchoolPresenter from presentation.Presenter.teacher import TeacherPresenter from presentation.views.user import UserView from presentation.controllers.user import UserController from presentation.Presenter.user import UserPresenter ''' # 1 ok class MainWindow(QWidget): """ # 假设其他导入和控制器/视图类已正确实现 """ def __init__(self): super().__init__() self.presenters = {} # 使用字典持久保存Presenter self.initUI() def initUI(self): self.tab_widget = QTabWidget(self) # 学校视图 self.school_view = SchoolView() school_controller = SchoolController() SchoolPresenter(self.school_view, school_controller) self.presenters['school'] = SchoolPresenter # 保持强引用 self.tab_widget.addTab(self.school_view, "学校管理") # 教师视图 self.teacher_view = TeacherView() teacher_controller = TeacherController() TeacherPresenter(self.teacher_view, teacher_controller, school_controller) self.presenters['teacher'] = TeacherPresenter # 保持强引用 self.tab_widget.addTab(self.teacher_view, "教师管理") # 用户视图 self.user_view = UserView() user_controller = UserController() UserPresenter(self.user_view, user_controller) self.presenters['user'] = UserPresenter # 保持强引用 self.tab_widget.addTab(self.user_view, "用户管理") layout = QVBoxLayout(self) layout.addWidget(self.tab_widget) self.setLayout(layout) self.setWindowTitle("主管理界面") self.resize(800, 600) class LoginWindow(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): layout = QVBoxLayout() self.username_label = QLabel("用户名:") self.username_input = QLineEdit() self.password_label = QLabel("密码:") self.password_input = QLineEdit() self.password_input.setEchoMode(QLineEdit.EchoMode.Password) self.login_button = QPushButton("登录") self.login_button.clicked.connect(self.login) layout.addWidget(self.username_label) layout.addWidget(self.username_input) layout.addWidget(self.password_label) layout.addWidget(self.password_input) layout.addWidget(self.login_button) self.setLayout(layout) self.setWindowTitle("登录") self.setFixedSize(300, 200) def login(self): username = self.username_input.text() password = self.password_input.text() ubll = UserController() user = ubll.get_user_by_username(username) if user and user.password == password: self.main_window = MainWindow() # 创建主窗口实例 self.main_window.show() # 显示主窗口 self.close() # 关闭登录窗口 else: QMessageBox.warning(self, "登录失败", "用户名或密码错误") if __name__ == '__main__': try: app = QApplication(sys.argv) app.setWindowIcon(QIcon('./favicon.ico')) login_window = LoginWindow() login_window.show() sys.exit(app.exec()) except Exception as e: QMessageBox.critical(None, "启动错误", f"应用程序启动失败: {str(e)}") sys.exit(1) ''' ''' 2 ok tab 考虑事件无效问题 class LoginWindow(QWidget): def __init__(self): super().__init__() self.initUI() # self.db = self.connect_to_database() self.tab_widget = None def initUI(self): layout = QVBoxLayout() self.username_label = QLabel("用户名:") self.username_input = QLineEdit() self.password_label = QLabel("密码:") self.password_input = QLineEdit() self.password_input.setEchoMode(QLineEdit.EchoMode.Password) self.login_button = QPushButton("登录") self.login_button.clicked.connect(self.login) layout.addWidget(self.username_label) layout.addWidget(self.username_input) layout.addWidget(self.password_label) layout.addWidget(self.password_input) layout.addWidget(self.login_button) self.setLayout(layout) self.setWindowTitle("登录") def login(self): username = self.username_input.text() password = self.password_input.text() print('login') ubll = UserController() user = ubll.get_user_by_username(username) print("user:", user) if user is None or user.password != password: QMessageBox.warning(self, "登录失败", "用户名或密码错误,请重试。") else: QMessageBox.information(self, "登录成功", "欢迎登录!") self.show_main_window() self.close() def show_main_window(self): try: # 不设置父窗口 self.tab_widget = QTabWidget() school_view = SchoolView() school_controller = SchoolController() school_presenter = SchoolPresenter(school_view, school_controller) self.tab_widget.addTab(school_view, "Schools") teacher_view = TeacherView() teacher_controller = TeacherController() teacher_presenter = TeacherPresenter(teacher_view, teacher_controller, school_controller) self.tab_widget.addTab(teacher_view, "Teachers") user_view = UserView() user_controller = UserController() user_presenter = UserPresenter(user_view, user_controller) #self.presenters['uers'] = user_presenter # 保持强引用 self.tab_widget.addTab(user_view, "Users") self.tab_widget.show() except Exception as e: QMessageBox.critical(self, "主窗体显示错误", f"显示主窗体时出现错误: {str(e)}") if __name__ == '__main__': try: app = QApplication(sys.argv) app.setWindowIcon(QIcon('./favicon.ico')) login_window = LoginWindow() login_window.show() sys.exit(app.exec()) except Exception as e: print(f"启动应用程序时出错: {e}") ''' # 3 菜单式的 ok class LoginWindow(QWidget): def __init__(self): super().__init__() self.initUI() self.school_view = None self.teacher_view = None self.user_view = None self.school_presenter = None self.teacher_presenter = None self.user_presenter = None self.main_window = None # 新增类属性 def initUI(self): layout = QVBoxLayout() self.username_label = QLabel("用户名:") self.username_input = QLineEdit() self.password_label = QLabel("密码:") self.password_input = QLineEdit() self.password_input.setEchoMode(QLineEdit.EchoMode.Password) self.login_button = QPushButton("登录") self.login_button.clicked.connect(self.login) layout.addWidget(self.username_label) layout.addWidget(self.username_input) layout.addWidget(self.password_label) layout.addWidget(self.password_input) layout.addWidget(self.login_button) self.setLayout(layout) self.setWindowTitle("登录") def login(self): username = self.username_input.text() password = self.password_input.text() ubll = UserController() user = ubll.get_user_by_username(username) print("user:", user) if user is None or user.password != password: QMessageBox.warning(self, "登录失败", "用户名或密码错误,请重试。") else: QMessageBox.information(self, "登录成功", "欢迎登录!") self.show_main_window() self.close() def show_main_window(self): try: # 正确创建主窗口并保持引用 self.main_window = QMainWindow() # 不再需要 QApplication.instance() self.main_window.setWindowTitle("Main Window") # 创建菜单栏 (关键修改1:直接使用 main_window 的方法创建) menu_bar = self.main_window.menuBar() # 这是正确获取 QMainWindow 菜单栏的方法 # 创建菜单项 main_menu = menu_bar.addMenu("Main") # 创建动作并绑定 (关键修改2:指定父级为菜单栏) schools_action = QAction("Schools", menu_bar) schools_action.triggered.connect(self.show_schools_view) main_menu.addAction(schools_action) teachers_action = QAction("Teachers", menu_bar) teachers_action.triggered.connect(self.show_teachers_view) main_menu.addAction(teachers_action) users_action = QAction("Users", menu_bar) users_action.triggered.connect(self.show_users_view) main_menu.addAction(users_action) # 初始化视图和 Presenter self.init_views() # 设置中央部件 (关键修改3:使用 StackedWidget 管理视图切换) self.stacked_widget = QStackedWidget() self.stacked_widget.addWidget(self.school_view) self.stacked_widget.addWidget(self.teacher_view) self.stacked_widget.addWidget(self.user_view) self.main_window.setCentralWidget(self.stacked_widget) # 设置窗口属性 self.main_window.setMinimumSize(800, 600) self.main_window.show() except Exception as e: import traceback traceback.print_exc() QMessageBox.critical(self, "Error", f"Failed to show main window: {str(e)}") def init_views(self): """初始化所有视图和 Presenter""" # 学校视图 self.school_view = SchoolView() school_controller = SchoolController() self.school_presenter = SchoolPresenter(self.school_view, school_controller) # 教师视图 self.teacher_view = TeacherView() teacher_controller = TeacherController() self.teacher_presenter = TeacherPresenter(self.teacher_view, teacher_controller, school_controller) # 用户视图 self.user_view = UserView() user_controller = UserController() self.user_presenter = UserPresenter(self.user_view, user_controller) def show_schools_view(self): self.school_view.show() self.teacher_view.hide() self.user_view.hide() def show_teachers_view(self): self.school_view.hide() self.teacher_view.show() self.user_view.hide() def show_users_view(self): self.school_view.hide() self.teacher_view.hide() self.user_view.show() if __name__ == '__main__': """ """ app = QApplication(sys.argv) login_window = LoginWindow() login_window.show() sys.exit(app.exec())
https://doc.qt.io/qtforpython-6/PySide6/QtGui/QAction.html
如果把main.py写
# encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/3/30 13:12 # User : geovindu # Product : PyCharm # Project : pymysqlDDDQt # File : login.py # explain : 学习 import sys from PyQt6.QtWidgets import QApplication, QTabWidget, QWidget, QVBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox,QMenuBar, QMenu, QMainWindow,QStackedWidget from PyQt6.QtGui import QIcon from PyQt6.QtGui import QAction from PyQt6.QtSql import QSqlDatabase, QSqlQuery ''' # 1 ok class MainWindow(QWidget): """ # 假设其他导入和控制器/视图类已正确实现 """ def __init__(self): super().__init__() self.presenters = {} # 使用字典持久保存Presenter self.initUI() def initUI(self): self.tab_widget = QTabWidget(self) # 学校视图 self.school_view = SchoolView() school_controller = SchoolController() SchoolPresenter(self.school_view, school_controller) self.presenters['school'] = SchoolPresenter # 保持强引用 self.tab_widget.addTab(self.school_view, "学校管理") # 教师视图 self.teacher_view = TeacherView() teacher_controller = TeacherController() TeacherPresenter(self.teacher_view, teacher_controller, school_controller) self.presenters['teacher'] = TeacherPresenter # 保持强引用 self.tab_widget.addTab(self.teacher_view, "教师管理") # 用户视图 self.user_view = UserView() user_controller = UserController() UserPresenter(self.user_view, user_controller) self.presenters['user'] = UserPresenter # 保持强引用 self.tab_widget.addTab(self.user_view, "用户管理") layout = QVBoxLayout(self) layout.addWidget(self.tab_widget) self.setLayout(layout) self.setWindowTitle("主管理界面") self.resize(800, 600) class LoginWindow(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): layout = QVBoxLayout() self.username_label = QLabel("用户名:") self.username_input = QLineEdit() self.password_label = QLabel("密码:") self.password_input = QLineEdit() self.password_input.setEchoMode(QLineEdit.EchoMode.Password) self.login_button = QPushButton("登录") self.login_button.clicked.connect(self.login) layout.addWidget(self.username_label) layout.addWidget(self.username_input) layout.addWidget(self.password_label) layout.addWidget(self.password_input) layout.addWidget(self.login_button) self.setLayout(layout) self.setWindowTitle("登录") self.setFixedSize(300, 200) def login(self): username = self.username_input.text() password = self.password_input.text() ubll = UserController() user = ubll.get_user_by_username(username) if user and user.password == password: self.main_window = MainWindow() # 创建主窗口实例 self.main_window.show() # 显示主窗口 self.close() # 关闭登录窗口 else: QMessageBox.warning(self, "登录失败", "用户名或密码错误") if __name__ == '__main__': try: app = QApplication(sys.argv) app.setWindowIcon(QIcon('./favicon.ico')) login_window = LoginWindow() login_window.show() sys.exit(app.exec()) except Exception as e: QMessageBox.critical(None, "启动错误", f"应用程序启动失败: {str(e)}") sys.exit(1) ''' ''' 2 ok tab 考虑事件无效问题 class LoginWindow(QWidget): def __init__(self): super().__init__() self.initUI() # self.db = self.connect_to_database() self.tab_widget = None def initUI(self): layout = QVBoxLayout() self.username_label = QLabel("用户名:") self.username_input = QLineEdit() self.password_label = QLabel("密码:") self.password_input = QLineEdit() self.password_input.setEchoMode(QLineEdit.EchoMode.Password) self.login_button = QPushButton("登录") self.login_button.clicked.connect(self.login) layout.addWidget(self.username_label) layout.addWidget(self.username_input) layout.addWidget(self.password_label) layout.addWidget(self.password_input) layout.addWidget(self.login_button) self.setLayout(layout) self.setWindowTitle("登录") def login(self): username = self.username_input.text() password = self.password_input.text() print('login') ubll = UserController() user = ubll.get_user_by_username(username) print("user:", user) if user is None or user.password != password: QMessageBox.warning(self, "登录失败", "用户名或密码错误,请重试。") else: QMessageBox.information(self, "登录成功", "欢迎登录!") self.show_main_window() self.close() def show_main_window(self): try: # 不设置父窗口 self.tab_widget = QTabWidget() school_view = SchoolView() school_controller = SchoolController() school_presenter = SchoolPresenter(school_view, school_controller) self.tab_widget.addTab(school_view, "Schools") teacher_view = TeacherView() teacher_controller = TeacherController() teacher_presenter = TeacherPresenter(teacher_view, teacher_controller, school_controller) self.tab_widget.addTab(teacher_view, "Teachers") user_view = UserView() user_controller = UserController() user_presenter = UserPresenter(user_view, user_controller) #self.presenters['uers'] = user_presenter # 保持强引用 self.tab_widget.addTab(user_view, "Users") self.tab_widget.show() except Exception as e: QMessageBox.critical(self, "主窗体显示错误", f"显示主窗体时出现错误: {str(e)}") if __name__ == '__main__': try: app = QApplication(sys.argv) app.setWindowIcon(QIcon('./favicon.ico')) login_window = LoginWindow() login_window.show() sys.exit(app.exec()) except Exception as e: print(f"启动应用程序时出错: {e}") ''' # 3 菜单式的 ok class LoginWindow(QWidget): def __init__(self): super().__init__() self.initUI() self.school_view = None self.teacher_view = None self.user_view = None self.school_presenter = None self.teacher_presenter = None self.user_presenter = None self.main_window = None # 新增类属性 def initUI(self): layout = QVBoxLayout() self.username_label = QLabel("用户名:") self.username_input = QLineEdit() self.password_label = QLabel("密码:") self.password_input = QLineEdit() self.password_input.setEchoMode(QLineEdit.EchoMode.Password) self.login_button = QPushButton("登录") self.login_button.clicked.connect(self.login) layout.addWidget(self.username_label) layout.addWidget(self.username_input) layout.addWidget(self.password_label) layout.addWidget(self.password_input) layout.addWidget(self.login_button) self.setLayout(layout) self.setWindowTitle("登录") def login(self): username = self.username_input.text() password = self.password_input.text() from presentation.controllers.user import UserController ubll = UserController() user = ubll.get_user_by_username(username) print("user:", user) if user is None or user.password != password: QMessageBox.warning(self, "登录失败", "用户名或密码错误,请重试。") else: QMessageBox.information(self, "登录成功", "欢迎登录!") self.show_main_window() self.close() def show_main_window(self): try: # 正确创建主窗口并保持引用 self.main_window = QMainWindow() # 不再需要 QApplication.instance() self.main_window.setWindowTitle("Main Window") # 创建菜单栏 (关键修改1:直接使用 main_window 的方法创建) menu_bar = self.main_window.menuBar() # 这是正确获取 QMainWindow 菜单栏的方法 # 创建菜单项 main_menu = menu_bar.addMenu("Main") # 创建动作并绑定 (关键修改2:指定父级为菜单栏) schools_action = QAction("Schools", menu_bar) schools_action.triggered.connect(self.show_schools_view) main_menu.addAction(schools_action) teachers_action = QAction("Teachers", menu_bar) teachers_action.triggered.connect(self.show_teachers_view) main_menu.addAction(teachers_action) users_action = QAction("Users", menu_bar) users_action.triggered.connect(self.show_users_view) main_menu.addAction(users_action) # 初始化视图和 Presenter self.init_views() # 设置中央部件 (关键修改3:使用 StackedWidget 管理视图切换) self.stacked_widget = QStackedWidget() self.stacked_widget.addWidget(self.school_view) self.stacked_widget.addWidget(self.teacher_view) self.stacked_widget.addWidget(self.user_view) self.main_window.setCentralWidget(self.stacked_widget) # 设置窗口属性 self.main_window.setMinimumSize(800, 600) self.main_window.show() except Exception as e: import traceback traceback.print_exc() QMessageBox.critical(self, "Error", f"Failed to show main window: {str(e)}") def init_views(self): """ 初始化所有视图和 Presenter """ from presentation.controllers.school import SchoolController from presentation.views.school import SchoolView from presentation.controllers.teacher import TeacherController from presentation.views.teacher import TeacherView from presentation.Presenter.school import SchoolPresenter from presentation.Presenter.teacher import TeacherPresenter from presentation.views.user import UserView from presentation.controllers.user import UserController from presentation.Presenter.user import UserPresenter # 学校视图 self.school_view = SchoolView() school_controller = SchoolController() self.school_presenter = SchoolPresenter(self.school_view, school_controller) # 教师视图 self.teacher_view = TeacherView() teacher_controller = TeacherController() self.teacher_presenter = TeacherPresenter(self.teacher_view, teacher_controller, school_controller) # 用户视图 self.user_view = UserView() user_controller = UserController() self.user_presenter = UserPresenter(self.user_view, user_controller) def show_schools_view(self): self.school_view.show() self.teacher_view.hide() self.user_view.hide() def show_teachers_view(self): self.school_view.hide() self.teacher_view.show() self.user_view.hide() def show_users_view(self): self.school_view.hide() self.teacher_view.hide() self.user_view.show()
# encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司 ® # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: python.exe -m pip install --upgrade pip # pip install sqlalchemy ORM DDD MVC pip install pymysql # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # OS : windows 10 https://doc.qt.io/qtforpython-6/PySide6/QtGui/QAction.html # python.exe -m pip install --upgrade pip # pip install pymysql pip install SQLAlchemy # pip3 install pyqt6 # pip install pyside6 # pip install pyqt6-tools # database : mysql 9.0 sql server 2019, postgreSQL 17.0 oracle 21c Neo4j # Datetime : 2025/3/20 20:32 # User : geovindu # Product : PyCharm # Project : pyMySqlDDDOrmDemo # File : main.py # explain : 学习 ''' create table School #創建表 ( `SchoolId` char(5) NOT NULL comment'主鍵primary key,學校編號', #採取手工輸入,也可以設計為自動添加自增長 為5位元,數位,字元,或數位和字元組合,在文本保存資料時,用程式碼進行限制 #`SchoolId` int(11) NOT NULL AUTO_INCREMENT comment'學校編號', #設計為自增長 `SchoolName` nvarchar(500) NOT NULL DEFAULT '' comment' 學校名稱', `SchoolTelNo` varchar(8) NULL DEFAULT '' comment'電話號碼', PRIMARY KEY (`SchoolId`) #主鍵 )ENGINE=MyISAM COMMENT='學校表 School Table' DEFAULT CHARSET=utf8; 、 create table Teacher #創建表 ( `TeacherId` char(5) NOT NULL comment'主鍵primary key,學生編號', `TeacherFirstName` nvarchar(100) NOT NULL DEFAULT '' comment' 名', `TeacherLastName` nvarchar(20) NOT NULL DEFAULT '' comment' 姓', `TeacherGender` char(2) NOT NULL DEFAULT '' comment'性別', `TeacherTelNo` varchar(8) NULL DEFAULT '' comment'電話號碼', `TeacherSchoolId` char(5) NOT NULL DEFAULT '' comment'外鍵 foreign key 學校ID', PRIMARY KEY (`TeacherId`), #主鍵 CONSTRAINT TeacherSchool_ibfk_1 FOREIGN KEY(TeacherSchoolId) REFERENCES School(SchoolId) #外鍵 )ENGINE=MyISAM COMMENT='老師表Teacher Table' DEFAULT CHARSET=utf8; CREATE TABLE Userlist ( `Id` int(11) NOT NULL AUTO_INCREMENT COMMENT '', `UserName` nvarchar(500) NOT NULL DEFAULT '' COMMENT '名称', `Password` varchar(18) NULL DEFAULT '' COMMENT '密码', `email` varchar(50) NULL DEFAULT '' COMMENT '邮件', PRIMARY KEY (`Id`) ) COMMENT='用户表' DEFAULT CHARSET=utf8; 项目结构 application --services --school.py --teacher.py domain --entities --school.py --teacher.py --repositories --school.py --teacher.py infrastructure --database --mysqlHelper.py --model --school.py --teacher.py --repositories --school.py --teacher.py presentation --controllers --school.py --teacher.py --presenters --school.py --teacher.py --views --school.py --teacher.py main.py ''' import sys from PyQt6.QtWidgets import QApplication, QTabWidget, QWidget, QVBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox,QMenuBar, QMenu, QMainWindow,QStackedWidget from PyQt6.QtGui import QIcon from PyQt6.QtGui import QAction from PyQt6.QtSql import QSqlDatabase, QSqlQuery from presentation.views.login import LoginWindow if __name__ == '__main__': """ """ app = QApplication(sys.argv) app.setWindowIcon(QIcon('./favicon.ico')) login_window = LoginWindow() login_window.show() sys.exit(app.exec())
def init_views(self): """ 初始化所有视图和 Presenter from presentation.controllers.school import SchoolController from presentation.views.school import SchoolView from presentation.controllers.teacher import TeacherController from presentation.views.teacher import TeacherView from presentation.Presenter.school import SchoolPresenter from presentation.Presenter.teacher import TeacherPresenter from presentation.views.user import UserView from presentation.controllers.user import UserController from presentation.Presenter.user import UserPresenter # 写在文件头 from presentation.controllers import * from presentation.Presenter import * from presentation.views import * """ from presentation.controllers import SchoolController,TeacherController,UserController from presentation.Presenter import SchoolPresenter,TeacherPresenter,UserPresenter from presentation.views import SchoolView,TeacherView,UserView
# encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/3/29 21:33 # User : geovindu # Product : PyCharm # Project : pymysqlDDDQt # File : __init__.py # explain : 学习 from .Presenter.school import SchoolPresenter from .Presenter.teacher import TeacherPresenter from .Presenter.user import UserPresenter from .controllers.school import SchoolController from .controllers.teacher import TeacherController from .controllers.user import UserController from .views.school import SchoolView from .views.teacher import TeacherView from .views.user import UserView from .views.login import LoginWindow __all__ = ['SchoolController','TeacherController','UserController','SchoolPresenter','TeacherPresenter','UserPresenter','SchoolView','TeacherView','UserView','LoginWindow']
哲学管理(学)人生, 文学艺术生活, 自动(计算机学)物理(学)工作, 生物(学)化学逆境, 历史(学)测绘(学)时间, 经济(学)数学金钱(理财), 心理(学)医学情绪, 诗词美容情感, 美学建筑(学)家园, 解构建构(分析)整合学习, 智商情商(IQ、EQ)运筹(学)生存.---Geovin Du(涂聚文)