我负责的就是一个界面布局,嵌入MPlayer播放器,时钟啊,图片滚动啊之类的就行了。最后在开发板上去跑这个程序,当然在PC机环境下测试好自己的程序后,直接烧到开发板肯定不行的,那么我们就需要交叉编译Qt程序,生成.bin可执行文件,然后在去编译一个MPlayer播放器,将他们同时烧过去,当然Qt程序需要的目录啊,图片啊,文件啊这些东西要在开发板处建立好; 这里我们采用的是nfs挂在文件系统,所以我们只需要在rootfs的nfs共享目录下的linux文件系统中放入相关的程序和文件就行了,很方便于修改和开发。
在做程序的过程中还是遇到了很多问题,比如进程的时候,因为涉及到嵌入MPlayer播放器,涉及到进程的相关控制,设计到开发板的分层显示功能,所以挺复杂的,但是在老师的帮助下,其实老师的功能很大了,因为很多地方我们都不懂,而且时间就三四天,想要完整的做完几乎是不可能的。所以最后结果也不是很理想,不过框架基本做完了。还算是有点收获的,只是结果不太令人满意,以后需要用心的去琢磨和学习知识,扎实很重要。
Qt和MPlayer部分的编译在另一篇文章中已经说说明了,需要自己动手实践后才有体会,因为过程中可能会遇到很多不同的问题。
下面我主要就是说下在代码(arm版本的)中主要的部分,因为相信很多人对QT已经很好了,我知识个菜鸟:
//主窗体
#include "mainwidget.h"
#include "clock.h"
#include "pic.h"
#include "message.h"
#include "mplayer.h"
MainWidget::MainWidget(QWidget *parent)
:QWidget(parent)
{
this->setAutoFillBackground(true);//1s step
QPalette palette;//2s step
palette.setBrush(QPalette::Background, QBrush(QPixmap("backt.jpg")));
this->setPalette(palette);//3s step
label_pl = new QLabel(this);
label_pr = new QLabel(this);
pm = new QMovie("logo.gif");
label_pl->setMovie(pm);
label_pr->setMovie(pm);
pm->start();
label_pl->setGeometry(0, 0, 100, 100);
label_pr->setGeometry(500, 0, 100, 100);
label_clk = new QLabel(this);
pix_clk = new QPixmap("clk.jpg");
label_wether = new QLabel(this);
pix_wether = new QPixmap("weather/light.png");
label_clk->setGeometry(620, 10, 180, 80);
label_clk->setPixmap(pix_clk->scaled(label_clk->width(), label_clk->height()));
label_wether->setGeometry(666, 110, 100, 90);
label_wether->setPixmap(pix_wether->scaled(label_wether->width(), label_wether->height()));
Clock *clk = new Clock(this);
clk->setGeometry(625, 20, 150, 50);
Pic *pic = new Pic(this);
pic->show();
Message *msg = new Message(this);
msg->show();
MPlayer *mplayer = new MPlayer(this);
mplayer->show();
this->setGeometry(0, 0, 800, 480);
}
//相关的文件夹目录
log 目录下
message.txt //一旦发现该目录下的此文件更新,
就重新加载滚动的文字;
pic.log // 保存当前图片的信息
video.log //保存当前播放视频的信息
picture 目录下
各种图片,用于广告图片显示,一旦发现有更新,
也是立即刷新图片列表。
video 目录下
视频文件 和 playlist.lst播放列表 //一旦发现有
新的视频更新或者删除,重新读取视频播放列表。
weather 目录,存放当天天气信息,本来打算用编程来读取
网络天气的,发现不行,最后放弃了,不想放弃的。呵呵!(后来有在网络达人的分享下搞定了。改天贴上)
当前工作目录下还有一个tmp目录,是文件系统有的,然后
我在其中创建了管道cmd(用mkfifo cmd),管道的作用是可以接受来自用户的对于
MPlayer播放器的控制命令,命令就是通过这个管道传送的,
可以播放,暂停,开始等命令。
//相关界面和控制技巧
MPlayer::MPlayer(QWidget *parent)
:QWidget(parent)
{
//刷新开发板屏幕
system("cat /dev/zero >/dev/fb0 2>/dev/null");
//创建一个进程,用于执行mplayer
process = new QProcess(parent);
//创建一个窗体,用于放置mplayer
renderTarget = new QWidget(this);
renderTarget->setGeometry(0, 100, 620, 380);
renderTarget->setAutoFillBackground(true);
QPalette palette = renderTarget->palette();
palette.setColor(QPalette::Background, Qt::black);
renderTarget->setPalette(palette);
//创建一个监视器,用于监视目录和目录下文件的变化
fileWatcher = new QFileSystemWatcher(this);
fileWatcher->addPath("video/");
//连接目录变化的槽,一旦变化就重新播放视频
connect(fileWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(play_video()));
QString common;
//构造一个mplayer播放的字符串,注意如果是播放列表的话,需要放在视频目录下,因为他会自动加上一个./video/目录,所以这样才可以,而且文件中存名字就好了,目录在播放时自动添加,这应该是设计好的
common = QString("%1%2%3%4%5%6%7%8%9").arg("./mplayer ").arg("-playlist ./video/playlist.lst -loop 0").arg(" -x ").arg(QString::number(renderTarget->width())).arg(" -y ").arg(renderTarget->height()).arg(" ").arg(" -geometry 0:100").arg(" -slave >/dev/null 2>&1");
process->start(common);
//如果有可读信息就读出来,也就是可以读出当前播放信息,然后拆分出需要的信息,并且写入日志文件
connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));
}
//滚动文字
#include
#include
#include
#include "message.h"
Message::Message(QWidget *parent)
:QLabel(parent)
{
label = new QLabel(parent);
QPixmap *pic = new QPixmap("txt.jpg");
label->setGeometry(100, 8, 400, 80);
label->setPixmap(pic->scaled(label->width(),label->height()));
label_txt = new QLabel(parent);
//Font's size setting;
str = str.fromLocal8Bit("快乐男孩!");
label_txt->setFont(QFont("wenquanyi", 20, QFont::Bold));
//Font's color setting;
QPalette pe_txt;
pe_txt.setColor(QPalette::WindowText,Qt::blue);
label_txt->setPalette(pe_txt);
QTimer *timer2 = new QTimer(this);
connect(timer2, SIGNAL(timeout()), this, SLOT(show_txt()));
timer2->start(20);
fileWatcher = new QFileSystemWatcher(this);
fileWatcher->addPath("log/");
connect(fileWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(set_txt()));
set_txt();
}
void Message::set_txt()
{
QFile file("log/message.txt");
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) // /r/n ---> /n
return;
char buffer[2048];
qint64 lineLen = file.readLine(buffer, sizeof(buffer));
if(lineLen != -1)
{
str = str.fromLocal8Bit(buffer);
//qDebug() << str;
}
file.close();
}
void Message::show_txt()
{
#if 1
static int i = 380;
if(i == 110) i = 380;
label_txt->setText(str);
label_txt->setGeometry(i--, 5, 300, 100);
#endif
}
//滚动图片
#include
#include "pic.h"
Pic::Pic(QWidget *parent)
:QLabel(parent)
{
flag = 1; //for picture moving
label = new QLabel(parent);
label->setGeometry(620, 200, 180, 200);
timer = new QTimer(this);
timer_lb = new QTimer(this);
fileWatcher = new QFileSystemWatcher(this);
fileWatcher->addPath("picture/");
connect(fileWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(build_pic()));
build_pic();
connect(timer, SIGNAL(timeout()), this, SLOT(show_pic()));
show_pic();
timer->start(30000);
connect(timer_lb, SIGNAL(timeout()), this, SLOT(update_label()));
timer_lb->start(1000);
}
void Pic::build_pic()
{
//qDebug() << "build pic" <
QDir *dir = new QDir("picture");
QStringList qst;
qst << "*.jpg";
qst = dir->entryList(qst);
pic_count = qst.count();
for(int i = 0; i < qst.count(); ++i)
{
QString string;
char buf[50];
strcpy(buf,"picture/");
string = strcat(buf, qst.at(i).toLocal8Bit().constData());
pic[i] = new QPixmap(string);
strcpy(name_list[i], string.toLocal8Bit().data());
//qDebug() << name_list[i];
}
}
void Pic::show_pic()
{
static int i = 0;
if(i == pic_count)
i = 0;
//before showing, save current picture's information to pic.log;
QFileInfo info(name_list[i]);
//获取图片文件信息,对视频不管用
qint64 size = info.size();
QDateTime created = info.created();
QDateTime lastModified = info.lastModified();
QDateTime lastRead = info.lastRead();
QString str;
str = QString("%1\n%2 Bytes\n%3\n%4\n%5\n").arg(name_list[i]).arg(QString::number(size, 10)).arg(created.toString()).arg(lastModified.toString()).arg(lastRead.toString());
//qDebug() << str;
QFile file("log/pic.log");
if(!file.open(QFile::WriteOnly | QFile::Truncate))
return;
QTextStream ts(&file);
ts << str;
file.close();
//测试
//qDebug() << name_list[i];
//qDebug() << QString::number(size, 10) << "Bytes";
//qDebug() << created.toString();
//qDebug() << lastModified.toString();
//qDebug() << lastRead.toString();
label->setPixmap(pic[i++]->scaled(label->width(), label->height()));
}
void Pic::update_label()
{
static int j = 200;
if(1 == flag)
j = j + 20;
else
j = j - 20;
if(280 == j)
flag = -1;
if(200 == j)
flag = 1;
label->setGeometry(620, j, 180, 200);
}
其实写这些东西可能没有什么用,只是表露以下思维方式,可能比较低效,但还是想写写,管他的了。
至于主函数这里就不怎么说了,因为要融合lcd.h文件,就是关于屏幕的一些设置,分层显示的一些东西,不是很了解,老师给了源码,就拿来用了。最后能在开发板上跑起来。
然后组员也都把服务器写好了,就差CGI程序和C服务器的结合,当点击网页的控制按钮提交信息后,就可以通过CGI程序获取文本框信息,或是上传图片,或是上传文字,当然还有按钮的值,然后判断是哪中按钮按下,程序根据判断执行不同的命令,发送不同的命令,终端收到相关命令后执行相应的操作就行了。
比如CGI程序获取了暂停mplayer播放的命令,就直接发送命令到开发板的服务器端,那个C程序就根据命令,向tmp/cmd管道写入相应命令就行了。
所以我的开发板需要同时运行三个进程,Qt+mplayer+服务器程序。大体就这样。
一个界面简单展示效果: