1. 配置Pycharm外部工具
点击Settings
找到External Tools 即,外部工具,点击右侧面板的加号添加
输入工具名称Name,Program填写外部工具程序的exe地址,Arguments填写数据参数,Working directory填写文件的工作地址
Pycharm提供了宏命令,点击加号可以查看Macros为宏命令,底下的Macro preview可以查看当前宏命令的内容
使用pycharm外部文件命令,唤出Qt Creator打开对应的ui文件
配置Qt Creator
Program: D:\qt562\Tools\QtCreator\bin\qtcreator.exe
Arguments: $FilePath$
Working directory: $FileDir$
参数解释:
使用安装好的Qt Creator软件,输入参数(Argument)即文件地址,使用Qt Creator软件打开当前的文件
配置PyUIC
PyUIC的作用是将ui文件转换为py文件
Program: D:\Anaconda3501\envs\python368\python.exe
Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
Working directory: $FileDir$
参数解释:
程序调用python文件,执行python.exe -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py表示使用PyQt5.uic.pyuic命令,执行当前文件名,-o输出的地址为$FileNameWithoutExtension$.py,即将$FileName$文件转换为python文件
2. Qt Creator命令 找到Qt Creator的位置,执行命令qtcreator.exe -h可以看到程序的命令介绍
3. Qt Designer命令 qt designer是python的一个库文件,位置一般在python385\Lib\site-packages\qt5_applications\Qt\bin
找到Qt Designer的位置,执行命令designer.exe -h可以看到程序的命令介绍
4. 对话框居中 dialog = QtWidgets.QDialog(MainWindow) d = Ui_Dialog() d.setupUi(dialog) screen = QApplication.desktop() dialog_size = dialog.geometry() x = (screen.width() - dialog_size.width()) // 2 y = (screen.height() - dialog_size.height()) // 2 dialog.setGeometry(x, y, dialog_size.width(), dialog_size.height()) dialog.exec_()
item = QtWidgets.QListWidgetItem() item.setData(1 , 'SYS01' ) item.setData(2 , 1 ) item.setData(3 , { 'id' : 1 ,'name' : 'test' }) item.setText(_translate("Dialog" , "微易邮箱配置" ))
为listWidget_2添加邮件自定义菜单
def __init__ (self ): """ """ self.listWidget_2.setContextMenuPolicy(Qt.CustomContextMenu) self.listWidget_2.customContextMenuRequested.connect(self.show_email_context_menu) def show_email_context_menu (self, position ): """ 自定义右键邮件配置菜单 :return: """ menu = QMenu() update_action = QAction("修改" , menu) update_action.triggered.connect(self.open_update_email_config) menu.addAction(update_action) delete_action = QAction("删除" , menu) delete_action.triggered.connect(self.delete_email_config) menu.addAction(delete_action) menu.exec_(self.listWidget_2.viewport().mapToGlobal(position))
7. QT开发服务流程 Dao层、Service层、Controller层
Dao层主要与数据库交互
Service层主要实现业务逻辑
Controller层主要处理业务层所需要的数据
Dao层出错 :
Dao层遇到错误,应该将其抛到Service层
Dao层
class EmailConfigDao : def __init__ (self ): pass def select_all_email_config (self ): """ 查询所有邮箱配置 """ sql = """ SELECT * FROM EmailConfig """ res = None try : res = db.fetch_all(sql) except Exception as err: print (err) raise err return res
Service层
class EmailConfigService : """ 邮箱配置Service层 """ def __init__ (self ): self.email_config_dao = EmailConfigDao() def select_all_email_config (self ): """ 查询所有邮箱配置 """ res = None try : res = self.email_config_dao.select_all_email_config() except Exception as err: print (err) return False , "获取数据失败" return JsonUtil.database_data_to_list_json(res)
8. 启动QT的同时启动FLask 可以在 PyQt 的主线程中启动 Flask 服务,但是为了避免阻塞 GUI,需要再线程中启动 Flask 服务。同时,当 PyQt 应用退出时,也可以关闭 Flask 服务。
class FlaskThreading (Thread ): """ 启动Flask线程 """ def __init__ (self ): Thread.__init__(self) self.srv = None self.app = app self.ctx = self.app.app_context() self.ctx.push() def run (self ): """ 启动线程 :return: """ try : self.srv = make_server(HOST, PORT, self.app) print ("Flask正在运行..." ) self.srv.serve_forever() except Exception as err: print ("启动错误【%s】" % str (err)) def shutdown (self ): """ 关闭线程 :return: """ try : self.srv.shutdown() print ("成功关闭Flask" ) except Exception as err: print ("关闭错误【%s】" % str (err))
def shutdown_flask (): """ 关闭Flask线程 :return: """ flask_threading.shutdown() if __name__ == '__main__' : init_table() qt_app = QApplication(sys.argv) my_main_win = Main() my_main_win.show() qt_app.aboutToQuit.connect(shutdown_flask) flask_threading.start() sys.exit(qt_app.exec ())
9. ui文件与逻辑代码分离 新建UI文件夹,implement为对应ui文件的逻辑文件。
可以使用继承,通过self访问父级属性
from PyQt5.QtWidgets import QDialogfrom service.EmailConfigService import EmailConfigServicefrom UI.emailConfig import Ui_Dialogfrom UI.component.Message import Message from common.Validate import Validateclass EmailConfig (QDialog, Ui_Dialog): """ 邮件配置窗口 """ def __init__ (self, call_back=None , config_mode='add' ): super (EmailConfig, self).__init__() self.setupUi(self) self.setWindowTitle("邮箱配置" ) self.call_back = call_back self.config_mode = config_mode self.data = {} self.email_config_service = EmailConfigService() self.pushButton.clicked.connect(self.save) self.pushButton_2.clicked.connect(self.cancel)
10. 主窗口 同样使用继承
class Main (QMainWindow, Ui_MainWindow): def __init__ (self ): super (Main, self).__init__() self.setupUi(self) self.setWindowTitle("邮件和短信服务" ) self.exportConfigDialog = None self.action.triggered.connect(self.open_config) def open_config (self ): """ 打开配置导航栏 :return: """ self.exportConfigDialog = ConfigDialog() self.exportConfigDialog.exec ()
打开窗口的写法
self.exportConfigDialog = ConfigDialog() self.exportConfigDialog.exec ()
启动窗口
if __name__ == '__main__' : qt_app = QApplication(sys.argv) my_main_win = Main() my_main_win.show() sys.exit(qt_app.exec ())
11. 定时器 场景:两个线程同时使用一个日志类,该日志类会使用qt的TextBrowser将日志输出。如果日志数量太多,就会导致qt界面卡顿、闪退
解决方案:使用Qt定时器,将日志内容分段输出,避免使用线程的同时操作Qt
class MyLoggerInfo (MyLogger ): text_browser = None lock = threading.Lock() log_cache = [] def __init__ (self ): super ().__init__() @staticmethod def set_text_browser (text_browser ): """ 设置日志信息框 :param text_browser: :return: """ MyLoggerInfo.text_browser = text_browser def print_log (self, msg, level='INFO' ): """ 输出日志 :param msg: 日志信息 :param level: 日志等级 :return: """ with self.lock: text_log = super ().print_log(msg, level) MyLoggerInfo.log_cache.append(StringUtils.get_formate_info_color(msg, level)) return text_log @staticmethod def display_logs (): """ 用于分段输出日志 :return: """ show_logs_num = 10 to_show = MyLoggerInfo.log_cache[:show_logs_num] MyLoggerInfo.log_cache = MyLoggerInfo.log_cache[show_logs_num:] for log_msg in to_show: if MyLoggerInfo.text_browser is not None : MyLoggerInfo.text_browser.append(log_msg) MyLoggerInfo.text_browser.verticalScrollBar().setValue( MyLoggerInfo.text_browser.verticalScrollBar().maximum())
if __name__ == '__main__' : init_table() qt_app = QApplication(sys.argv) my_main_win = Main() timer = QTimer() my_logger_info = MyLoggerInfo() MyLoggerInfo.set_text_browser(my_main_win.textBrowser_2) timer.timeout.connect(my_logger_info.display_logs) timer.start(1000 ) qt_app.aboutToQuit.connect(my_main_win.shutdown_threading) my_main_win.open_threading() my_main_win.showMaximized() my_main_win.show() sys.exit(qt_app.exec ())
在该日志类添加一个缓存日志log_cache,使用静态是为了保证所有的日志都在该缓存日志里
在该日志类添加一个输出日志方法display_logs,用于展示日志信息
在主函数中,实例化定时器,将display_logs方法绑定到该定时器中