def addFolderToLibrary(self): dir = QFileDialog.getExistingDirectory(None, "Open Directory", Foo.readConfig('options')['music_folder'], QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) self.thread = WorkThread(dir, True) self.thread.finished.connect(self.tree.initUI) self.thread.start()
def scanMusicFolder(self): thread = QtCore.QThread(self) thread.worker = WorkThread( Foo.readConfig('options')['music_folder'], False) thread.worker.moveToThread(thread) thread.started.connect(thread.worker.process) thread.worker.finished.connect(thread.quit) thread.worker.finished.connect(thread.worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.finished.connect(self.tree.initUI) thread.start()
def train_model1(self): if self.Data.columns[0] != 'date': self.label_current_message.setText( '請確認資料欄位名稱,第一個欄位為date,且格式為yyyy/mm/dd或yyyy-mm-dd') else: self.label_current_message.setText('模型計算中,請稍後...') self.Data.loc[:, 'date'] = pd.to_datetime(self.Data.loc[:, 'date']) self.Data = self.Data.sort_values('date') self.column_name = self.Data.columns[1:] # self.p_range, self.d_range, self.q_range = range(0, 4), range(0, 2), range(0, 4)############### pdq, self.column_model_dict = list( itertools.product(self.p_range, self.d_range, self.q_range)), {} self.value_bar = 0 self.bar_upload.setValue(self.value_bar) # TODO: new threadl class. self.work = WorkThread(self.Data, self.column_name, pdq, self.model, self.model_fit) self.work.start() self.work.processbar_trigger.connect(self.set_processbar_value) self.work.result_trigger.connect(self.complete_slot)
def addFolderToLibrary(self): dir = QFileDialog.getExistingDirectory( None, "Open Directory", Foo.readConfig('options')['music_folder'], QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) thread = QtCore.QThread(self) thread.worker = WorkThread(dir, True) thread.worker.moveToThread(thread) thread.started.connect(thread.worker.process) thread.worker.finished.connect(thread.quit) thread.worker.finished.connect(thread.worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.finished.connect(self.tree.initUI) thread.start()
class MainWindow(QMainWindow): def __init__(self): super().__init__() # 設定持續使用的變數 self.Data = None # 輸入資料 self.column_name = None # 輸入資料需要建立模型的變數名稱 self.model = None # 未訓練的模型,只有參數 self.column_model_dict = None self.worker = None self.model_fit = None # 已訓練的模型 self.result = None # 訓練預測結果整理 self.value_bar = 0 self.p_range, self.d_range, self.q_range = range(0, 7), range( 0, 3), range(0, 7) #【設定初始化,UI標題與視窗大小】 self.setWindowTitle('Marketing model ver 1.0') self.setWindowIcon(QIcon("favicon.ico")) self.resize(QSize(1300, 950)) #【設定UI中的元件】 # 按鍵顯示 self.btn_upload_csv = QPushButton('載入csv資料') self.btn_run_model = QPushButton('執行預測') self.btn_run_break = QPushButton('動作中斷') self.btn_download_result = QPushButton('下載預測結果') # 字元顯示 self.label_maintitle = QLabel('銷售模型預測程式') self.label_upload_filename = QLabel() # 如果一開始沒有要設定內容,可直接設定初始為空白 self.label_input_data = QLabel('輸入資料') self.label_output_plot = QLabel('預測結果折線圖') self.label_output_data = QLabel('預測兩期結果') self.label_current_message = QLabel('') # self.version_number = QLabel('V1.0') # 進度條顯示 self.bar_upload = QProgressBar() # 表格顯示 self.table_input_data = QTableView() self.table_output_data = QTableView() # 圖片顯示 self.plot_output_result = MplWidget() ### 字型設定 self.label_maintitle.setStyleSheet( "QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 15pt; font-weight: bold;}" ) self.label_input_data.setStyleSheet( "QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 12pt; font-weight: bold;}" ) self.label_output_plot.setStyleSheet( "QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 12pt; font-weight: bold;}" ) self.label_output_data.setStyleSheet( "QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 12pt; font-weight: bold;}" ) self.label_upload_filename.setStyleSheet( "QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 9pt}" ) self.label_current_message.setStyleSheet( "QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 10pt;}" ) self.label_upload_filename.setWordWrap(True) # 自動換行 self.label_current_message.setWordWrap(True) ### 按鍵字元設定 self.btn_upload_csv.setStyleSheet( "QPushButton{font-family: Microsoft JhengHei;}") self.btn_run_model.setStyleSheet( "QPushButton{font-family: Microsoft JhengHei;}") self.btn_run_break.setStyleSheet( "QPushButton{font-family: Microsoft JhengHei;}") self.btn_download_result.setStyleSheet( "QPushButton{font-family: Microsoft JhengHei;}") ### 進度條設定 self.bar_upload.setRange(0, 4) self.bar_upload.setValue(0) self.bar_upload.setStyleSheet(""" QProgressBar{ font-family: Microsoft JhengHei; background-color: rgb(255, 230, 204); text-align: center; } QProgressBar::chunk{ background-color: rgb(230, 132, 0); } """) ### 表格大小設定 self.table_input_data.horizontalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) # 把顯示表格的寬調整到最小 self.table_output_data.setMinimumHeight(105) # 設定顯示的最小高度 self.table_output_data.setMaximumHeight(110) # 設定顯示的最大高度 ### 圖片大小設定 self.plot_output_result.setMinimumHeight(475) #【設定佈局(layout)】 # main layout layout = QHBoxLayout( ) # 建立layout並指定layout為水平切分 # 建立layout之後要定義一個widget讓layout設定進去(註*1) # left layout left_layout = QVBoxLayout() # 設定此layout為垂直切分 left_layout.addWidget(self.label_maintitle) # 建立layout之後就可以塞元件了 left_layout.addWidget(self.btn_upload_csv) left_layout.addWidget(self.bar_upload) left_layout.addWidget(self.label_upload_filename) left_layout.addWidget(self.label_input_data) left_layout.addWidget(self.table_input_data) left_widget = QWidget() left_widget.setLayout( left_layout) # 建立left layout的widget(參考main layout的註*1) # right layout right_layout = QVBoxLayout() right_layout.addWidget(self.label_output_plot) right_layout.addWidget(self.plot_output_result) right_layout.addWidget(self.label_output_data) right_layout.addWidget(self.table_output_data) # 在right layout裡面加入一個水平切分的子layout run_output_layout = QHBoxLayout() ### run_output_layout.addWidget(self.btn_run_model) run_output_layout.addWidget(self.btn_run_break) run_output_layout.addWidget(self.btn_download_result) run_output_widget = QWidget() run_output_widget.setLayout(run_output_layout) # 子layout收尾成widget run_process_layout = QHBoxLayout() ### run_process_layout.addWidget(self.label_current_message) run_process_layout.addWidget(self.bar_upload) # run_process_layout.addWidget(self.version_number) run_process_layout.setStretchFactor(self.label_current_message, 3) run_process_layout.setStretchFactor(self.bar_upload, 2) # run_process_layout.setStretchFactor(self.version_number, 1) run_process_widget = QWidget() run_process_widget.setLayout(run_process_layout) # 子layout收尾成widget right_layout.addWidget( run_output_widget ) # 在right_layout加入run_output_widget與run_process_widget right_layout.addWidget(run_process_widget) right_widget = QWidget() right_widget.setLayout(right_layout) # 建立right layout的widget layout.addWidget( left_widget) # 設定好left與right layout的widget之後加入在main layout layout.addWidget(right_widget) layout.setStretchFactor(left_widget, 1) # 設定left_widget與right_widget的比例 layout.setStretchFactor(right_widget, 3) main_widget = QWidget() # (註*1)每一次建layout後要用widget包 main_widget.setLayout(layout) # (註*1)每一次建layout後要用widget包 self.setCentralWidget(main_widget) # 設定main_widget為中心視窗 #【設定button觸發的slot(function)】 self.btn_upload_csv.clicked.connect(self.upload_data_slot) self.btn_run_model.clicked.connect(self.run_model_slot) self.btn_run_break.clicked.connect(self.break_slot) self.btn_download_result.clicked.connect(self.download_data_slot) # 【設定thread】 self.work = None self.stopped = None # 暫停thread標籤 def upload_data_slot(self): """Slot of uploading data (with btn_upload_csv)""" file, _ = QFileDialog.getOpenFileName( self, "Open file", "", "Data Files (*.csv)") # 建立開啟檔案的對話盒(dialog) if file: print('file path: {}'.format(file)) self.label_upload_filename.setText( file) # 將label_upload_filename複寫為檔名(file) self.Data = pd.read_table(r'{}'.format(file), sep=',') # 寫入檔案 self.table_input_data.setModel(pandasModel( self.Data)) # 在table_input_data顯示輸入資料的表格 def run_model_slot(self): """Slot of running model (with btn_run_model)""" if self.Data is None: self.label_current_message.setText('尚未有資料以執行!請確認是否已載入資料。') else: self.stopped = False self.train_model1() self.btn_run_model.setEnabled(False) def break_slot(self): """Slot of stopping (with btn_run_break)""" if (self.Data is None) or (self.stopped != False): print('正常不反應') self.label_current_message.setText('') else: print('Thread stopped.') self.work.stopped = True self.bar_upload.reset() self.label_current_message.setText('程序中斷。') self.btn_run_model.setEnabled(True) def complete_slot(self, data): """Slot of stopping (with btn_run_break)""" # Show result self.result = data self.table_output_data.setModel( pandasModel(data.loc[:, ['date'] + [i for i in self.column_name]]) ) # 顯示表格在table_output_data self.show_plot() # 參照show_plot() self.label_current_message.setText('模型計算完畢!') self.stopped = False self.btn_run_model.setEnabled(True) def download_data_slot(self): """Slot of downloading data (with btn_download_result)""" if self.result is None: self.label_current_message.setText('尚未有預測結果!請確認是否已載入資料並執行預測。') else: fileName, _ = QFileDialog.getSaveFileName( self, 'Save file', '', '*.csv') # 建立儲存檔案的對話盒(dialog) if fileName: self.result['date'] = pd.to_datetime(self.result['date']) raw_input_data = self.Data.copy( ) # 需要把原資料copy,否則直接取用的話,輸出結果會隨著下載次數而無謂增加 output_data = raw_input_data.append( self.result.loc[:, ['date'] + [i for i in self.column_name]]) output_data.to_csv(fileName, index=None) def train_model1(self): if self.Data.columns[0] != 'date': self.label_current_message.setText( '請確認資料欄位名稱,第一個欄位為date,且格式為yyyy/mm/dd或yyyy-mm-dd') else: self.label_current_message.setText('模型計算中,請稍後...') self.Data.loc[:, 'date'] = pd.to_datetime(self.Data.loc[:, 'date']) self.Data = self.Data.sort_values('date') self.column_name = self.Data.columns[1:] # self.p_range, self.d_range, self.q_range = range(0, 4), range(0, 2), range(0, 4)############### pdq, self.column_model_dict = list( itertools.product(self.p_range, self.d_range, self.q_range)), {} self.value_bar = 0 self.bar_upload.setValue(self.value_bar) # TODO: new threadl class. self.work = WorkThread(self.Data, self.column_name, pdq, self.model, self.model_fit) self.work.start() self.work.processbar_trigger.connect(self.set_processbar_value) self.work.result_trigger.connect(self.complete_slot) def set_processbar_value(self, value): self.bar_upload.setValue(value) def show_plot(self): """Slot of showing plot""" if self.result is None: print('目前無結果。') else: self.plot_output_result.setRows(len( self.column_name)) # 設定subplot的列數 for i, column in enumerate(self.column_name): self.plot_output_result.canvas.ax[ i].plot( # 畫原資料 + 預測結果,以紅色線表示 range(1, len(self.Data) + 3), [i for i in self.Data.loc[:, column]] + [i for i in self.result.loc[:, column]], linewidth=1, color='firebrick') self.plot_output_result.canvas.ax[ i].plot( # 畫原資料,以藍色線表示(使得只有預測曲線是紅的) range(1, len(self.Data) + 1), self.Data.loc[:, column], color='steelblue') self.plot_output_result.canvas.ax[i].fill_between( # 畫信賴區間的背景 range(len(self.Data), len(self.Data) + 3), [self.Data.loc[:, column].values[-1]] + [i for i in self.result.loc[:, column + '_LB']], [self.Data.loc[:, column].values[-1]] + [i for i in self.result.loc[:, column + '_UB']], facecolor='salmon', alpha=0.6, interpolate=True) self.plot_output_result.canvas.ax[i].set_ylabel(column) self.plot_output_result.canvas.ax[-1].set_xlabel( 'Week', fontproperties=FontProperties(fname="SimHei.ttf", size=14)) self.plot_output_result.canvas.figure.subplots_adjust( wspace=0.1, hspace=0.5) # 調整子圖間距 self.plot_output_result.canvas.draw() # 類似plt.show()
class Foo(QtGui.QMainWindow): def __init__(self): super(Foo, self).__init__() self.initUI() def initUI(self): config = Foo.readConfig('options') self.timeOut = -1 self.radio = False self.statusBar().showMessage('Ready') self.createMenu() self.setWindowTitle("Foo.cd") self.player = Player(Foo.readConfig('audio')) self.player.bus.connect('message::eos', self.stop) self.player.bus.connect('message::duration-changed', self.onDurationChanged) self.tree = Tree(self, config['tree_order']) self.tree.addSongs.connect(self.addSongsFromTree) self.tree.customContextMenuRequested.connect(self.tmpTag) if not self.radio: self.table=Table( self, config) self.handlerATF = self.player.playbin.connect("about-to-finish", self.onAboutToFinish) self.table.runAction.connect(self.tableAction) else: configRadio = Foo.readConfigRadios() self.table=TableRadio( self, configRadio) self.table.runAction.connect(self.tableAction) self.handlerT = self.player.bus.connect('message::tag', self.table.onTag) self.playbackButtons = PlaybackButtons(None) self.playbackButtons.buttonPlay.clicked.connect(self.toggleSong) self.playbackButtons.buttonStop.clicked.connect(self.stop) self.playbackButtons.buttonPrev.clicked.connect(self.previous) self.playbackButtons.buttonNext.clicked.connect(self.next) self.volumeSlider = VolumeSlider(self) self.scrollSlider = widget.createScrollSlider(self) self.scrollSlider.sliderMoved.connect(self.player.seek) self.scrollSlider.sliderPressed.connect(self.player.toggle) self.scrollSlider.sliderReleased.connect(self.player.toggle) self.volumeSlider.sliderMoved.connect(self.player.setVolume) self.pixmap = Image(self, config['cover_names'], config['extensions']) # Album cover connections self.tree.selectionModel().selectionChanged.connect(lambda: self.pixmap.onSelectionChanged(self.tree.getChildren()[0].get('file', None))) self.table.selectionModel().selectionChanged.connect(lambda: self.pixmap.onSelectionChanged(self.table.getSelection().get('file', None))) self.searchArea = SearchArea(self) self.searchArea.searchLine.returnPressed.connect(self.startSearch) self.playbackButtons.addWidget(self.volumeSlider) self.playbackButtons.addWidget(self.scrollSlider) splitterLeftRight = QtGui.QSplitter() self.splitterTopBottom = QtGui.QSplitter(Qt.Vertical, self) self.infoFrame = QtGui.QFrame() infoLayout = QtGui.QVBoxLayout() infoLayout.setContentsMargins(0,0,0,0) infoLayout.addLayout(self.playbackButtons) infoLayout.addWidget(self.pixmap) self.infoFrame.setLayout(infoLayout) libLayout = QtGui.QVBoxLayout() libLayout.setContentsMargins(0,0,0,0) libLayout.addWidget(self.tree) libLayout.addLayout(self.searchArea) libFrame = QtGui.QFrame() libFrame.setLayout(libLayout) self.splitterTopBottom.addWidget(self.table) self.splitterTopBottom.addWidget(self.infoFrame) self.splitterTopBottom.setStretchFactor(0,3) self.splitterTopBottom.setStretchFactor(1,1) splitterLeftRight.addWidget(libFrame) splitterLeftRight.addWidget(self.splitterTopBottom) splitterLeftRight.setStretchFactor(0,2) splitterLeftRight.setStretchFactor(1,3) mainLayout = QtGui.QGridLayout() mainLayout.setContentsMargins(4, 4, 4, 4) mainLayout.addWidget(splitterLeftRight) dummyWidget = QtGui.QWidget() dummyWidget.setLayout(mainLayout) self.setCentralWidget(dummyWidget) self.setTabOrder(self.tree, self.table) dictShortcuts = self.readConfig('shortcuts') modifier = dictShortcuts['modifier']+'+' self.shortQuit = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['quit']), self, self.close) self.shortStop = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['stop']), self, self.stop) self.shortPlayPause = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['play_pause']), self, self.toggleSong) self.shortSongPrevious = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['previous']), self, self.previous) self.shortSongNext = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['next']), self, self.next) self.shortVolDown = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['volume_down']), self, self.volumeSlider.decr) self.shortVolUp = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['volume_up']), self, self.volumeSlider.incr) self.shortRadioMode = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['radio_mode']), self, self.toggleRadio) self.shortEqualizer = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['equalizer']), self, self.openEqualizer) pipeWorker = WorkThreadPipe() pipeWorker.hotKey.connect(self.onHotKey) pipeWorker.start() self.show() def keyReleaseEvent(self, event): if event.key() == Qt.Key_Alt: self.menuBar().setVisible(not self.menuBar().isVisible()) else: QWidget.keyPressEvent(self, event) # Triggered by player end of stream event # or called by hand to stop the stream def stop(self, bus=None, msg=None): self.player.stop() self.scrollSlider.setValue(0) self.table.displayPlayToStop() self.stopStatusEmission('Ready') def previous(self): if self.table.playingId > 0: self.player.stop() self.table.playingId-=1 self.player.add(self.table.model().item(self.table.playingId,0).data()['file']) self.player.play() def next(self): if self.table.model().rowCount()-1 > self.table.playingId: self.player.stop() self.table.playingId+=1 self.player.add(self.table.model().item(self.table.playingId,0).data()['file']) self.player.play() def toggleSong(self): state = self.player.playbin.get_state(Gst.State.NULL) if state[1] == Gst.State.PLAYING: self.table.displayPlayToPause() self.player.toggle() status = self.statusBar().currentMessage().replace('Playing', 'Paused') self.stopStatusEmission(status) else: self.table.displayPauseToPlay(self.table.playingId) self.player.toggle() #self.onDurationChanged(0,0) status = self.table.getStatus() self.setStatusEmission(status) # Triggered by player when a song starts def onDurationChanged(self, bus, msg): self.table.displayNext() print('Duration changed signal !') # Triggered by player at the end of a song def onAboutToFinish(self, bus): if self.table.model().rowCount()-1 > self.table.playingId: print('About to finish !') self.table.playingId+=1 self.player.add(self.table.model().item(self.table.playingId,0).data()['file']) def addSongsFromTree(self, list, play): if not self.radio: i = self.table.model().rowCount() for l in list: self.table.addRow(l) self.table.resizeRowsToContents() if play: self.stop() self.player.add(list[0]['file']) self.player.play() self.table.displayStopToPlay(i) status = self.table.getStatus() self.setStatusEmission(status) def setStatusEmission(self, status): if self.timeOut > 0: GObject.source_remove(self.timeOut) self.timeOut = GObject.timeout_add(1000, self.update, status) def stopStatusEmission(self, status): if self.timeOut > 0: GObject.source_remove(self.timeOut) self.timeOut = GObject.timeout_add(0, self.update, status) self.timeOut=-1 def update(self, status): print('.') try: duration_nanosecs = self.player.getDuration() duration = float(duration_nanosecs) / 1000000000 self.scrollSlider.setRange(0, duration) nanosecs = self.player.getPosition() position = float(nanosecs) // 1000000000 self.scrollSlider.setValue(position) m, s = divmod(position, 60) self.statusBar().showMessage(status.replace('%',"%02d:%02d" % (m, s))) except Exception as e: print(e) pass if 'Playing' in status: return True else: return False def tableAction(self, str): if str == 'stop': self.stop() elif str == 'play': if self.table.selectedIndexes(): index = self.table.selectedIndexes()[0] else: index= self.table.model().index(self.table.selectionModel().currentIndex().row(),0) songURI = index.model().itemFromIndex(index).data()['file'] self.player.stop() self.player.add(songURI) self.player.play() self.table.displayStopToPlay(index.row()) status = self.table.getStatus() self.setStatusEmission(status) @staticmethod def readConfig(section): parser = RawConfigParser() if getattr(sys, 'frozen', False): # frozen parser.read(os.path.dirname(os.path.realpath(sys.executable))+'/config') else: # unfrozen parser.read(os.path.dirname(os.path.realpath(__file__))+'/config') return dict(parser.items(section)) #Create menu bar def createMenu(self): self.menuBar() self.menuBar().setVisible(False) actionMenu = self.menuBar().addMenu('&Action') scanMusicFolderAction = QtGui.QAction('Scan Music Folder', self) showShortcutAction = QtGui.QAction('Show Shortcut',self) addFolderToLibraryAction = QtGui.QAction('Add Folder to Library',self) self.toggleRadioAction= QtGui.QAction('Switch to Radio mode',self) if not self.radio: self.toggleRadioAction.setText('Switch to Radio mode') else: self.toggleRadioAction.setText('Switch to Library mode') #scanMusicFolderAction.setShortcut('Ctrl+N') #scanMusicFolderAction.setStatusTip('Create new file') scanMusicFolderAction.triggered.connect(self.scanMusicFolder) actionMenu.addAction(scanMusicFolderAction) showShortcutAction.triggered.connect(self.showShortcut) actionMenu.addAction(showShortcutAction) addFolderToLibraryAction.triggered.connect(self.addFolderToLibrary) actionMenu.addAction(addFolderToLibraryAction) self.toggleRadioAction.triggered.connect(self.toggleRadio) actionMenu.addAction(self.toggleRadioAction) # Menu Action 1 def scanMusicFolder(self): self.thread = WorkThread(Foo.readConfig('options')['music_folder'], False) self.thread.finished.connect(self.tree.initUI) self.thread.start() # Menu Action 2 def showShortcut(self): dictSC = Foo.readConfig('shortcuts') message = '''<b>'''+dictSC['modifier']+'''+'''+dictSC['stop']+'''</b> : Stop<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['quit']+'''</b> : Quit<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['play_pause']+'''</b> : Play/Pause <br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['previous']+'''</b> : Previous<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['next']+'''</b> : Next<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['volume_down']+'''</b> : Volume down<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['volume_up']+'''</b> : Volume up<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['radio_mode']+'''</b> : Toggle radio mode<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['equalizer']+'''</b> : Equalizer<br/>''' print(len(self.findChildren(QtCore.QObject))) box = QMessageBox.about(self, 'About Shortcuts', message) print(len(self.findChildren(QtCore.QObject))) print('must delete') # Menu Action3 # Must be subdirectory of music folder otherwise wont be rescanned def addFolderToLibrary(self): dir = QFileDialog.getExistingDirectory(None, "Open Directory", Foo.readConfig('options')['music_folder'], QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) self.thread = WorkThread(dir, True) self.thread.finished.connect(self.tree.initUI) self.thread.start() # Menu Action4 def toggleRadio(self): self.table.deleteLater() self.table.close() if not self.radio: configRadio = Foo.readConfig('radios') self.table=TableRadio(self.tree, configRadio) self.toggleRadioAction.setText('Switch to Library mode') self.radio=True self.player.playbin.disconnect(self.handlerATF) self.handlerT=self.player.bus.connect('message::tag', self.table.onTag) else: config = Foo.readConfig('options') self.table=Table( self.tree, config) self.toggleRadioAction.setText('Switch to Radio mode') self.radio=False self.handlerATF = self.player.playbin.connect("about-to-finish",self.onAboutToFinish) self.player.bus.disconnect(self.handlerT) self.splitterTopBottom.addWidget(self.table) # Since the frame is already attached to the splitter, # it only moves it to the new position self.splitterTopBottom.addWidget(self.infoFrame) self.splitterTopBottom.setStretchFactor(0,3) self.splitterTopBottom.setStretchFactor(1,1) self.table.runAction.connect(self.tableAction) self.setTabOrder(self.tree, self.table) @QtCore.pyqtSlot() def startSearch(self): input = self.searchArea.searchLine.text() db = thread.load() songList = [] songGenerator = (Song(self.tree.comm, **dict) for dict in db) self.tree.model().removeRows(0, self.tree.model().rowCount()) if self.searchArea.searchExact.isChecked(): songList = [ e for e in songGenerator if e.exactMatch(input) ] elif self.searchArea.searchPrecise.isChecked(): songList = [ e for e in songGenerator if e.preciseMatch(input) ] else: songList = [ e for e in songGenerator if e.fuzzyMatch(input) ] del db[:] songList.sort(key=self.tree.sortFunc) self.tree.populateTree(songList) @QtCore.pyqtSlot(str) def onHotKey(self, key): print('Hotkey was pressed', key) if key == 'quit': self.shortQuit.activated.emit() if key == 'stop': self.shortStop.activated.emit() if key == 'play_pause': self.shortPlayPause.activated.emit() if key == 'volume_up': self.shortVolUp.activated.emit() if key == 'volume_down': self.shortVolDown.activated.emit() if key == 'song_next': self.shortSongNext.activated.emit() if key == 'song_prev': self.shortSongPrev.activated.emit() if key == 'tree_up': if self.radio: self.table.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Up, Qt.KeyboardModifier(), '')) else: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Up, Qt.KeyboardModifier(), '')) if key == 'tree_down': if self.radio: self.table.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Down, Qt.KeyboardModifier(), '')) else: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Down, Qt.KeyboardModifier(), '')) if key == 'tree_left': if not self.radio: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Left, Qt.KeyboardModifier(), '')) if key == 'tree_right': if not self.radio: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Right, Qt.KeyboardModifier(), '')) if key == 'tree_validate': if self.radio: self.table.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Return, Qt.KeyboardModifier(), '')) else: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Return, Qt.KeyboardModifier(), '')) if key == 'tree_append': if not self.radio: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Return, Qt.KeyboardModifier(QtCore.Qt.ShiftModifier), '')) if key == 'radio_mode': self.shortRadioMode.activated.emit() def tmpTag(self, position): menu = QtGui.QMenu() tagging = QtGui.QAction('Tagging',self) replayGain = QtGui.QAction('ReplayGain',self) tagging.triggered.connect(self.openTagging) replayGain.triggered.connect(self.startReplayGain) menu.addAction(tagging) menu.addAction(replayGain) menu.exec_(self.tree.viewport().mapToGlobal(position)) def startReplayGain(self): children = self.tree.getChildren() self.RG = ReplayGain([x['file'] for x in children]) self.RG.exec_() def openTagging(self): children = self.tree.getChildren() #[7:] to drop the 'file://' appended for gstreamer retag = Retagging([x['file'][7:] for x in children]) res = retag.exec_() if res: self.tree.initUI() print(res) def openEqualizer(self): from configparser import RawConfigParser equa = Equalizer(self, Foo.readConfig('audio')) equa.equalize.connect(self.applyEqua) if equa.exec_(): parser = RawConfigParser() parser.read(os.path.dirname(os.path.realpath(__file__))+'/config') parser['audio']['settings']= str(equa.config) with open(os.path.dirname(os.path.realpath(__file__))+'/config', 'w') as configfile: parser.write(configfile) def applyEqua(self,band, value): print('receiving equa', str(band), value) if str(band) == 'band0' and value == 0: self.player.equalizer.set_property('band0', 0.01) else: self.player.equalizer.set_property(str(band), value)
def scanMusicFolder(self): self.thread = WorkThread(Foo.readConfig('options')['music_folder'], False) self.thread.finished.connect(self.tree.initUI) self.thread.start()