PyQt/图表/PyQtChart/ChartView/ChatWidget.py
2018-11-02 13:38:42 +08:00

256 lines
8.5 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Created on 2017年12月20日
@author: Irony."[讽刺]
@site: http://alyl.vip, http://orzorz.vip, http://coding.net/u/892768447, http://github.com/892768447
@email: 892768447@qq.com
@file: ChatWidget
@description:
'''
from collections import OrderedDict
import json
import os
import sys
from PyQt5.Qsci import QsciScintilla, QsciLexerJSON
from PyQt5.QtChart import QChartView
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QColor, QFont, QFontMetrics, QKeySequence, QMovie
from PyQt5.QtWidgets import QSplitter, QTreeWidget, QApplication, QWidget,\
QVBoxLayout, QPushButton, QTreeWidgetItem, QMessageBox, QShortcut, QLabel
import chardet
from ChartView import ChartView # @UnresolvedImport
__version__ = "0.0.1"
class LoadingWidget(QLabel):
def __init__(self, *args, **kwargs):
super(LoadingWidget, self).__init__(*args, **kwargs)
self.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
self._movie = QMovie("loading.gif")
self.setMovie(self._movie)
def deleteLater(self):
self._movie.stop()
self._movie.deleteLater()
del self._movie
super(LoadingWidget, self).deleteLater()
def show(self):
self.setVisible(True)
super(LoadingWidget, self).show()
self._movie.start()
def closeEvent(self, event):
self._movie.stop()
self.setVisible(False)
super(LoadingWidget, self).closeEvent(event)
class ClassifyWidget(QTreeWidget):
fileSelected = pyqtSignal(str)
def __init__(self, *args, **kwargs):
super(ClassifyWidget, self).__init__(*args, **kwargs)
self.setHeaderHidden(True)
self.setColumnCount(1)
self.itemDoubleClicked.connect(self.onItemDoubleClicked)
baseDir = "分类"
for name in os.listdir(baseDir):
path = os.path.join(baseDir, name)
if os.path.isdir(path):
item = QTreeWidgetItem(self)
item.setText(0, name)
for file in os.listdir(path):
path = os.path.join(path, file)
if os.path.isfile(path) and file.endswith(".json"):
item = QTreeWidgetItem(item)
item.setText(0, os.path.splitext(file)[0])
item.setToolTip(0, path)
self.expandAll()
def onItemDoubleClicked(self, item):
file = item.toolTip(0)
if file:
self.fileSelected.emit(file)
class CodeScintilla(QsciScintilla):
def __init__(self, *args, **kwargs):
super(CodeScintilla, self).__init__(*args, **kwargs)
self.init()
self.linesChanged.connect(self.onLinesChanged)
def onLinesChanged(self):
self.setMarginWidth(0, self.fontMetrics().width(str(self.lines())) + 6)
def init(self):
self.setUtf8(True)
lexer = QsciLexerJSON(self)
self.setLexer(lexer)
self.setAutoCompletionCaseSensitivity(False) # 忽略大小写
self.setAutoCompletionSource(self.AcsAll)
self.setAutoCompletionThreshold(1) # 一个字符就弹出补全
self.setAutoIndent(True) # 自动缩进
self.setBackspaceUnindents(True)
self.setBraceMatching(self.StrictBraceMatch)
self.setIndentationGuides(True)
self.setIndentationsUseTabs(False)
self.setIndentationWidth(4)
self.setTabIndents(True)
self.setTabWidth(4)
self.setWhitespaceSize(1)
self.setWhitespaceVisibility(self.WsVisible)
self.setWhitespaceForegroundColor(Qt.gray)
self.setWrapIndentMode(self.WrapIndentFixed)
self.setWrapMode(self.WrapWord)
# 折叠
self.setFolding(self.BoxedTreeFoldStyle, 2)
self.setFoldMarginColors(QColor("#676A6C"), QColor("#676A6D"))
font = self.font() or QFont()
font.setFamily("Consolas")
font.setFixedPitch(True)
font.setPointSize(13)
self.setFont(font)
self.setMarginsFont(font)
self.fontmetrics = QFontMetrics(font)
lexer.setFont(font)
self.setMarginWidth(0, self.fontmetrics.width(str(self.lines())) + 6)
self.setMarginLineNumbers(0, True)
self.setMarginsBackgroundColor(QColor("gainsboro"))
self.setMarginWidth(1, 0)
self.setMarginWidth(2, 14) # 折叠区域
# 绑定自动补齐热键Alt+/
completeKey = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Slash), self)
completeKey.setContext(Qt.WidgetShortcut)
completeKey.activated.connect(self.autoCompleteFromAll)
class CodeWidget(QWidget):
runSignal = pyqtSignal(str)
def __init__(self, *args, **kwargs):
super(CodeWidget, self).__init__(*args, **kwargs)
layout = QVBoxLayout(self, spacing=0)
layout.setContentsMargins(0, 0, 0, 0)
self.runButton = QPushButton(
"运行", self, objectName="RunButton", clicked=self.onRunButton)
self.codeScintilla = CodeScintilla(self)
layout.addWidget(self.runButton)
layout.addWidget(self.codeScintilla)
def onRunButton(self):
text = self.text()
if not text:
return QMessageBox.information(self, "提示", "json数据不能为空")
self.runSignal.emit(text)
def openFile(self, file):
try:
with open(file, "rb") as fp:
text = fp.read()
encoding = chardet.detect(text) or {}
encoding = encoding.get(
"encoding", "utf-8") or "utf-8"
text = text.decode(encoding)
try:
text = json.dumps(
json.loads(text, encoding=encoding,
object_pairs_hook=OrderedDict),
ensure_ascii=False, indent=4)
except Exception as e:
print(e)
self.setText(text)
except Exception as e:
QMessageBox.critical(self, "错误", str(e))
def setText(self, text):
self.codeScintilla.setText(text)
def text(self):
return self.codeScintilla.text().strip()
class ChartWidget(QWidget):
def __init__(self, *args, **kwargs):
super(ChartWidget, self).__init__(*args, **kwargs)
self.resize(800, 600)
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
self.splitter = QSplitter(self)
layout.addWidget(self.splitter)
self.splitter.setOrientation(Qt.Horizontal)
self.splitter.setStretchFactor(0, 2)
self.splitter.setStretchFactor(1, 3)
self.splitter.setStretchFactor(2, 5)
self.splitter.setAutoFillBackground(True)
self.splitter.setChildrenCollapsible(False)
self.splitter.setHandleWidth(2)
# 分类
self.classifyWidget = ClassifyWidget(self)
self.splitter.addWidget(self.classifyWidget)
# 代码
self.codeWidget = CodeWidget(self)
self.splitter.addWidget(self.codeWidget)
# 等待界面
self.loadingWidget = LoadingWidget(self, visible=False)
self.loadingWidget.resize(self.size())
# 绑定信号槽
self.classifyWidget.fileSelected.connect(self.codeWidget.openFile)
self.codeWidget.runSignal.connect(self.onRun)
def onRun(self, text):
self.setEnabled(False)
self.loadingWidget.show()
# 解析json生成view并添加
if hasattr(self, "previewView"):
# 删除旧view
self.previewView.setParent(None)
self.previewView.setVisible(False)
self.previewView.hide()
self.previewView.deleteLater()
del self.previewView
self.previewView = self.getChartView(text)
if isinstance(self.previewView, QChartView):
self.splitter.addWidget(self.previewView)
else:
QMessageBox.warning(self, "提示", self.previewView)
del self.previewView
self.setEnabled(True)
self.loadingWidget.close()
def getChartView(self, text):
try:
return ChartView(text)
except Exception as e:
return str(e)
def resizeEvent(self, event):
super(ChartWidget, self).resizeEvent(event)
self.loadingWidget.resize(self.size())
def closeEvent(self, event):
self.loadingWidget.close()
self.loadingWidget.deleteLater()
del self.loadingWidget
super(ChartWidget, self).closeEvent(event)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = ChartWidget()
w.show()
sys.exit(app.exec_())