目录
QIODevice官方解释及个人分析
Audio Example官方实例解析
QIODevice类是Qt中I/O设备的接口。
提供了读和写的接口,QIODevice是抽象的不能被实用化。
调用设备之前,要使用open()来设置打开方式(ReadOnly和ReadWrite)。可以使用write()或putChar()向设备写数据
,同样可以使用rad(),raedLine()或readAll()去读设备。当不用的时候调用close()关闭操作。
QIODevice区分了两种设备类型 随机访问设备 和 顺序设备。
随机访问设备:使用seek()可以任意访问位置,可以使用pos()定位文件的位置,QFile和QBuffer都是随机访问设备。
顺序访问设备:不能任意访问位置,数据必须一次性读取,pos()和size()在顺序访问设备里面都不能正常工作。
QTcpSocket和QProcess都是顺序访问设备。
可以使用isSequential()看看他属于什么设备类型。
当能读时会发出readyRead()信号。调用bytesAvailable()查看当前能读取的字节数。向设备写数据时会发射
bytesWritten()信号。调用bytesToWrite()来查看待写入的字节数。
QIODevice的子类QTcpSocket和QProcess都是异步处理的,但也可以使用waitForReadyRead()和waitForBytesWritten
()去让他阻塞。
QProcess gzip;
gzip.start("gzip", QStringList() << "-c");
if (!gzip.waitForStarted())
return false;
gzip.write("uncompressed data");
QByteArray compressed;
while (gzip.waitForReadyRead())
compressed += gzip.readAll();
这里可以看到QProcess这个顺序访问设备开启一个外部进程,并且使用了阻塞的方式,如果这个调用是放在GUI线程里面的,那么肯定会有问题,界面肯定会卡住。
注意:这个问题一点要注意,在本人参与的项目中,很多人写的程序,都喜欢用GUI线程去读东西,一旦处理不好,就会造成阻塞。建议Qt开发经验或技巧不足的朋友,多多使用线程去读写这些东西,不要使用GUI线程去做(其实在Qt中有很多方式和技巧可以在GUI线程里面操作,同时也不会阻塞GUI线程)
这里是官方的实例,我先把代码贴上,因为版权占用太多,我把版权去掉了,但这个例子是Qt官方提供的,特产声明(本人励志做一个有节操的程序员,不仅要看破,而且要说破)
源码如下:
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
QT_CHARTS_BEGIN_NAMESPACE
class QLineSeries;
class QChart;
QT_CHARTS_END_NAMESPACE
QT_CHARTS_USE_NAMESPACE
class XYSeriesIODevice;
QT_BEGIN_NAMESPACE
class QAudioInput;
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
private:
XYSeriesIODevice *m_device;
QChart *m_chart;
QLineSeries *m_series;
QAudioInput *m_audioInput;
};
#endif // WIDGET_H
xyseriesiodevice.h
#ifndef XYSERIESIODEVICE_H
#define XYSERIESIODEVICE_H
#include
#include
QT_CHARTS_BEGIN_NAMESPACE
class QXYSeries;
QT_CHARTS_END_NAMESPACE
QT_CHARTS_USE_NAMESPACE
class XYSeriesIODevice : public QIODevice
{
Q_OBJECT
public:
explicit XYSeriesIODevice(QXYSeries * series, QObject *parent = 0);
protected:
qint64 readData(char * data, qint64 maxSize);
qint64 writeData(const char * data, qint64 maxSize);
private:
QXYSeries *m_series;
};
#endif // XYSERIESIODEVICE_H
main.cpp
#include
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.cpp
#include "widget.h"
#include
#include
#include
#include
#include
#include
#include
#include "xyseriesiodevice.h"
QT_CHARTS_USE_NAMESPACE
Widget::Widget(QWidget *parent)
: QWidget(parent),
m_device(0),
m_chart(0),
m_series(0),
m_audioInput(0)
{
m_chart = new QChart;
QChartView *chartView = new QChartView(m_chart);
chartView->setMinimumSize(800, 600);
m_series = new QLineSeries;
m_chart->addSeries(m_series);
QValueAxis *axisX = new QValueAxis;
axisX->setRange(0, 2000);
axisX->setLabelFormat("%g");
axisX->setTitleText("Samples");
QValueAxis *axisY = new QValueAxis;
axisY->setRange(-1, 1);
axisY->setTitleText("Audio level");
m_chart->setAxisX(axisX, m_series);
m_chart->setAxisY(axisY, m_series);
m_chart->legend()->hide();
m_chart->setTitle("Data from the microphone");
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(chartView);
setLayout(mainLayout);
QAudioFormat formatAudio;
formatAudio.setSampleRate(8000);
formatAudio.setChannelCount(1);
formatAudio.setSampleSize(8);
formatAudio.setCodec("audio/pcm");
formatAudio.setByteOrder(QAudioFormat::LittleEndian);
formatAudio.setSampleType(QAudioFormat::UnSignedInt);
QAudioDeviceInfo inputDevices = QAudioDeviceInfo::defaultInputDevice();
m_audioInput = new QAudioInput(inputDevices,formatAudio, this);
m_device = new XYSeriesIODevice(m_series, this);
m_device->open(QIODevice::WriteOnly);
m_audioInput->start(m_device);
}
Widget::~Widget()
{
m_audioInput->stop();
m_device->close();
}
xyseriesiodevice.cpp
#include "xyseriesiodevice.h"
#include
XYSeriesIODevice::XYSeriesIODevice(QXYSeries * series, QObject *parent) :
QIODevice(parent),
m_series(series)
{
}
qint64 XYSeriesIODevice::readData(char * data, qint64 maxSize)
{
Q_UNUSED(data)
Q_UNUSED(maxSize)
return -1;
}
qint64 XYSeriesIODevice::writeData(const char * data, qint64 maxSize)
{
qint64 range = 2000;
QVector oldPoints = m_series->pointsVector();
QVector points;
int resolution = 4;
if (oldPoints.count() < range) {
points = m_series->pointsVector();
} else {
for (int i = maxSize/resolution; i < oldPoints.count(); i++)
points.append(QPointF(i - maxSize/resolution, oldPoints.at(i).y()));
}
qint64 size = points.count();
for (int k = 0; k < maxSize/resolution; k++)
points.append(QPointF(k + size, ((quint8)data[resolution * k] - 128)/128.0));
m_series->replace(points);
return maxSize;
}
这里只提下这个XYSeriesIODevice这个类,
此类为QIODevice的子类。
这里提出2个问题:
为毛要重写readData()和writeData()这两个函数?
为毛readDatat()里面是空的而writeData()这函数却对QXYSeries进行了操作?
下面来依次回答这2个问题!
通过官方文档得到readData()和writeData()为纯虚函数,所以一定要写上去。
第二个问题,因为QAuidoInput::start(QIODevice *device)中把音频数据发送到device中了,他是以写入的形式发到device中的,内部肯定是有个回调,回调了writeData(),所以在那里面写曲线即可。