pythonでfoobarのalternativeを作る 26 version 15

2019/06/11 21:07 by yamasyuh68
  :追加された部分   :削除された部分
(差分が大きい場合、文字単位では表示しません)
pythonでfoobarのalternativeを作る 26
190610
# Player 作り込み
- label の文字列をセンターに
色々調べたけど単純にdesignerで設定した( ´∀`)
画像が無いときにテキストを表示するだけ
ファイルに画像が埋め込まれていないときはフォルダを調べるようにしたいんだけどそれはまだ

- 行の削除
この機能は必須ですよね、モデルの操作になる
一つずつとまとめての二種類ある
アルバム行を削除する場合はその個°小野タイトル行も削除するようにした
foobarと同じ挙動です
```
QStandardItemModel.removeRows (self, int row, int count, QModelIndex parent = QModelIndex())
QAbstractItemModel.removeRows (self, int row, int count, QModelIndex parent = QModelIndex())
```
- 削除キーを使うのでtreeviewのサブクラスに実装した
```
keyPressEvent (self, QKeyEvent event)
int QKeyEvent.key (self) == Qt.Key_Delete
```
- Toolbarにスライダーをつける
```
QAction QToolBar.addSeparator (self)
QAction QToolBar.addWidget (self, QWidget widget)
```
表示するのは簡単だった
使い方はまだわかんない( ´∀`)
普通のスライダーだと、演奏時間に応じてずりずりするのと、マウスのグリグリで進めたり戻ったりさせることになるね

## リストへのドラッグ関係

- リストの末尾へのドラッグは出来た(・∀・)ノ
insertでいけた
基本はドロップ先のインデクスの+1になる
- 精密にやるのならこれと組み合わせるのかな
QAbstractItemView.DropIndicatorPosition
ドロップ先のインデクスとIndicatorの値の組み合わせで挙動を変える必要ありだと思う
>This enum indicates the position of the drop indicator in relation to the index at the current mouse position:
QAbstractItemView.OnItem 0 The item will be dropped on the index. 
QAbstractItemView.AboveItem 1 The item will be dropped above the index. 
QAbstractItemView.BelowItem 2 The item will be dropped below the index. 
QAbstractItemView.OnViewport 3 The item will be dropped onto a region of the viewport with no items. The way each view handles items dropped onto the viewport depends on the behavior of the underlying model in use. 


- DropIndicatorを消す
ドロップ後も消えないバグがあった
デフォルト動作のままなら消えるので、自分で実装したので何かが不足してるんだと思う
QAbstractItemView.setDropIndicatorShown (self, bool enable)
これを使ってドロップの後で消して、dragMoveEvent で見えるようにしたらまあまあうまく動いてます
----
190611
# Player 作り込み
- 連続演奏も実装、そこそこ使えるようになってきた

https://live.staticflickr.com/65535/48042927111_690c97b8b2_z.jpg
- スライダーは見せかけ( ´∀`)
```
import sqlite3 , re ,vlc ,time ,os ,urllib.parse
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication,QWidget,QMainWindow , QAction , QListView,QVBoxLayout,QSlider,QLabel
from PyQt5.QtGui import QStandardItemModel , QStandardItem ,QPixmap 
from PyQt5.QtCore import  QTimer ,Qt
import ui 
from sqlView_mylist import mylist ,taginfo

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.ui = ui.Ui_MainWindow()  
        self.ui.setupUi(self)

        self.db=<pass>
        line='select artist ,album,title ,path from  musics order by artist ,album,title'
        self.model=self.sqlexecute(line)
        self.ui.treeView.setModel(self.model)  # tree
        self.model2 = QStandardItemModel()     # tagview model
        self.ui.listView.setModel(self.model2)  # list_tag
        self.current={'file':'' , 'dur':0 , 'list':None , 'row':0}

        self.setaction()
        self.makenewtab('default')
        self.p = vlc.MediaPlayer() 

        self.timer = QtCore.QTimer(self)
        self.timer.setInterval(500)
        self.timer.timeout.connect(self.monitoring)
        self.taginfo=taginfo(self)
        self.autoplay=False

    def setaction(self):
        actionPlay = QAction('Play', self)
        actionPlay.triggered.connect(self.actionplay)
        actionPause = QAction('Pause', self)
        actionPause.triggered.connect(self.actionpause)
        actionStop = QAction('Stop', self)
        actionStop.triggered.connect(self.actionstop)
        actionBye = QAction('BYE', self)
        actionBye.triggered.connect(self.actionbye)
        actionsave = QAction('save', self)
        actionsave.triggered.connect(self.actionsave)
        actionset = QAction('set', self)
        actionset.triggered.connect(self.actionset)

        self.ui.toolBar.addAction(actionPlay)
        self.ui.toolBar.addAction(actionPause)
        self.ui.toolBar.addAction(actionStop)
        self.ui.toolBar.addAction(actionsave)
        self.ui.toolBar.addAction(actionset)
        self.ui.toolBar.addAction(actionBye)

        self.ui.toolBar.addSeparator()
        self.slider=QSlider(Qt.Horizontal)
        self.time=QLabel('0:0/0:0')
        self.ui.toolBar.addWidget(self.time)
        self.ui.toolBar.addWidget(self.slider)

    def makenewtab(self,name):
        self.current['list'] = mylist()
        self.ui.tabWidget.addTab(self.current['list'], name)
        self.ui.tabWidget.setCurrentWidget(self.current['list'])
        lyt = QVBoxLayout()
        lyt.setContentsMargins(0, 0, 0, 0)
        lyt.setSpacing(0)
        self.current['list'].setLayout(lyt)
        self.current['list'].doubleClicked.connect(self.ListdoubleClicked)

    def ListdoubleClicked(self,e):
        row=self.current['list'].selectionModel().currentIndex().row()
        fname=e.siblingAtColumn(2).data()
        if not fname :  # title-row --> return
            return
        if self.p.is_playing() :
            self.removeplay()
            self.p.stop()
        else:
            self.timer.start()
        self.actionplay(fname,row)

    def actionplay(self,f,row):
        self.current['file']=f
        self.p.set_mrl(f)  
        self.p.play() 
        self.taginfo.show(f)
        self.current['list'].model().setItem (row,1, QStandardItem('▶'))
        self.current['list'].setCurrentIndex(self.current['list'].model().index(row,0)) 
        self.setWindowTitle(f)

    def removeplay(self):
        delrow=self.current['list'].model().findItems('▶',Qt.MatchExactly,1)[0].row()
        self.current['list'].model().setItem(delrow,1,QStandardItem(''))
        return delrow

    def monitoring(self):
        if self.p.is_playing() :
            self.ui.statusbar.showMessage(str(self.p.get_time()))
        else:
            row=self.removeplay()+1
            fname=self.current['list'].model().index(row,2).data()
            if not fname: # no path but album?
                row+=1
                fname=self.current['list'].model().index(row,2).data()
                if not fname:  # check again
                    fname=self.current['list'].model().index(1,2).data()
                    row=1
            self.actionplay(fname,row)

    def actionpause(self):
        self.p.pause()

    def actionstop(self):
        self.p.stop()
        self.timer.stop()
        self.removeplay()
        self.autoplay=False

    def actionset(self):
        t=self.p.get_length()
        self.p.set_time(t-3000)

        # index = self.current['list'].model().index(3, 0);
        # self.current['list'].setCurrentIndex (index)
        # index=self.current['list'].selectedIndexes ()[0]
        # self.current['list'].setFirstColumnSpanned (index.row() ,index.parent() ,1)
        
        pass

    def actionsave(self):
        for i in range(self.current['list'].model().rowCount()):
            for p in range(self.current['list'].model().columnCount()):
                print(self.current['list'].model().index(i,p).data() + ' , ' , end ='')
            print('') # 改行する

    def sqlexecute( self, line ):
        conn = sqlite3.connect( self.db )
        c = conn.cursor()
        item=['×','×']
        tree=[None,None,None,None]
        model = QStandardItemModel()
        for l in  c.execute(line) :
            # print(l)
            if item[0] != l[0] :      # 1 a-artist
                tree[1] = QStandardItem(l[0])
                model.appendRow(tree[1])
                item[0]=l[0]
            if item[1] != l[1] :      # 1 date album
                tree[2] = QStandardItem( l[1] )
                tree[1].appendRow(tree[2])
                item[1]=l[1]
            tree[3]=QStandardItem(l[2]) , QStandardItem(l[3])
            # tree[3].setData(l[3])
            tree[2].appendRow(tree[3])         # l[3] path 入れてない

        c.close()
        conn.close()
        return model

    def actionbye(self):
        # with open( 'data.pickle', 'wb') as f :
        #     pickle.dump( self.model ,f)
        quit()

    def search(self,e):
        item=self.ui.lineEdit.text()
        temp=self.ui.treeView.model()
        if  item==''  or (len(item)==1 and  re.match('[a-zA-Z0-9_.,]',item) ) :
        # if item=='' :
            if temp == self.model :
                pass
            else:
                self.ui.treeView.setModel(self.model)
                del temp
        else :
            item="'%"+item+"%'"
            line='select artist ,album,title ,path from  musics  where \
                artist like {}  or path like {} or title like {}\
                order by artist ,album,title'.format(item,item,item)
            self.ui.treeView.setModel(self.sqlexecute(line))
            if temp != self.model:
                del temp

    def treeClicked(self,e):
        path=( e.siblingAtColumn(1).data() )
        if path:                 # dataがあればタイトル
            self.taginfo.show(path)

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())
```

- 久しぶりにコードののせたな
職場で構想練ってある程度のコード書いて、家に帰ってからそれを実行
結構エラー無くいけるので少し驚いている
逆に効率的かも





      

190610

Player 作り込み

  • label の文字列をセンターに
    色々調べたけど単純にdesignerで設定した( ´∀`)
    画像が無いときにテキストを表示するだけ
    ファイルに画像が埋め込まれていないときはフォルダを調べるようにしたいんだけどそれはまだ

  • 行の削除
    この機能は必須ですよね、モデルの操作になる
    一つずつとまとめての二種類ある
    アルバム行を削除する場合はその個°小野タイトル行も削除するようにした
    foobarと同じ挙動です

QStandardItemModel.removeRows (self, int row, int count, QModelIndex parent = QModelIndex())
QAbstractItemModel.removeRows (self, int row, int count, QModelIndex parent = QModelIndex())
  • 削除キーを使うのでtreeviewのサブクラスに実装した
keyPressEvent (self, QKeyEvent event)
int QKeyEvent.key (self) == Qt.Key_Delete
  • Toolbarにスライダーをつける
QAction QToolBar.addSeparator (self)
QAction QToolBar.addWidget (self, QWidget widget)

表示するのは簡単だった
使い方はまだわかんない( ´∀`)
普通のスライダーだと、演奏時間に応じてずりずりするのと、マウスのグリグリで進めたり戻ったりさせることになるね

リストへのドラッグ関係

  • リストの末尾へのドラッグは出来た(・∀・)ノ
    insertでいけた
    基本はドロップ先のインデクスの+1になる
  • 精密にやるのならこれと組み合わせるのかな
    QAbstractItemView.DropIndicatorPosition
    ドロップ先のインデクスとIndicatorの値の組み合わせで挙動を変える必要ありだと思う

This enum indicates the position of the drop indicator in relation to the index at the current mouse position:
QAbstractItemView.OnItem 0 The item will be dropped on the index.
QAbstractItemView.AboveItem 1 The item will be dropped above the index.
QAbstractItemView.BelowItem 2 The item will be dropped below the index.
QAbstractItemView.OnViewport 3 The item will be dropped onto a region of the viewport with no items. The way each view handles items dropped onto the viewport depends on the behavior of the underlying model in use.

  • DropIndicatorを消す
    ドロップ後も消えないバグがあった
    デフォルト動作のままなら消えるので、自分で実装したので何かが不足してるんだと思う
    QAbstractItemView.setDropIndicatorShown (self, bool enable)
    これを使ってドロップの後で消して、dragMoveEvent で見えるようにしたらまあまあうまく動いてます

190611

Player 作り込み

  • 連続演奏も実装、そこそこ使えるようになってきた

  • スライダーは見せかけ( ´∀`)
import sqlite3 , re ,vlc ,time ,os ,urllib.parse
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication,QWidget,QMainWindow , QAction , QListView,QVBoxLayout,QSlider,QLabel
from PyQt5.QtGui import QStandardItemModel , QStandardItem ,QPixmap 
from PyQt5.QtCore import  QTimer ,Qt
import ui 
from sqlView_mylist import mylist ,taginfo

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.ui = ui.Ui_MainWindow()  
        self.ui.setupUi(self)

        self.db=<pass>
        line='select artist ,album,title ,path from  musics order by artist ,album,title'
        self.model=self.sqlexecute(line)
        self.ui.treeView.setModel(self.model)  # tree
        self.model2 = QStandardItemModel()     # tagview model
        self.ui.listView.setModel(self.model2)  # list_tag
        self.current={'file':'' , 'dur':0 , 'list':None , 'row':0}

        self.setaction()
        self.makenewtab('default')
        self.p = vlc.MediaPlayer() 

        self.timer = QtCore.QTimer(self)
        self.timer.setInterval(500)
        self.timer.timeout.connect(self.monitoring)
        self.taginfo=taginfo(self)
        self.autoplay=False

    def setaction(self):
        actionPlay = QAction('Play', self)
        actionPlay.triggered.connect(self.actionplay)
        actionPause = QAction('Pause', self)
        actionPause.triggered.connect(self.actionpause)
        actionStop = QAction('Stop', self)
        actionStop.triggered.connect(self.actionstop)
        actionBye = QAction('BYE', self)
        actionBye.triggered.connect(self.actionbye)
        actionsave = QAction('save', self)
        actionsave.triggered.connect(self.actionsave)
        actionset = QAction('set', self)
        actionset.triggered.connect(self.actionset)

        self.ui.toolBar.addAction(actionPlay)
        self.ui.toolBar.addAction(actionPause)
        self.ui.toolBar.addAction(actionStop)
        self.ui.toolBar.addAction(actionsave)
        self.ui.toolBar.addAction(actionset)
        self.ui.toolBar.addAction(actionBye)

        self.ui.toolBar.addSeparator()
        self.slider=QSlider(Qt.Horizontal)
        self.time=QLabel('0:0/0:0')
        self.ui.toolBar.addWidget(self.time)
        self.ui.toolBar.addWidget(self.slider)

    def makenewtab(self,name):
        self.current['list'] = mylist()
        self.ui.tabWidget.addTab(self.current['list'], name)
        self.ui.tabWidget.setCurrentWidget(self.current['list'])
        lyt = QVBoxLayout()
        lyt.setContentsMargins(0, 0, 0, 0)
        lyt.setSpacing(0)
        self.current['list'].setLayout(lyt)
        self.current['list'].doubleClicked.connect(self.ListdoubleClicked)

    def ListdoubleClicked(self,e):
        row=self.current['list'].selectionModel().currentIndex().row()
        fname=e.siblingAtColumn(2).data()
        if not fname :  # title-row --> return
            return
        if self.p.is_playing() :
            self.removeplay()
            self.p.stop()
        else:
            self.timer.start()
        self.actionplay(fname,row)

    def actionplay(self,f,row):
        self.current['file']=f
        self.p.set_mrl(f)  
        self.p.play() 
        self.taginfo.show(f)
        self.current['list'].model().setItem (row,1, QStandardItem('▶'))
        self.current['list'].setCurrentIndex(self.current['list'].model().index(row,0)) 
        self.setWindowTitle(f)

    def removeplay(self):
        delrow=self.current['list'].model().findItems('▶',Qt.MatchExactly,1)[0].row()
        self.current['list'].model().setItem(delrow,1,QStandardItem(''))
        return delrow

    def monitoring(self):
        if self.p.is_playing() :
            self.ui.statusbar.showMessage(str(self.p.get_time()))
        else:
            row=self.removeplay()+1
            fname=self.current['list'].model().index(row,2).data()
            if not fname: # no path but album?
                row+=1
                fname=self.current['list'].model().index(row,2).data()
                if not fname:  # check again
                    fname=self.current['list'].model().index(1,2).data()
                    row=1
            self.actionplay(fname,row)

    def actionpause(self):
        self.p.pause()

    def actionstop(self):
        self.p.stop()
        self.timer.stop()
        self.removeplay()
        self.autoplay=False

    def actionset(self):
        t=self.p.get_length()
        self.p.set_time(t-3000)

        # index = self.current['list'].model().index(3, 0);
        # self.current['list'].setCurrentIndex (index)
        # index=self.current['list'].selectedIndexes ()[0]
        # self.current['list'].setFirstColumnSpanned (index.row() ,index.parent() ,1)
        
        pass

    def actionsave(self):
        for i in range(self.current['list'].model().rowCount()):
            for p in range(self.current['list'].model().columnCount()):
                print(self.current['list'].model().index(i,p).data() + ' , ' , end ='')
            print('') # 改行する

    def sqlexecute( self, line ):
        conn = sqlite3.connect( self.db )
        c = conn.cursor()
        item=['×','×']
        tree=[None,None,None,None]
        model = QStandardItemModel()
        for l in  c.execute(line) :
            # print(l)
            if item[0] != l[0] :      # 1 a-artist
                tree[1] = QStandardItem(l[0])
                model.appendRow(tree[1])
                item[0]=l[0]
            if item[1] != l[1] :      # 1 date album
                tree[2] = QStandardItem( l[1] )
                tree[1].appendRow(tree[2])
                item[1]=l[1]
            tree[3]=QStandardItem(l[2]) , QStandardItem(l[3])
            # tree[3].setData(l[3])
            tree[2].appendRow(tree[3])         # l[3] path 入れてない

        c.close()
        conn.close()
        return model

    def actionbye(self):
        # with open( 'data.pickle', 'wb') as f :
        #     pickle.dump( self.model ,f)
        quit()

    def search(self,e):
        item=self.ui.lineEdit.text()
        temp=self.ui.treeView.model()
        if  item==''  or (len(item)==1 and  re.match('[a-zA-Z0-9_.,]',item) ) :
        # if item=='' :
            if temp == self.model :
                pass
            else:
                self.ui.treeView.setModel(self.model)
                del temp
        else :
            item="'%"+item+"%'"
            line='select artist ,album,title ,path from  musics  where \
                artist like {}  or path like {} or title like {}\
                order by artist ,album,title'.format(item,item,item)
            self.ui.treeView.setModel(self.sqlexecute(line))
            if temp != self.model:
                del temp

    def treeClicked(self,e):
        path=( e.siblingAtColumn(1).data() )
        if path:                 # dataがあればタイトル
            self.taginfo.show(path)

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())
  • 久しぶりにコードののせたな
    職場で構想練ってある程度のコード書いて、家に帰ってからそれを実行
    結構エラー無くいけるので少し驚いている
    逆に効率的かも