Qt 笔记

好记性不如烂笔头,记录一些Qt学习过程中的笔记。


1 遍历所有session dbus的服务名和接口名的参考方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void testDbusInterface()
{
if (!QDBusConnection::sessionBus().isConnected()) {
fprintf(stderr, "Cannot connect to the D-Bus session bus.\n"
"To start it, run:\n"
"\teval `dbus-launch --auto-syntax`\n");
return 1;
}

QDBusReply<QStringList> reply = QDBusConnection::sessionBus().interface()->registeredServiceNames();
if (!reply.isValid()) {
qDebug() << "Error:" << reply.error().message();
exit(1);
}

foreach (QString name, reply.value())
qDebug() << name;

QDBusConnection bus = QDBusConnection::sessionBus();
QDBusInterface dbus_iface("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", bus);
qDebug() << dbus_iface.call("ListNames").arguments().at(0);

qDebug() << QDBusConnection::sessionBus().interface()->registeredServiceNames().value();
}

2 解决Qt视频闪烁或黑屏白屏问题

Qt调用第三方库渲染视频造成闪烁或者白屏黑屏,使用Qt嵌入SDL2或XCB或OPenGL(XCB使用dri3渲染引擎)窗口进行视频渲染时(即把Qt的窗口句柄传给SDL2/XCB/opengl,在Qt的QWidget上显示视频),当视频流没有刷新时,此时拖动Qt窗口主界面,则视频显示区域变为黑板或者白板,而当有视频流刷新时,则视频显示区域恢复正常,出现这种情况的原因是Qt自身的渲染引擎和第三方库渲染发生冲突造成的。为了解决该问题,只要屏蔽掉Qt自身渲染引擎即可解决问题,即在QWidget::winId()被传给SDL2或XCB或opengl的那个继承QWidget的自定义类中进行处理,重写要被第三方库渲染的控件,在其构造函数中添加setAttribute(Qt::WA_PaintOnScreen,true),并重新实现父类的虚函数QPaintEngine *paintEngine() const,具体做法见下面的代码。

  1. 重写自己要被第三方库渲染的控件,在其构造函数中添加如下代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    Widget::Widget(QWidget *parent) :
    QWidget(parent)
    {
    this->setFixedSize(580, 800);

    XcbWidget *m_xcbWidget = new XcbWidget(this);
    m_xcbWidget->setFixedSize(480, 800);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->setSpacing(10);
    mainLayout->setMargin(0);
    mainLayout->addWidget(m_xcbWidget);
    this->setLayout(mainLayout);
    }

    int Widget::initXcbDri3()
    {
    xcb_window_t win;
    xcb_connection_t *c;

    int ret;
    int drm_fd;

    c = QX11Info::connection();

    win = (uintptr_t)m_xcbWidget->winId();
    printf("win Id:%d\n", win);

    //init and get drm fd from xcb-dri3
    drm_fd = xcb_dri3_helper_open(c, win);
    if (drm_fd < 0) {
    fprintf(stderr, "ERROR: DRI3 failed to initialize");
    goto fail;
    }

    ret = xcb_dri3_helper_drawable_init(c, win, &draw, drm_fd);
    if (ret) {
    returun 1;
    }

    return 0;
    }

    XcbWidget::XcbWidget(QWidget *parent)
    : QWidget(parent)

    {
    setFixedSize(480, 800);
    setAttribute(Qt::WA_PaintOnScreen, true);//重写要被第三方库渲染的控件,在其构造函数中添加setAttribute(Qt::WA_PaintOnScreen, true)
    }
  2. 重新实现父类虚函数 QPaintEngine *paintEngine() const,这里需要配合setAttribute(Qt::WA_PaintOnScreen, true)进行使用,避免Qt的渲染引擎和dri3的渲染引擎冲突而导致无视频刷新时拖动界面时出现的白板或黑板现象

    1
    2
    3
    4
    QPaintEngine *XcbWidget::paintEngine() const
    {
    return 0;
    }

3 解决Qt中signals和gio/gst中signals冲突的问题

在Qt工程中,一个类中用到gio或gst的函数,且在引入gio或gst的头文件后,编译时会遇到类似如下的报错:error: expected unqualified-id before ‘public’ GDBusSignalInfo **signals;。遇到这种情况,有几种办法可以解决。

  1. 所有glib的头文件引入放在Qt的头文件引入之前
  2. pro文件中加入:CONFIG += no_keywords, 并在代码中使用Q_SIGNALS替换signals
  3. #undef signals …… #define signals public

原因分析:结构体_GDBusInterfaceInfo中的signals与Qt中的信号signals关键词冲突了。

1
2
3
4
5
6
7
8
9
10
struct _GDBusInterfaceInfo
{
/*< public >*/
volatile gint ref_count;
gchar *name;
GDBusMethodInfo **methods;
GDBusSignalInfo **signals;
GDBusPropertyInfo **properties;
GDBusAnnotationInfo **annotations;
};

下面代码段演示了第三种的使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
utils.h

#include <QObject>
class Utils : public QObject
{
Q_OBJECT

public:
explicit Utils(QObject *parent = 0);
~Utils();

};


utils.cpp
#include "utils.h"

#undef signals
extern "C" {
#include <gio/gio.h>
#include <gio/gunixmounts.h>
#include <gio/gdesktopappinfo.h>
#include <gio/gappinfo.h>
}
#define signals public

Utils::Utils(QObject *parent) :
QObject(parent)
{

}

Utils::~Utils()
{

}

4 Qt qDebug打印信息处理

在调试Qt程序时,经常需要qDebug打印信息,尽快定位bug,在发布Qt程序时,去掉debug打印,可以加快程序执行速度,减小程序体积。这时候我们如果手动注释qDebug就太麻烦了,可以使用宏来解决该问题,如下所示:
在pro文件里加上一行预定义宏即可。

1
2
DEFINES += QT_NO_DEBUG_OUTPUT \
QT_NO_WARNING_OUTPUT

代码中的使用方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef QT_DEBUG
return 1;
#else
return 0;
#endif

#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug deg, const MyInfo &info)
{
QDebugStateSaver saver(deg);
Q_UNUSED(saver)

deg.space() << "name:" << info.name();
deg << "Address:" << info.addressList();

return deg;
}
#endif

5 Qt Dbus解析 Dict of {String, Dict of {String, Variant}}类型的数据

参考代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
QDBusInterface m_interface("org.freedesktop.NetworkManager",
"/org/freedesktop/NetworkManager/Settings",
"org.freedesktop.NetworkManager.Settings",
QDBusConnection::systemBus() );
QDBusReply<QList<QDBusObjectPath>> m_reply = m_interface.call("ListConnections");
QList<QDBusObjectPath> m_objNets = m_reply.value();
foreach (QDBusObjectPath objNet, m_objNets){
qDebug()<<"Setting path: "<<objNet.path(); //列出每一个网络设置的对象路径
QDBusInterface m_interface("org.freedesktop.NetworkManager",
objNet.path(),
"org.freedesktop.NetworkManager.Settings.Connection",
QDBusConnection::systemBus());
QDBusMessage reply = m_interface.call("GetSettings");
const QDBusArgument &dbusArg = reply.arguments().at( 0 ).value<QDBusArgument>();
//DBus type : a{sa{sv}}, a map with a key of QString, which maps to another map of QString,QVariant
QMap<QString,QMap<QString,QVariant>> map;
dbusArg >> map;
//qDebug() << "Map is: " << map;
for(QString key : map.keys() ){
QMap<QString,QVariant> innerMap = map.value(key);
qDebug() << "Key: " << key;
if (key == "ipv4") {
for (QString inner_key : innerMap.keys()){
qDebug() << " " << inner_key << ":" << innerMap.value(inner_key);
}
}
}
}

李翔 wechat
微信交流
谢谢支持
0%