class MainWindow(QWidget): def __init__(self): QWidget.__init__(self) self.setGeometry(100, 100, 300, 200) self.show() self.grid = QGridLayout(self) self.grid.setContentsMargins(0, 0, 0, 0) self.web = QWebEngineView() self.web.load(QUrl(link)) self.grid.addWidget(self.web, 0, 0) self.web2 = QWebEngineView() self.web2.hide() self.web2.load(QUrl(link)) self.grid.addWidget(self.web2, 0, 0) timer = QtCore.QTimer(self) timer.timeout.connect(self.refresh) timer.start(int(sys.argv[-1])) def refresh(self): print(int(time.time())) def finished(): browser, another = self.web, self.web2 if another.isHidden(): browser, another = another, browser time.sleep(1) browser.show() another.hide() if self.web2.isHidden(): self.web2.reload() self.web2.loadFinished.connect(finished) else: self.web.reload() self.web.loadFinished.connect(finished)
class ViewMainWindow(QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() self.directory = '' self.sizes = [] self.files = [] self.chart_views = [] self.setupUi(self) # 打开工作空间按钮 self.button_load_dir = QPushButton(self.widget_directory) self.button_load_dir.setText("打开新的工作空间") self.button_load_dir.clicked.connect(self.open_new_directory) self.verticalLayout_directory.addWidget(self.button_load_dir) # 渲染列表HTML self.dir_list_html = QWebEngineView(self.widget_directory) self.dir_list_channel = QWebChannel(self.dir_list_html.page()) self.dir_list_obj = DirListObj() self.dir_list_obj.sig_file_item_clicked.connect(self.on_choose_file) self.dir_list_channel.registerObject("dir_list_obj", self.dir_list_obj) self.dir_list_html.page().setWebChannel(self.dir_list_channel) self.dir_list_html.load(QUrl.fromLocalFile(os.path.abspath('view/html/file_list.html'))) self.verticalLayout_directory.addWidget(self.dir_list_html) self.dir_list_html.hide() # 打开工作空间按钮与函数绑定 self.actionNew_Workspace.triggered.connect(self.open_new_directory) # 关闭工作空间按钮与函数绑定 self.actionClose_Workspace.triggered.connect(self.clock_directory) # 加载配置文件按钮与函数绑定 self.actionLoad_Setting.triggered.connect(self.select_setting_file) # 加载默认的配置文件 self.setting = Setting("setting.json") def on_choose_file(self, file_id): """ 打开一个数据文件 :param file_id: 文件在内存中的序号 :return: """ print("try to load", self.files[file_id]) datas = read_data(os.path.join(self.directory, self.files[file_id]), self.setting.channels) # 删除之前存在的图表 for chart_view in self.chart_views: self.verticalLayout_charts.removeWidget(chart_view) chart_view.deleteLater() self.chart_views.clear() # 创建新的图表 for i in range(self.setting.channels): chart_view = View_Chart(self.setting.line_colors[i], self.setting.background_colors[i], self.setting.x_axis_colors[i], self.setting.y_axis_colors[i], self.setting.tooltip_colors[i], datas[i]) self.chart_views.append(chart_view) self.verticalLayout_charts.addWidget(chart_view) def clock_directory(self): """ 关闭当前打开的工作空间 :return: """ self.dir_list_html.hide() self.button_load_dir.show() for chart_view in self.chart_views: self.verticalLayout_charts.removeWidget(chart_view) chart_view.deleteLater() self.chart_views.clear() def open_new_directory(self): """ 打开一个新的目录 隐藏打开按钮 显示新的文件列表 :return: """ self.on_change_directory() self.button_load_dir.hide() self.dir_list_html.show() def on_change_directory(self): """ 选择一个新的工作目录 遍历其中以.data结尾的文件 显示文件名和大小 :return: """ self.directory = QFileDialog.getExistingDirectory(self, "选择工作目录") if not os.path.exists(self.directory): return listdir = os.listdir(self.directory) self.files.clear() self.sizes.clear() for _dir in listdir: path = os.path.join(self.directory, _dir) if os.path.isfile(path) and path.endswith(".data"): self.files.append(_dir) self.sizes.append(os.path.getsize(path)) self.dir_list_html.page().runJavaScript("updateList({0},{1})".format(self.files, self.sizes)) def select_setting_file(self): """ 选择配置文件 :return: """ setting_file = QFileDialog.getOpenFileName(self, "选择配置文件", filter="JSON Files(*.json)") self.setting = Setting(setting_file[0])
class View_Main(QMainWindow, Ui_MainWindow): classroom_briefs = [] class_brief_threads = [] view_real_time = None def __init__(self): super().__init__() self.setupUi(self) # 四个页面的切换 self.widget_building.clicked.connect(self.change_page_class) self.widget_status.clicked.connect(self.change_page_status) self.widget_abnormal.clicked.connect(self.change_page_abnormal) self.widget_record.clicked.connect(self.change_page_record) # 从数据库读取教室信息 get_class_briefs(self.classroom_briefs) # 多线程完成教室初始化显示 threads = [] for brief in self.classroom_briefs: threads.append( threading.Thread(target=init_thumbnail, args=(brief, ))) for thread in threads: thread.start() thread.join() # 注册教室列表 self.class_web = QWebEngineView(self.page_class) self.class_channel = QWebChannel(self.class_web.page()) self.class_obj = ClassObj() # 注册按教学楼分类的标题组件 self.building_title_web = QWebEngineView(self.page_class) self.building_title_web.setMaximumHeight(90) self.building_title_web.setMinimumHeight(90) self.building_title_channel = QWebChannel( self.building_title_web.page()) self.building_title_obj = BuildingTitleObj() # 注册按状态分类的标题栏组件 self.state_title_web = QWebEngineView(self.page_class) self.state_title_web.setMinimumHeight(65) self.state_title_web.setMaximumHeight(65) self.state_title_channel = QWebChannel(self.state_title_web.page()) self.state_title_obj = StateTitleObj() self.setup_class_page() # 注册上课回看列表需要的组件 self.record_list_page = QWebEngineView(self.page_reocrd) self.record_list_channel = QWebChannel(self.record_list_page.page()) self.record_list_obj = RecordListObj() self.setup_record_table() def setup_class_page(self): # 初始化按教学楼搜索标题栏 self.building_title_obj.sig_confirm_clicked.connect( self.sift_by_building) self.building_title_channel.registerObject('building_title_obj', self.building_title_obj) self.building_title_web.page().setWebChannel( self.building_title_channel) self.building_title_web.load( QUrl.fromLocalFile( os.path.abspath('view/html/TitleBuilding.html'))) # 初始化按状态搜索标题栏 self.state_title_channel.registerObject('state_title_obj', self.state_title_obj) self.state_title_web.page().setWebChannel(self.state_title_channel) self.state_title_web.load( QUrl.fromLocalFile(os.path.abspath('view/html/TitleState.html'))) self.state_title_web.hide() # 初始化教室页面 self.class_obj.sig_class_item_clicked.connect(self.open_real_time) self.class_channel.registerObject('class_obj', self.class_obj) self.class_web.page().setWebChannel(self.class_channel) self.class_web.load( QUrl.fromLocalFile(os.path.abspath('view/html/ClassTable.html'))) self.class_web.loadFinished.connect(self.refresh_page) self.verticalLayout_7.addWidget(self.building_title_web) self.verticalLayout_7.addWidget(self.state_title_web) self.verticalLayout_7.addWidget(self.class_web) # 统计学生人数线程对象生成 for brief in self.classroom_briefs: self.class_brief_threads.append( ClassBriefThread(brief, self.class_web.page())) for thread in self.class_brief_threads: thread.start() def refresh_page(self): # 刷新教室列表的显示 init_table = '' for brief in self.classroom_briefs: if brief.isShow: init_table += HTMLFactory.get_instance().class_brief_box_first( brief) self.class_web.page().runJavaScript( "setupTable('{0}')".format(init_table)) def open_real_time(self, class_brief_id): for brief in self.classroom_briefs: if brief.classroom.classroom_id == class_brief_id: print( ">>>>>>>>>>>>>>>>>>>>>> classroom {0} begin to be monitored" .format(class_brief_id)) for thread in self.class_brief_threads: thread.pause() time.sleep(2) self.view_real_time = View_RealTime(brief) self.view_real_time.sig_on_closed.connect(self.resume) self.view_real_time.showMaximized() break def sift_by_building(self, campus, building, floor): # 按照教学楼显示 # 根据校区、教学楼、教室号来进行筛选 for brief in self.classroom_briefs: if (campus in brief.classroom.campus) and ( building in brief.classroom.building) and ( floor in brief.classroom.floor): if not brief.isShow: self.add_box(brief) brief.isShow = True elif brief.isShow: self.remove_box(brief) brief.isShow = False # 初始化上课回看列表 def setup_record_table(self): self.record_list_obj.sig_record_list_item_clicked.connect( self.open_replay) self.record_list_channel.registerObject('record_list_obj', self.record_list_obj) self.record_list_page.page().setWebChannel(self.record_list_channel) self.verticalLayout_10.addWidget(self.record_list_page) self.record_list_page.load( QUrl.fromLocalFile(os.path.abspath('view/html/Record.html'))) def open_replay(self, item_id): self.view_replay = View_Replay() self.view_replay.showMaximized() def change_page_class(self): for thread in self.class_brief_threads: thread.resume() self.stackedWidget.setCurrentIndex(0) self.building_title_web.show() self.state_title_web.hide() for brief in self.classroom_briefs: if not brief.isShow: self.add_box(brief) brief.isShow = True def change_page_status(self): for thread in self.class_brief_threads: thread.resume() self.stackedWidget.setCurrentIndex(0) self.building_title_web.hide() self.state_title_web.show() for brief in self.classroom_briefs: if not brief.isShow: self.add_box(brief) brief.isShow = True def change_page_abnormal(self): for thread in self.class_brief_threads: thread.resume() self.stackedWidget.setCurrentIndex(0) self.building_title_web.hide() self.state_title_web.hide() for brief in self.classroom_briefs: if brief.isAbnormal: if not brief.isShow: self.add_box(brief) brief.isShow = True else: if brief.isShow: self.remove_box(brief) brief.isShow = False def add_box(self, brief): box = HTMLFactory.get_instance().class_brief_box_first(brief) update_class_table_lock.acquire() self.class_web.page().runJavaScript("addBox('{0}')".format(box)) update_class_table_lock.release() def remove_box(self, brief): update_class_table_lock.acquire() self.class_web.page().runJavaScript("removeBox('class_{}')".format( brief.classroom.classroom_id)) update_class_table_lock.release() def change_page_record(self): self.stackedWidget.setCurrentIndex(1) for thread in self.class_brief_threads: thread.pause() # 关闭实时监控页之后调用 def resume(self): for thread in self.class_brief_threads: thread.resume()
class Nexico(QMainWindow, Ui_MainWindow): """ Nexico user interface main class """ def __init__(self, splash, nexicoBase, config, selectionName="standard", parent=None): """ Constructor """ QMainWindow.__init__(self) self.setupUi(self) qfdb = QFontDatabase() fi = qfdb.addApplicationFont(":fonts/resources/FreeSans.otf") try: self.font = qfdb.font( qfdb.applicationFontFamilies(fi)[0], "Light", False) except: self.font = None self.config = config self.nbBestKids = int(self.config["configuration"]["nbBestKids"]) self.currentSection = None self.selectedWord = "" self.selectedTokeni = None self.sectList = [] self.base = nexicoBase self.wordTableWidget.setHorizontalHeaderLabels( [self.tr("word"), self.tr("frequency")]) self.autoSelect = 0 false_positives = set(["aliases", "undefined"]) self.encodings = set( name for imp, name, ispkg in pkgutil.iter_modules(encodings.__path__) if not ispkg) self.encodings.difference_update(false_positives) self.encodings = sorted(self.encodings) self.statusbar.showMessage(self.tr("Welcome!"), 20000) self.fileNameEdit.setText(selectionName) self.pb = QtWidgets.QProgressBar(self.statusBar()) self.statusBar().addPermanentWidget(self.pb) self.pb.hide() self.splash = splash self.selecting = False self.graphicsView.setRenderHints( QtGui.QPainter.Antialiasing or QtGui.QPainter.SmoothPixmapTransform) self.ngra = self.ngraDial.sliderPosition() self.renoword = re.compile("\W+$", re.U + re.I + re.M) self.webView = QWebView() self.collocations = Collocations(self) #self.gridLayout_3.addWidget(self.graphcanvas, 0, 0, 1, 1) self.gridLayout_3.addWidget(self.webView, 0, 0, 1, 1) # start with collocation open? #openwithcolloc=int(self.config["configuration"]["openwithcolloc"]) # False openwithcolloc = False self.actionCollocations.setChecked(openwithcolloc) self.on_actionCollocations_toggled(openwithcolloc) #self.graphButton.setChecked(True) #self.specos=None # dict of collocations for current word # TODO: solve the memory problem of qsplitter: #self.hsplitter=QSplitter(1, self.centralwidget) # 2=vertical orientation #self.centralGridLayout.addWidget(self.hsplitter, 0, 1) #self.vspgridLayout = QtGui.QGridLayout(self.hsplitter) #self.vspgridLayout.setSpacing(0) #self.hsplitter.setHandleWidth(8) #self.vspgridLayout.setContentsMargins(2, 0, 2, 0) #self.vspgridLayout.addWidget(self.westwidget, 0, 0) #self.vspgridLayout.addWidget(self.eastwidget) self.load() self.filter.textChanged.connect(self.filterChanged) self.colfilter.textChanged.connect(self.colfilterChanged) self.recenter = RecenterClass() # def load(self, encoding="autodetect"): # self.specTableWidget.hide() self.wordTableWidget.clear() self.sectionMap.clear() #print 14 self.base.progressChanged.connect(self.updateProgress) self.base.finished.connect(self.loadFinished) self.base.start() def updateProgress(self, i, message="Loading..."): if self.pb.isHidden(): self.pb.show() self.pb.setValue(i) if message: self.statusbar.showMessage(message) def loadFinished(self): """ loading of base is finished """ self.base.progressChanged.emit(95.0, "Showing table for first section...") if not len(self.sectionMap): # first time: self.splash.finish(self) self.sectrast = self.base.sectrast #s[0] #my default sectrast is the first of the base i just created #self.sectionMap.clear() if self.sectrast: for si, section in enumerate( self.sectrast.sections): # pour chaque section # u"\u25A1" u"◻" carre = QtWidgets.QListWidgetItem("\u25A1", self.sectionMap) carre.section = section carre.setToolTip("<b>" + str(section) + ":</b>" + (self.sectrast.urls[si] or "")) if self.font: carre.setFont(self.font) self.sectionMap.setCurrentRow(0) # select the first square #self.actionComputeSpecificity.setEnabled(True) self.statusbar.showMessage("Finished loading", 2000) self.pb.hide() if self.actionCollocations.isChecked(): # autostart the collocation stuff: self.wordTableWidget.selectRow(0) self.graphButton.setChecked(True) def fillTokenTable(self): """ fills the token table with: - all the tokens - for each token: its total frequency its frequency in the selected selection its specificity for the selected selection called for new section selection """ if debug: print("fillTokenTable", self.selection) self.wordTableWidget.clear() self.wordTableWidget.setSortingEnabled(False) self.wordTableWidget.setRowCount(len(self.base.d)) self.wordTableWidget.setColumnCount(4) fi = re.compile(str(self.filter.text())) for i, tokeni in enumerate(self.base.d): s = self.base.d.idtotoken[tokeni] #.decode("utf-8") worditem = QtWidgets.QTableWidgetItem(s) if self.renoword.match(s): # nowords get tooltip # TODO: check what's going on here: 0x8e ValueError: no such name #for l in s: # print l.encode("utf-8"),type(l),len(l),hex(ord(l)) # print unicodedata.name(unicode(l)) try: worditem.setToolTip(" - ".join( [unicodedata.name(str(l)) for l in s])) except ValueError: try: worditem.setToolTip("special control character: " + " - ".join([ unicodedata.category(str(l)) + ":" + hex(ord(str(l))) for l in s ])) except: print("can't find unicode data for", [s]) #,s.encode("iso-8859-1") if debug: print("fillTokenTable", self.selection, 2) self.wordTableWidget.setItem(i, 0, worditem) if debug: print("fillTokenTable", self.selection, 3) self.wordTableWidget.setRowHidden( i, not fi.search(self.wordTableWidget.item(i, 0).text())) totfreqitem = QtWidgets.QTableWidgetItem() if debug: print("fillTokenTable", self.selection, 4) #totfreqitem.setData(Qt.EditRole, len(self.sectrast.tokens[token])) totfreqitem.setData(Qt.EditRole, self.base.d.freqs[tokeni]) totfreqitem.setTextAlignment(QtCore.Qt.AlignRight) self.wordTableWidget.setItem(i, 1, totfreqitem) if debug: print("fillTokenTable", self.selection, 5) freqitem = QtWidgets.QTableWidgetItem('%7d' % sum([ self.base.sectrast.bows[se].get(tokeni, 0) for se in self.selection ])) freqitem.setTextAlignment(QtCore.Qt.AlignRight) self.wordTableWidget.setItem(i, 2, freqitem) if debug: print("fillTokenTable", self.selection, 6) specitem = QtWidgets.QTableWidgetItem() # try: specitem.setData( Qt.EditRole, self.sectrast.specificity[tokeni][self.selection]) except: self.sectrast.computeOtherSpecificity(self.selection) specitem.setData( Qt.EditRole, self.sectrast.specificity[tokeni][self.selection]) self.loadFinished() specitem.setTextAlignment(QtCore.Qt.AlignRight) if debug: print("fillTokenTable", self.selection, 7) self.wordTableWidget.setItem(i, 3, specitem) if debug: print("fillTokenTable", self.selection, 8) self.wordTableWidget.setHorizontalHeaderLabels([ self.tr("token"), self.tr("totfreq"), self.tr("freq"), self.tr("spec") ]) self.wordTableWidget.verticalHeader().setStyleSheet( "QHeaderView { font-size: 6pt; }") self.wordTableWidget.resizeColumnsToContents() self.wordTableWidget.setSortingEnabled(True) if debug: print("fillTokenTable", self.selection, 9) self.wordTableWidget.sortItems(3, 1) # sort by specificity, descending self.actionSaveTable.setEnabled(True) self.actionSaveGraph.setEnabled(True) def filterChanged( self, text ): # TODO: redo that with a real QAbstractItemModel and QSortFilterProxyModel try: fi = re.compile(str(text)) except: return # TODO: show errors in regex? for i in range(self.wordTableWidget.rowCount()): self.wordTableWidget.setRowHidden( i, not fi.search(self.wordTableWidget.item(i, 0).text())) def colfilterChanged( self, text ): # TODO: redo that with a real QAbstractItemModel and QSortFilterProxyModel try: fi = re.compile(str(text)) except: return # TODO: show errors in regex? for i in range(self.collocTableWidget.rowCount()): self.collocTableWidget.setRowHidden( i, not fi.search(self.collocTableWidget.item(i, 0).text())) #def selectToken(self,token): def colloc(self, token): """ fills the colloc table """ if debug: print("fillCollocTable", token) if self.ngra not in self.sectrast.specollocs: self.sectrast.computeCollocations( self.ngra) # compute collocations only the first time if not token: self.pb.hide() return #selectedTokeni = self.base.d.token2id[self.selectedWord] #d=self.sectrast.specollocs[selectedTokeni] #for coi in sorted(d,key=d.get,reverse=True): #print "___",self.base.d.idtotoken[coi],d[coi] try: self.selectedTokeni = self.base.d.token2id[ token] # .encode("utf-8") except: self.selectedTokeni = self.base.d.token2id[token] specos = { i: sp for i, sp in self.sectrast.specollocs[self.ngra][ self.selectedTokeni].items() if sp != 0 } #print self.selectedTokeni self.collocTableWidget.clear() self.collocTableWidget.setSortingEnabled(False) self.collocTableWidget.setRowCount(len(specos)) self.collocTableWidget.setColumnCount(4) fi = re.compile(str(self.colfilter.text())) for i, tokeni in enumerate(specos): s = self.base.d.idtotoken[tokeni] #.decode("utf-8") worditem = QtWidgets.QTableWidgetItem(s) if self.renoword.match(s): # nowords get tooltip # TODO: check what's going on here: 0x8e ValueError: no such name #for l in s: # print l.encode("utf-8"),type(l),len(l),hex(ord(l)) # print unicodedata.name(unicode(l)) try: worditem.setToolTip(" - ".join( [unicodedata.name(str(l)) for l in s])) except ValueError: try: worditem.setToolTip("special control character: " + " - ".join([ unicodedata.category(str(l)) + ":" + hex(ord(str(l))) for l in s ])) except: print("can't find unicode data for", [s]) #,s.encode("iso-8859-1") self.collocTableWidget.setItem(i, 0, worditem) self.collocTableWidget.setRowHidden( i, not fi.search(self.collocTableWidget.item(i, 0).text())) totfreqitem = QtWidgets.QTableWidgetItem() #totfreqitem.setData(Qt.EditRole, len(self.sectrast.tokens[token])) totfreqitem.setData(Qt.EditRole, self.base.d.freqs[tokeni]) totfreqitem.setTextAlignment(QtCore.Qt.AlignRight) self.collocTableWidget.setItem(i, 1, totfreqitem) freqitem = QtWidgets.QTableWidgetItem( '%7d' % self.sectrast.collocs[self.ngra][self.selectedTokeni].get( tokeni, 0)) freqitem.setTextAlignment(QtCore.Qt.AlignRight) self.collocTableWidget.setItem(i, 2, freqitem) specitem = QtWidgets.QTableWidgetItem() specitem.setData(Qt.EditRole, specos[tokeni]) #try: #specitem.setData(Qt.EditRole, self.sectrast.specificity[tokeni][self.selection] ) #except: #self.sectrast.computeOtherSpecificity(self.selection) #specitem.setData(Qt.EditRole, self.sectrast.specificity[tokeni][self.selection]) #self.loadFinished() specitem.setTextAlignment(QtCore.Qt.AlignRight) self.collocTableWidget.setItem(i, 3, specitem) self.collocTableWidget.setHorizontalHeaderLabels([ self.tr("token"), self.tr("totfreq"), self.tr("cooc"), self.tr("spec") ]) self.collocTableWidget.verticalHeader().setStyleSheet( "QHeaderView { font-size: 6pt; }") self.collocTableWidget.resizeColumnsToContents() self.collocTableWidget.setSortingEnabled(True) #print 7777 self.collocTableWidget.sortItems(3, 1) # sort by specificity, descending #self.actionSaveTable.setEnabled(True) #self.actionSaveGraph.setEnabled(True) self.statusbar.showMessage("Finished loading", 3000) self.pb.hide() def updateInfo(self): """ fills - the text above the token table - the information line under the sectionMap """ if len(self.selection) == 1: infospec = "Specificity table for section {nr}.".format( nr=str(self.selection[0])) elif len(self.selection) < 10: infospec = "sections {nr}.".format(nr=str(self.selection)[1:-1]) else: infospec = "{totalselect} sections: {start}...{end}".format( totalselect=len(self.selection), start=str([s for s in self.selection[:3]])[1:-1], end=str([s for s in self.selection[-3:]])[1:-1]) self.tableBox.setTitle(infospec) self.pageNameLabel.setText( str(sum([self.sectrast.nrtoks[s] for s in self.selection])) + " tokens" ) # todo: think of how to show the names of files: self.selection[0][1].split("/")[-1]+" - "+ infomap = "Text with {totok} tokens in {totsec} sections.".format( totok=self.sectrast.size, totsec=len(self.sectrast.sections)) if self.selectedWord: infograph = "Occurrences of '{token}'".format( token=str(self.selectedWord)) # self.graphicsBox.setTitle(infograph) if self.graphButton.isChecked(): self.graphicsBox.setToolTip( infograph + ". Colors show specificity of the token.".format( token=str(self.selectedWord))) infomap = infomap + " Colors show occurrences (pink squares) and specifities (red +, green - background) of '{token}'.".format( token=str(self.selectedWord)) self.mapBox.setTitle(infomap) self.mapBox.setToolTip(infomap) @pyqtSlot() def on_sectionMap_itemSelectionChanged(self): """ Slot documentation goes here. """ if not len(self.sectionMap.selectedItems()): return if self.selecting: return if debug: print("on_sectionMap_itemSelectionChanged", 1) #self.selection=tuple([s.section.id for s in self.sectionMap.selectedItems()]) self.selection = tuple( [s.section for s in self.sectionMap.selectedItems()]) if len(self.selection) >= 1: remot = re.compile(r"\b(" + str(self.selectedWord) + r")\b", re.U) #text=remot.sub(r"<span style='color:red'>\1</span>", self.sectionMap.selectedItems()[0].section.getText()) text = remot.sub( r"<span style='color:red'>\1</span>", self.base.rowIdFunction( self.sectionMap.selectedItems()[0].section)) if debug: print("on_sectionMap_itemSelectionChanged", 2) self.editSection.setHtml(text) if debug: print("on_sectionMap_itemSelectionChanged", 3) # print text self.sectionBox.setTitle( "Content of section " + str(self.selection[0]) + " - " + (self.sectrast.urls[self.sectrast.sections.index( self.selection[0])] or "").split("/")[-1] + " - " + str(self.sectrast.nrtoks[self.selection[0]]) + " tokens") if debug: print("on_sectionMap_itemSelectionChanged", 4) #print self.sectrast.nrtoks[self.selection[0]] else: self.sectionBox.setTitle("No section selected ") self.editSection.setHtml("") self.fillTokenTable() self.updateInfo() # TODO: make multi-word specificities possible # @pyqtSlot() # def on_wordTableWidget_itemSelectionChanged(self): # print self.wordTableWidget.selectedIndexes() # rows=sorted(set([i.row() for i in self.wordTableWidget.selectedIndexes()] )) # self.selectedWords = sorted([unicode(self.wordTableWidget.item(r, 0).text()) for r in rows]) # self.selectedTokenis = [self.base.d.token2id[unicode(self.wordTableWidget.item(r, 0).text())] for r in rows] # print self.selectedTokenis #@pyqtSignature("QTableWidgetItem*, QTableWidgetItem*") @pyqtSlot(QTableWidgetItem, QTableWidgetItem) def on_collocTableWidget_currentItemChanged(self, item, previous): if not item: item = previous print(46546, item, previous) try: selectedWord = str( self.collocTableWidget.item(item.row(), 0).text()) #self.selectedTokeni = self.base.d.token2id[self.selectedWord] print(selectedWord) self.selectWordInWordTableWidget(selectedWord) except Exception as e: print("oh, something wrong", Exception, e) #self.selectedTokeni=0 def selectWordInWordTableWidget(self, word): for i in range(self.wordTableWidget.rowCount()): if self.wordTableWidget.item(i, 0).text() == word: self.wordTableWidget.selectRow(i) break #@pyqtSignature("QTableWidgetItem*, QTableWidgetItem*") def on_wordTableWidget_currentItemChanged(self, item, previous): #print "000",item, previous if not item: item = previous try: self.selectedWord = str( self.wordTableWidget.item(item.row(), 0).text()) try: self.selectedTokeni = self.base.d.token2id[ self. selectedWord] # TODO: clean this mess up! .encode("utf-8") except: self.selectedTokeni = self.base.d.token2id[self.selectedWord] except Exception as e: print("oh, something wrong", Exception, e) self.selectedTokeni = 0 #print 8888 self.sectionMap.clearSelection() red = QtGui.QColor("red") green = QtGui.QColor("green") whitebrush = QtGui.QBrush(QtCore.Qt.white, QtCore.Qt.NoBrush) self.smin, self.smax, self.fmax = 0, 0, 0 # print self.currwordsectspecdic for i, section in enumerate(self.sectrast.sections): #s=self.currwordsectspecdic[(i, )] # print i,section,sorted(self.sectrast.specificity[self.selectedTokeni]) # try: s = self.sectrast.specificity[self.selectedTokeni][( section, )] # TODO: check why error on windows! # except:s=0 if s > 0: #self.sectionMap.item(i).setBackgroundColor(red.darker(30*s)) self.sectionMap.item(i).setBackground( QtGui.QBrush(QtGui.QColor(QtCore.Qt.red).darker(30 * s))) elif s < 0: self.sectionMap.item(i).setBackground( QtGui.QBrush( QtGui.QColor(QtCore.Qt.green).darker(30 * -s))) else: self.sectionMap.item(i).setBackground(whitebrush) freq = self.sectrast.bows[section].get(self.selectedTokeni, 0) if freq: self.sectionMap.item(i).setForeground( QtGui.QBrush(QtCore.Qt.magenta)) else: self.sectionMap.item(i).setForeground( QtGui.QBrush(QtCore.Qt.black)) if s > self.smax: self.smax = s elif s < self.smin: self.smin = s if freq > self.fmax: self.fmax = freq self.updateInfo() #if self.currwordsectspecdic: #print ";.isChecked()",self.graphButton.isChecked() #print self.autoSelect,"jjj" if self.actionCollocations.isChecked(): self.colloc(self.selectedWord) #print self.autoSelect,"uuu" if self.autoSelect: #sleep(.5) #print self.recenter.word #if self.recenter.word==self.selectedWord: if self.autoSelect and self.graphButton.isChecked(): #print "sleep",self.recenter.word #self.autoSelect=0 #sleep(.5) baseUrl = QUrl.fromLocalFile( QDir.current().absoluteFilePath("lib/resources/about.html") ) # any html file to base the setHtml!!! self.webView.setHtml(self.collocations.graph(self.nbBestKids), baseUrl) #self.makeCollocGraph() #sleep(.5) self.webView.page().mainFrame().addToJavaScriptWindowObject( "pyObj", self.recenter) #self.autoSelect=1 #print 111,self.recenter.word return if self.graphButton.isChecked(): self.makeCollocGraph() else: self.makeSpecGraph() #print "www" self.actionSelect_sections_with_occurrences.setEnabled(True) self.actionSelectposspecificsections.setEnabled(True) self.actionSelectnegspecificsections.setEnabled(True) def makeSpecGraph(self, numMarks=10): """ draws the curve of the evolution of occurrences and specificities in the sections """ #if self.graphcanvas: self.graphcanvas.hide() self.graphicsView.show() #print "makeSpecGraph" size = self.graphicsView.size() scene = QtWidgets.QGraphicsScene(self) # scene.addText(self.selectedWord) specpath = QtGui.QPainterPath() specpath.setFillRule(Qt.WindingFill) freqpath = QtGui.QPainterPath() specpath.moveTo(0, 0) freqpath.moveTo(0, 0) nrsects = len(self.sectrast.sections) snry = size.height() / (self.smax - self.smin + 1) * .75 fnry = size.height() / (self.fmax + 1) * .5 tex = int(nrsects / numMarks) if nrsects > 100: pathw = 1.0 else: pathw = 3.0 for i, si in enumerate(self.sectrast.sections): s = self.sectrast.specificity[self.selectedTokeni][(si, )] specpath.lineTo( QtCore.QPointF(i * size.width() * .8 / nrsects, -s * snry)) freqpath.lineTo( QtCore.QPointF( i * size.width() * .8 / nrsects, -self.sectrast.bows[si].get(self.selectedTokeni, 0) * fnry)) if not tex or not i % tex: num = scene.addText(str(i), QtGui.QFont("Helvetica", 6)) num.setPos(QtCore.QPointF(i * size.width() * .8 / nrsects, 0)) specpath.lineTo(QtCore.QPointF(i * size.width() * .8 / nrsects, 0)) freqpath.lineTo(QtCore.QPointF(i * size.width() * .8 / nrsects, 0)) specpath.lineTo(0, 0) freqpath.lineTo(0, 0) scene.addPath( specpath, QtGui.QPen(self.base.specColor, pathw, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin), QtGui.QBrush(self.base.specColor)) scene.addPath( freqpath, QtGui.QPen(self.base.freqColor, pathw, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.graphicsView.centerOn(0, 0) scene.addText(self.selectedWord).moveBy(0, 20) self.graphicsView.setScene(scene) self.graphicsView.fitInView(scene.sceneRect(), 1) self.graphicsView.show() self.actionCopyGraphToClipboard.setEnabled(True) # print self.graphicsView.sceneRect () , size, self.graphicsView.size() @pyqtSlot() def on_actionSaveGraph_triggered(self): if self.selectedWord: filename = self.selectedWord + "-specificity.png" else: filename = "specificity.png" fileName = QFileDialog.getSaveFileName( self, "Save Graph as png, svg, or pdf", filename, "PNG Image (*.png);;PDF File(*.pdf);;SVG File(*.svg)")[0] if str(fileName).endswith(".png"): #pixMap=QPixmap.grabWidget( self.graphicsView) pixMap = self.graphicsView.grab() pixMap.save(fileName) elif str(fileName).endswith(".pdf"): pdfPrinter = QPrinter() pdfPrinter.setOutputFormat(QPrinter.PdfFormat) pdfPrinter.setPaperSize( QSizeF(self.graphicsView.width(), self.graphicsView.height()), QPrinter.Point) pdfPrinter.setFullPage(True) pdfPrinter.setOutputFileName(fileName) pdfPainter = QPainter() pdfPainter.begin(pdfPrinter) self.graphicsView.render(pdfPainter) pdfPainter.end() elif str(fileName).endswith(".svg"): svgGen = QSvgGenerator() svgGen.setFileName(fileName) svgGen.setSize( QSize(self.graphicsView.width(), self.graphicsView.height())) svgGen.setViewBox( QRect(0, 0, self.graphicsView.width(), self.graphicsView.height())) svgGen.setTitle(filename) svgGen.setDescription("Specificity graph generated by Gromoteur") painter = QPainter(svgGen) self.graphicsView.render(painter) painter.end() @pyqtSlot() def on_actionOpen_graph_in_browser_triggered(self): self.collocations.viewGraphInBrowser() @pyqtSlot() def on_actionCopyGraphToClipboard_triggered(self): #pixMap=QPixmap.grabWidget( self.graphicsView) pixMap = self.graphicsView.grab() # print type(pixMap) clipboard = QApplication.clipboard() clipboard.setPixmap(pixMap) # QApplication::clipboard()->setPixmap( QPixmap( "path to my png" ) ) @pyqtSlot() def on_actionSaveTable_triggered(self): # self.specTableWidget.show() #replacer=re.compile("\n filename = QFileDialog.getSaveFileName(self, self.tr("Save the table"), "nexico-export.csv", "*.*")[0] if filename: if debug: print("filename", filename) out = codecs.open(filename, "w", "utf-8") out.write("\t".join([ str(self.wordTableWidget.horizontalHeaderItem(c).text()) for c in range(self.wordTableWidget.columnCount()) ]) + "\n") for r in range(self.wordTableWidget.rowCount()): out.write("\t".join([ str(self.wordTableWidget.item(r, 0).text()).replace( "\n", "↩").replace("\t", "⇥") ] + [ str(self.wordTableWidget.item(r, c).text()).strip() for c in range(1, self.wordTableWidget.columnCount()) ]) + "\n") out.close() self.statusbar.showMessage("Exported " + filename, 3000) @pyqtSlot() def on_actionSelect_sections_with_occurrences_triggered(self): """ select the sections that contain the selected token """ if debug: print("actionSelect_sections_with_occurrences") self.selecting = True for i, si in enumerate(self.sectrast.sections): freq = self.sectrast.bows[si].get(self.selectedTokeni, 0) if freq: self.sectionMap.item(i).setSelected(True) else: self.sectionMap.item(i).setSelected(False) self.selecting = False self.on_sectionMap_itemSelectionChanged() @pyqtSlot() def on_actionSelectposspecificsections_triggered(self): """ select the sections that are marked as positive specificity """ if debug: print("on_actionSelectposspecificsections_activated") self.selecting = True for i, si in enumerate(self.sectrast.sections): s = self.sectrast.specificity[self.selectedTokeni][(si, )] if s > 0: self.sectionMap.item(i).setSelected(True) else: self.sectionMap.item(i).setSelected(False) self.selecting = False self.on_sectionMap_itemSelectionChanged() @pyqtSlot() def on_actionSelectnegspecificsections_triggered(self): """ select the sections that are marked as negative specificity """ if debug: print("on_actionSelectnegspecificsections_activated") self.selecting = True for i, si in enumerate(self.sectrast.sections): s = self.sectrast.specificity[self.selectedTokeni][(si, )] if s < 0: self.sectionMap.item(i).setSelected(True) else: self.sectionMap.item(i).setSelected(False) self.selecting = False self.on_sectionMap_itemSelectionChanged() @pyqtSlot() def on_actionPreferences_triggered(self): """ opening the help dialog """ PreferencesDialog(self).exec_() self.nbBestKids = int(self.config["configuration"]["nbBestKids"]) #@pyqtSignature("bool") def on_actionCollocations_toggled(self, checked): """ """ self.colloGroupBox.setVisible(checked) self.collocationlabel.setVisible(checked) #if checked: self.graphButton.setChecked(checked) self.wordTableWidget.selectRow(0) self.config["configuration"]["openwithcolloc"] = int(checked) self.config.write() @pyqtSlot() def on_ngraDial_sliderReleased(self): """ ngra slider released: new value of ngra """ self.ngraDial.setEnabled(False) self.ngra = self.ngraDial.sliderPosition() if self.ngra not in self.sectrast.specollocs: self.sectrast.computeCollocations(self.ngra) if self.actionCollocations.isChecked(): self.colloc(self.selectedWord) self.ngraDial.setEnabled(True) @pyqtSlot() def on_actionInformationNexico_triggered(self): """ select the sections that are marked as negative specificity """ QMessageBox.about( self, "Nexico! - information", "Nexico is a tool for textual statistics inside Gromoteur.\nThis is free software distributed under GPL Version 3.\nPlease visit gromoteur.ilpga.fr for further information." ) #QMessageBox::about ( QWidget * parent, const QString & title, const QString & text ) def makeCollocGraph(self): #print "makeCollocGraph" if (self.autoSelect or not self.selectedTokeni or self.ngra not in self.sectrast.specollocs): return self.graphicsBoxTitle = self.graphicsBox.title() if debug: QtWebKit.QWebSettings.globalSettings().setAttribute( QtWebKit.QWebSettings.DeveloperExtrasEnabled, True) self.webView.setPage(None) # necessary for repeated recentering #self.recenter=RecenterClass() #self.webView.settings().setUserStyleSheetUrl(QUrl(":images/images/graphstyle.css")); baseUrl = QUrl.fromLocalFile( QDir.current().absoluteFilePath("lib/resources/about.html") ) # any html file to base the setHtml!!! self.webView.setHtml(self.collocations.graph(self.nbBestKids), baseUrl) #self.webView.page().mainFrame().addToJavaScriptWindowObject("pyObj", self.recenter) #self.webView.page().mainFrame().addToJavaScriptWindowObject("pyObj", self.recenter) # 2019 to recreate! https://doc.qt.io/qt-5/qtwebenginewidgets-qtwebkitportingguide.html #print 3 self.graphicsBox.setTitle("Collocations") self.actionOpen_graph_in_browser.setEnabled(True) #@pyqtSignature("bool") def on_graphButton_toggled(self, checked): """ Show and hide the cooc graph """ if checked: self.graphicsView.hide() self.makeCollocGraph() self.webView.show() else: self.webView.hide() self.graphicsBox.setTitle(self.graphicsBoxTitle) self.graphicsView.show() def clean(self, text): """ not used """ text = re.sub(r"\s+", " ", text, re.U) text = re.sub(r"\t+", " ", text, re.U) text = text.replace("...", "…") apost = re.compile(r"[\‘\’]", re.U) text = apost.sub(r"'", text) return text def words(self, text): """ not used """ text = self.clean(text) ponct = re.compile(r"(?<=\w)([\!\,\?\.\:\;»«])", re.U) text = ponct.sub(r" \1", text) apost = re.compile(r"([\'\(»«\‘\’])", re.U) text = apost.sub(r"\1 ", text) words = text.split() return words
class TrendPage(QWidget): def __init__(self, *args, **kwargs): super(TrendPage, self).__init__(*args, **kwargs) layout = QHBoxLayout(self) layout.setContentsMargins(QMargins(0, 0, 0, 1)) layout.setSpacing(0) self.variety_folded = ScrollFoldedBox() self.variety_folded.left_mouse_clicked.connect(self.variety_clicked) layout.addWidget(self.variety_folded) # 右侧是QTableWidget用于显示数据表信息 # tableinfo_layout.addWidget(self.data_table) # layout.addLayout(tableinfo_layout) # 右侧是webView r_layout = QVBoxLayout(self) self.table_lib_btn = QPushButton("数据库", self, objectName='libBtn') self.table_lib_btn.setToolTip("点击查看当前品种数据表") self.table_lib_btn.setCursor(Qt.PointingHandCursor) self.table_lib_btn.hide() self.table_lib_btn.clicked.connect(self.reverse_charts_and_table) r_layout.addWidget(self.table_lib_btn, alignment=Qt.AlignLeft) self.charts_loader = QWebEngineView(self) r_layout.addWidget(self.charts_loader) self.data_table = DataTableWidget(self) r_layout.addWidget(self.data_table) self.data_table.hide() layout.addLayout(r_layout) self.setLayout(layout) # 设置折叠窗的样式 self.variety_folded.setFoldedStyleSheet(""" QScrollArea{ border: none; } #foldedBox{ border-right: 1px solid rgb(180, 180, 180); } #foldedHead{ background-color: rgb(145,202,182); border-bottom: 1px solid rgb(200,200,200); border-right: 1px solid rgb(180, 180, 180); max-height: 30px; } #headLabel{ padding:8px 5px; font-weight: bold; font-size: 15px; } #foldedBody{ background-color: rgb(240, 240, 240); border-right: 1px solid rgb(180, 180, 180); } /*折叠窗内滚动条样式*/ #foldedBox QScrollBar:vertical{ width: 5px; background: transparent; } #foldedBox QScrollBar::handle:vertical { background: rgba(0, 0, 0, 30); width: 5px; border-radius: 5px; border: none; } #foldedBox QScrollBar::handle:vertical:hover,QScrollBar::handle:horizontal:hover { background: rgba(0, 0, 0, 80); } """) self.setStyleSheet(""" #libBtn{border:1px solid rgb(200,200,200);border-left:none;color:rgb(254,255,255);background-color:rgb(255,87,87);padding:5px 10px;font-size:14px;font-weight:bold;border-bottom-right-radius:5px} #libBtn:hover{color:rgb(15,67,146);font-weight:bold;background-color:rgb(74,247,198)} """) self.charts_loader.load(QUrl(settings.SERVER_ADDR + 'trend/charts/')) def resizeEvent(self, event): # 设置折叠窗的大小 box_width = self.parent().width() * 0.228 self.variety_folded.setFixedWidth(box_width + 8) self.variety_folded.setBodyHorizationItemCount() self.charts_loader.setFixedWidth(self.parent().width() - box_width - 8) # 获取所有品种组和品种 def getGroupVarieties(self): try: r = requests.get(url=settings.SERVER_ADDR + 'variety/?way=group') if r.status_code != 200: raise ValueError('获取失败!') response = json.loads(r.content.decode('utf-8')) except Exception as e: settings.logger.error("【基本分析】模块获取左侧品种菜单失败:{}".format(e)) else: for group_item in response['variety']: head = self.variety_folded.addHead(group_item['name']) body = self.variety_folded.addBody(head=head) for sub_item in group_item['subs']: body.addButton(sub_item['id'], sub_item['name']) self.variety_folded.container.layout().addStretch() # 点击了品种,显示当前品种下的品种页显示的图形 def variety_clicked(self, vid, text): self.charts_loader.load( QUrl(settings.SERVER_ADDR + 'trend/variety-charts/' + str(vid) + '/')) self.get_current_variety_table(vid, text) # 点击了品种,请求当前品种下的所有数据表 def get_current_variety_table(self, vid, text): try: r = requests.get(url=settings.SERVER_ADDR + 'variety/{}/trend/table/'.format(vid)) if r.status_code != 200: raise ValueError("获取品种该数据表失败!") response = json.loads(r.content.decode('utf8')) except Exception as e: settings.logger.error("【基本分析】模块获取品种下的数据表失败:{}".format(e)) else: self.data_table.show_tables(response["tables"]) self.table_lib_btn.show() # 切换图形与表格的显示 def reverse_charts_and_table(self): if self.data_table.isHidden(): self.charts_loader.hide() self.data_table.show() self.table_lib_btn.setText("图形库") self.table_lib_btn.setToolTip("点击查看当前品种图形") else: self.data_table.hide() self.charts_loader.show() self.table_lib_btn.setText("数据库") self.table_lib_btn.setToolTip("点击查看当前品种数据表")
class VarietyPriceWindow(AncestorWindow): name = "variety_price" export_table_signal = pyqtSignal() def __init__(self, *args, **kwargs): super(VarietyPriceWindow, self).__init__(*args, **kwargs) """绑定公用属性""" self.products = None self.db_worker = None # 线程是否结束标志位 self.exchange_lib_thread_over = True self.selected_variety_thread_over = True """总布局""" self.vertical_layout = QVBoxLayout() # 总纵向布局 top_select = QHBoxLayout() # 顶部横向条件选择栏 """交易所选择下拉框""" exchange_label = QLabel('选择交易所:') self.exchange_lib = QComboBox() self.exchange_lib.activated[str].connect( self.exchange_lib_selected) # 选择交易所调用的方法 """品种选择下拉框""" variety_label = QLabel('选择品种:') self.variety_lib = QComboBox() self.variety_lib.setMinimumSize(80, 20) self.variety_lib.activated[str].connect( self.variety_lib_selected) # 选择品种所调用的方法 """时间选择""" begin_time_label = QLabel("起始日期:") self.begin_time = QDateEdit( QDate.currentDate().addDays(-2)) # 参数为设置的日期 self.begin_time.setDisplayFormat('yyyy-MM-dd') # 时间显示格式 self.begin_time.setCalendarPopup(True) # 使用日历选择时间 end_time_label = QLabel("终止日期:") self.end_time = QDateEdit(QDate.currentDate().addDays(-1)) # 参数为设置的日期 self.end_time.setDisplayFormat('yyyy-MM-dd') # 时间显示格式 self.end_time.setCalendarPopup(True) # 使用日历选择时间 """确认按钮""" self.confirm_button = QPushButton("确定") self.confirm_button.clicked.connect(self.confirm) """水平布局添加控件""" top_select.addWidget(exchange_label) top_select.addWidget(self.exchange_lib) top_select.addWidget(variety_label) top_select.addWidget(self.variety_lib) top_select.addWidget(begin_time_label) top_select.addWidget(self.begin_time) top_select.addWidget(end_time_label) top_select.addWidget(self.end_time) top_select.addWidget(self.confirm_button) """自定义部件""" # 工具栏 self.tools = ToolWidget() tool_btn = QPushButton("季节图表") self.tool_view_all = QPushButton("返回总览") self.tool_view_all.setEnabled(False) self.tool_view_all.clicked.connect(self.return_view_all) self.tools.addTool(tool_btn) self.tools.addTool(self.tool_view_all) self.tools.addSpacer() tool_btn.clicked.connect(self.season_table) # 画布 self.map_widget = MapWidget() # 表格 self.table_widget = TableWidget(4) # 设置格式 self.table_widget.set_style( header_labels=['日期', '价格', '成交量合计', '持仓量合计']) """创建QSplitter""" self.show_splitter = QSplitter() self.show_splitter.setOrientation(Qt.Vertical) # 垂直拉伸 # 加入自定义控件 self.show_splitter.addWidget(self.map_widget) self.show_splitter.addWidget(self.table_widget) """垂直布局添加布局和控件并设置到窗口""" self.vertical_layout.addLayout(top_select) self.vertical_layout.addWidget(self.tools) self.vertical_layout.addWidget(self.show_splitter) # 加入控件 self.web_view = QWebEngineView() self.web_view.load(QUrl("file:///static/html/variety_price.html")) self.web_view.page().profile().downloadRequested.connect( self.download_requested) # 页面下载请求(导出excel) self.show_splitter.addWidget(self.web_view) self.web_view.hide() # 隐藏,刚开始不可见 """js交互通道""" web_channel = QWebChannel(self.web_view.page()) self.web_view.page().setWebChannel(web_channel) # 网页设置信息通道 web_channel.registerObject("season_table", self.tools) # 注册信号对象 web_channel.registerObject("export_table", self) # 导出表格数据信号对象 self.season_table_file = None # 季节表的保存路径 self.setLayout(self.vertical_layout) def fill_init_data(self): """填充交易所""" self.exchange_lib.clear() for lib in RESEARCH_LIB: self.exchange_lib.addItem(lib) # 获取当前交易所的品种并填充 self.exchange_lib_selected() def exchange_lib_selected(self): """交易所选择""" if not self.exchange_lib_thread_over: QMessageBox.information(self, "错误", "您的手速太快啦...", QMessageBox.Ok) return self.confirm_button.setEnabled(False) lib = self.exchange_lib.currentText() self.variety_lib.clear() if lib == "中国金融期货交易所": key = 'cffex' self.db_worker = self.cffex_getter self.products = CFFEX_PRODUCT_NAMES elif lib == "上海期货交易所": key = 'shfe' self.db_worker = self.shfe_getter self.products = SHFE_PRODUCT_NAMES elif lib == "大连商品交易所": key = 'dce' self.db_worker = self.dce_getter self.products = DCE_PRODUCT_NAMES elif lib == "郑州商品交易所": key = 'czce' self.db_worker = self.czce_getter self.products = CZCE_PRODUCT_NAMES else: self.db_worker = None self.products = None QMessageBox.information(self, '错误', "没有此项交易所..", QMessageBox.Ok) return for variety in GOODS_LIB.get(key): self.variety_lib.addItem(variety) # 关闭交易所选择 self.exchange_lib_thread_over = False # 品种选择 self.variety_lib_selected() def get_variety_en(self, variety): """获取相应的品种英文代号""" # 获取品种英文名称 if not self.products: # print("没有品种库:", self.products) QMessageBox.warning(self, "错误", "内部发生未知错误") return '' return self.products.get(variety) def variety_lib_selected(self): """ 选择品种所调用的方法,线程执行: 查询当前品种上市的日期 """ # 设置确认按钮不可用 self.confirm_button.setEnabled(False) if not self.selected_variety_thread_over: QMessageBox.warning(self, "错误", "您手速太快啦...", QMessageBox.Ok) return # 状态显示 variety = self.variety_lib.currentText() self.message_signal.emit("正在查询" + variety + "的数据时间区间...") en_variety = self.get_variety_en(variety) self.selected_variety_thread_over = False # 设置品种选择关闭 if self.db_worker: self.variety_selected_thread = VarietySelectedThread( db_worker=self.db_worker, variety=en_variety) self.variety_selected_thread.result_signal.connect( self.change_time_interval) self.variety_selected_thread.start() def change_time_interval(self, data): """根据品种选择线程的信号改变当前时间显示区间""" current_date = datetime.datetime.today() min_date = datetime.datetime.strptime(data[0], "%Y%m%d") max_date = datetime.datetime.strptime(data[1], "%Y%m%d") # 计算天数间隔 big_time_interval = -(current_date - min_date).days # 要往前取数,调整为负值 small_time_interval = -(current_date - max_date).days # 设置时间 self.begin_time.setDate(QDate.currentDate().addDays(big_time_interval)) self.end_time.setDate(QDate.currentDate().addDays(small_time_interval)) self.confirm_button.setEnabled(True) # 设置提交按钮为可用 # 设置完时间就所有锁打开 self.exchange_lib_thread_over = True self.selected_variety_thread_over = True # 状态显示时间区间查询完毕 self.message_signal.emit("时间区间查询完毕!") def clear_map_table(self): self.map_widget.delete() def confirm(self): """确认按钮点击""" # 开启定时器 self.timer.start(1000) # 改变确认按钮的状态 self.confirm_button.setText("提交成功") self.confirm_button.setEnabled(False) # 清除原图表并设置样式 self.map_widget.delete() self.table_widget.clear() self.table_widget.set_style( header_labels=['日期', '价格', '成交量合计', '持仓量合计']) # 根据时间段取得时间生成器类,查询相关数据,计算结果,返回时间列表及对应的价格列表 lib = self.exchange_lib.currentText() variety = self.variety_lib.currentText() variety_en = self.get_variety_en(variety) begin_time = re.sub('-', '', str(self.begin_time.date().toPyDate())) end_time = re.sub('-', '', str(self.end_time.date().toPyDate())) print("确认提交:\n当前交易所:{}\n当前品种:{},英文{}\n起始时间:{}\n终止时间:{}\n".format( lib, variety, variety_en, begin_time, end_time)) # 转成可计算的datetime.datetime时间对象 begin_time_datetime_cls = datetime.datetime.strptime( begin_time, "%Y%m%d") end_time_datetime_cls = datetime.datetime.strptime(end_time, "%Y%m%d") # 起止时间应早于终止时间 if begin_time_datetime_cls >= end_time_datetime_cls: QMessageBox.warning(self, "错误", "起止时间应早于终止时间", QMessageBox.Ok) self.message_signal.emit("时间选择有误!") self.timer.stop() self.cost_time = 0 # 设置确认按钮可用 self.confirm_button.setText("确定") self.confirm_button.setEnabled(True) return # 生成时间器对象 iterator_cls = GenerateTime(begin=begin_time_datetime_cls, end=end_time_datetime_cls) print("执行线程") if self.db_worker: # 线程执行查询目标数据 self.confirm_thread = ConfirmQueryThread(db_worker=self.db_worker, iterator=iterator_cls, variety=variety_en, lib=lib) self.confirm_thread.result_signal.connect(self.draw_map_table) self.confirm_thread.process_signal.connect(self.show_process) self.confirm_thread.start() def show_process(self, data): self.process_signal.emit(data) def draw_map_table(self, data): """数据展示""" print("结果", data) # 设置样式 self.map_widget.set_style() # 画图 x_data = [] y_data = [] tuple_data_list = data.get("data") message = data.get("message") for item in tuple_data_list: x_data.append(item[0]) y_data.append(item[1]) self.map_widget.axes.set_title(message) self.map_widget.map(x_data=x_data, y_data=y_data) # 表格数据填充 self.table_widget.table(data=tuple_data_list) self.message_signal.emit("处理完毕,生成图表成功!") self.timer.stop() self.cost_time = 0 self.confirm_button.setText("确定") self.confirm_button.setEnabled(True) def season_table(self): """处理展示季节图表""" # 菜单可用状态改变 main_window = self.parent().parent() main_window.export_table.setEnabled(True) # 获取表格的行数和列数 col-列,row-行 # col_count = self.table_widget.columnCount() row_count = self.table_widget.rowCount() # if not row_count: # return # 隐藏与可见的处理 self.confirm_button.setEnabled(False) self.map_widget.hide() self.table_widget.hide() self.web_view.show() self.tool_view_all.setEnabled(True) # 获取数据,处理数据,将结果数据传入页面展示 # print("列数", col_count) # print("行数", row_count) # 遍历获取数据 data = OrderedDict() for row in range(row_count): date = self.table_widget.item(row_count - 1, 0).text() # date = date[:4] + "/" + date[4:6] + "/" + date[6:] price = self.table_widget.item(row_count - 1, 1).text() if date[:4] not in data.keys(): data[date[:4]] = [] data[date[:4]].append([date, price]) # for col in range(col_count): # print(self.table_widget.item(row_count-1, col).text(), ' ', end='') row_count -= 1 # 数据处理 finally_data = self.data_handler(data) # print(finally_data) self.tools.tool_click_signal.emit(finally_data) # 数据传到页面 def return_view_all(self): # 加入自定义控件 self.confirm_button.setEnabled(True) self.web_view.hide() self.map_widget.show() self.table_widget.show() self.tool_view_all.setEnabled(False) # 菜单可用状态改变 main_window = self.parent().parent() main_window.export_table.setEnabled(False) @staticmethod def generate_axis_x(): """生成横坐标数据, 以闰年计""" start_day = datetime.datetime.strptime("20160101", "%Y%m%d") end_day = datetime.datetime.strptime("20161231", "%Y%m%d") axis_x = [] for date in GenerateTime(begin=start_day, end=end_day).generate_time(): axis_x.append(date[4:]) return axis_x def data_handler(self, data): """ 页面展示图表的数据处理 :param data: :return: json Data """ axis_x = self.generate_axis_x( ) # 生成横坐标,整理用于作折线的原始数据,结果的结构{year:[[date, value], [date, value],...]} month_data = OrderedDict() # 创建一个字典存放数据 map_data = OrderedDict() # 存用于作图的数据 # 将数据以月份为单位分开,结果的结构 {year:{month:[up_down, shock]}} for year in data: # 年为单位的数据 month_data[year] = {} map_data[year] = [] for year_item in data[year]: # 每年的各个数据 for x in axis_x: if x == year_item[0][4:]: map_data[year].append([x, year_item[1]]) # 放入当天的数据用于作图的 # 根据时间将数据重新整理 month = year_item[0][4:6] if month not in month_data[year].keys(): month_data[year][month] = [] month_data[year][month].append( year_item ) # month_data = json.dumps(month_data) # {year:{month:[[date, price], ...]}} new_month_data = OrderedDict() last_price = None for y in month_data: # {year:{month:[[date, price], ...]}} if y not in new_month_data: new_month_data[y] = OrderedDict() for m in [ '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12' ]: one_month_data = month_data[y].get(m) if one_month_data: last = int(one_month_data[-1][1]) # 计算涨跌 up_down = None if last_price: up_down = "%.4f" % ((last - last_price) / last_price) if last_price else "-" up_down = "%.2f" % (float(up_down) * 100) if last_price else "-" last_price = last # 计算波幅 data_set = [] for item in one_month_data: data_set.append(int(item[1])) min_price = min(data_set) max_price = max(data_set) shock = "%.4f" % ((max_price - min_price) / min_price) if min_price else "-" # 波幅 shock = "%.2f" % (float(shock) * 100) if min_price else "-" new_month_data[y][m] = [] new_month_data[y][m].append(up_down) new_month_data[y][m].append(shock) else: last_price = None # title的处理 title = "" if self.name == "variety_price": title = self.exchange_lib.currentText( ) + self.variety_lib.currentText() + "品种权重指数" if self.name == "main_contract": title = self.exchange_lib.currentText( ) + self.variety_lib.currentText() + "主力合约指数" # 整理数据 finally_data = dict() finally_data["raw"] = data finally_data["result"] = new_month_data finally_data["mapData"] = map_data finally_data["title"] = title return json.dumps(finally_data) def download_requested(self, download_item): # 保存位置选择,默认桌面 if not download_item.isFinished() and download_item.state() == 0: cur_window = self.parent().parent().window_stack.currentWidget() if cur_window.name == "variety_price": title = "品种权重指数季节表" elif cur_window.name == "main_contract": title = "主力合约指数季节表" else: return desktop_path = get_desktop_path() save_path = QFileDialog.getExistingDirectory( self, "选择保存的位置", desktop_path) if not save_path: return cur_time = datetime.datetime.strftime(datetime.datetime.now(), "%Y%m%d") excel_name = cur_window.exchange_lib.currentText( ) + cur_window.variety_lib.currentText() + title + cur_time file_path = save_path + "/" + excel_name + ".xls" download_item.setPath(file_path) download_item.accept() self.season_table_file = file_path download_item.finished.connect(self.download_finished) def download_finished(self): try: if self.season_table_file: open_dialog = QMessageBox.question( self, "成功", "导出保存成功!\n是否现在打开?", QMessageBox.Yes | QMessageBox.No) if open_dialog == QMessageBox.Yes: open_excel( self.season_table_file) # 调用Microsoft Excel 打开文件 self.season_table_file = None except Exception as e: pass