6.视频播放器
设计过程如下:
1)新建项目:
新建Qt Widgets Application,项目名称为“Player”,勾选ui界面设计选项,基类选择“QWidget”,类名命名为“Player”,并添加该工程的头文件和源文件。
2)完善.pro文件:
在.pro文件中添加如下代码:
QT += network \
xml \
multimedia \
multimediawidgets \
Widgets
3)实现视频播放器功能
使用传递到qvideowidget中的qmediaplayer对象来控制视频输出。为了提供应用程序播放列表功能,我们还使用qplaylist对象。要激活对话框上的播放和停止等各种功能,单击按钮的事件会发出play()和stop()信号,这些信号连接到qmediaplayer的play()和stop()插槽。关键代码如下:
connect(controls, SIGNAL(play()), player, SLOT(play()));
connect(controls, SIGNAL(pause()), player, SLOT(pause()));
connect(controls, SIGNAL(stop()), player, SLOT(stop()));
打开电脑中的文件,其程序代码如下:
void Player::open()
{
QFileDialog fileDialog(this);
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
fileDialog.setWindowTitle(tr("Open Files"));
QStringList supportedMimeTypes = m_player->supportedMimeTypes();
if (!supportedMimeTypes.isEmpty()) {
supportedMimeTypes.append("audio/x-m3u"); // MP3 playlists
fileDialog.setMimeTypeFilters(supportedMimeTypes);
}
fileDialog.setDirectory(QStandardPaths::standardLocations(QStandardPaths::MoviesLocation).value(0, QDir::homePath()));
if (fileDialog.exec() == QDialog::Accepted)
addToPlaylist(fileDialog.selectedUrls());
}
该部分效果如图3-27所示:
图3-27 打开电脑中的视频文件
播放视频的效果如图3-28所示:
图3-28 播放列表中的视频
4)获取volume并设置用户界面,关键程序代码如下:
controls->setvolume(player->volume());
5)实现音量调节功能,关键代码如下:
connect(controls, SIGNAL(changeVolume(int)), player, SLOT(setVolume(int)));
7)通过qvideowidget对象更改各种视频属性。可以通过单击一个按钮进入全屏模式,然后再次返回。按下“视频调整”对话框按钮,可以接触到更微妙的功能,该对话框有一组滑块,用来更改正在观看的视频的亮度、对比度、色调和饱和度。connect()语句成对出现,因此对用户界面小部件(相关滑块)或qvideowidget对象的更改将更新另一个对象。关键代码如下:
connect(brightnessSlider, SIGNAL(sliderMoved(int)), videoWidget,
SLOT(setBrightness(int)));
connect(videoWidget, SIGNAL(brightnessChanged(int)),
brightnessSlider, SLOT(setValue(int)));
connect(contrastSlider, SIGNAL(sliderMoved(int)), videoWidget,
SLOT(setContrast(int)));
connect(videoWidget, SIGNAL(contrastChanged(int)), contrastSlider,
SLOT(setValue(int)));
connect(hueSlider, SIGNAL(sliderMoved(int)), videoWidget,
SLOT(setHue(int)));
connect(videoWidget, SIGNAL(hueChanged(int)), hueSlider,
SLOT(setValue(int)));
connect(saturationSlider, SIGNAL(sliderMoved(int)), videoWidget,
SLOT(setSaturation(int)));
connect(videoWidget, SIGNAL(saturationChanged(int)),
saturationSlider, SLOT(setValue(int)));
暂停正在播放的视频的效果如图3-29所示:
图3-29 暂停正在播放的视频
播放倍速下拉列表如图3-30所示:
图3-30 倍速播放下拉列表
全屏效果如图3-31所示:
图3-31 全屏播放
“main.cpp”文件的程序代码如下:
#include <QApplication>
#include <QMessageBox>
#include <QMainWindow>
#include <QDesktopWidget>
#include <QVariant>
#include <QSettings>
#include <QFileDialog>
#include <QCommandLineParser>
#include "ui_mainwindow.h"
static const char geometryKey[] = "Geometry";
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
~MainWindow();
void openMedia(const QString &mediaUrl);
public slots:
void on_mediaPlayer_PlayStateChange(int newState);
void on_actionOpen_triggered();
void on_actionExit_triggered();
void on_actionAbout_triggered();
void on_actionAboutQt_triggered();
private:
void updateWindowTitle(const QString &state);
Ui::MainWindow m_ui;
};
MainWindow::MainWindow()
{
m_ui.setupUi(this);
QSettings settings(QSettings::IniFormat, QSettings::UserScope,
QCoreApplication::organizationName(), QCoreApplication::applicationName());
const QByteArray restoredGeometry = settings.value(QLatin1String(geometryKey)).toByteArray();
if (restoredGeometry.isEmpty() || !restoreGeometry(restoredGeometry)) {
const QRect availableGeometry = QApplication::desktop()->availableGeometry(this);
const QSize size = (availableGeometry.size() * 4) / 5;
resize(size);
move(availableGeometry.center() - QPoint(size.width(), size.height()) / 2);
}
m_ui.mediaPlayer->dynamicCall("enableContextMenu", false);
m_ui.mediaPlayer->dynamicCall("stretchToFit", true);
updateWindowTitle("");
}
MainWindow::~MainWindow()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope,
QCoreApplication::organizationName(), QCoreApplication::applicationName());
settings.setValue(QLatin1String(geometryKey), saveGeometry());
}
void MainWindow::on_mediaPlayer_PlayStateChange(int newState)
{
static const QHash<int, const char *> stateMapping {
{1, "Stopped"},
{2, "Paused"},
{3, "Playing"},
{4, "Scanning Forwards"},
{5, "Scanning Backwards"},
{6, "Buffering"},
{7, "Waiting"},
{8, "Media Ended"},
{9, "Transitioning"},
{10, "Ready"},
{11, "Reconnecting"},
};
const char *stateStr = stateMapping.value(newState, "");
updateWindowTitle(tr(stateStr));
}
void MainWindow::on_actionOpen_triggered()
{
QFileDialog fileDialog(this, tr("Open File"));
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
fileDialog.setFileMode(QFileDialog::ExistingFile);
fileDialog.setMimeTypeFilters({ "application/octet-stream", "video/x-msvideo", "video/mp4", "audio/mpeg", "audio/mp4" });
if (fileDialog.exec() == QDialog::Accepted)
openMedia(fileDialog.selectedFiles().first());
}
void MainWindow::on_actionExit_triggered()
{
QCoreApplication::quit();
}
void MainWindow::on_actionAbout_triggered()
{
QMessageBox::about(this, tr("About Media Player"),
tr("This Example has been created using the ActiveQt integration into Qt Designer.\n"
"It demonstrates the use of QAxWidget to embed the Windows Media Player ActiveX\n"
"control into a Qt application."));
}
void MainWindow::on_actionAboutQt_triggered()
{
QMessageBox::aboutQt(this, tr("About Qt"));
}
void MainWindow::openMedia(const QString &mediaUrl)
{
if (!mediaUrl.isEmpty())
m_ui.mediaPlayer->dynamicCall("URL", mediaUrl);
}
void MainWindow::updateWindowTitle(const QString &state)
{
QString appName = QCoreApplication::applicationName();
QString title = state.isEmpty() ? appName :
QString("%1 (%2)").arg(appName, state);
setWindowTitle(title);
}
#include "main.moc"
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
QCoreApplication::setApplicationName(QLatin1String("Active Qt Media Player"));
QCoreApplication::setOrganizationName(QLatin1String("QtProject"));
MainWindow w;
QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::applicationName());
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("file", "The media file to open.");
parser.process(app);
if (!parser.positionalArguments().isEmpty())
w.openMedia(parser.positionalArguments().constFirst());
w.show();
return app.exec();
}
视频调整效果如图3-32所示:
图3-32 视频调整
7.动画播放器
设计过程如下:
1)新建项目:
新建Qt Widgets Application,项目名称为“analogclock”,基类为“QWindow",类名命名为“RasterWindow”,并添加该工程的头文件“rasterwindow.h" 和文件“rasterwindow.cpp"。
2)完善头文件:
在头文件中添加需要使用的函数,如RasterWindow、render、exposeEvent和resizeEvent等。
3)创建显示页面:
利用setGeometry函数在屏幕上创建显示页面,本实验中使用 setGeometry(100, 100, 300, 200);创建了一个从屏幕上(100,100)位置开始(即为最左上角的点),显示一个300*200的界面(宽300,高200)。
4)设置窗口显示页面:
利用setTitle设置窗口的标题为“时钟”,使用resize设置窗口的大小为(200,200),然后利用m_timerId = startTimer(1000);启动一个计时器,用每秒来重新绘制时钟。
5)设计指针:
在绘制时钟之前,先定义三个Qpoints列表和三个Qcolors,用于时针、分针和秒针,设置指针的大小、颜色和透明度,比如QColor secondColor(0, 127, 221, 191);中秒针的颜色alpha分量为191,这意味着它的透明度为75%。
用qpainer::Antialiasing调用qpainer::setrenderInt()以打开反锯齿,使对角线的绘制更加平滑。
利用 p->translate(width() / 2, height() / 2);将原点移动到窗口的中心,缩放操作可确保以下绘图操作缩放以适合窗口,绘制一个固定大小的钟面,它将被定位和缩放,以便它位于窗口的中心。程序代码如下所示:
// 设置分针
p->setPen(Qt::NoPen);
p->setBrush(minuteColor);
p->save();
p->rotate(6.0 * (time.minute() + time.second() / 60.0));
p->drawConvexPolygon(minuteHand, 3);
p->restore();
p->setPen(minuteColor);
for (int j = 0; j < 60; ++j) {
if ((j % 5) != 0)
p->drawLine(92, 0, 96, 0);
p->rotate(6.0);
}
//设置秒针
p->setPen(Qt::NoPen);
p->setBrush(secondColor);
p->save();
p->rotate(6.0 * (time.second()));
p->drawConvexPolygon(secondHand, 3);
p->restore();
p->setPen(hourColor);
for (int k = 0; k < 60; ++k) {
p->drawLine(96, 0, 96, 0);
p->rotate(6.0);
}
}
利用setPen实现画笔,用setBrush实现画刷,画刷用于填充多边形和其他几何图形。将笔设置为qt::nopen,由于指针不需要任何轮廓,所以使用更加适合的纯色画笔。使用drawLine在钟的边缘画出每小时的记号,然后旋转坐标系,以便画笔为下一个作好准备。分针和秒针的绘制及相关操作与时针相同。部分代码如下:
void AnalogClockWindow::render(QPainter *p)
{
static const QPoint hourHand[3] = {
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -50)
};
static const QPoint minuteHand[3] = {
QPoint(7, 8),
QPoint(-7,8),
QPoint(0, -70)
};
static const QPoint secondHand[3] = {
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -90)
};
QColor hourColor(0,127,0, 191);
QColor minuteColor(0, 127, 127, 191);
QColor secondColor(0, 127, 221, 191);
}
时钟的表盘如图3-33所示:
图3-33 时钟的表盘
6)完善主函数,在main函数中添加如下代码:
QGuiApplication app(argc, argv);
AnalogClockWindow clock;
clock.show();
return app.exec();
时钟运行的效果如图3-34所示:
图3-34 时钟运行效果
3.2 消息响应及功能模块设计
设计过程如下:
1)在ImgProcessor类中添加createActions()函数用于创建所有的动作、createMenus()函数用于创建菜单、createToolBars()函数用于创建工具栏;接着声明实现主窗口所需的各个元素,包括菜单、工具栏及各个动作等;最后声明用到的槽函数。关键代码如下:
ImgProcessor::ImgProcessor(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle(tr("Easy Word")); //设置窗体标题
showWidget =new ShowWidget(this); //(a)
setCentralWidget(showWidget);
/* 创建动作、菜单、工具栏的函数 */
createActions();
createMenus();
createToolBars();
if(img.load("image.png"))
{
//在imageLabel对象中放置图像
showWidget->imageLabel->setPixmap(QPixmap::fromImage(img));
}
}
2)添加loadFile()事件处理函数,该函数利用QFile和QTextStream完成具体读取文件内容的工作,关键代码如下:
void ImgProcessor::loadFile(QString filename)
{
printf("file name:%s\n",filename.data());
QFile file(filename);
if(file.open(QIODevice::ReadOnly|QIODevice::Text))
{
QTextStream textStream(&file);
while(!textStream.atEnd())
{
showWidget->text->append(textStream.readLine());
printf("read line\n");
}
printf("end\n");
}
}
3)对象与槽之间的响应流程图如下:
手机扫一扫
移动阅读更方便
你可能感兴趣的文章