이전 포스팅에서 ListView에 아이템을 QAbstractModel을 상속받은 클래스를 통해 동적으로 관리하는 예제를 진행해봤습니다.
이번 포스팅에서는 Combobox에 위와 같이 Model을 적용시켜 보고 이전에 만들었던 TimeTimer에 시간이 다 되었을 때 알림 소리를 낼 수 있게 SoundEffect, Sound를 적용시켜 보겠습니다.
위 예제는 이전 TimeTimer 예제를 보고 오시면 이해하는데 더 많은 도움을 받으실 수 있습니다.
먼저 Combobox에 적용시킬 Model을 먼저 만들겠습니다. 이번에는 Model을 관리할 Manager 클래스 없이 바로 직접 지정해보려 합니다.
import SoundListItem 1.0
...
Label {
text : "알람 소리"
Layout.preferredWidth: parent.nWidth
Layout.preferredHeight: parent.nHeight
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
ComboBox {
id : alarmCombo
Layout.preferredWidth: parent.nWidth + 70
Layout.preferredHeight: parent.nHeight
Layout.alignment: Qt.AlignCenter
model : SoudListModelItem {}
delegate: comboDelegate
}
QAbstractListModel을 상속받는 SoundListModelItem을 만들어줍니다. 이번에는 단일 아이템만 노출시키므로 roleName는 따로 override 하지 않았습니다. 하지만 rowCount와 datat는 무조건 override 해주어야 합니다.
#ifndef SoundListModelItem_H
#define SoundListModelItem_H
#include <QAbstractListModel>
class SoundListModelItem : public QAbstractListModel
{
Q_OBJECT
public:
explicit SoundListModelItem(QObject *parent = nullptr);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
void loadAlarmList();
private:
QStringList alarmSoundList;
};
#endif // SoundListModelItem_H
이 예제에서는 Alarm sound를 윈도우 자체가 가지고 있는 항목들을 사용하려 합니다.
#include "SoundListModelItem.h"
#include <QDebug>
#include <QDirIterator>
SoundListModelItem::SoundListModelItem(QObject *parent)
: QAbstractListModel{parent}
{
loadAlarmList();
}
int SoundListModelItem::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return alarmSoundList.count();
}
QVariant SoundListModelItem::data(const QModelIndex &index, int role) const
{
int nRow = index.row();
if ( nRow < 0 || nRow >= alarmSoundList.count() ) {
return QVariant();
}
switch (role) {
case Qt::DisplayRole:
return alarmSoundList.value(nRow);
}
return QVariant();
}
void SoundListModelItem::loadAlarmList()
{
QString sPath = "C:/Windows/Media";
QDirIterator it(sPath, QDir::Files);
while (it.hasNext()) {
it.next();
if ( it.fileName().indexOf("Alarm") != -1 ) {
alarmSoundList.append(it.fileName());
}
}
}
Windows 폴더 아래 Media 폴더에는 각종 wav 파일이 있는데 여기서 Alarm 파일명을 가진 파일들만 가져오려고 합니다.
물론 qml에서 C++의 클래스를 사용하기 위해서 qmlRegisterType을 해주어야 합니다.
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "TimeTimerMgr.h"
#include "SoundListModelItem.h"
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
qmlRegisterType<SoundListModelItem>("SoundListItem", 1,0, "SoundListModelItem");
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/TimeTimer.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app,
[url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}
, Qt::QueuedConnection);
engine.load(url);
TimeTimerMgr timerMgr;
timerMgr.SetEngine(&engine);
return app.exec();
}
다음으로 qml Combox Model에 Delegate를 설정하겠습니다. 리스트에 파일명이랑 재생 버튼을 두고 버튼을 클릭하면 미리듣기 해보는 방식으로 해보려 합니다.
Component {
id : comboDelegate
Row {
Rectangle {
width: alarmCombo.width - 30
height : 30
Text {
anchors.fill : parent
text : model.display
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Button {
width: 30
height : 30
Text {
anchors.fill : parent
text : "재생"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked : {
// sound play
}
}
}
}
여기서 SoundEffect를 사용해보겠습니다. SoundEfffect Component 생성 후 id 만 지정합니다. 이후 Button의 onClicked에서 source 지정 후 play 시켜주면 됩니다.
Component {
id : comboDelegate
Row {
Rectangle {
width: alarmCombo.width - 30
height : 30
Text {
anchors.fill : parent
text : model.display
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
MouseArea {
anchors.fill: parent
onClicked: {
alarmSound.stop()
alarmCombo.displayText = model.display
alarmCombo.popup.close()
}
}
}
}
Button {
width: 30
height : 30
Text {
anchors.fill : parent
text : "재생"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked : {
alarmSound.source = "file:C:/Windows/Media/" + model.display
console.log(alarmSound.source)
alarmSound.play()
}
}
}
}
SoundEffect {
id : alarmSound
}
해당 효과까지 적용한 결과는 아래와 같습니다. 재생 버튼을 클릭하면 해당 wav 파일을 들어볼 수 있고 원하는 알람 소리를 클릭하면 combobox의 popup을 닫고 combox에 해당 파일명을 display 해줍니다.
이제 이 선택한 알림 소리를 타이머가 다 되었을 때 재생시켜 보겠습니다. SettingDialog.qml로 부터 signal을 받아 알람 파일명을 TimeTimerMgr까지 가져옵니다. 그리고 Timeout이 되었을 때 QSound::play 함수를 실행시킵니다.
#include "TimeTimerMgr.h"
#include <QQmlProperty>
#include <QSound>
TimeTimerMgr::TimeTimerMgr(QObject *parent)
: QObject{parent}
, m_pDialog(NULL)
, m_engine(NULL)
, m_pWindow(NULL)
, m_pTimeCanvas(NULL)
, m_nTime(0)
, m_nCount(0)
, m_sAlarmSound("")
{
connect(&timer, SIGNAL(timeout()), this, SLOT(Slot_Timeout()), Qt::UniqueConnection);
}
void TimeTimerMgr::showDialog()
{
if ( m_pDialog != NULL ) { return; }
m_pDialog = new ConfigureDialog(this, m_engine);
connect(m_pDialog, SIGNAL(Emit_setColor(QColor)), this, SLOT(Slot_GetColor(QColor)), Qt::UniqueConnection);
connect(m_pDialog, SIGNAL(Emit_setOpacity(double)), this, SLOT(Slot_GetOpacity(double)), Qt::UniqueConnection);
connect(m_pDialog, SIGNAL(Emit_setAlwaysOnTop(bool)), this, SLOT(Slot_GetAlwaysOnTop(bool)), Qt::UniqueConnection);
connect(m_pDialog, SIGNAL(Emit_setAlarmSound(QString)), this, SLOT(Slot_GetAlarmSound(QString)), Qt::UniqueConnection);
connect(m_pDialog, SIGNAL(Emit_Close()), this, SLOT(Slot_DialogClose()), Qt::UniqueConnection);
TimerSetting settingValue;
settingValue.color = m_pTimeCanvas->property("timeColor").value<QColor>();
settingValue.opacity = m_pWindow->property("dOpacity").toDouble();
settingValue.bAlwaysOnTop = m_pWindow->property("bAlwaysOnTop").toBool();
settingValue.sAlarmSound = m_sAlarmSound;
m_pDialog->Show();
m_pDialog->SetSettingValue(settingValue);
}
...
void TimeTimerMgr::Slot_Timeout()
{
m_nCount++;
m_pTimeCanvas->setProperty("setSecond", (m_nTime*60-m_nCount));
QMetaObject::invokeMethod(m_pTimeCanvas, "rePaint");
if ( m_nTime*60 == m_nCount ) {
timer.stop();
m_pWindow->setFlag(Qt::WindowStaysOnTopHint, false);
m_pWindow->setProperty("bAlwaysOnTop", false);
QSound::play("C:/Windows/Media/" + m_sAlarmSound);
}
}
...
풀 코드는 아래 Github 링크에서 확인하실 수 있습니다.
'Programming > Qt' 카테고리의 다른 글
[Qt] Static Build (exe 파일 단독 실행) (0) | 2023.04.20 |
---|---|
[Qt] QML 정리 포스팅 모음 (2) | 2023.04.20 |
[Qt] QML(7) - ListView/Model C++ 로 처리하기 (0) | 2023.04.19 |
[Qt] QML(6) - Loader, Binding, Connection (0) | 2023.04.18 |
[Qt] QML(5) - TimeTimer 프로그램 만들기 (0) | 2023.04.17 |