126 lines
3.8 KiB
Python
126 lines
3.8 KiB
Python
import ctypes
|
|
import platform
|
|
import sys
|
|
import traceback
|
|
import webbrowser
|
|
import types
|
|
import threading
|
|
|
|
import qdarkstyle # type: ignore
|
|
from PySide6 import QtGui, QtWidgets, QtCore
|
|
from loguru import logger
|
|
|
|
from ..setting import SETTINGS
|
|
from ..utility import get_icon_path
|
|
from ..locale import _
|
|
|
|
|
|
Qt = QtCore.Qt
|
|
|
|
|
|
def create_qapp(app_name: str = "VeighNa Trader") -> QtWidgets.QApplication:
|
|
"""
|
|
Create Qt Application.
|
|
"""
|
|
# Set up dark stylesheet
|
|
qapp: QtWidgets.QApplication = QtWidgets.QApplication(sys.argv)
|
|
qapp.setStyleSheet(qdarkstyle.load_stylesheet(qt_api="pyside6"))
|
|
|
|
# Set up font
|
|
font: QtGui.QFont = QtGui.QFont(SETTINGS["font.family"], SETTINGS["font.size"])
|
|
qapp.setFont(font)
|
|
|
|
# Set up icon
|
|
icon: QtGui.QIcon = QtGui.QIcon(get_icon_path(__file__, "vnpy.ico"))
|
|
qapp.setWindowIcon(icon)
|
|
|
|
# Set up windows process ID
|
|
if "Windows" in platform.uname():
|
|
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
|
|
app_name
|
|
)
|
|
|
|
# Exception Handling
|
|
exception_widget: ExceptionWidget = ExceptionWidget()
|
|
|
|
def excepthook(
|
|
exc_type: type[BaseException],
|
|
exc_value: BaseException,
|
|
exc_traceback: types.TracebackType | None
|
|
) -> None:
|
|
"""Show exception detail with QMessageBox."""
|
|
logger.opt(exception=(exc_type, exc_value, exc_traceback)).critical("Main thread exception")
|
|
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
|
|
|
msg: str = "".join(traceback.format_exception(exc_type, exc_value, exc_traceback))
|
|
exception_widget.signal.emit(msg)
|
|
|
|
sys.excepthook = excepthook
|
|
|
|
def threading_excepthook(args: threading.ExceptHookArgs) -> None:
|
|
"""Show exception detail from background threads with QMessageBox."""
|
|
if args.exc_value and args.exc_traceback:
|
|
logger.opt(exception=(args.exc_type, args.exc_value, args.exc_traceback)).critical("Background thread exception")
|
|
sys.__excepthook__(args.exc_type, args.exc_value, args.exc_traceback)
|
|
|
|
msg: str = "".join(traceback.format_exception(args.exc_type, args.exc_value, args.exc_traceback))
|
|
exception_widget.signal.emit(msg)
|
|
|
|
threading.excepthook = threading_excepthook
|
|
|
|
return qapp
|
|
|
|
|
|
class ExceptionWidget(QtWidgets.QWidget):
|
|
""""""
|
|
signal: QtCore.Signal = QtCore.Signal(str)
|
|
|
|
def __init__(self, parent: QtWidgets.QWidget | None = None) -> None:
|
|
""""""
|
|
super().__init__(parent)
|
|
|
|
self.init_ui()
|
|
self.signal.connect(self.show_exception)
|
|
|
|
def init_ui(self) -> None:
|
|
""""""
|
|
self.setWindowTitle(_("触发异常"))
|
|
self.setFixedSize(600, 600)
|
|
|
|
self.msg_edit: QtWidgets.QTextEdit = QtWidgets.QTextEdit()
|
|
self.msg_edit.setReadOnly(True)
|
|
|
|
copy_button: QtWidgets.QPushButton = QtWidgets.QPushButton(_("复制"))
|
|
copy_button.clicked.connect(self._copy_text)
|
|
|
|
community_button: QtWidgets.QPushButton = QtWidgets.QPushButton(_("求助"))
|
|
community_button.clicked.connect(self._open_community)
|
|
|
|
close_button: QtWidgets.QPushButton = QtWidgets.QPushButton(_("关闭"))
|
|
close_button.clicked.connect(self.close)
|
|
|
|
hbox: QtWidgets.QHBoxLayout = QtWidgets.QHBoxLayout()
|
|
hbox.addWidget(copy_button)
|
|
hbox.addWidget(community_button)
|
|
hbox.addWidget(close_button)
|
|
|
|
vbox: QtWidgets.QVBoxLayout = QtWidgets.QVBoxLayout()
|
|
vbox.addWidget(self.msg_edit)
|
|
vbox.addLayout(hbox)
|
|
|
|
self.setLayout(vbox)
|
|
|
|
def show_exception(self, msg: str) -> None:
|
|
""""""
|
|
self.msg_edit.setText(msg)
|
|
self.show()
|
|
|
|
def _copy_text(self) -> None:
|
|
""""""
|
|
self.msg_edit.selectAll()
|
|
self.msg_edit.copy()
|
|
|
|
def _open_community(self) -> None:
|
|
""""""
|
|
webbrowser.open("https://www.vnpy.com/forum/forum/2-ti-wen-qiu-zhu")
|