QT

1.

  qt uml图

  qt自定义事件已经事件循环原理:参考   threaddata的原理

  qamke2cmake

  qt编译顺序:参考

  以前的Qt Doc(官方

  Qt的元对象系统的详解

  qt的属性

  qt6在线下载安装:参考     qt Automation下载安装

  dashboard

  qtcreator下载编译 

  build qt6

  CONFIG += qt 的作用

  qtbase 编译

  单元测试:参考

  完整的测试代码:

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
* Author: Alex
* mail: abnk@qq.com
* File Type: unix Name: test.cpp
* Created Time: 2021-07-23 10:15 33
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include <QtTest/QtTest>

// 参考: https://blog.51cto.com/u_9291927/2114179
// qmake -project "QT+=testlib
// qmake && make && ./qt_test

class TestQString: public QObject
{
    Q_OBJECT
private slots:
    void toUpper();
    void toUpper_data();
};

void TestQString::toUpper()
{
    // 原来没有测试数据的时候需要将测试数据一个一个的写到代码里面。
    // QString str = "Hello";
    // QVERIFY(str.toUpper() == "HELLO");
    // QCOMPARE(str.toUpper(), QString("HELLO"));

    QFETCH(QString, lowerString);
    QFETCH(QString, upperResult);

    // 添加的数据只需要被调用一次就被批量测试完了
    QCOMPARE(lowerString.toUpper(), upperResult);
}

// 为测试函数提供数据的函数必须与该测试函数同名,并加上_data后缀
void TestQString::toUpper_data()
{
    QTest::addColumn<QString>("lowerString");
    QTest::addColumn<QString>("upperResult");

    QTest::newRow("all lower") << "hello" << "HELLO";
    QTest::newRow("mixed")     << "Hello" << "HELLO";
    QTest::newRow("all upper") << "HELLO" << "HELLO";
}

QTEST_APPLESS_MAIN(TestQString);    // 同类名
#include "test.moc"                 // 文件名+.moc
test.cpp

  Qt官方 autotest   参考

2. QScopeGuard

  析构的时候会做一些事情。

template <typename F>
class [[nodiscard]] QScopeGuard
{
public:
    explicit QScopeGuard(F &&f) noexcept
        : m_func(std::move(f))
    {
    }

    explicit QScopeGuard(const F &f) noexcept
        : m_func(f)
    {
    }

    QScopeGuard(QScopeGuard &&other) noexcept
        : m_func(std::move(other.m_func))
        , m_invoke(qExchange(other.m_invoke, false))
    {
    }

    ~QScopeGuard() noexcept
    {
        if (m_invoke)
            m_func();
    }

    void dismiss() noexcept
    {
        m_invoke = false;
    }

private:
    Q_DISABLE_COPY(QScopeGuard)

    F m_func;
    bool m_invoke = true;
};

#ifdef __cpp_deduction_guides
template <typename F> QScopeGuard(F(&)()) -> QScopeGuard<F(*)()>;
#endif

//! [qScopeGuard]
template <typename F>
[[nodiscard]] QScopeGuard<typename std::decay<F>::type> qScopeGuard(F &&f)
{
    return QScopeGuard<typename std::decay<F>::type>(std::forward<F>(f));
}
View Code

3. run in main thread (use lambda)

/*!
  rewrite from:  https://zhuanlan.zhihu.com/p/364710810
*/
#include <QtCore/QCoreApplication>
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QDebug>
#include <QtCore/QQueue>
#include <functional>
#include <unistd.h>  // sleep

using Callback = std::function <void(QQueue <void *>)>;

class Worker : public QObject
{
    Q_OBJECT
public:
    Worker() {
        moveToThread(&m_thread);
        m_thread.start();
    }
public slots:
    void slotRunInSub() {                   // add callback
        // qDebug() << "run in sub thread slot:" << QThread::currentThreadId();
        if (m_workerCallback) {
            m_workerCallback(m_queue);
        }
        emit mSig();
    }
signals:
     void mSig();
private:
     QThread m_thread;
     QQueue <void *> m_queue;
     Callback m_workerCallback;
public:
    void setCallback(Callback &&func, void *arg) {
        m_queue.enqueue(arg);
        m_workerCallback = std::forward<Callback>(func);
    }
};

class Dummy : public QObject
{
    Q_OBJECT

public:
    Dummy(QObject* parent=0) : QObject(parent) {
        QObject::connect(this, SIGNAL(sig()), &worker, SLOT(slotRunInSub()));        // update
        QObject::connect(&worker, SIGNAL(mSig()), this, SLOT(slotRunInMain()));  // process
    }
    // template <>
    void PostToChild(Callback &&func, void *arg) {
        // m_queue.enqueue(arg);
        worker.setCallback(std::forward<Callback>(func), arg);
    }
    void PostToMain(Callback &&func, void *arg) {
        m_queue.enqueue(arg);
        m_callback = std::forward<Callback>(func);
        sigToSubThd();   // call slot, note sub thread process data
    }

public slots:
    void sigToSubThd() {
        emit sig();
    }
signals:
    void sig();

public slots:
    void slotRunInMain() {      // update
        qDebug() << "run in main: " << QThread::currentThreadId();
        if (m_callback) {
            m_callback(m_queue);
        }
    }

private:
    Worker worker;
    QQueue <void *> m_queue;
    Callback m_callback;
};

#include "main.moc"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug() << "main thread: " << QThread::currentThreadId();

    // QCoreApplication::instance()->thread();

    Dummy dummy;
    int data = 1111;

    dummy.PostToChild([](QQueue <void *> queue){            // in sub thread
        //        1. memcpy  data;
        //        2. process data;
        //        3. enqueue data;
        qDebug() << "run in sub thread slot:" << QThread::currentThreadId();
        sleep(5);
    }, (void *)&data);                               // set cb, copy data and enqueue.

    int enqueueData = 2222;
    dummy.PostToMain([](QQueue <void *> queue){         // in sub thread
        void *deData = queue.dequeue();
         qDebug() << "dequeue: " << *(int *)deData;     // dequeue data, and update???
         qDebug() << "run in main thread: " << QThread::currentThreadId();
    }, (void *)&enqueueData);

    qDebug() << "async exec";

    return a.exec();
}
View Code

  and then, add concurent,

  add ensure connect sub to main.

  add move to main thread

  add variable args function and declytype

  moveToThread has memory hosting relationship 

/*!
  rewrite from:  https://zhuanlan.zhihu.com/p/364710810
*/
#include <QtCore/QCoreApplication>
#include <QtWidgets/QApplication>
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QDebug>
#include <QtCore/QQueue>
#include <functional>
#include <unistd.h>  // sleep
#include <thread>

#include <QStyle>
#include <QTimer>
#include <QPushButton>
#include <QMainWindow>

using Callback = std::function <void(QQueue <void *>)>;

class Worker : public QObject
{
    Q_OBJECT
public:
    Worker() {
        moveToThread(&m_thread);
        m_thread.start();
    }
    ~Worker() {
        if (m_thread.isRunning()) {
            // m_thread.deleteLater();
            // m_thread.exit(0);
            m_thread.quit();
            m_thread.wait();
        }
    }
public slots:
    void slotRunInSub() {                   // add callback
        // qDebug() << "run in sub thread slot:" << QThread::currentThreadId();
        if (m_workerCallback) {
            m_workerCallback(m_queue);
        }
        emit mSig();
    }
signals:
     void mSig();
private:
     QThread m_thread;
     QQueue <void *> m_queue;
     Callback m_workerCallback;
public:
    void setCallback(Callback &&func, void *arg) {
        m_queue.enqueue(arg);
        m_workerCallback = std::forward<Callback>(func);
    }
};

class Dummy : public QObject
{
    Q_OBJECT
public:
    Dummy(QObject* parent=0) : QObject(parent) {
        // Guranentee connect main thread to child
        if (QCoreApplication::instance() && QCoreApplication::instance()->thread()) {
            moveToThread(QCoreApplication::instance()->thread());
            QObject::connect(this, SIGNAL(signalConnectInMainToChild()), this, SLOT(slotConnectInMainToChild()));
            // qDebug() << "Dummy is constructor in main: " << QThread::currentThreadId();
        }
        emit signalConnectInMainToChild();
    }
    ~Dummy() {
//        if (worker) {
//            worker->deleteLater();
//            worker = nullptr;
//        }
    }
    // template <>
    void PostToChild(Callback &&func, void *arg) {
        // m_queue.enqueue(arg);
        worker->setCallback(std::forward<Callback>(func), arg);
    }
    void PostToMain(Callback &&func, void *arg) {
        m_queue.enqueue(arg);
        m_callback = std::forward<Callback>(func);
        sigToSubThd();   // call slot, note sub thread process data
    }

public slots:
    void sigToSubThd() {
        emit sig();
    }

    void slotConnectInMainToChild() {
        worker = new Worker;
        qDebug() << "Dummy is connect in main: " << QThread::currentThreadId();
        QObject::connect(this, SIGNAL(sig()), worker, SLOT(slotRunInSub()));        // update
        QObject::connect(worker, SIGNAL(mSig()), this, SLOT(slotRunInMain()));  // process
    }

signals:
    void sig();
    void signalConnectInMainToChild();

public slots:
    void slotRunInMain() {      // update
        qDebug() << "run in main: " << QThread::currentThreadId();
        if (m_callback) {
            m_callback(m_queue);
        }
    }

private:
    Worker *worker;
    QQueue <void *> m_queue;
    Callback m_callback;
};

#include "main.moc"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    qDebug() << "main thread: " << QThread::currentThreadId();

    // QCoreApplication::instance()->thread();

    std::thread thd([]{
        Dummy dummy;
        // dummy.signalConnectInMainToChild();
        sleep(1);
        int data = 1111;

        dummy.PostToChild([](QQueue <void *> queue){            // in sub thread
            //        1. memcpy  data;
            //        2. process data;
            //        3. enqueue data;
            qDebug() << "run in sub thread slot:" << QThread::currentThreadId();
            // sleep(5);
        }, (void *)&data);                               // set cb, copy data and enqueue.

        int enqueueData = 2222;
        dummy.PostToMain([](QQueue <void *> queue){         // in sub thread
            void *deData = queue.dequeue();
            qDebug() << "dequeue: " << *(int *)deData;     // dequeue data, and update???
            qDebug() << "run in main thread: " << QThread::currentThreadId();
        }, (void *)&enqueueData);

        qDebug() << "async exec";

        sleep(6);
        // qApp->quit();
    });

    thd.detach();



    QMainWindow w;
    QWidget central;
    QPushButton button(&central);
    w.setCentralWidget(&central);

#if 1
    // analogue render event
    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, [&button]{
        static bool flag = false;
        QStyle *style = QApplication::style();
        QIcon openPicture = style->standardIcon(QStyle::SP_TitleBarMenuButton);
        QIcon inforIron = style->standardIcon(QStyle::SP_DialogYesButton);
        button.setIcon(flag ? openPicture : inforIron);
        flag = !flag;
    });
    timer.setInterval(200);
    timer.start();
#endif

#if 0
    // single event ocupaid block
    QObject o;
    QTimer::singleShot(100, &o, [&button]{
        // while(1)
        {
            sleep(1);
            qDebug() << QThread::currentThreadId();

            static bool flag = false;
            QStyle* style = QApplication::style();
            QIcon openPicture = style->standardIcon(QStyle::SP_TitleBarMenuButton);
            QIcon inforIron = style->standardIcon(QStyle::SP_MediaSkipBackward);
            button.setIcon(flag ? openPicture : inforIron);
            flag = !flag;
        }
    });
#endif


    w.show();

    qDebug() << "enter exec";
    return a.exec();
}
View Code

4. QRunnable

  参考

4. 国际化

  参考

5. 一些布局的技巧:

 

    QHBoxLayout *hLayoutAppRm = new QHBoxLayout;
    mainLayout->addLayout(hLayoutAppRm);
    QLabel *iconLabel = new QLabel();
    iconLabel->setFrameShape(QFrame::Box);
    DLabel *appNameLabel = new DLabel(m_model->getAppName());
    appNameLabel->setFrameShape(QFrame::Box);
    appNameLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    DPushButton *appRmButton = new DPushButton("Uninstall");

    DFontSizeManager::instance()->bind(appNameLabel, DFontSizeManager::T5, QFont::DemiBold);
    iconLabel->setPixmap(getAppIcon(m_model->getIcon(), QSize(48, 48)));


    hLayoutAppRm->addWidget(iconLabel,0);
    hLayoutAppRm->setSpacing(0);
    hLayoutAppRm->addWidget(appNameLabel, 1);
    hLayoutAppRm->addWidget(appRmButton, 0);
View Code

6. 关于 QObject 宏

  

QDbus:

  参考   参考   参考

  Dtk里面的应用:

#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <DListView>
#include <QtDBus>

#include <QObject>
#include <DApplication>
#include <DDBusSender>
#include <QDBusPendingCallWatcher>

DWIDGET_USE_NAMESPACE

// #include "main.moc"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    auto async = DDBusSender()
    .service("com.deepin.dde.ControlCenter")
    .interface("com.deepin.dde.ControlCenter")
    .path("/com/deepin/dde/ControlCenter")
    .method("Toggle")
    .call();

    // QDBusPendingCall async = interface.asyncCall("setName", "Brion");

    // 等待结束,async.waitForFinished ()
    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, nullptr);

    QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [](QDBusPendingCallWatcher *call)
    {
        QDBusPendingReply<QString> reply = *call;
        if (!reply.isError()) {
            QString name= reply.argumentAt<0>();
            qDebug()<<"QDBusPendingReply name = "<<name;
        }
        call->deleteLater();
    });

    return app.exec();
}
View Code

  示例:注册一个服务,分别调用set、get方法:

#include <QApplication>
#include <QDebug>
#include <DListView>
#include <QtDBus>

#include <QObject>
#include <DApplication>
#include <DDBusSender>
#include <QDBusPendingCallWatcher>

DWIDGET_USE_NAMESPACE

void testFunc1() {
    if (!QDBusConnection::connectToBus(QDBusConnection::SessionBus,QString("c2box")).isConnected()) {
        fprintf(stderr, "Cannot connect to the D-Bus session bus.\n"
                        "To start it, run:\n"
                        "\teval `dbus-launch --auto-syntax`\n");
        return;
    }

    if (!QDBusConnection::connectToBus(QDBusConnection::SessionBus,QString("c2box")).registerService("com.alex.one")) {
        fprintf(stderr, "%s\n", qPrintable(QDBusConnection::connectToBus(QDBusConnection::SessionBus,QString("c2box")).lastError().message()));
        exit(1);
    }

    // PlayerSetting* playerSetting = this;
    // 把playerSetting 作为interface,即把playerSetting对象中的
    QDBusConnection::connectToBus(QDBusConnection::SessionBus,QString("c2box")).registerObject("alex.one.test", nullptr, QDBusConnection::ExportAllSlots);

    // http://seen.blog.chinaunix.net/uid-23023613-id-219100.html
}



class test: public QObject
{
    Q_OBJECT
    //定义Interface名称为com.scorpio.test.value
    // Q_CLASSINFO("D-Bus Interface", "com.scorpio.test.value")
    Q_CLASSINFO("D-Bus Interface", "com.alex.daemon.Grub2.EditAuth")
public:
    // test(int value)
    test() {
         EditShellAuthUsers << "alex" << "one";
    }

public slots:
    QString SetGrubEditShellAuth(const QString & user, const QString & passwd) {
        // EditShellAuthUsers << user.toString() << passwd.toString();
        EditShellAuthUsers << user << passwd;
        return QDBusError(QDBusError::NoError, "").errorString(QDBusError::NoError);
    }

    QStringList GetGrubEditShellAuth() {
        return EditShellAuthUsers;
    }

    QDBusError DisableGrubEditShellAuth(const QString &user) {
        return QDBusError(QDBusError::NoError, "");
    }

private:
    // int m_value;
    QStringList EditShellAuthUsers;

private:
    std::shared_ptr<DDBusData> m_dbusData;
};

void testFunc2() {
    // 建立到session bus的连接
    QDBusConnection connection = QDBusConnection::sessionBus();

    // 在 session bus 上注册名为 com.scorpio.test 的服务
    if (!connection.registerService("com.alex.daemon.Grub2")) {
        qInfo() << "error:" << connection.lastError().message();
        exit(-1);
    }
    test t;

    // 注册名为 /test/objects 的对象,把类 Object 所有槽函数导出为 object 的 method
    connection.registerObject("/test/objects", &t, QDBusConnection::ExportAllSlots);

    qApp->exec();
}


void testFunc3() {
#if 1
    //构造一个method_call消息,服务名称为:com.scorpio.test,对象路径为:/test/objects
    //接口名称为com.scorpio.test.value,method名称为value
    QDBusMessage message = QDBusMessage::createMethodCall("com.alex.daemon.Grub2",
                           "/test/objects",
                           "com.alex.daemon.Grub2.EditAuth",
                           "SetGrubEditShellAuth");

    // message.setArguments({QVariant(QString("alex")), QVariant(QString("one"))});
    message.setArguments({QString("alex"), QString("one")});

    //发送消息
    QDBusMessage response = QDBusConnection::sessionBus().call(message);

    if (! response.errorMessage().isEmpty()) {
        qInfo() << response.errorMessage();
    }
#endif

    // qApp->exec();
//}
//void testFunc4() {


    //构造一个method_call消息,服务名称为:com.scorpio.test,对象路径为:/test/objects
    //接口名称为com.scorpio.test.value,method名称为value
    QDBusMessage message2 = QDBusMessage::createMethodCall("com.alex.daemon.Grub2",
                           "/test/objects",
                           "com.alex.daemon.Grub2.EditAuth",
                           "GetGrubEditShellAuth");

    //发送消息
    QDBusMessage response2 = QDBusConnection::sessionBus().call(message2);
    //判断method是否被正确返回
    if (response2.type() == QDBusMessage::ReplyMessage) {
        //从返回参数获取返回值
        qInfo() << response2.arguments().takeFirst().toList();
        // int value = response.arguments().takeFirst().toInt();
        // qInfo() << QString("value =  %1").arg(value);
    } else {
        // qInfo() << "method called failed!";
        qInfo() << response2.errorMessage();
    }

    qApp->exec();
}

#include "main.moc"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

#if 1
    //! 1. 注册一个服务
    // 建立到session bus的连接
    QDBusConnection connection = QDBusConnection::sessionBus();

    // 在 session bus 上注册名为 com.scorpio.test 的服务
    if (!connection.registerService("com.alex.daemon.Grub2")) {
        qInfo() << "error:" << connection.lastError().message();
        exit(-1);
    }

    test t;
    // 注册名为 /test/objects 的对象,把类 Object 所有槽函数导出为 object 的 method
    connection.registerObject("/test/objects", &t, QDBusConnection::ExportAllSlots);

    //    testFunc1();
    //    testFunc2();
#endif
    //! 1. 分别调用 set 和 get 方法
    testFunc3();
//    testFunc4();
    return app.exec();
}
View Code

打印预览模糊的解决方案:

  高分屏下 pixmap 要设置devicePixRatio

#if 0
    // 模糊
    QPainter painter(_printer);
    QImage image ("/home/alex/Pictures/Wallpapers/144883671.jpg");
    image = image.scaled(_printer->pageRect().size(), Qt::AspectRatioMode::KeepAspectRatio, Qt::SmoothTransformation);
    painter.drawImage(0, 0, image);
#else
    // 不模糊
    QImage test_image("/home/alex/Pictures/Wallpapers/144883671.jpg");

    // 直接传递原始数据 但绘制进缩放后的rect中
    const QRect &page_rect = _printer->pageRect();
    QSize target_size = test_image.size();
    QRect target_rect;

    target_size.scale(qMin(test_image.width(), page_rect.width()), qMin(test_image.height(), test_image.height()), Qt::KeepAspectRatio);
    target_rect.setSize(target_size);
    target_rect.moveCenter(page_rect.center());

    QPainter painter(_printer);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    painter.drawImage(target_rect, test_image);
#endif
View Code

QPaintDevice:

  参考

QSurface 

  参考

 qt拖放

  参考

qt winid

ShellSurface *ShellSurface::fromQtWinId(WId wid)
{
    QWindow *window = nullptr;

    for (auto win : qApp->allWindows()) {
        if (win->winId() == wid) {
            window = win;
            break;
        }
    }

    if (!window) {
        return nullptr;
    }
    return fromWindow(window);
}

qApp

void DSplitScreenWidget::disabledByScreenGeometryAndWindowSize(QWidgetList wList)
{
    QDesktopWidget *desktop = qApp->desktop();
    QWidget *window = this->window();

    if (Q_LIKELY(desktop) && Q_LIKELY(window)) {
        QRect screenRect = desktop->screenGeometry(window);

        // 窗口尺寸大于屏幕分辨率时 禁用控件
        if (screenRect.width() < window->minimumWidth() || screenRect.height() < window->minimumHeight())
            for (QWidget *w : wList)
                w->setDisabled(true);
    }
}

qt 日志系统

  参考

qt 状态机:

  参考    参考    参考(快速上手)    知乎参考
qt的md5、toHex等操作:

  参考

qt的一些基础组件:

  参考

qt的广播、组播、单播:参考    參考

linux上的ipc机制深度详解

qdbus:

  参考    系列文章    详细的用法总结的很好    遍历对象熟   

  参考(org.freedesktop.DBus.Introspectable.Introspect)

  防火墙,使用Dbus命令

命令行参数的用法:

  参考

窗口坐标转换:

  参考   模拟鼠标点击事件

绘制背景色:

  自绘参考    参考

void SettingLabel::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setPen(Qt::NoPen);
    if (DApplicationHelper::instance()->themeType() == DApplicationHelper::LightType) {
        painter.setBrush(QColor(0, 0, 0, 0.03 * 255));
    } else {
        painter.setBrush(QColor(255, 255, 255, 0.03 * 255));
    }
    if (underMouse()) {
        painter.setBrush(Qt::red);
    }
    painter.drawRoundedRect(rect(), 0, 0);

    return QWidget::paintEvent(event);
}
View Code

   dock网络连接绘制hover:

--- a/plugins/bluetooth/componments/bluetoothapplet.cpp
+++ b/plugins/bluetooth/componments/bluetoothapplet.cpp
@@ -107,6 +107,9 @@ void SettingLabel::paintEvent(QPaintEvent *event)
     } else {
         painter.setBrush(QColor(255, 255, 255, 0.03 * 255));
     }
+    if (underMouse()) {
+        painter.setBrush(Qt::red);
+    }
     painter.drawRoundedRect(rect(), 0, 0);
 
     return QWidget::paintEvent(event);
View Code

QMetaObjectBuilder

  参考

QEventDispatcher:

  参考 

  参考

  参考

  为QThread安装event dipatcher:参考

定时器的设计

  参考

运行lambda在任意线程中的讨论:

  参考

event_fd 与 qt 的事件机制:

  参考(epoll 中weakUp用法的精妙之处)

combobox的绘制:

  主要由这些地方控制:

  ChameleonStyle::drawComboBoxLabel

  SC_ComboBoxListBoxPopup

  ChameleonStyle::drawMenuItem

  弹出窗口其实就是个菜单

qeventdispathcer:

  参考patch

  参考

  poll和epoll源码剖析 

  查看所有 fd 包括定时器的:

ls -l /proc/`pidof epoll_dispatcher`/fd/

定时器:

  参考

响应主题的变化:

void GraphicsView::changeEvent(QEvent *e)
themeTypeChanged
GraphicsView::onThemeTypeChanged

hook的用法:

+//    HookOverride(&QtWaylandClient::QWaylandScreen::physicalSize, [](QtWaylandClient::QWaylandScreen *s){
+//        QSizeF physicalSize = HookCall(s, &QtWaylandClient::QWaylandScreen::physicalSize);
+//        qInfo() << "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx physicalSize: " << physicalSize;
+//        return physicalSize;
+//    });
View Code

窗口阴影:

dtk已提供圆角的DArrowRectangle,参照如下 demo 设置进行。

设置为setArrowWidth(40), setArrowHeight(26); 细节与 徐冰倩 沟通

指定为 DArrowRectangle::FloatWindow 则没有窗口阴影效果,DArrowRectangle::FloatWiddget 有窗口阴影效果但是没有模糊效果。这是底层窗口的类型差异导致的。

有窗口阴影效果的时候在非特效模式下会有黑框需要特别注意。

代码改动地方较多,会涉及到网络模块的插件、拖动时的 tooltip 等,建议应用自己修改。


int main(int argc, char **argv) {
    QApplication app(argc, argv);
    DArrowRectangle *pRectangle_2 = new DArrowRectangle(DArrowRectangle::ArrowBottom, DArrowRectangle::FloatWindow);
    pRectangle_2->setAttribute(Qt::WA_DeleteOnClose);
    pRectangle_2->setWindowFlag(Qt::ToolTip);
    pRectangle_2->setMargin(10);
    pRectangle_2->setShadowXOffset(0);
    pRectangle_2->setShadowYOffset(6);
    pRectangle_2->setShadowBlurRadius(20);
    pRectangle_2->setRadius(18);

    // 设置尖角宽高
    pRectangle_2->setArrowWidth(50);
    pRectangle_2->setArrowHeight(30);               
    pRectangle_2->setRadiusArrowStyleEnable(true);                                      // 改尖角为圆角
    pRectangle_2->setBorderColor(QColor(0, 0, 0, qRound(0.05 * 255)));     // 设置阴影颜色
    pRectangle_2->setRadiusArrowStyleEnable(true);
    pRectangle_2->setWindowFlags(Qt::X11BypassWindowManagerHint);   // 禁止移动
    // pRectangle_2->setAttribute(Qt::WA_TranslucentBackground);               
    QLabel *pContentWidget_2 = new QLabel("深度音乐");
    pContentWidget_2->setAlignment(Qt::AlignCenter);
    pContentWidget_2->setFixedSize(90, 40);
    pRectangle_2->setContent(pContentWidget_2);
    pRectangle_2->show(100, 100);

    return app.exec();

}
View Code

 

 

 

 

 

 

  

 

 

 

 

 

 

posted @ 2021-07-23 10:12  AlexOne  阅读(260)  评论(0编辑  收藏  举报