안녕하세요.
요즘 파이썬을 재미있게 공부하며, Python + PyQt5 로 만든 음악플레이어입니다.
Python, Qt를 공부하는 분들께 혹시 도움이 될까 싶어 작성해 보았습니다.
pyinstaller 로 만든 windows 실행파일 링크 : https://drive.google.com/file/d/1I3FlIMizBUN5Z_y9UpOX6D2hi10kUA02/view?usp=sharing
pyinstaller로 만든 windows용 실행파일이 항상 파일크기가 너무 큰데(MFC 대비), 줄이는 방법을 알고계시면 알려주시면 감사하겠습니다.
아래는 소스코드 입니다.
전체 코드는 2개의 파이썬 파일로 구성되어 있습니다.(main.py, player.py)
소스코드 1 (main.py)
from
PyQt5.QtWidgets
import
*
import
sys
from
player
import
*
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling,
True
)
class
CWidget(QWidget):
def
__init__(
self
):
super
().__init__()
self
.player
=
CPlayer(
self
)
self
.playlist
=
[]
self
.selectedList
=
[
0
]
self
.playOption
=
QMediaPlaylist.Sequential
self
.setWindowTitle(
'Ocean Coding School'
)
self
.initUI()
def
initUI(
self
):
vbox
=
QVBoxLayout()
# 1.Play List
box
=
QVBoxLayout()
gb
=
QGroupBox(
'Play List'
)
vbox.addWidget(gb)
self
.table
=
QTableWidget(
0
,
2
,
self
)
self
.table.setHorizontalHeaderItem(
0
, QTableWidgetItem(
'Title'
))
self
.table.setHorizontalHeaderItem(
1
, QTableWidgetItem(
'Progress'
))
# read only
self
.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
# single row selection
self
.table.setSelectionBehavior(QAbstractItemView.SelectRows)
# signal
self
.table.itemSelectionChanged.connect(
self
.tableChanged)
self
.table.itemDoubleClicked.connect(
self
.tableDbClicked)
box.addWidget(
self
.table)
hbox
=
QHBoxLayout()
btnAdd
=
QPushButton(
'Add List'
)
btnDel
=
QPushButton(
'Del List'
)
btnAdd.clicked.connect(
self
.addList)
btnDel.clicked.connect(
self
.delList)
hbox.addWidget(btnAdd)
hbox.addWidget(btnDel)
box.addLayout(hbox)
gb.setLayout(box)
# 2.Play Control
box
=
QHBoxLayout()
gb
=
QGroupBox(
'Play Control'
)
vbox.addWidget(gb)
text
=
[
'◀◀'
,
'▶'
,
'⏸'
,
'▶▶'
,
'■'
]
grp
=
QButtonGroup(
self
)
for
i
in
range
(
len
(text)):
btn
=
QPushButton(text[i],
self
)
grp.addButton(btn, i)
box.addWidget(btn)
grp.buttonClicked[
int
].connect(
self
.btnClicked)
# Volume
self
.slider
=
QSlider(Qt.Horizontal,
self
)
self
.slider.setRange(
0
,
100
)
self
.slider.setValue(
50
)
self
.slider.valueChanged[
int
].connect(
self
.volumeChanged)
box.addWidget(
self
.slider)
gb.setLayout(box)
# 3.Play Option
box
=
QHBoxLayout()
gb
=
QGroupBox(
'Play Option'
)
vbox.addWidget(gb)
str
=
[
'current item once'
,
'current item in loop'
,
'sequential'
,
'loop'
,
'random'
]
grp
=
QButtonGroup(
self
)
for
i
in
range
(
len
(
str
)):
btn
=
QRadioButton(
str
[i],
self
)
if
i
=
=
QMediaPlaylist.Sequential:
btn.setChecked(
True
)
grp.addButton(btn, i)
box.addWidget(btn)
grp.buttonClicked[
int
].connect(
self
.radClicked)
gb.setLayout(box)
self
.setLayout(vbox)
self
.show()
def
tableChanged(
self
):
self
.selectedList.clear()
for
item
in
self
.table.selectedIndexes():
self
.selectedList.append(item.row())
self
.selectedList
=
list
(
set
(
self
.selectedList))
if
self
.table.rowCount()!
=
0
and
len
(
self
.selectedList)
=
=
0
:
self
.selectedList.append(
0
)
#print(self.selectedList)
def
addList(
self
):
files
=
QFileDialog.getOpenFileNames(
self
,
'Select one or more files to open'
, ''
,
'Sound (*.mp3 *.wav *.ogg *.flac *.wma)'
)
cnt
=
len
(files[
0
])
row
=
self
.table.rowCount()
self
.table.setRowCount(row
+
cnt)
for
i
in
range
(row, row
+
cnt):
self
.table.setItem(i,
0
, QTableWidgetItem(files[
0
][i
-
row]))
pbar
=
QProgressBar(
self
.table)
pbar.setAlignment(Qt.AlignCenter)
self
.table.setCellWidget(i,
1
, pbar)
self
.createPlaylist()
def
delList(
self
):
row
=
self
.table.rowCount()
index
=
[]
for
item
in
self
.table.selectedIndexes():
index.append(item.row())
index
=
list
(
set
(index))
index.reverse()
for
i
in
index:
self
.table.removeRow(i)
self
.createPlaylist()
def
btnClicked(
self
,
id
):
if
id
=
=
0
:
#◀◀
self
.player.prev()
elif
id
=
=
1
:
#▶
if
self
.table.rowCount()>
0
:
self
.player.play(
self
.playlist,
self
.selectedList[
0
],
self
.playOption)
elif
id
=
=
2
:
#⏸
self
.player.pause()
elif
id
=
=
3
:
#▶▶
self
.player.
next
()
else
:
#■
self
.player.stop()
def
tableDbClicked(
self
, e):
self
.player.play(
self
.playlist,
self
.selectedList[
0
],
self
.playOption)
def
volumeChanged(
self
):
self
.player.upateVolume(
self
.slider.value())
def
radClicked(
self
,
id
):
self
.playOption
=
id
self
.player.updatePlayMode(
id
)
def
paintEvent(
self
, e):
self
.table.setColumnWidth(
0
,
self
.table.width()
*
0.7
)
self
.table.setColumnWidth(
1
,
self
.table.width()
*
0.2
)
def
createPlaylist(
self
):
self
.playlist.clear()
for
i
in
range
(
self
.table.rowCount()):
self
.playlist.append(
self
.table.item(i,
0
).text())
#print(self.playlist)
def
updateMediaChanged(
self
, index):
if
index>
=
0
:
self
.table.selectRow(index)
def
updateDurationChanged(
self
, index, msec):
#print('index:',index, 'duration:', msec)
self
.pbar
=
self
.table.cellWidget(index,
1
)
if
self
.pbar:
self
.pbar.setRange(
0
, msec)
def
updatePositionChanged(
self
, index, msec):
#print('index:',index, 'position:', msec)
self
.pbar
=
self
.table.cellWidget(index,
1
)
if
self
.pbar:
self
.pbar.setValue(msec)
if
__name__
=
=
'__main__'
:
app
=
QApplication(sys.argv)
w
=
CWidget()
sys.exit(app.exec_())
소스코드 2 (player.py)
from
PyQt5.QtMultimedia
import
QMediaPlaylist, QMediaContent, QMediaPlayer
from
PyQt5.QtCore
import
Qt, QUrl
class
CPlayer:
def
__init__(
self
, parent):
# 윈도우 객체
self
.parent
=
parent
self
.player
=
QMediaPlayer()
self
.player.currentMediaChanged.connect(
self
.mediaChanged)
self
.player.durationChanged.connect(
self
.durationChanged)
self
.player.positionChanged.connect(
self
.positionChanged)
self
.playlist
=
QMediaPlaylist()
def
play(
self
, playlists, startRow
=
0
, option
=
QMediaPlaylist.Sequential):
if
self
.player.state()
=
=
QMediaPlayer.PausedState:
self
.player.play()
else
:
self
.createPlaylist(playlists, startRow, option)
self
.player.setPlaylist(
self
.playlist)
self
.playlist.setCurrentIndex(startRow)
self
.player.play()
def
pause(
self
):
self
.player.pause()
def
stop(
self
):
self
.player.stop()
def
prev(
self
):
self
.playlist.previous()
def
next
(
self
):
self
.playlist.
next
()
def
createPlaylist(
self
, playlists, startRow
=
0
, option
=
QMediaPlaylist.Sequential):
self
.playlist.clear()
for
path
in
playlists:
url
=
QUrl.fromLocalFile(path)
self
.playlist.addMedia(QMediaContent(url))
self
.playlist.setPlaybackMode(option)
def
updatePlayMode(
self
, option):
self
.playlist.setPlaybackMode(option)
def
upateVolume(
self
, vol):
self
.player.setVolume(vol)
def
mediaChanged(
self
, e):
self
.parent.updateMediaChanged(
self
.playlist.currentIndex())
def
durationChanged(
self
, msec):
if
msec>
0
:
self
.parent.updateDurationChanged(
self
.playlist.currentIndex(), msec)
def
positionChanged(
self
, msec):
if
msec>
0
:
self
.parent.updatePositionChanged(
self
.playlist.currentIndex(), msec)
개발환경
Windows 10 pro 64bit
Python 3.7, PyQt5
감사합니다.
파이썬은 최근 머신러닝에 관심이 생겨 독학으로 공부하였고 PyQt는 사이트 이름이 잘 기억나지 않는데 zip code(?) 라는 사이트에서 자료를 참조해가며 사용법을 배웠습니다.
단순히 Qt에서 만들어 놓은 클래스를 활용했을뿐입니다.