QAudioOutput 无法播放声音的问题
在 Windows 上使用 MSVC 编译的 Qt 程序,无法播放声音,QAudioDeviceInfo::availableDevices
返回空列表。
这是因为没能正确加载 Qt 插件。需要将 Qt\msvc2017_64\plugins
目录下的 audio 目录复制到可执行文件所在目录。
使用 windeployqt
部署后即可正确运行。
插件加载正确后,仍然发生无声音的问题,且 Qt 无任何报错。通过 QAudioDeviceInfo 查看支持的音频格式为:
("audio/pcm")
(8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 192000)
(8, 16, 24, 32, 48, 64)
(LittleEndian)
(SignedInt, UnSignedInt, Float)
程序设置的音频格式为 32 位、小端、浮点数,在支持的范围内。
这个问题上的回答提到:
Qt 音频在 Windows 上,8 位数据只支持 UnSignedInt,16 位数据支持 SignedInt
但是没有提到 float 类型,怀疑可能不支持,改用 16 位 SignedInt 后可以正常播放。
另外,使用其支持列表返回的 64 位会报错,可以判断支持列表是假的。
QCustomPlot 启用 OpenGL
编译时添加预编译宏 QCUSTOMPLOT_USE_OPENGL
,用绘图的 QCustomPlot
子类调用 setOpenGl(true)
,并链接 OpenGL32
在 Windows 上使用
OpenGL32
存在很严重的性能问题,可以改为使用 freeglut
图像错乱问题
修改 QCPPaintBufferGlFbo::draw
,添加上下文切换的代码。
void QCPPaintBufferGlFbo::draw(QCPPainter *painter) const
{
if (!painter || !painter->isActive())
{
qDebug() << Q_FUNC_INFO << "invalid or inactive painter passed";
return;
}
if (!mGlFrameBuffer)
{
qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?";
return;
}
// 添加
if (QOpenGLContext::currentContext() != mGlContext.data()) {
mGlContext.data()->makeCurrent(mGlContext.data()->surface());
}
painter->drawImage(0, 0, mGlFrameBuffer->toImage());
}
编译 Qt 源码,没有生成 libqxcb.so 的问题
Qt 通过不同的插件,在不同的平台上进行显示,例如:
libqlinuxfb.so
用于 Frame Bufferlibqxcb.so
用于 X11libqwayland-generic.so
用于 Wayland
构建 X11 插件需要依赖许多 xcb 的开发包,可以通过下面的命令安装:
Qt 5.15.2:
sudo apt install libfontconfig1-dev \
libfreetype6-dev \
libx11-dev \
libx11-xcb-dev \
libxext-dev \
libxfixes-dev \
libxi-dev \
libxrender-dev \
libxcb1-dev \
libxcb-glx0-dev \
libxcb-keysyms1-dev \
libxcb-image0-dev \
libxcb-shm0-dev \
libxcb-icccm4-dev \
libxcb-sync0-dev \
libxcb-xfixes0-dev \
libxcb-shape0-dev \
libxcb-randr0-dev \
libxcb-render-util0-dev \
libxcb-xinerama0-dev \
libxkbcommon-dev \
libxkbcommon-x11-dev
Qt 6.5:
sudo apt install libfontconfig1-dev \
libfreetype6-dev \
libx11-dev \
libx11-xcb-dev \
libxext-dev \
libxfixes-dev \
libxi-dev \
libxrender-dev \
libxcb1-dev \
libxcb-cursor-dev \
libxcb-glx0-dev \
libxcb-keysyms1-dev \
libxcb-image0-dev \
libxcb-shm0-dev \
libxcb-icccm4-dev \
libxcb-sync-dev \
libxcb-xfixes0-dev \
libxcb-shape0-dev \
libxcb-randr0-dev \
libxcb-render-util0-dev \
libxcb-util-dev \
libxcb-xinerama0-dev \
libxcb-xkb-dev \
libxkbcommon-dev \
libxkbcommon-x11-dev
安装后重新构建即可:
rm config.cache
./configure -nomake examples -prefix /opt/qt-6.5.2 -opensource -confirm-license -release -xcb
make
make install
单独编译某个模块的命令为:
make module-qtbase # 单独编译 qtbase
make module-qtbase-install_subtargets # 单独安装 qtbase
另外,如果需要 OpenGL 的话,可以安装以下包:
sudo apt install libgl1-mesa-dev \
libglu1-mesa-dev \
libx11-dev
如果不需要 OpenGL 的话,在 configure 步骤添加
-no-opengl
选项即可。
如果需要使用 SSL 的话,可以安装以下包:
sudo apt install libssl-dev \
openssl
如果不需要 OpenGL 的话,在 configure 步骤添加
-no-ssl
选项即可。
缓存问题:
执行过 configure 之后再安装依赖,再次执行 configure 仍会提示缺少依赖,可以删除 config.cache
来解决。
查找路径问题:
执行 configure 时可以使用 -I
和 -L
选项添加查找路径。
参考:
QObject 与 dllimport 的相关问题
Qt 的元对象编译(MOC)系统会根据标记了 Q_OBJECT
的类生成代码。由于类通常在头文件中,因此通常需要将头文件加入编译。
add_library(lib SHARED lib.h lib.cpp)
在 Windows 上引用 lib 时,可能会遇到 staticMetaObject 符号未定义的错误。
add_executable(demo main.cpp)
即使创建动态库时,将 CMAKE_EXPORT_ALL_SYMBOLS
设为 ON
也不行。
set(CMAKE_EXPORT_ALL_SYMBOLS ON)
add_library(lib SHARED lib.h lib.cpp)
这是因为只有函数符号可以自动导入,而staticMetaObject 是静态数据成员,全局数据必须通过 __declspec(dllimport) 手动导入。
参考 CMake 文档。
正确的解决办法是声明 dllexport 和 dllimport
#ifdef BUILD_SHARED
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declscpe(dllimport)
#endif
class DLL_EXPORT XXX : public QObject
{
Q_OBJECT
};
不清楚这个机制的人可能会在外部项目中将 lib.h 加入编译,这样错误也会消失,因为 lib.h 重新 moc 并编译了一份。
add_executable(demo main.cpp lib.h)
但这是错误的解决办法,这将导致外部项目和库中的 staticMetaObject 是不同的对象。
并且,如果引用的头文件中已经声明了 DLL_EXPORT
,同时外部项目不是 BUILD_SHARED
(例如构建可执行程序)。此时 DLL_EXPORT
将被解析为 __declscpe(dllimport)
,从而导致头文件报 不允许 dllimport 静态数据成员 staticMetaObject
的错误。
Qt 布局不更新的问题
修改 QWidget
在 QWidget 已经加入布局之后,修改其大小,布局不会自动更新。需要调用 QWidget::updateGeometry
方法。
类似的,修改子布局时需要调用
QLayout::updateGeometry
方法。
修改 QSpacerItem
在 QSpacerItem 已经加入布局之后,修改其大小,布局不会自动更新。需要调用 QLayout::invalidate
方法。
另外还可以调用 QWidget::adjustSize
方法调整大小.
Qt 日志模块
旧的方式:
#include <QDebug>
qDebug() << "hello world"
现在默认所有日志都不打印,因此这种方式看不到打印
QT_LOGGING_RULES="*.debug=false"
新的方式:
#include <QLoggingCategory>
QLoggingCategory category("my.module");
qCDebug(category) << "hello world";
需要配置打印哪些模块的日志
QT_LOGGING_RULES="*.debug=false;my.module.debug=true"
其中日志类型支持 debug
, info
, warning
, critical
四种类型
qDebug
等旧接口所属模块名为 default
, 因此如下配置可以使旧的方式打印可见:
QT_LOGGING_RULES="*.debug=false;default.debug=true"
QtQuick/QML 中 console.log
属于 qml
或 js
模块,因此使用如下配置可以使其打印可见:
QT_LOGGING_RULES="*.debug=false;qml.debug=true"
Qt 资源文件打开失败的问题
首先,Qt 的资源文件需要使用 Q_INIT_RESOURCE
宏进行初始化,参数为 qrc
文件的文件名,例如:
Q_INIT_RESOURCE(theme); // 初始化 theme.qrc
Q_INIT_RESOURCE(icon); // 初始化 icon.qrc
并且,这个宏必须在全局命名空间下调用,例如:
static inline void initResource()
{
Q_INIT_RESOURCE(theme); // 初始化 theme.qrc
Q_INIT_RESOURCE(icon); // 初始化 icon.qrc
}
namespace DemoNamespace
{
class DemoClass
{
public:
DemoClass()
{
initResource(); // 调用初始化函数
}
};
};
并且,可以使用 Q_CLEANUP_RESOURCE
宏来显式删除资源。
Q_INIT_RESOURCE
仅在将资源构建为静态库时是必须的,在构建动态库和应用程序中时可以省略。
但是我遇到的是另一个问题 —— Qt 的资源集合文件不能重名
在库中创建了名为 theme.qrc
的资源集合文件,之后在应用程序中再次创建一个名为 theme.qrc
的资源集合文件。库的 theme.qrc
会失效。
这个问题仅在 Linux 上存在,而在 Windows 上不存在。因此无法确定是 Feature 还是 Bug。
Ubuntu 上配置 QtQuick/QML 开发环境
安装以下包:
sudo apt install qtbase5-dev # Qt5 基础开发包
sudo apt install qtquickcontrols2-5-dev # QtQuick 基础开发包
sudo apt install qtdeclarative5-dev # Qt5 的 CMake 模块
sudo apt install qtcreator # Qt Creator
sudo apt install qttools5-dev # Qt5 工具,包含 Qt5Designer、Qt5LinguistTools 等
sudo apt install qmlscene # QML 预览工具
QML 导入失败时,表示没有安装对应的模块,deb 包名为 qml-module-*
。
例如 QtQuick.Dialogs
的 deb 包名为 qml-module-qtquick-dialogs
。
遇到的一些问题
最初安装的包:
sudo apt install qtbase5-dev
sudo apt install qtquickcontrols2-5-dev
sudo apt install qtcreator
执行 CMake 失败
Could not find a package configuration file provided by "Qt5Quick"
with any of the following names:
Qt5QuickConfig.cmake
qt5quick-config.cmake
原因: 没有安装 Qt 的 CMake 模块
解决: sudo apt install qtdeclarative5-dev
Could not find a package configuration file provided by "Qt5LinguistTools"
with any of the following names:
Qt5LinguistToolsConfig.cmake
qt5linguisttools-config.cmake
原因: 没有安装 Qt5 Linguist Tools 的 CMake 模块
解决: sudo apt install qttools5-dev
导入 QtQuick.Controls 2 失败
QQmlApplicationEngine failed to load component
qrc:/main.qml:2:1: plugin cannot be loaded for module "QtQuick.Controls": Cannot protect module QtQuick.Controls 2 as it was never registered
原因: 没有安装 QtQuick.Controls 2 的运行时环境
解决: sudo apt install qml-module-qtquick-controls2
导入 QtQuick.Dialogs 失败
module "QtQuick.Dialogs" is not installed
原因: 没有安装 QtQuick.Dialogs
解决: sudo apt install qml-module-qtquick-dialogs