class VideoPlayer(QWidget): def __init__(self, aPath, parent=None): super(VideoPlayer, self).__init__(parent) self.setAttribute(Qt.WA_NoSystemBackground, True) self.setAcceptDrops(True) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.StreamPlayback) self.mediaPlayer.setVolume(80) self.videoWidget = QVideoWidget(self) self.videoWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.videoWidget.setMinimumSize(QSize(640, 360)) self.lbl = QLineEdit('00:00:00') self.lbl.setReadOnly(True) self.lbl.setFixedWidth(70) self.lbl.setUpdatesEnabled(True) self.lbl.setStyleSheet(stylesheet(self)) self.elbl = QLineEdit('00:00:00') self.elbl.setReadOnly(True) self.elbl.setFixedWidth(70) self.elbl.setUpdatesEnabled(True) self.elbl.setStyleSheet(stylesheet(self)) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setFixedWidth(32) self.playButton.setStyleSheet("background-color: black") self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal, self) self.positionSlider.setStyleSheet(stylesheet(self)) self.positionSlider.setRange(0, 100) self.positionSlider.sliderMoved.connect(self.setPosition) self.positionSlider.sliderMoved.connect(self.handleLabel) self.positionSlider.setSingleStep(2) self.positionSlider.setPageStep(20) self.positionSlider.setAttribute(Qt.WA_TranslucentBackground, True) self.clip = QApplication.clipboard() self.process = QProcess(self) self.process.readyRead.connect(self.dataReady) self.process.finished.connect(self.playFromURL) self.myurl = "" # channel list self.channelList = QListView(self) self.channelList.setMinimumSize(QSize(150, 0)) self.channelList.setMaximumSize(QSize(150, 4000)) self.channelList.setFrameShape(QFrame.Box) self.channelList.setObjectName("channelList") self.channelList.setStyleSheet("background-color: black; color: #585858;") self.channelList.setFocus() # for adding items to list must create a model self.model = QStandardItemModel() self.channelList.setModel(self.model) self.controlLayout = QHBoxLayout() self.controlLayout.setContentsMargins(5, 0, 5, 0) self.controlLayout.addWidget(self.playButton) self.controlLayout.addWidget(self.lbl) self.controlLayout.addWidget(self.positionSlider) self.controlLayout.addWidget(self.elbl) self.mainLayout = QHBoxLayout() # contains video and cotrol widgets to the left side self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.addWidget(self.videoWidget) self.layout.addLayout(self.controlLayout) # adds channels list to the right self.mainLayout.addLayout(self.layout) self.mainLayout.addWidget(self.channelList) self.setLayout(self.mainLayout) self.myinfo = "©2020\nTIVOpy v1.0" self.widescreen = True #### shortcuts #### self.shortcut = QShortcut(QKeySequence("q"), self) self.shortcut.activated.connect(self.handleQuit) self.shortcut = QShortcut(QKeySequence("u"), self) self.shortcut.activated.connect(self.playFromURL) self.shortcut = QShortcut(QKeySequence(Qt.Key_Space), self) self.shortcut.activated.connect(self.play) self.shortcut = QShortcut(QKeySequence(Qt.Key_F), self) self.shortcut.activated.connect(self.handleFullscreen) self.shortcut = QShortcut(QKeySequence(Qt.Key_Escape), self) self.shortcut.activated.connect(self.exitFullscreen) self.shortcut.activated.connect(self.handleFullscreen) self.shortcut = QShortcut(QKeySequence("i"), self) self.shortcut.activated.connect(self.handleInfo) self.shortcut = QShortcut(QKeySequence("s"), self) self.shortcut.activated.connect(self.toggleSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Right), self) self.shortcut.activated.connect(self.forwardSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Left), self) self.shortcut.activated.connect(self.backSlider) self.mediaPlayer.setVideoOutput(self.videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.positionChanged.connect(self.handleLabel) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) self.populateChannelList() self.selectChannel() self.initialPlay() def playFromURL(self): self.mediaPlayer.pause() self.myurl = self.clip.text() self.mediaPlayer.setMedia(QMediaContent(QUrl(self.myurl))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() print(self.myurl) def dataReady(self): self.myurl = str(self.process.readAll(), encoding='utf8').rstrip() ### self.myurl = self.myurl.partition("\n")[0] print(self.myurl) self.clip.setText(self.myurl) self.playFromURL() def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPause)) else: self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionSlider.setValue(position) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) mtime = QTime(0, 0, 0, 0) mtime = mtime.addMSecs(self.mediaPlayer.duration()) self.elbl.setText(mtime.toString()) def setPosition(self, position): self.mediaPlayer.setPosition(position) def handleError(self): self.playButton.setEnabled(False) print("Error: ", self.mediaPlayer.errorString()) def handleQuit(self): self.mediaPlayer.stop() print("Goodbye ...") app.quit() def contextMenuRequested(self, point): menu = QMenu() actionURL = menu.addAction(QIcon.fromTheme("browser"), "URL from Clipboard (u)") menu.addSeparator() actionToggle = menu.addAction(QIcon.fromTheme("next"), "Show / Hide Channels (s)") actionFull = menu.addAction(QIcon.fromTheme("view-fullscreen"), "Fullscreen (f)") menu.addSeparator() actionInfo = menu.addAction(QIcon.fromTheme("help-about"), "About (i)") menu.addSeparator() actionQuit = menu.addAction(QIcon.fromTheme("application-exit"), "Exit (q)") actionQuit.triggered.connect(self.handleQuit) actionFull.triggered.connect(self.handleFullscreen) actionInfo.triggered.connect(self.handleInfo) actionToggle.triggered.connect(self.toggleSlider) actionURL.triggered.connect(self.playFromURL) menu.exec_(self.mapToGlobal(point)) def wheelEvent(self, event): mscale = event.angleDelta().y() / 13 self.mediaPlayer.setVolume(self.mediaPlayer.volume() + mscale) print("Volume: " + str(self.mediaPlayer.volume())) def mouseDoubleClickEvent(self, event): if event.buttons() == Qt.LeftButton: self.handleFullscreen() def handleFullscreen(self): if self.windowState() and Qt.WindowFullScreen: self.showNormal() else: self.showFullScreen() def exitFullscreen(self): self.showNormal() def handleInfo(self): QMessageBox.about(self, "About", self.myinfo) def toggleSlider(self): if self.positionSlider.isVisible(): self.hideSlider() else: self.showSlider() def hideSlider(self): self.channelList.hide() self.playButton.hide() self.lbl.hide() self.positionSlider.hide() self.elbl.hide() def showSlider(self): self.channelList.show() self.playButton.show() self.lbl.show() self.positionSlider.show() self.elbl.show() self.channelList.setFocus() def forwardSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 1000 * 60) def backSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 1000 * 60) def volumeUp(self): self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 10) print("Volume: " + str(self.mediaPlayer.volume())) def volumeDown(self): self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 10) print("Volume: " + str(self.mediaPlayer.volume())) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() elif event.mimeData().hasText(): event.accept() else: event.ignore() def dropEvent(self, event): print("drop") if event.mimeData().hasUrls(): url = event.mimeData().urls()[0].toString() print("url = ", url) self.mediaPlayer.stop() self.mediaPlayer.setMedia(QMediaContent(QUrl(url))) self.playButton.setEnabled(True) self.mediaPlayer.play() elif event.mimeData().hasText(): mydrop = event.mimeData().text() print("generic url = ", mydrop) self.mediaPlayer.setMedia(QMediaContent(QUrl(mydrop))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() def loadFilm(self, f): self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(f))) self.playButton.setEnabled(True) self.mediaPlayer.play() def populateChannelList(self): # file must be in same directory as the script FILEPATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "canaletv.txt") # lines from file with "channel name" -- "link" channelArray = [] # split file by line and adding it to the array with open(FILEPATH) as f: for line in f: channelArray.append(line.rstrip()) # dictionary with key = channel name and value = link self.channelDict = dict(ch.split(" -- ") for ch in channelArray) for channel in self.channelDict.keys(): item = QStandardItem(channel) self.model.appendRow(item) def selectedItemBehavior(self, index): # gets the link for the selected channel and plays it itms = self.channelList.selectedIndexes() for it in itms: channel = it.data() link = self.channelDict[channel] self.mediaPlayer.setMedia(QMediaContent(QUrl(link))) self.play() def selectChannel(self): # selecting channel from sidebar calls selectedItemBehavior self.selModel = self.channelList.selectionModel() self.selModel.selectionChanged.connect(self.selectedItemBehavior) def initialPlay(self): # play somenting when app opens self.mediaPlayer.setMedia(QMediaContent(QUrl("https://vid.hls.protv.ro/proxhdn/proxhd_3_34/index.m3u8?1"))) self.play() def handleLabel(self): self.lbl.clear() mtime = QTime(0, 0, 0, 0) self.time = mtime.addMSecs(self.mediaPlayer.position()) self.lbl.setText(self.time.toString())
class Window(QWidget): def __init__(self, parent, jugadores, equipos): super().__init__() self.parent = parent self.__setUp(jugadores, equipos) def __setUp(self, jugadores, equipos): self.setGeometry(0, 30, 1366, 697) oImage = QImage("Assets/Fondo").scaled(1366, 697) # Ponemos el Background palette = QPalette() palette.setBrush(10, QBrush(oImage)) self.setPalette(palette) self.newfont = QFont("Copperplate Gothic Light", 12, QFont.Black) self.italicfont = QFont("Copperplate Gothic Light", 8) self.italicfont.setItalic(True) self.smallfont = QFont("Copperplate Gothic Light", 8) self.boton_equipo = QPushButton('Mi equipo', self) self.boton_equipo.setFont(self.newfont) self.boton_equipo.clicked.connect(self.ver_equipo) self.boton_equipo.setStyleSheet(boton_yeah) self.boton_equipo.setGeometry(613, 225, 140, 45) self.boton_campeonatos = QPushButton('Campeonatos', self) self.boton_campeonatos.setFont(self.newfont) self.boton_campeonatos.clicked.connect(self.campeonatos) self.boton_campeonatos.setStyleSheet(boton_yeah) self.boton_campeonatos.setGeometry(613, 300, 140, 45) self.show() self.boton_atras = QPushButton('Atrás', self) self.boton_atras.setFont(self.newfont) self.boton_atras.clicked.connect(self.atras) self.boton_atras.setStyleSheet(boton_yeah) self.boton_atras.setGeometry(1275, 1, 90, 40) self.__ptje = 60 self.cuadro_info = QLabel(self) self.booleanos = {'e': False, 'j': False, 'c': False, 'k': False} self.equipos = equipos self.lista_jugadores = [] for i in jugadores: self.lista_jugadores.append(Jugador(self, *i, scaled=0.8)) self.__jugadores = [QLabel(self) for i in range(11)] self.__jugadores_afuera = [ Jugador(self, x.id, x.nombre, x.nombre_completo, x.club, x.liga, x.nacionalidad, x.overall) for x in self.lista_jugadores if x not in self.__jugadores ] @property def listo(self): contador = 0 for i in self.__jugadores: if isinstance(i, Jugador): contador += 1 return contador >= 11 def ver_equipo(self): oImage = QImage("Assets/cancha_inferior").scaled( 1366, 697) # Ponemos el Background palette = QPalette() palette.setBrush(10, QBrush(oImage)) self.setPalette(palette) self.booleanos['e'] = True self.boton_atras.show() self.boton_campeonatos.hide() self.boton_equipo.hide() self.buscador_jugador = MyLineEdit('buscar jugador', self) self.buscador_jugador.setFont(self.italicfont) self.buscador_jugador.setGeometry(10, 535, 120, 25) self.buscador_jugador.show() self.boton_buscar = QPushButton('Buscar', self) self.boton_buscar.setFont(self.smallfont) self.boton_buscar.setStyleSheet(boton_yeah) self.boton_buscar.setGeometry(135, 525, 75, 40) self.boton_buscar.clicked.connect(self.buscar) self.boton_buscar.show() self.label_puntaje = QLabel(self) self.label_puntaje.setText(' Esperanza: ' + str(self.__ptje)) self.label_puntaje.setFont(self.newfont) self.label_puntaje.setStyleSheet(label_yeah) self.label_puntaje.setGeometry(1200, 520, 160, 40) self.label_puntaje.show() for i in self.__jugadores_afuera: i.create_layout() self.scroll_jugadores = Scroll(self.__jugadores_afuera, self) self.scroll_jugadores.move(0, 570) self.scroll_jugadores.show() self.reajustar_formacion() for i in self.__jugadores: i.en_cancha = True i.show() def buscar(self): lista = [] for i in self.__jugadores_afuera: if self.buscador_jugador.text() in i.nombre_completo: lista.append(i) if len(lista) > 0: self.scroll_jugadores.mostrar_busqueda(lista) def seleccion(self, jugador): self.cuadro_info.hide() if jugador.en_cancha: self.cuadro_info = CuadroInfo(self, jugador) self.cuadro_info.move(jugador.x, jugador.y) def reajustar_formacion(self): lista = list(self.__jugadores) if lista: self.cuadro_info.hide() lista[0].move(646, 450) lista.pop(0) for i in range(4): lista[0].move(205 + 300 * i, 350) lista.pop(0) for i in range(4): lista[0].move(195 + 310 * i, 210) lista.pop(0) for i in range(2): lista[0].move(520 + 220 * i, 70) lista.pop(0) def campeonatos(self): oImage = QImage("Assets/torneo").scaled(1366, 697) # Ponemos el Background palette = QPalette() palette.setBrush(10, QBrush(oImage)) self.setPalette(palette) self.booleanos['c'] = True self.boton_atras.show() self.boton_campeonatos.hide() self.boton_equipo.hide() self.label_equipos = QLabel(' Equipos', self) self.label_equipos.setGeometry(150, 50, 100, 30) self.label_equipos.setFont(self.newfont) self.label_equipos.setStyleSheet(label_yeah) self.label_equipos.show() self.label_resultados = QLabel(' Resultados', self) self.label_resultados.setGeometry(538, 50, 124, 30) self.label_resultados.setFont(self.newfont) self.label_resultados.setStyleSheet(label_yeah) self.label_resultados.show() self.label_respuestas = QLabel(' Respuestas', self) self.label_respuestas.setGeometry(988, 50, 124, 30) self.label_respuestas.setFont(self.newfont) self.label_respuestas.setStyleSheet(label_yeah) self.label_respuestas.show() self.boton_simular = QPushButton('Jugar', self) self.boton_simular.setStyleSheet(boton_yeah) self.boton_simular.setGeometry(350, 150, 100, 45) self.boton_simular.clicked.connect(self.simular) self.boton_simular.setFont(self.newfont) self.boton_simular.show() self.boton_random = QPushButton('Al azar', self) self.boton_random.setStyleSheet(boton_yeah) self.boton_random.setGeometry(350, 250, 100, 45) self.boton_random.clicked.connect(lambda: self.simular(True)) self.boton_random.setFont(self.newfont) self.boton_random.show() self.consulta_usuario = QPushButton('Datos usuario', self) self.consulta_usuario.setEnabled(False) self.consulta_usuario.setStyleSheet(mini_boton_yeah) self.consulta_usuario.setGeometry(760, 130, 100, 25) self.consulta_usuario.setFont(self.smallfont) self.consulta_usuario.clicked.connect(lambda: self.consulta(0)) self.consulta_usuario.show() self.consulta_ganadores = QPushButton('Ganadores', self) self.consulta_ganadores.setEnabled(False) self.consulta_ganadores.setStyleSheet(mini_boton_yeah) self.consulta_ganadores.setGeometry(760, 170, 100, 25) self.consulta_ganadores.clicked.connect(lambda: self.consulta(2)) self.consulta_ganadores.setFont(self.smallfont) self.consulta_ganadores.show() self.edit_equipo = MyLineEdit('Ingrese equipo', self) self.edit_equipo.setGeometry(715, 210, 100, 25) self.edit_equipo.setFont(self.italicfont) self.edit_equipo.show() self.consulta_equipo = QPushButton('Consultar', self) self.consulta_equipo.setEnabled(False) self.consulta_equipo.setStyleSheet(mini_boton_yeah) self.consulta_equipo.setGeometry(830, 210, 100, 25) self.consulta_equipo.setFont(self.smallfont) self.consulta_equipo.clicked.connect(lambda: self.consulta(1)) self.consulta_equipo.show() self.edit_fase = MyLineEdit('Ingrese fase', self) self.edit_fase.setGeometry(715, 250, 100, 25) self.edit_fase.setFont(self.italicfont) self.edit_fase.show() self.consulta_fase = QPushButton('Consultar', self) self.consulta_fase.setEnabled(False) self.consulta_fase.setStyleSheet(mini_boton_yeah) self.consulta_fase.setGeometry(830, 250, 100, 25) self.consulta_fase.setFont(self.smallfont) self.consulta_fase.clicked.connect(lambda: self.consulta(4)) self.consulta_fase.show() self.edit_partido = MyLineEdit('id partido', self) self.edit_partido.setGeometry(715, 290, 100, 25) self.edit_partido.setFont(self.italicfont) self.edit_partido.show() self.consulta_partido = QPushButton('Consultar', self) self.consulta_partido.setEnabled(False) self.consulta_partido.setStyleSheet(mini_boton_yeah) self.consulta_partido.setGeometry(830, 290, 100, 25) self.consulta_partido.setFont(self.smallfont) self.consulta_partido.clicked.connect(lambda: self.consulta(3)) self.consulta_partido.show() self.resultados = QListView(self) self.resultados.setGeometry(500, 100, 200, 450) self.items_resultado = [] self.model_resultados = QStandardItemModel(self.resultados) self.resultados.show() self.respuestas = QListView(self) self.respuestas.setGeometry(950, 100, 200, 450) self.items_respuestas = [] self.model_respuestas = QStandardItemModel(self.respuestas) self.respuestas.show() self.view = QListView(self) self.view.setGeometry(100, 100, 200, 450) model = QStandardItemModel(self.view) item = QStandardItem('Tu equipo, ' + str(self.__ptje)) item.setCheckable(True) item.setEditable(False) model.appendRow(item) self.items = [item] for i in self.equipos: item = QStandardItem(i[0] + ', ' + str(i[1])) item.setCheckable(True) item.setEditable(False) model.appendRow(item) self.items.append(item) self.view.setModel(model) self.view.show() self.edits = [self.edit_equipo, self.edit_partido, self.edit_fase] self.botones = [ self.consulta_partido, self.consulta_fase, self.consulta_usuario, self.consulta_equipo, self.consulta_ganadores ] def consulta(self, i): consultas = [ self.parent.consulta_usuario, lambda: self.parent.consulta_equipo(self.edit_equipo.text()), self.parent.consulta_ganadores, lambda: self.parent.consulta_partido(self.edit_partido.text()), lambda: self.parent.consulta_fase(self.edit_fase.text()) ] consultas[i]() def simular(self, random=False): if not random: equipos = [] for i in self.items: if i.checkState() == 2: equipos.append(i.text().split(',')) else: equipos = [x.text().split(',') for x in sample(self.items, 16)] if len(equipos) == 16: self.parent.simular_campeonato(equipos) for i in self.botones: i.setEnabled(True) def atras(self): oImage = QImage("Assets/fondo").scaled(1366, 697) palette = QPalette() palette.setBrush(10, QBrush(oImage)) self.setPalette(palette) self.boton_equipo.show() self.boton_campeonatos.show() self.boton_atras.hide() if self.booleanos['e']: self.label_puntaje.hide() self.scroll_jugadores.hide() for i in self.__jugadores: i.hide() self.buscador_jugador.hide() self.boton_buscar.hide() elif self.booleanos['c']: self.view.hide() self.boton_simular.hide() for i in self.edits: i.hide() for i in self.botones: i.hide() self.resultados.hide() self.respuestas.hide() self.boton_random.hide() self.label_respuestas.hide() self.label_resultados.hide() self.label_equipos.hide() for x in self.booleanos: self.booleanos[x] = False def cambio(self, x): self.booleanos['k'] = True self.jugador_cambiando = Jugador(self, x.id, x.nombre, x.nombre_completo, x.club, x.liga, x.nacionalidad, x.overall) self.jugador_seleccionado = x self.cuadro_info.hide() def intercambio(self, j2, cancha=False): i = self.__jugadores.index(self.jugador_seleccionado) self.booleanos['k'] = False if not cancha: self.scroll_jugadores.intercambio(j2, self.jugador_cambiando) self.__jugadores[i] = next(x for x in self.lista_jugadores if x.nombre == j2.nombre) self.reajustar_formacion() self.__jugadores[i].show() self.__jugadores[i].en_cancha = True self.jugador_seleccionado.hide() self.jugador_seleccionado.en_cancha = False j1 = self.jugador_seleccionado j3 = next(x for x in self.__jugadores_afuera if x.id == j2.id) self.__jugadores_afuera[self.__jugadores_afuera.index( j3)] = Jugador(self, j1.id, j1.nombre, j1.nombre_completo, j1.club, j1.liga, j1.nacionalidad, j1.overall) else: j = self.__jugadores.index(j2) self.__jugadores[i] = j2 self.__jugadores[j] = self.jugador_seleccionado self.reajustar_formacion() self.parent.cambio_jugador(self.jugador_seleccionado.nombre_completo, j2.nombre_completo, cancha) def mousePressEvent(self, event): self.cuadro_info.hide() self.booleanos['k'] = False if self.booleanos['e']: self.buscador_jugador.reset() if self.booleanos['c']: for i in self.edits: i.reset() def keyPressEvent(self, key): if self.booleanos['e'] and key.key() == Qt.Key_Return: self.boton_buscar.click() def agregar_jugador(self, jugador): for i in self.__jugadores: if not isinstance(i, Jugador): j = self.__jugadores.index(i) self.__jugadores[j] = (next(x for x in self.lista_jugadores if x.nombre == jugador.nombre)) self.reajustar_formacion() self.__jugadores[j].show() self.__jugadores[j].en_cancha = True self.scroll_jugadores.intercambio(jugador) self.parent.entra_jugador(jugador.nombre_completo) break @property def puntaje(self): return self.__ptje @puntaje.setter def puntaje(self, value): self.__ptje = value self.label_puntaje.setText(' Esperanza :' + str(value)) ### funciones para ser utilizadas por alumnos def cambiar_esperanza( self, valor ): # decidí hacerlo una función, ya que es más fácil darles una función que explicar que lo deben usar como propiedad. self.puntaje = valor def agregar_resultado(self, resultado): item = QStandardItem(resultado) item.setEditable(False) self.model_resultados.appendRow(item) self.items_resultado.append(item) self.resultados.setModel(self.model_resultados) def agregar_respuesta(self, respuesta): item = QStandardItem(respuesta) item.setEditable(False) self.model_respuestas.appendRow(item) self.items_respuestas.append(item) self.respuestas.setModel(self.model_respuestas) def resetear_resultados(self): self.resultados.hide() self.resultados = QListView(self) self.resultados.setGeometry(500, 100, 200, 450) self.items_resultado = [] self.model_resultados = QStandardItemModel(self.resultados) self.resultados.show() for i in self.botones: i.setEnabled(False) def resetear_respuestas(self): self.respuestas.hide() self.respuestas = QListView(self) self.respuestas.setGeometry(950, 100, 200, 450) self.items_respuestas = [] self.model_respuestas = QStandardItemModel(self.respuestas) self.respuestas.show()
class FileManager(QWidget, _HalWidgetBase): def __init__(self, parent=None): super(FileManager, self).__init__(parent) self.title = 'Qtvcp File System View' self.left = 10 self.top = 10 self.width = 640 self.height = 480 self._last = 0 if INFO.PROGRAM_PREFIX is not None: self.user_path = os.path.expanduser(INFO.PROGRAM_PREFIX) else: self.user_path = (os.path.join(os.path.expanduser('~'), 'linuxcnc/nc_files')) user = os.path.split(os.path.expanduser('~'))[-1] self.media_path = (os.path.join('/media', user)) temp = [('User', self.user_path), ('Media', self.media_path)] self._jumpList = OrderedDict(temp) self.currentPath = None self.currentFolder = None self.PREFS_ = None self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) pasteBox = QHBoxLayout() self.textLine = QLineEdit() self.textLine.setToolTip('Current Director/selected File') self.pasteButton = QToolButton() self.pasteButton.setEnabled(False) self.pasteButton.setText('Paste') self.pasteButton.setToolTip( 'Copy file from copy path to current directory/file') self.pasteButton.clicked.connect(self.paste) self.pasteButton.hide() pasteBox.addWidget(self.textLine) pasteBox.addWidget(self.pasteButton) self.copyBox = QFrame() hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) self.copyLine = QLineEdit() self.copyLine.setToolTip('File path to copy from, when pasting') self.copyButton = QToolButton() self.copyButton.setText('Copy') self.copyButton.setToolTip('Record current file as copy path') self.copyButton.clicked.connect(self.recordCopyPath) hbox.addWidget(self.copyButton) hbox.addWidget(self.copyLine) self.copyBox.setLayout(hbox) self.copyBox.hide() self.model = QFileSystemModel() self.model.setRootPath(QDir.currentPath()) self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files) self.model.setNameFilterDisables(False) self.model.rootPathChanged.connect(self.folderChanged) self.list = QListView() self.list.setModel(self.model) self.list.resize(640, 480) self.list.clicked[QModelIndex].connect(self.listClicked) self.list.activated.connect(self._getPathActivated) self.list.setAlternatingRowColors(True) self.list.hide() self.table = QTableView() self.table.setModel(self.model) self.table.resize(640, 480) self.table.clicked[QModelIndex].connect(self.listClicked) self.table.activated.connect(self._getPathActivated) self.table.setAlternatingRowColors(True) header = self.table.horizontalHeader() header.setSectionResizeMode(0, QHeaderView.Stretch) header.setSectionResizeMode(1, QHeaderView.ResizeToContents) header.setSectionResizeMode(3, QHeaderView.ResizeToContents) header.swapSections(1, 3) header.setSortIndicator(1, Qt.AscendingOrder) self.table.setSortingEnabled(True) self.table.setColumnHidden(2, True) # type self.table.verticalHeader().setVisible(False) # row count header self.cb = QComboBox() self.cb.currentIndexChanged.connect(self.filterChanged) self.fillCombobox(INFO.PROGRAM_FILTERS_EXTENSIONS) self.cb.setMinimumHeight(30) self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2 = QToolButton() self.button2.setText('User') self.button2.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button2.setMinimumSize(60, 30) self.button2.setToolTip( 'Jump to User directory.\nLong press for Options.') self.button2.clicked.connect(self.onJumpClicked) self.button3 = QToolButton() self.button3.setText('Add Jump') self.button3.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.button3.setMinimumSize(60, 30) self.button3.setToolTip('Add current directory to jump button list') self.button3.clicked.connect(self.onActionClicked) self.settingMenu = QMenu(self) self.button2.setMenu(self.settingMenu) hbox = QHBoxLayout() hbox.addWidget(self.button2) hbox.addWidget(self.button3) hbox.insertStretch(2, stretch=0) hbox.addWidget(self.cb) windowLayout = QVBoxLayout() windowLayout.addLayout(pasteBox) windowLayout.addWidget(self.copyBox) windowLayout.addWidget(self.list) windowLayout.addWidget(self.table) windowLayout.addLayout(hbox) self.setLayout(windowLayout) self.show() def _hal_init(self): if self.PREFS_: last_path = self.PREFS_.getpref('last_loaded_directory', self.user_path, str, 'BOOK_KEEPING') LOG.debug("lAST FILE PATH: {}".format(last_path)) if not last_path == '': self.updateDirectoryView(last_path) else: self.updateDirectoryView(self.user_path) # get all the saved jumplist paths temp = self.PREFS_.getall('FILEMANAGER_JUMPLIST') self._jumpList.update(temp) else: LOG.debug("lAST FILE PATH: {}".format(self.user_path)) self.updateDirectoryView(self.user_path) # install jump paths into toolbutton menu for i in self._jumpList: self.addAction(i) # set recorded columns sort settings self.SETTINGS_.beginGroup("FileManager-{}".format(self.objectName())) sect = self.SETTINGS_.value('sortIndicatorSection', type=int) order = self.SETTINGS_.value('sortIndicatorOrder', type=int) self.SETTINGS_.endGroup() if not None in (sect, order): self.table.horizontalHeader().setSortIndicator(sect, order) # when qtvcp closes this gets called # record jump list paths def _hal_cleanup(self): if self.PREFS_: for i, key in enumerate(self._jumpList): if i in (0, 1): continue self.PREFS_.putpref(key, self._jumpList.get(key), str, 'FILEMANAGER_JUMPLIST') # record sorted columns h = self.table.horizontalHeader() self.SETTINGS_.beginGroup("FileManager-{}".format(self.objectName())) self.SETTINGS_.setValue('sortIndicatorSection', h.sortIndicatorSection()) self.SETTINGS_.setValue('sortIndicatorOrder', h.sortIndicatorOrder()) self.SETTINGS_.endGroup() ######################### # callbacks ######################### # add shown text and hidden filter data from the INI def fillCombobox(self, data): for i in data: self.cb.addItem(i[0], i[1]) def folderChanged(self, data): data = os.path.normpath(data) self.currentFolder = data self.textLine.setText(data) def updateDirectoryView(self, path, quiet=False): if os.path.exists(path): self.list.setRootIndex(self.model.setRootPath(path)) self.table.setRootIndex(self.model.setRootPath(path)) else: LOG.debug( "Set directory view error - no such path {}".format(path)) if not quiet: STATUS.emit( 'error', LOW_ERROR, "File Manager error - No such path: {}".format(path)) # retrieve selected filter (it's held as QT.userData) def filterChanged(self, index): userdata = self.cb.itemData(index) self.model.setNameFilters(userdata) def listClicked(self, index): # the signal passes the index of the clicked item dir_path = os.path.normpath(self.model.filePath(index)) if self.model.fileInfo(index).isFile(): self.currentPath = dir_path self.textLine.setText(self.currentPath) return root_index = self.model.setRootPath(dir_path) self.list.setRootIndex(root_index) self.table.setRootIndex(root_index) def onUserClicked(self): self.showUserDir() def onMediaClicked(self): self.showMediaDir() # jump directly to a saved path shown on the button def onJumpClicked(self): data = self.button2.text() if data.upper() == 'MEDIA': self.showMediaDir() elif data.upper() == 'USER': self.showUserDir() else: temp = self._jumpList.get(data) if temp is not None: self.updateDirectoryView(temp) else: STATUS.emit('error', linuxcnc.OPERATOR_ERROR, 'file jumopath: {} not valid'.format(data)) log.debug('file jumopath: {} not valid'.format(data)) # jump directly to a saved path from the menu def jumpTriggered(self, data): if data.upper() == 'MEDIA': self.button2.setText('{}'.format(data)) self.button2.setToolTip( 'Jump to Media directory.\nLong press for Options.') self.showMediaDir() elif data.upper() == 'USER': self.button2.setText('{}'.format(data)) self.button2.setToolTip( 'Jump to User directory.\nLong press for Options.') self.showUserDir() else: self.button2.setText('{}'.format(data)) self.button2.setToolTip('Jump to directory:\n{}'.format( self._jumpList.get(data))) self.updateDirectoryView(self._jumpList.get(data)) # add a jump list path def onActionClicked(self): i = self.currentFolder try: self._jumpList[i] = i except Exception as e: print(e) button = QAction(QIcon.fromTheme('user-home'), i, self) # weird lambda i=i to work around 'function closure' button.triggered.connect(lambda state, i=i: self.jumpTriggered(i)) self.settingMenu.addAction(button) # get current selection and update the path # then if the path is good load it into linuxcnc # record it in the preference file if available def _getPathActivated(self): if self.list.isVisible(): row = self.list.selectionModel().currentIndex() else: row = self.table.selectionModel().currentIndex() self.listClicked(row) fname = self.currentPath if fname is None: return if fname: self.load(fname) def recordCopyPath(self): data, isFile = self.getCurrentSelected() if isFile: self.copyLine.setText(os.path.normpath(data)) self.pasteButton.setEnabled(True) else: self.copyLine.setText('') self.pasteButton.setEnabled(False) STATUS.emit('error', OPERATOR_ERROR, 'Can only copy a file, not a folder') def paste(self): res = self.copyFile(self.copyLine.text(), self.textLine.text()) if res: self.copyLine.setText('') self.pasteButton.setEnabled(False) ######################## # helper functions ######################## def addAction(self, i): axisButton = QAction(QIcon.fromTheme('user-home'), i, self) # weird lambda i=i to work around 'function closure' axisButton.triggered.connect(lambda state, i=i: self.jumpTriggered(i)) self.settingMenu.addAction(axisButton) def showList(self, state=True): if state: self.table.hide() self.list.show() else: self.table.show() self.list.hide() def showTable(self, state=True): self.showList(not state) def showCopyControls(self, state): if state: self.copyBox.show() self.pasteButton.show() else: self.copyBox.hide() self.pasteButton.hide() def showMediaDir(self, quiet=False): self.updateDirectoryView(self.media_path, quiet) def showUserDir(self, quiet=False): self.updateDirectoryView(self.user_path, quiet) def copyFile(self, s, d): try: shutil.copy(s, d) return True except Exception as e: LOG.error("Copy file error: {}".format(e)) STATUS.emit('error', OPERATOR_ERROR, "Copy file error: {}".format(e)) return False @pyqtSlot(float) @pyqtSlot(int) def scroll(self, data): if data > self._last: self.up() elif data < self._last: self.down() self._last = data # moves the selection up # used with MPG scrolling def up(self): self.select_row('up') # moves the selection down # used with MPG scrolling def down(self): self.select_row('down') def select_row(self, style='down'): style = style.lower() if self.list.isVisible(): i = self.list.rootIndex() selectionModel = self.list.selectionModel() else: i = self.table.rootIndex() selectionModel = self.table.selectionModel() row = selectionModel.currentIndex().row() self.rows = self.model.rowCount(i) if style == 'last': row = self.rows elif style == 'up': if row > 0: row -= 1 else: row = 0 elif style == 'down': if row < self.rows - 1: row += 1 else: row = self.rows - 1 else: return top = self.model.index(row, 0, i) selectionModel.setCurrentIndex( top, QItemSelectionModel.Select | QItemSelectionModel.Rows) selection = QItemSelection(top, top) selectionModel.clearSelection() selectionModel.select(selection, QItemSelectionModel.Select) # returns the current highlighted (selected) path as well as # whether it's a file or not. def getCurrentSelected(self): if self.list.isVisible(): selectionModel = self.list.selectionModel() else: selectionModel = self.table.selectionModel() index = selectionModel.currentIndex() dir_path = os.path.normpath(self.model.filePath(index)) if self.model.fileInfo(index).isFile(): return (dir_path, True) else: return (dir_path, False) # This can be class patched to do something else def load(self, fname=None): try: if fname is None: self._getPathActivated() return self.recordBookKeeping() ACTION.OPEN_PROGRAM(fname) STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME') except Exception as e: LOG.error("Load file error: {}".format(e)) STATUS.emit('error', NML_ERROR, "Load file error: {}".format(e)) # This can be class patched to do something else def recordBookKeeping(self): fname = self.currentPath if fname is None: return if self.PREFS_: self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(), str, 'BOOK_KEEPING') self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING')
class RequestsOperations(QWidget): def __init__(self, parent): super().__init__(parent) self.initUI() self.__ops = [] def initUI(self): self.layout = QFormLayout() self.layout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) self.layout.setLabelAlignment(Qt.AlignLeft) self.layout.setFormAlignment(Qt.AlignLeft | Qt.AlignTop) twoListsOfSets = QWidget() twoListsOfSets.setLayout(QHBoxLayout()) twoListsOfSets.layout().setContentsMargins(5, 10, 5, 5) twoListsOfSets.layout().setSpacing(0) effect = QGraphicsDropShadowEffect() effect.setBlurRadius(10) effect.setColor(QColor(0, 0, 0, 160)) effect.setOffset(0.0) self.requestList = QListView() self.requestList.setSpacing(3) self.requestList.setAutoFillBackground(True) self.requestList.setGraphicsEffect(effect) self.requestList.setFrameStyle(QFrame.NoFrame) self.requestList.viewport().setAutoFillBackground(False) self.requestList.setFlow(QListView.LeftToRight) self.requestList.setWrapping(True) self.requestList.setResizeMode(QListView.Adjust) self.requestList.setUniformItemSizes(True) self.requestsModel = QStandardItemModel() self.requestList.setModel(self.requestsModel) effect = QGraphicsDropShadowEffect() effect.setBlurRadius(10) effect.setColor(QColor(0, 0, 0, 160)) effect.setOffset(0.0) self.requestList2 = QListView() self.requestList2.setSpacing(3) self.requestList2.setAutoFillBackground(True) self.requestList2.setGraphicsEffect(effect) self.requestList2.setFrameStyle(QFrame.NoFrame) self.requestList2.viewport().setAutoFillBackground(False) self.requestList2.setFlow(QListView.LeftToRight) self.requestList2.setWrapping(True) self.requestList2.setResizeMode(QListView.Adjust) self.requestList2.setUniformItemSizes(True) self.requestsModel2 = QStandardItemModel() self.requestList2.setModel(self.requestsModel2) twoListsOfSets.layout().addWidget(self.requestList) twoListsOfSets.layout().addWidget(self.requestList2) self.layout.addRow("SETS", twoListsOfSets) self.layout.addRow(HorizontalLine(self)) self.operationSelection = QGroupBox() self.operationSelection.setFlat(True) self.operationSelection.setLayout(QVBoxLayout()) self.buttonIntersection = QRadioButton("Intersection") self.operationSelection.layout().addWidget(self.buttonIntersection) self.buttonIntersection.clicked.connect( self.__disableSecondRequestList) self.buttonIntersection.click() self.buttonUnion = QRadioButton("Union") self.operationSelection.layout().addWidget(self.buttonUnion) self.buttonUnion.clicked.connect(self.__disableSecondRequestList) self.buttonDiff = QRadioButton("Difference") self.operationSelection.layout().addWidget(self.buttonDiff) self.buttonDiff.clicked.connect(self.__enableSecondRequestList) self.layout.addRow("OPERATION", self.operationSelection) self.buttonApplyWidget = QWidget() self.buttonApplyWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.buttonApplyLayout = QHBoxLayout() self.buttonApplyLayout.setContentsMargins(0, 0, 0, 0) self.buttonApplyWidget.setLayout(self.buttonApplyLayout) self.buttonApply = QPushButton("Apply") self.buttonApply.clicked.connect(self.__applyOp) self.operationSelection.layout().addWidget(self.buttonApply) self.buttonApplyLayout.addWidget(self.buttonApply, alignment=Qt.AlignRight) self.layout.addRow("", self.buttonApplyWidget) self.layout.addRow(HorizontalLine(self)) self.layout.addRow("RESULTS", None) self.resultingSets = QTableView() self.resultingSets.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.resultingSets.verticalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.resultingSets.setModel(OperationsTableModel()) self.layout.addRow(self.resultingSets) self.layout.addRow(HorizontalLine(self)) self.outputSetSelection = QComboBox() self.outputSetSelection.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) self.layout.addRow("OUTPUT SET", self.outputSetSelection) self.setLayout(self.layout) def outputSet(self): return self.outputSetSelection.currentText() def setOutputSet(self, outputSetName): self.outputSetSelection.setCurrentText(outputSetName) @property def ops(self): return copy.deepcopy(self.__ops) def __applyOp(self): includedSets = [ self.requestsModel.item(i).text() for i in range(self.requestsModel.rowCount()) if self.requestsModel.item(i).data(Qt.CheckStateRole) == QVariant( Qt.Checked) ] if self.buttonUnion.isChecked(): if len(includedSets) > 1: opName = SetNameManagement.getUniqueSetName() self.addOp(OverpassUnion(opName), includedSets) logging.info("Union created.") else: logging.error("The union must have at least two sets.") elif self.buttonIntersection.isChecked(): if len(includedSets) > 1: opName = SetNameManagement.getUniqueSetName() self.addOp(OverpassIntersection(opName), includedSets) logging.info("Intersection created.") else: logging.error("The intersection must have at least two sets.") elif self.buttonDiff.isChecked(): excludedSets = [ self.requestsModel2.item(i).text() for i in range(self.requestsModel2.rowCount()) if self.requestsModel2.item(i).data(Qt.CheckStateRole) == QVariant(Qt.Checked) ] if len(includedSets) == 1 and len(excludedSets) > 0: opName = SetNameManagement.getUniqueSetName() self.addOp(OverpassDiff(includedSets[0], opName), excludedSets) logging.info("Difference created.") else: logging.error( "The difference must have only one set selected in the first list and at least one in the other." ) logging.debug("LINE") def addOp(self, op, sets=None): SetNameManagement.assign(op.name) self.__ops.append(op) if sets is not None: op.addSets(sets) self.resultingSets.model().addOp(op.name, op) self.addRequest(op.name) self.cleanRequestList() def __enableSecondRequestList(self): self.requestList2.show() def __disableSecondRequestList(self): self.requestList2.hide() def addRequest(self, name): self.requestsModel.beginInsertRows(QModelIndex(), self.requestsModel.rowCount(), self.requestsModel.rowCount()) item = QStandardItem(name) item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setData(QVariant(Qt.Unchecked), Qt.CheckStateRole) self.requestsModel.appendRow(item) self.requestsModel.endInsertRows() self.requestsModel2.beginInsertRows(QModelIndex(), self.requestsModel2.rowCount(), self.requestsModel2.rowCount()) item = QStandardItem(name) item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setData(QVariant(Qt.Unchecked), Qt.CheckStateRole) self.requestsModel2.appendRow(item) self.requestsModel2.endInsertRows() self.outputSetSelection.addItem(name) def removeSetAndDependencies(self, setName): removeList = [setName] for set in removeList: logging.info("Removing set '{}'.".format(set)) removeList.extend( [i for i in self.__removeSet(set) if i not in removeList]) logging.debug("LINE") def __removeSet(self, setName): dependencies = [] for op in self.__ops: op.removeSet(setName) if not op.isValid(): dependencies.append(op.name) for i in range(self.requestsModel.rowCount()): if self.requestsModel.item(i).text() == setName: self.requestsModel.beginRemoveRows(QModelIndex(), i, i) self.requestsModel.removeRow(i) self.requestsModel.endInsertRows() self.requestsModel2.beginRemoveRows(QModelIndex(), i, i) self.requestsModel2.removeRow(i) self.requestsModel2.endInsertRows() self.outputSetSelection.removeItem(i) break for op in self.__ops: if op.name == setName: self.resultingSets.model().removeOp(setName) self.__ops.remove(op) break SetNameManagement.releaseName(setName) return dependencies def reset(self): while len(self.ops) > 0: self.removeSetAndDependencies(self.ops[0].name) def cleanRequestList(self): for i in range(self.requestsModel.rowCount()): self.requestsModel.item(i).setData(QVariant(Qt.Unchecked), Qt.CheckStateRole) self.requestsModel2.item(i).setData(QVariant(Qt.Unchecked), Qt.CheckStateRole) def keyPressEvent(self, event): if event.key() == Qt.Key_Backspace and self.resultingSets.hasFocus(): advice = "Are you sure?\nAll sets containing this one will be deleted if they are no longer valid" reply = QMessageBox.question(self, "Remove request operation", advice) if reply == QMessageBox.Yes: select = self.resultingSets.selectionModel() while len(select.selectedRows()) > 0: self.removeSetAndDependencies( self.resultingSets.model().getOpByIndex( select.selectedRows()[0].row())) event.accept()
class MainWindow(QWidget): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.playlistView = QListView() self.switch_status = 2 self.video_widget = QVideoWidget() self.playlist = QMediaPlaylist() self.model = PlaylistModel(self.playlist) self.titleBar = TitleBar(self) self.currentTimeLabel = QLabel() self.timeSlider = QSlider() self.totalTimeLabel = QLabel() self.mediaPlayer = QMediaPlayer() self.open_btn = QPushButton('Open File') self.play_btn = QPushButton() self.prev_btn = QPushButton() self.stop_btn = QPushButton() self.next_btn = QPushButton() self.switch_media_widgets_btn = QPushButton() self.pseudo_label = QLabel() self.vol_label = QLabel() self.volume_slider = Slider(Qt.Horizontal) self.gui() self.set_children_focus_policy(Qt.NoFocus) def gui(self): self.currentTimeLabel.setMinimumSize(QSize(80, 0)) self.currentTimeLabel.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.timeSlider.setOrientation(Qt.Horizontal) self.totalTimeLabel.setMinimumSize(QSize(80, 0)) self.totalTimeLabel.setAlignment(Qt.AlignLeading | Qt.AlignLeft | Qt.AlignVCenter) self.playlistView.setAcceptDrops(True) self.playlistView.setProperty("showDropIndicator", True) self.playlistView.setDragDropMode(QAbstractItemView.DropOnly) self.playlistView.setAlternatingRowColors(True) self.playlistView.setUniformItemSizes(True) self.setWindowFlags(Qt.FramelessWindowHint) self.setWindowTitle('Media Player') self.titleBar.label.setText('Media Player') self.setWindowIcon(QIcon('icon_png/media_player.png')) self.setGeometry(600, 200, 850, 600) self.timeSlider.setRange(0, 0) self.play_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.prev_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipBackward)) self.next_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipForward)) self.stop_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) self.switch_media_widgets_btn.setIcon(self.style().standardIcon(QStyle.SP_FileDialogDetailedView)) self.vol_label.setText("") self.vol_label.setPixmap(QPixmap("icon_png/speaker-volume.png")) self.currentTimeLabel.setText("00:00") self.totalTimeLabel.setText("00:00") self.volume_slider.setValue(self.mediaPlayer.volume()) self.mediaPlayer.setVideoOutput(self.video_widget) self.mediaPlayer.setPlaylist(self.playlist) self.playlistView.setModel(self.model) self.video_widget.hide() sizegrip = QSizeGrip(self) self.setAcceptDrops(True) inner_h_box = QHBoxLayout() inner_h_box.addWidget(self.prev_btn) inner_h_box.addWidget(self.stop_btn) inner_h_box.addWidget(self.next_btn) vol_h_box = QHBoxLayout() vol_h_box.addWidget(self.vol_label, 0) vol_h_box.addWidget(self.volume_slider, 1) h_box = QHBoxLayout() h_box.addWidget(self.open_btn) h_box.addWidget(self.play_btn, 0) h_box.addLayout(inner_h_box, 0) h_box.addWidget(self.switch_media_widgets_btn, 0) h_box.addWidget(self.pseudo_label, 1) h_box.addLayout(vol_h_box, 0) h_box.addWidget(sizegrip, 0, Qt.AlignBottom | Qt.AlignRight) video_slider_h_box = QHBoxLayout() video_slider_h_box.addWidget(self.currentTimeLabel) video_slider_h_box.addWidget(self.timeSlider) video_slider_h_box.addWidget(self.totalTimeLabel) v_box = QVBoxLayout() v_box.addWidget(self.titleBar, 0) v_box.addWidget(self.video_widget, 1) v_box.addWidget(self.playlistView, 1) v_box.addLayout(video_slider_h_box, 0) v_box.addLayout(h_box, 0) inner_h_box.setContentsMargins(20, 0, 10, 0) vol_h_box.setContentsMargins(0, 0, 20, 0) h_box.setContentsMargins(20, 0, 0, 0) v_box.setContentsMargins(0, 0, 0, 0) video_slider_h_box.setSpacing(10) h_box.setSpacing(0) v_box.setSpacing(0) self.setLayout(v_box) self.enabler() # connections self.open_btn.clicked.connect(self.open_file) self.play_btn.clicked.connect(self.play_media) self.stop_btn.clicked.connect(self.stop_media) self.prev_btn.pressed.connect(self.play_prev) self.next_btn.pressed.connect(self.play_next) self.switch_media_widgets_btn.pressed.connect(self.switch_media) self.playlist.currentIndexChanged.connect(self.playlist_position_changed) selection_model = self.playlistView.selectionModel() selection_model.selectionChanged.connect(self.playlist_selection_changed) self.mediaPlayer.durationChanged.connect(self.update_duration) self.mediaPlayer.positionChanged.connect(self.update_position) self.timeSlider.valueChanged.connect(self.mediaPlayer.setPosition) self.mediaPlayer.stateChanged.connect(self.media_state) self.mediaPlayer.volumeChanged.connect(self.volume_changed) self.volume_slider.valueChanged.connect(self.set_volume) def set_children_focus_policy(self, policy): def recursive_set_child_focus_policy(parent_q_widget): for childQWidget in parent_q_widget.findChildren(QWidget): childQWidget.setFocusPolicy(policy) recursive_set_child_focus_policy(childQWidget) recursive_set_child_focus_policy(self) def enabler(self, state=False): if state is False: self.play_btn.setEnabled(False) self.prev_btn.setEnabled(False) self.stop_btn.setEnabled(False) self.next_btn.setEnabled(False) else: self.play_btn.setEnabled(True) self.stop_btn.setEnabled(True) self.prev_btn.setEnabled(True) self.next_btn.setEnabled(True) def switch_media(self): if self.switch_status == 0: self.video_widget.hide() self.playlistView.show() self.switch_status = 1 self.switch_media_widgets_btn.setEnabled(True) elif self.switch_status == 1: self.video_widget.show() self.playlistView.hide() self.switch_status = 0 self.switch_media_widgets_btn.setEnabled(True) else: self.video_widget.hide() self.playlistView.show() self.switch_media_widgets_btn.setEnabled(False) def play_media(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() self.ui_handler() def ui_handler(self): if not self.playlist.isEmpty(): self.enabler(True) file_path = QFileInfo(self.mediaPlayer.currentMedia().canonicalUrl().toString()).fileName() ext = os.path.splitext(file_path)[-1].lower() audio_ext = ['.flac', '.mp3'] video_ext = ['.mp4', '.m4a', '.mov', '.flv', 'avi', '3gp', '.mkv', '.wmv'] if ext in audio_ext: self.switch_status = 2 self.switch_media() if self.isFullScreen(): self.fullscreen() elif ext in video_ext: self.switch_status = 1 self.switch_media() self.setWindowTitle(file_path + ' - Media Player') self.titleBar.label.setText(file_path + ' - Media Player') def stop_media(self): if self.mediaPlayer.state() != QMediaPlayer.StoppedState: self.mediaPlayer.stop() self.setWindowTitle('Media Player') self.titleBar.label.setText('Media Player') def fullscreen(self): if self.switch_status == 2 or self.isFullScreen(): self.titleBar.show() self.timeSlider.show() self.currentTimeLabel.show() self.totalTimeLabel.show() self.volume_slider.show() self.open_btn.show() self.play_btn.show() self.prev_btn.show() self.stop_btn.show() self.next_btn.show() self.switch_media_widgets_btn.show() self.pseudo_label.show() self.vol_label.show() self.showNormal() else: self.titleBar.hide() self.timeSlider.hide() self.currentTimeLabel.hide() self.totalTimeLabel.hide() self.volume_slider.hide() self.open_btn.hide() self.play_btn.hide() self.prev_btn.hide() self.stop_btn.hide() self.next_btn.hide() self.switch_media_widgets_btn.hide() self.pseudo_label.hide() self.vol_label.hide() self.showFullScreen() def mouseDoubleClickEvent(self, event: QMouseEvent): event.accept() if event.button() == Qt.LeftButton: self.fullscreen() def media_state(self): os_sleep = WindowsInhibitor() if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.play_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) if os.name == 'nt': os_sleep = WindowsInhibitor() os_sleep.inhibit() else: self.play_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) if os_sleep: os_sleep.uninhibit() def play_next(self): self.playlist.next() def media_seek(self, seek): if not self.playlist.isEmpty(): player = self.mediaPlayer if (player.duration() - seek) > player.position(): player.setPosition(player.position() + seek) def play_prev(self): self.playlist.previous() def dragEnterEvent(self, e): if e.mimeData().hasUrls(): e.acceptProposedAction() def dropEvent(self, e): for url in e.mimeData().urls(): ext = os.path.splitext(url.fileName())[-1].lower() allowed_ext = ['.flac', '.mp3', '.mp4', '.m4a', '.mov', '.flv', 'avi', '3gp', '.mkv', '.wmv'] if ext in allowed_ext: self.playlist.addMedia( QMediaContent(url) ) self.model.layoutChanged.emit() if self.mediaPlayer.state() != QMediaPlayer.PlayingState: i = self.playlist.mediaCount() - len(e.mimeData().urls()) self.playlist.setCurrentIndex(i) if not self.playlist.isEmpty(): self.play_media() def open_file(self): filter_files = "Media (*.mp3 *.mp4 *.mkv);; Videos files (*.mp4 *.mkv);; Music Files(*.mp3)" paths, _ = QFileDialog.getOpenFileNames(self, "Open file", "", filter_files) if paths: self.mediaPlayer.pause() for path in paths: self.playlist.addMedia( QMediaContent( QUrl.fromLocalFile(path) ) ) i = self.playlist.mediaCount() - len(paths) self.playlist.setCurrentIndex(i) self.play_media() self.model.layoutChanged.emit() def update_duration(self, duration): self.mediaPlayer.duration() self.timeSlider.setMaximum(duration) if duration >= 0: self.totalTimeLabel.setText(hhmmss(duration)) def update_position(self, position): if position >= 0: self.currentTimeLabel.setText(hhmmss(position)) self.timeSlider.blockSignals(True) self.timeSlider.setValue(position) self.timeSlider.blockSignals(False) def playlist_selection_changed(self, ix): i = ix.indexes()[0].row() self.playlist.setCurrentIndex(i) self.ui_handler() def playlist_position_changed(self, i): if i > -1: ix = self.model.index(i) self.playlistView.setCurrentIndex(ix) def set_volume(self, value): self.mediaPlayer.setVolume(value) def volume_changed(self, value): self.volume_slider.setValue(value) def keyPressEvent(self, event): key = event.key() modifiers = int(event.modifiers()) if (modifiers and modifiers & MOD_MASK == modifiers and key > 0 and key != Qt.Key_Shift and key != Qt.Key_Alt and key != Qt.Key_Control and key != Qt.Key_Meta): key_name = QKeySequence(modifiers + key).toString() if key_name == 'Ctrl+Right': self.media_seek(30000) elif key_name == 'Ctrl+Left': self.media_seek(-30000) elif key_name == 'Ctrl+Up': self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 5) elif key_name == 'Ctrl+Down': self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 5) elif key_name == 'Ctrl+O': self.open_file() else: if event.key() == Qt.Key_Space: self.play_media() elif event.key() == Qt.Key_MediaPlay: self.play_media() elif event.key() == Qt.Key_MediaNext: self.play_next() elif event.key() == Qt.Key_MediaPrevious: self.play_prev() elif event.key() == Qt.Key_Escape: self.close() elif event.key() == Qt.Key_F: self.fullscreen() elif event.key() == Qt.Key_Right: self.media_seek(5000) elif event.key() == Qt.Key_Left: self.media_seek(-5000)