<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[源赖朝的部落格威力缩小版]]></title><description><![CDATA[兄友弟恭源赖朝]]></description><link>https://www.leiex.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1753373399436/15d90590-4450-4415-aa67-c0e3e61ce5b8.png</url><title>源赖朝的部落格威力缩小版</title><link>https://www.leiex.com</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 10:07:32 GMT</lastBuildDate><atom:link href="https://www.leiex.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Glad使用总结]]></title><description><![CDATA[和传统的GLEW不同，GLAD类似springboot starter，是一个开源的按需生成OpenGL函数Loader的WEB服务，GLAD2的官方地址为https://gen.glad.sh/，GLAD1的生成地址是https://glad.dav1d.de/，二者的API差异很大，本文以GLAD2的使用为例
使用WEB服务生成代码：
进入GLAD2的WEB页面后，可按Generator（编程语言），OpenGL各API版本，如OpenGL, OpenGL ES, GLX，WGL等，选了AP...]]></description><link>https://www.leiex.com/glad-usage</link><guid isPermaLink="true">https://www.leiex.com/glad-usage</guid><category><![CDATA[glad]]></category><category><![CDATA[openGL]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Sat, 19 Jul 2025 16:29:18 GMT</pubDate><content:encoded><![CDATA[<p>和传统的GLEW不同，GLAD类似springboot starter，是一个开源的按需生成OpenGL函数Loader的WEB服务，GLAD2的官方地址为<a target="_blank" href="https://gen.glad.sh/">https://gen.glad.sh/</a>，GLAD1的生成地址是<a target="_blank" href="https://glad.dav1d.de/">https://glad.dav1d.de/</a>，二者的API差异很大，本文以GLAD2的使用为例</p>
<p>使用WEB服务生成代码：</p>
<p>进入GLAD2的WEB页面后，可按Generator（编程语言），OpenGL各API版本，如OpenGL, OpenGL ES, GLX，WGL等，选了API版本后，Extensions可按需选择，或使用ADD ALL一键加入所有扩展（推荐）</p>
<p>Options中有几个重要选项：</p>
<p>alias - 默认情况下，glad的OpenGL函数带glad_前缀，例如glEnable，需使用glad_glEnable，选中这个选项后，可直接使用glEnable，不需要带前缀</p>
<p>loader - 生成gladLoadXXX()这种不带参数的loader，如果不选，则需使用自己传入如glfwgetprocaddress这样的load function的版本，尤其是WGL，有大坑，这个选项非常推荐选上</p>
<p>点击generate后，会进入一个页面，包含include，src和glad.zip（下载后加入到项目中的代码），官方推荐的使用方式是将其中的*.h，*.c文件直接加入到自己项目中的源代码中，比如在add_execution/add_library时，如果需要编译成so/dll这样的动态链接库，需有以下几点要注意：</p>
<p>编译成动态链接库时，glad需定义GLAD_API_CALL_EXPORT_BUILD，否则不会导出函数，可使用target_add_definitions在CMakeLists.txt加入</p>
<p>使用glad动态链接库的程序，需定义GLAD_API_CALL_EXPORT，否则会链接失败，另外#include &lt;glad/gl.h&gt;需放在所有其它有#include &lt;gl.h&gt;之类包含了OpenGL的头文件之前的位置，否则会编译失败</p>
<p>动态链接时，程序中所有模块只需调用一次loader即可初始化OpenGL函数地址，可通过判断glad_glEnable函数指针是否为nullptr来判断是否需调用loader，WGL可通过判断相应的glad_wglXXX是否为nullptr来按需调用loader</p>
]]></content:encoded></item><item><title><![CDATA[解决QWidget用winId获取HWND而导致Qt程序无事件消息的问题]]></title><description><![CDATA[问题原因：
当对一个QWidget调用winId时，默认情况下，Qt会对该窗口进行Native化，从而导致如鼠标等事件被其它原生窗口接管，表现出来的现像就是窗口不响应任何事件
解决思路：
防止Qt窗口Native化
解决办法：
第一步，在创建QApplication对象之前设置：
QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
//注意：Qt::AA_NativeWindows受环境变量 QT_USE_NATI...]]></description><link>https://www.leiex.com/qwidget-winid-hwnd-qt-no-event</link><guid isPermaLink="true">https://www.leiex.com/qwidget-winid-hwnd-qt-no-event</guid><category><![CDATA[Qt]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Mon, 07 Jul 2025 15:14:51 GMT</pubDate><content:encoded><![CDATA[<p>问题原因：</p>
<p>当对一个QWidget调用winId时，默认情况下，Qt会对该窗口进行Native化，从而导致如鼠标等事件被其它原生窗口接管，表现出来的现像就是窗口不响应任何事件</p>
<p>解决思路：</p>
<p>防止Qt窗口Native化</p>
<p>解决办法：</p>
<p>第一步，在创建QApplication对象之前设置：</p>
<pre><code class="lang-cpp">QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
<span class="hljs-comment">//注意：Qt::AA_NativeWindows受环境变量 QT_USE_NATIVE_WINDOWS控制，</span>
<span class="hljs-comment">//有可能环境变量被别的软件修改，所以也需要设置下</span>
QApplication::setAttribute(Qt::AA_NativeWindows,<span class="hljs-literal">false</span>);
</code></pre>
<p>第二步，在调用winId之前对该QWidget设置：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">this</span>-&gt;setAttribute(Qt::WA_DontCreateNativeAncestors);
</code></pre>
]]></content:encoded></item><item><title><![CDATA[解决因OpenGL渲染窗口高宽比导致图形变形]]></title><description><![CDATA[在 OpenGL 中，由于窗口的 宽高比（aspect ratio） 与绘制内容的坐标系统不一致，图像会出现拉伸、压缩等变形现象。为了解决这个问题，可根据窗口的大小调整投影矩阵，确保图像在视觉上保持原始比例。
先通过glViewPort调整视口
void resizeGL(int w, int h) {
    glViewport(0, 0, w, h);
}

再根据窗口高宽比，计算出合适的投影矩阵，这样体现出来的样式，就是截掉了宽高比之外的内容，显示的内容不变形，正圆就是正圆，不会被拉伸成...]]></description><link>https://www.leiex.com/opengl-window-size-aspect-ratio-problem</link><guid isPermaLink="true">https://www.leiex.com/opengl-window-size-aspect-ratio-problem</guid><category><![CDATA[openGL]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Wed, 18 Jun 2025 15:07:51 GMT</pubDate><content:encoded><![CDATA[<p>在 OpenGL 中，由于窗口的 <strong>宽高比（aspect ratio）</strong> 与绘制内容的坐标系统不一致，图像会出现拉伸、压缩等变形现象。为了解决这个问题，可根据窗口的大小调整投影矩阵，确保图像在视觉上保持原始比例。</p>
<p>先通过glViewPort调整视口</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">resizeGL</span><span class="hljs-params">(<span class="hljs-keyword">int</span> w, <span class="hljs-keyword">int</span> h)</span> </span>{
    glViewport(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, w, h);
}
</code></pre>
<p>再根据窗口高宽比，计算出合适的投影矩阵，这样体现出来的样式，就是截掉了宽高比之外的内容，显示的内容不变形，正圆就是正圆，不会被拉伸成椭圆</p>
<pre><code class="lang-c"><span class="hljs-keyword">float</span> aspect=(<span class="hljs-keyword">float</span>)w/h;
glm::mat4 projection;
<span class="hljs-keyword">if</span>(aspect&gt;=<span class="hljs-number">1.0f</span>){
    projection = glm::ortho(-aspect, aspect, <span class="hljs-number">-1.0f</span>, <span class="hljs-number">1.0f</span>, <span class="hljs-number">-0.1f</span>, <span class="hljs-number">1.0f</span>);
}<span class="hljs-keyword">else</span>{
    projection = glm::ortho(<span class="hljs-number">-1.0f</span>, <span class="hljs-number">1.0f</span>, <span class="hljs-number">-1.0f</span>/aspect, <span class="hljs-number">1.0f</span>/aspect, <span class="hljs-number">-0.1f</span>, <span class="hljs-number">1.0f</span>);
}
</code></pre>
<p>顶点着色器就按标准方式乘以对应的矩阵</p>
<pre><code class="lang-c"><span class="hljs-meta">#version 330 core</span>
layout (location = <span class="hljs-number">0</span>) in vec3 aPos;
...
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-comment">// 注意乘法要从右向左读</span>
    gl_Position = projection * view * model * vec4(aPos, <span class="hljs-number">1.0</span>);
    ...
}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[现代cmake使用技巧]]></title><description><![CDATA[不要再用nmake/make了，直接使用—build/—install吧，也不需要特意定义CMAKE_BUILD_TYPE，非常方便
#编译
cmake --build . --config Debug/Release
#安装，将安装到CMAKE_INSTALL_PREFIX下，默认是安装Release配置
cmake --install . --config Debug/Release

环境变量，设定好后就是全局可用，不会因为add_subdirectory而变化，在多级的子项目时尤其好用：...]]></description><link>https://www.leiex.com/morden-cmake-tips</link><guid isPermaLink="true">https://www.leiex.com/morden-cmake-tips</guid><category><![CDATA[CMake]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Thu, 05 Jun 2025 15:23:31 GMT</pubDate><content:encoded><![CDATA[<p>不要再用nmake/make了，直接使用—build/—install吧，也不需要特意定义CMAKE_BUILD_TYPE，非常方便</p>
<pre><code class="lang-bash"><span class="hljs-comment">#编译</span>
cmake --build . --config Debug/Release
<span class="hljs-comment">#安装，将安装到CMAKE_INSTALL_PREFIX下，默认是安装Release配置</span>
cmake --install . --config Debug/Release
</code></pre>
<p>环境变量，设定好后就是全局可用，不会因为add_subdirectory而变化，在多级的子项目时尤其好用：</p>
<pre><code class="lang-bash"><span class="hljs-built_in">set</span>(ENV{PROJ_BASE_DIR} <span class="hljs-variable">${CMAKE_CURRENT_SOURCE_DIR}</span>)
</code></pre>
<p>带缓存的PATH变量，可让Visual Studio/CMake GUI等工具有一个可选择文件夹路径的变量，并保存在缓存中，非常方便编辑：</p>
<pre><code class="lang-bash"><span class="hljs-built_in">set</span>(OPENCV_DIR <span class="hljs-variable">$ENV</span>{OPENCV_ROOT} CACHE PATH <span class="hljs-string">"Root path of opencv"</span>)
    <span class="hljs-keyword">if</span>(DEFINED OPENCV_DIR)
        list(APPEND CMAKE_PREFIX_PATH <span class="hljs-variable">${OPENCV_DIR}</span>)
    endif()
</code></pre>
<p>设置exe/dll/pdb文件输出路径：</p>
<pre><code class="lang-bash"><span class="hljs-built_in">set</span>(CMAKE_RUNTIME_OUTPUT_DIRECTORY <span class="hljs-variable">$ENV</span>{PROJ_OUTPUT_DIR}/out)
<span class="hljs-built_in">set</span>(CMAKE_LIBRARY_OUTPUT_DIRECTORY <span class="hljs-variable">$ENV</span>{PROJ_OUTPUT_DIR}/out)
<span class="hljs-built_in">set</span>(CMAKE_PDB_OUTPUT_DIRECTORY <span class="hljs-variable">$ENV</span>{PROJ_OUTPUT_DIR}/pdbs)
</code></pre>
<p>使用file命令的GLOB_RECURSE，子目录下的源文件也能一并扫描出来：</p>
<pre><code class="lang-bash">file(GLOB_RECURSE SRC_CPP <span class="hljs-variable">${PROJECT_SOURCE_DIR}</span> *cpp)
</code></pre>
<p>使用target_compile_definitions给代码定义#define，子项目的DLL和EXE区别对待，其中，PRIVATE只应用于编译本项目时有效，PUBLIC应用于全局（所有子项目共享）：</p>
<pre><code class="lang-bash"><span class="hljs-comment">#For DLL</span>
target_compile_definitions(foo PRIVATE API_EXPORT_BUILD)
<span class="hljs-comment">#For EXE</span>
target_compile_definitions(bar PRIVATE API_EXPORT)
</code></pre>
]]></content:encoded></item><item><title><![CDATA[cmake管理使用了qt的项目的正确使用方法]]></title><description><![CDATA[可将QT5_DIR（包括了bin/inclue/lib等目录的那个基础目录，不是lib/cmake）加到CMAKE_PREFIX_PATH中，防止find_package无法使用
cmake对qt moc有如下几个函数封装：
qt_wrap_ui([输出]MOC后的源文件列表 [输入]MOC前的.ui文件)
qt_wrap_cpp([输出]MOC后的源文件列表 [输入]MOC前的源文件，通常是包含了Q_OBJECT的.hpp)
qt_add_resources([输出]MOC后的源文件列表 [输...]]></description><link>https://www.leiex.com/cmake-with-qt</link><guid isPermaLink="true">https://www.leiex.com/cmake-with-qt</guid><category><![CDATA[CMake]]></category><category><![CDATA[Qt]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Mon, 07 Apr 2025 15:03:13 GMT</pubDate><content:encoded><![CDATA[<p>可将QT5_DIR（包括了bin/inclue/lib等目录的那个基础目录，不是lib/cmake）加到CMAKE_PREFIX_PATH中，防止find_package无法使用</p>
<p>cmake对qt moc有如下几个函数封装：</p>
<p>qt_wrap_ui([输出]MOC后的源文件列表 [输入]MOC前的.ui文件)</p>
<p>qt_wrap_cpp([输出]MOC后的源文件列表 [输入]MOC前的源文件，通常是包含了Q_OBJECT的.hpp)</p>
<p>qt_add_resources([输出]MOC后的源文件列表 [输入]MOC前的.qrc文件)</p>
<p>经过这三步后，就可以将moc后在源文件add_exectuable/add_library了</p>
<p>示例代码：</p>
<pre><code class="lang-bash"><span class="hljs-comment">#让cmake能找到qt，防止find_package无法使用</span>
list(APPEND CMAKE_PREFIX_PATH <span class="hljs-variable">${QT5_DIR}</span>)

<span class="hljs-comment">#将使用Designer编辑好的.ui文件处理为C++源文件</span>
file(GLOB UI_SRC ui/*.ui)
qt_wrap_ui(MOC_UI_SRC <span class="hljs-variable">${UI_SRC}</span>)

<span class="hljs-comment">#将带有如Q_OBJECT等Meta-Object的头文件处理为moc后的C++头/源文件</span>
file(GLOB FORM_SRC include/ui/*.hpp)
qt_wrap_cpp(MOC_FORM_SRC <span class="hljs-variable">${FORM_SRC}</span>)

<span class="hljs-comment">#将Qt资源文件(*.qrc)编译为C++源文件</span>
file(GLOB FORM_QRC ui/*.qrc)
qt_add_resources(MOC_FORM_QRC <span class="hljs-variable">${FORM_QRC}</span>)

<span class="hljs-comment">#正确使用find_package</span>
find_package(Qt5 COMPONENTS Core Widgets REQUIRED)

<span class="hljs-comment">#处理完后的源码作为exe/lib的输入</span>
add_exectuable(example <span class="hljs-variable">${MOC_UI_SRC}</span>
<span class="hljs-variable">${MOC_FORM_SRC}</span>
<span class="hljs-variable">${FORM_QRC}</span>)

<span class="hljs-comment">#链接Qt库，该命令会自动将Qt5对应的的include目录加入至include directories</span>
target_link_libraries(example PRIVATE Qt5::Widgets)
</code></pre>
]]></content:encoded></item><item><title><![CDATA[wxDialog/wxWindow根据控件自适应大小]]></title><description><![CDATA[在使用wxSizer时，用Add (wxWindow window, int proportion=0, int flag=0, int border=0, wxObject userData=NULL)方法，将flag设置为wxALL，如果使用wxEXPAND，则会出现额外的空间，导致控件之间的间隔变的很大，效果很难看
在Add完所有控件后，调用wxSizer的SetSizeHints (wxWindow *window)方法，window参数传入窗口指针]]></description><link>https://www.leiex.com/wxdialogwxwindow</link><guid isPermaLink="true">https://www.leiex.com/wxdialogwxwindow</guid><category><![CDATA[wxWidgets]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Tue, 03 Dec 2024 13:54:27 GMT</pubDate><content:encoded><![CDATA[<p>在使用wxSizer时，用Add (wxWindow <em>window, int proportion=0, int flag=0, int border=0, wxObject</em> userData=NULL)方法，将flag设置为wxALL，如果使用wxEXPAND，则会出现额外的空间，导致控件之间的间隔变的很大，效果很难看</p>
<p>在Add完所有控件后，调用wxSizer的SetSizeHints (wxWindow *window)方法，window参数传入窗口指针</p>
]]></content:encoded></item><item><title><![CDATA[CPack NSIS example]]></title><description><![CDATA[#Installation;
if(WIN32)
install(TARGETS ${proj} RUNTIME DESTINATION bin)
install(FILES ${SQLite3_LIBRARIES}/sqlite3.dll DESTINATION bin)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resources/share DESTINATION bin)
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE...]]></description><link>https://www.leiex.com/cpack-nsis-example</link><guid isPermaLink="true">https://www.leiex.com/cpack-nsis-example</guid><category><![CDATA[CMake]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Fri, 22 Nov 2024 15:16:59 GMT</pubDate><content:encoded><![CDATA[<pre><code class="lang-bash"><span class="hljs-comment">#Installation;</span>
<span class="hljs-keyword">if</span>(WIN32)
install(TARGETS <span class="hljs-variable">${proj}</span> RUNTIME DESTINATION bin)
install(FILES <span class="hljs-variable">${SQLite3_LIBRARIES}</span>/sqlite3.dll DESTINATION bin)
install(DIRECTORY <span class="hljs-variable">${CMAKE_SOURCE_DIR}</span>/resources/share DESTINATION bin)
install(FILES <span class="hljs-variable">${CMAKE_SOURCE_DIR}</span>/LICENSE.txt DESTINATION .)
<span class="hljs-comment">#set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION .)</span>
<span class="hljs-built_in">set</span>(CPACK_NSIS_MUI_ICON <span class="hljs-variable">${CMAKE_SOURCE_DIR}</span>/resources/app_icon.ico)
<span class="hljs-built_in">set</span>(CPACK_NSIS_MODIFY_PATH <span class="hljs-string">"ON"</span>)
<span class="hljs-built_in">set</span>(CPACK_CREATE_DESKTOP_LINKS <span class="hljs-variable">${proj}</span>)
<span class="hljs-built_in">set</span>(CPACK_PACKAGE_EXECUTABLES <span class="hljs-variable">${proj}</span> <span class="hljs-variable">${APP_NAME}</span>)
endif()
<span class="hljs-built_in">set</span>(CPACK_PACKAGE_NAME <span class="hljs-variable">${APP_NAME}</span>)
<span class="hljs-built_in">set</span>(CPACK_PACKAGE_VERSION <span class="hljs-variable">${APP_VERSION_MAJOR}</span>.<span class="hljs-variable">${APP_VERSION_MINOR}</span>.<span class="hljs-variable">${APP_VERSION_FIX}</span>)
<span class="hljs-built_in">set</span>(CPACK_DEBIAN_PACKAGE_ARCHITECTURE <span class="hljs-variable">${CMAKE_SYSTEM_PROCESSOR}</span>)
<span class="hljs-built_in">set</span>(CPACK_RESOURCE_FILE_LICENSE <span class="hljs-variable">${CMAKE_SOURCE_DIR}</span>/LICENSE.txt)

include(InstallRequiredSystemLibraries)
include(CPack)
</code></pre>
]]></content:encoded></item><item><title><![CDATA[wxWidgets实现托盘图标动态右键菜单]]></title><description><![CDATA[首先，按标准流程，基于wxTaskbarIcon实现一个类
namespace TrayThem {
class TrayIcon : public wxTaskBarIcon {
protected:
  virtual wxMenu *CreatePopupMenu();

public:
  explicit TrayIcon(wxTaskBarIconType iconType = wxTBI_DEFAULT_TYPE);
  ~TrayIcon();
};
};

然后，重载它的Cre...]]></description><link>https://www.leiex.com/wxwidgets-wxtaskbaricon-contextmenu</link><guid isPermaLink="true">https://www.leiex.com/wxwidgets-wxtaskbaricon-contextmenu</guid><category><![CDATA[wxWidgets]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Wed, 06 Nov 2024 15:48:54 GMT</pubDate><content:encoded><![CDATA[<p>首先，按标准流程，基于wxTaskbarIcon实现一个类</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">namespace</span> TrayThem {
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TrayIcon</span> :</span> <span class="hljs-keyword">public</span> wxTaskBarIcon {
<span class="hljs-keyword">protected</span>:
  <span class="hljs-function"><span class="hljs-keyword">virtual</span> wxMenu *<span class="hljs-title">CreatePopupMenu</span><span class="hljs-params">()</span></span>;

<span class="hljs-keyword">public</span>:
  <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">TrayIcon</span><span class="hljs-params">(wxTaskBarIconType iconType = wxTBI_DEFAULT_TYPE)</span></span>;
  ~TrayIcon();
};
};
</code></pre>
<p>然后，重载它的CreatePopupMenu方法，每次对它点击右键时，就会调用这个方法返回的wxMenu指针，菜单关闭时，这个wxMenu对象就会被销毁</p>
<p>示例代码如下：</p>
<pre><code class="lang-cpp">wxMenu *TrayThem::TrayIcon::CreatePopupMenu() {
  wxMenu *cm = <span class="hljs-keyword">new</span> wxMenu();
  wxMenuItem *menuShow = cm-&gt;Append(wxID_ANY, <span class="hljs-string">"Show Program"</span>);
  <span class="hljs-keyword">this</span>-&gt;Bind(wxEVT_MENU, &amp;TrayThem::TrayIcon::OnMenuShow, <span class="hljs-keyword">this</span>,
             menuShow-&gt;GetId());
  wxMenu *mp = <span class="hljs-keyword">new</span> wxMenu();
  cm-&gt;AppendSubMenu(mp, <span class="hljs-string">"Programs"</span>);
  BizBus::GetInstance()-&gt;TraverseProgram(
      [](<span class="hljs-keyword">void</span> *opaque, <span class="hljs-built_in">std</span>::<span class="hljs-built_in">shared_ptr</span>&lt;ProgramInfo&gt; info, <span class="hljs-keyword">bool</span> isRunning) {
        wxMenu *mp = <span class="hljs-keyword">static_cast</span>&lt;wxMenu *&gt;(opaque);
        wxMenuItem *item = mp-&gt;AppendCheckItem(wxID_ANY, info-&gt;program_name);
        item-&gt;Check(isRunning);
      },
      mp);
  cm-&gt;AppendSeparator();
  wxMenuItem *menuExit = cm-&gt;Append(wxID_ANY, <span class="hljs-string">"Exit"</span>);
  <span class="hljs-keyword">this</span>-&gt;Bind(wxEVT_MENU, &amp;TrayThem::TrayIcon::OnMenuExit, <span class="hljs-keyword">this</span>,
             menuExit-&gt;GetId());
  <span class="hljs-keyword">return</span> cm;
}
</code></pre>
<p>注意，由于每次使用右键菜单后，菜单就会被销毁，因此菜单项的选中状态不会保存，需要自己另外存储，下次创建菜单时，再调用Check方法选中</p>
]]></content:encoded></item><item><title><![CDATA[多列wxListCtrl使用技巧]]></title><description><![CDATA[以官方Wiki的minimal example为例：
// Example uses fictive class "Item" and fictive getters to access them. Adapt for your needs

class MyFrame : public wxFrame
{
    wxListCtrl* m_item_list;

public:
    MyFrame() : wxFrame(NULL, wxID_ANY,  wxT("Hello wxWid...]]></description><link>https://www.leiex.com/wxlistctrl-usage</link><guid isPermaLink="true">https://www.leiex.com/wxlistctrl-usage</guid><category><![CDATA[wxWidgets]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Wed, 23 Oct 2024 15:56:23 GMT</pubDate><content:encoded><![CDATA[<p>以官方Wiki的minimal example为例：</p>
<pre><code class="lang-cpp"><span class="hljs-comment">// Example uses fictive class "Item" and fictive getters to access them. Adapt for your needs</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFrame</span> :</span> <span class="hljs-keyword">public</span> wxFrame
{
    wxListCtrl* m_item_list;

<span class="hljs-keyword">public</span>:
    MyFrame() : wxFrame(<span class="hljs-literal">NULL</span>, wxID_ANY,  wxT(<span class="hljs-string">"Hello wxWidgets"</span>), wxPoint(<span class="hljs-number">50</span>,<span class="hljs-number">50</span>), wxSize(<span class="hljs-number">800</span>,<span class="hljs-number">600</span>))
    {
        wxPanel* mainPane = <span class="hljs-keyword">new</span> wxPanel(<span class="hljs-keyword">this</span>);
        wxBoxSizer* sizer = <span class="hljs-keyword">new</span> wxBoxSizer(wxHORIZONTAL);

        m_item_list = <span class="hljs-keyword">new</span> wxListCtrl(mainPane, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);

        <span class="hljs-comment">// Add first column       </span>
        wxListItem col0;
        col0.SetId(<span class="hljs-number">0</span>);
        col0.SetText( _(<span class="hljs-string">"Foo"</span>) );
        col0.SetWidth(<span class="hljs-number">50</span>);
        m_item_list-&gt;InsertColumn(<span class="hljs-number">0</span>, col0);

        <span class="hljs-comment">// Add second column</span>
        wxListItem col1;
        col1.SetId(<span class="hljs-number">1</span>);
        col1.SetText( _(<span class="hljs-string">"Name"</span>) );
        m_item_list-&gt;InsertColumn(<span class="hljs-number">1</span>, col1);

        <span class="hljs-comment">// Add third column     </span>
        wxListItem col2;
        col2.SetId(<span class="hljs-number">2</span>);
        col2.SetText( _(<span class="hljs-string">"Comments"</span>) );
        m_item_list-&gt;InsertColumn(<span class="hljs-number">2</span>, col2);


        <span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> item_amount = getItemAmount();
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> n=<span class="hljs-number">0</span>; n&lt;item_amount; n++)
        {
            Item* curritem = getItem(n);

            wxListItem item;
            item.SetId(n);
            item.SetText( curritem-&gt;getName() );

            m_item_list-&gt;InsertItem( item );

            <span class="hljs-comment">// set value in first column</span>
            <span class="hljs-keyword">if</span> (!curritem-&gt;isFoo())
            {
                m_item_list-&gt;SetItem(n, <span class="hljs-number">0</span>, wxT(<span class="hljs-string">"Foo"</span>));
            }
            <span class="hljs-keyword">else</span>
            {
                m_item_list-&gt;SetItem(n, <span class="hljs-number">0</span>, wxT(<span class="hljs-string">"Bar"</span>));
            }

            <span class="hljs-comment">// set value in second column</span>
            m_item_list-&gt;SetItem(n, <span class="hljs-number">1</span>, curritem-&gt;getName());

            <span class="hljs-comment">// set value in third column</span>
            m_item_list-&gt;SetItem(n, <span class="hljs-number">2</span>, curritem-&gt;getDescription());

        }

        sizer-&gt;Add(m_item_list,<span class="hljs-number">1</span>, wxEXPAND | wxALL, <span class="hljs-number">10</span>);
        mainPane-&gt;SetSizer(sizer);
    }
};

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span>:</span> <span class="hljs-keyword">public</span> wxApp
{
    wxFrame* m_frame;
<span class="hljs-keyword">public</span>:

    <span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">OnInit</span><span class="hljs-params">()</span>
    </span>{
        m_frame = <span class="hljs-keyword">new</span> MyFrame();
        m_frame-&gt;Show();
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    } 

};

IMPLEMENT_APP(MyApp)
</code></pre>
<p>由于官方的API文档描述的比较简单，整理一下使用时的注意事项：</p>
<ul>
<li><p>要使用带表头的多列List，初始化时，需有wxLC_REPORT的flag（注意不同flag会有冲突）</p>
</li>
<li><p>使用ClearAll清除表格时，表头（Columns）也会一起被清除，需要重新添加</p>
</li>
<li><p>添加表头有两种方式：</p>
</li>
</ul>
<ol>
<li><p>AppendColumn，简单方便</p>
</li>
<li><p>构造一个wxListItem后，再InsertColumn（官方Minimal Example的方式）</p>
</li>
</ol>
<ul>
<li>添加数据的方式有点奇怪，需分为两步：</li>
</ul>
<ol>
<li><p>先获取到索引（可用GetItemCount方法取当前Item的数量作为index），再使用InsertItem插入一个Item，这个方法会返回新Item的index，作为下一步使用</p>
</li>
<li><p>插入Item后，使用SetItem(index,column,label,imageIndex=-1)方法，给刚才的Item设置各列显示的数据，如需设置自定义数据、图片、字体等高级功能，可用wxListItem的重载版本</p>
</li>
</ol>
<p>新增Item的示例代码如下：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">int</span> TrayThem::MainWidget::cbReloadPrograms(<span class="hljs-keyword">void</span> *argument, <span class="hljs-keyword">int</span> argc,
                                           <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">char</span> **azColName) {
  <span class="hljs-keyword">if</span> (argument == <span class="hljs-literal">nullptr</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
  }
  <span class="hljs-keyword">auto</span> mw = <span class="hljs-keyword">static_cast</span>&lt;TrayThem::MainWidget *&gt;(argument);
  <span class="hljs-keyword">auto</span> programs = mw-&gt;m_lvPrograms;
  <span class="hljs-keyword">int</span> index = programs-&gt;GetItemCount();
  programs-&gt;InsertItem(index, <span class="hljs-string">""</span>);
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; argc; i++) {
    programs-&gt;SetItem(index, i, argv[i] == <span class="hljs-literal">nullptr</span> ? <span class="hljs-string">""</span> : argv[i]);
  }
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>关于事件，常用的事件主要有wxEVT_LIST_ITEM_SELECTED和wxEVT_LIST_ITEM_DESELECTED，分别对应选中和取消选中Item，对应的事件处理函数原型为：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">handler</span><span class="hljs-params">(wxListEvent &amp;event)</span></span>;
</code></pre>
<p>其中，event.GetItem可取到选中的Item，GetText可取到对应的Label，如果是单行选择模式的List（初始化时，设置了wxLC_SINGLE_SEL的flag），则GetText会返回第一列的Label</p>
<p>获取同一行中其它列的Text，可使用GetItemLabel方法，示例代码如下：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">void</span> TrayThem::MainWidget::OnProgramSelected(wxListEvent &amp;event) {
  wxListItem item = event.GetItem();
  <span class="hljs-keyword">this</span>-&gt;m_SelectedId = item.GetText();
  <span class="hljs-keyword">this</span>-&gt;m_SelectedProgram.program_id = <span class="hljs-keyword">this</span>-&gt;m_SelectedId;
  <span class="hljs-keyword">int</span> col = item.GetColumn();
  <span class="hljs-keyword">this</span>-&gt;m_SelectedProgram.running_status =
      <span class="hljs-keyword">this</span>-&gt;m_lvPrograms-&gt;GetItemText(item, ++col);
  <span class="hljs-keyword">this</span>-&gt;m_SelectedProgram.program_name =
      <span class="hljs-keyword">this</span>-&gt;m_lvPrograms-&gt;GetItemText(item, ++col);
  <span class="hljs-keyword">this</span>-&gt;m_SelectedProgram.autostart =
      <span class="hljs-keyword">this</span>-&gt;m_lvPrograms-&gt;GetItemText(item, ++col) == <span class="hljs-string">"1"</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;
  <span class="hljs-keyword">this</span>-&gt;m_SelectedProgram.execution =
      <span class="hljs-keyword">this</span>-&gt;m_lvPrograms-&gt;GetItemText(item, ++col);
  <span class="hljs-keyword">this</span>-&gt;m_SelectedProgram.working_directory =
      <span class="hljs-keyword">this</span>-&gt;m_lvPrograms-&gt;GetItemText(item, ++col);
  <span class="hljs-keyword">this</span>-&gt;m_SelectedProgram.parameters =
      <span class="hljs-keyword">this</span>-&gt;m_lvPrograms-&gt;GetItemText(item, ++col);
}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[WEB Worker DEMO]]></title><description><![CDATA[Requirement: a web server, here we use python to run a simple web server
  python.exe -m SimpleHTTPServer 8080
  #For python3, use this command:
  python3 -m http.server 8080


The HTML, master code
  <!DOCTYPE HTML>
  <html>
      <head>
          <...]]></description><link>https://www.leiex.com/web-worker-demo</link><guid isPermaLink="true">https://www.leiex.com/web-worker-demo</guid><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Tue, 24 Sep 2024 09:45:47 GMT</pubDate><content:encoded><![CDATA[<ul>
<li><p>Requirement: a web server, here we use python to run a simple web server</p>
<pre><code class="lang-bash">  python.exe -m SimpleHTTPServer 8080
  <span class="hljs-comment">#For python3, use this command:</span>
  python3 -m http.server 8080
</code></pre>
</li>
<li><p>The HTML, master code</p>
<pre><code class="lang-xml">  <span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">HTML</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>WEB Workder DEMO<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
          <span class="hljs-comment">//Add version number to avoid cache;</span>
          <span class="hljs-keyword">let</span> workerJsFile = <span class="hljs-string">"worker.js?version="</span> + <span class="hljs-built_in">Date</span>.now();
          <span class="hljs-keyword">var</span> worker = <span class="hljs-keyword">new</span> Worker(workerJsFile);

          worker.onmessage = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
              <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"content"</span>).innerHTML = event.data;
          };

          <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">startTimer</span>(<span class="hljs-params"></span>) </span>{
              worker.postMessage(<span class="hljs-string">"START"</span>);
          }

          <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stopTimer</span>(<span class="hljs-params"></span>) </span>{
              worker.postMessage(<span class="hljs-string">"STOP"</span>);
          }
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/css"</span>&gt;</span><span class="css">
  <span class="hljs-selector-tag">table</span> {
      <span class="hljs-attribute">border-collapse</span>:true;
      <span class="hljs-attribute">border-spacing</span>:<span class="hljs-number">0</span>;
  }
  <span class="hljs-selector-tag">thead</span> {
      <span class="hljs-attribute">background</span>: lightgray;
  }
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">border</span>=<span class="hljs-string">"1px"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Current Time<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>
              &lt;/<span class="hljs-attr">thead</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"content"</span>&gt;</span>

  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">tfoot</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"start"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"startTimer()"</span>&gt;</span>Start<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"stop"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"stopTimer()"</span>&gt;</span>Stop<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                      <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">tfoot</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
</li>
<li><p>The JS, worker code</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">var</span> runningTimer;
  <span class="hljs-comment">//await must in async function;</span>
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">report</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-comment">//const d = new Date();</span>
      <span class="hljs-keyword">var</span> strPost = <span class="hljs-string">"Fail to get time from server"</span>;
      <span class="hljs-keyword">const</span> timeServer = <span class="hljs-string">"http://worldtimeapi.org/api/timezone/Asia/Shanghai"</span>;
      <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> fetch(timeServer);
      <span class="hljs-keyword">if</span> (response.ok) {
          <span class="hljs-keyword">let</span> json = <span class="hljs-keyword">await</span> response.json();
          strPost=json.datetime;
      }
      <span class="hljs-built_in">this</span>.postMessage(strPost);
  }
  <span class="hljs-built_in">this</span>.addEventListener(<span class="hljs-string">"message"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
      <span class="hljs-keyword">let</span> cmd = event.data;
      <span class="hljs-keyword">switch</span> (cmd) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">"START"</span>:
          <span class="hljs-built_in">this</span>.postMessage(<span class="hljs-string">"Started"</span>);
          <span class="hljs-built_in">clearInterval</span>(runningTimer);
          runningTimer = <span class="hljs-built_in">setInterval</span>(report, <span class="hljs-number">1000</span>);
          <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">"STOP"</span>:
          <span class="hljs-built_in">this</span>.postMessage(<span class="hljs-string">"Stopped"</span>);
          <span class="hljs-built_in">clearInterval</span>(runningTimer);
          <span class="hljs-keyword">break</span>;
      }

  }, <span class="hljs-literal">false</span>);
</code></pre>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[C/c++隐藏结构体/类成员的方法]]></title><description><![CDATA[纯C实现隐藏结构体（实现不透明结构体）的方法：
假设我们要开发一个库example.so，但又不想把某结构体的内容开放到SDK的头文件中，那么可以这样处理：

准备三个文件：example.h（SDK的头文件），example_internal.h（不开放，存放了结构体的真实定义），example.c

各文件内容如下：
 example.h:
 /* opaque types */
 struct example_struct;
 /* helper functions */
 __decls...]]></description><link>https://www.leiex.com/cc-hide-struct-class-member</link><guid isPermaLink="true">https://www.leiex.com/cc-hide-struct-class-member</guid><category><![CDATA[C++]]></category><category><![CDATA[C]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Fri, 20 Sep 2024 08:34:52 GMT</pubDate><content:encoded><![CDATA[<p>纯C实现隐藏结构体（实现不透明结构体）的方法：</p>
<p>假设我们要开发一个库example.so，但又不想把某结构体的内容开放到SDK的头文件中，那么可以这样处理：</p>
<ol>
<li><p>准备三个文件：example.h（SDK的头文件），example_internal.h（不开放，存放了结构体的真实定义），example.c</p>
</li>
<li><p>各文件内容如下：</p>
<p> example.h:</p>
<pre><code class="lang-c"> <span class="hljs-comment">/* opaque types */</span>
 <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">example_struct</span>;</span>
 <span class="hljs-comment">/* helper functions */</span>
 __declspec( dllexport ) <span class="hljs-function">struct example_struct* <span class="hljs-title">create_example</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> id,<span class="hljs-keyword">const</span> <span class="hljs-keyword">float</span> rate)</span></span>;
 __declspec( dllexport ) <span class="hljs-function"><span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> <span class="hljs-title">get_example_id</span><span class="hljs-params">(struct example_struct *example)</span></span>;
 __declspec( dllexport ) <span class="hljs-function"><span class="hljs-keyword">const</span> <span class="hljs-keyword">float</span> <span class="hljs-title">get_example_rate</span><span class="hljs-params">(struct example_struct *example)</span></span>;
 __declspec( dllexport ) <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">free_example</span><span class="hljs-params">(struct example_struct *example)</span></span>;
</code></pre>
<p> example_internal.h:</p>
<pre><code class="lang-c"> <span class="hljs-comment">/* The real structure */</span>
 <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">example_struct</span> {</span>
 <span class="hljs-keyword">int</span> id;
 <span class="hljs-keyword">float</span> rate;
 <span class="hljs-keyword">int</span> hiddenInt;
 <span class="hljs-keyword">float</span> hiddenRate;
 };
</code></pre>
<p> example.c:</p>
<pre><code class="lang-c"> <span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"example.h"</span></span>
 <span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"example_internal.h"</span></span>
 <span class="hljs-function">struct example_struct* <span class="hljs-title">create_example</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> id,<span class="hljs-keyword">const</span> <span class="hljs-keyword">float</span> rate)</span></span>{
     <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">example_struct</span> *<span class="hljs-title">example</span>=(<span class="hljs-title">struct</span> <span class="hljs-title">example_struct</span>*)<span class="hljs-title">malloc</span>(<span class="hljs-title">sizeof</span>(<span class="hljs-title">struct</span> <span class="hljs-title">example_struct</span>));</span>
     <span class="hljs-keyword">return</span> example;
 }

 <span class="hljs-function"><span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> <span class="hljs-title">get_example_id</span><span class="hljs-params">(struct example_struct *example)</span></span>{
     <span class="hljs-keyword">if</span>(!example){
         <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
     }
     <span class="hljs-keyword">return</span> example-&gt;id;
 }

 <span class="hljs-comment">/* Ohter helper functions ... */</span>
</code></pre>
</li>
<li><p>生成好库后，只需要把example.so和example.h打包进SDK里就可以被用来开发了</p>
</li>
</ol>
<p>C++实现隐藏类成员的方法：</p>
<p>还是以example.so为例：</p>
<ol>
<li><p>在头文件中定义一个不透明结构体/类，实际的内容放在实现文件中，注意：由于编译时，不能明确知道它的构造及析构函孙，因此无法使用智能指针</p>
<p> example.hpp</p>
<pre><code class="lang-cpp"> __declspec( dllexport ) <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">example</span> {</span>
 <span class="hljs-keyword">public</span>:
 <span class="hljs-function"><span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getId</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span></span>;
 <span class="hljs-function"><span class="hljs-keyword">const</span> <span class="hljs-keyword">float</span> <span class="hljs-title">getRate</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span></span>;
 <span class="hljs-keyword">private</span>:
 <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">exampleImpl</span>;</span>
 <span class="hljs-comment">//opaque pointer;</span>
 exampleImpl *m_impl;
 };
</code></pre>
<p> example.cpp</p>
</li>
<li><pre><code class="lang-cpp">   <span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"example.hpp"</span></span>
   <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">exampleImpl</span> {</span>
   <span class="hljs-keyword">public</span>:
    <span class="hljs-keyword">int</span> m_id;
    <span class="hljs-keyword">float</span> m_rate;
    <span class="hljs-keyword">int</span> m_hideId;
    <span class="hljs-keyword">float</span> m_hideRate;
   };

   <span class="hljs-function"><span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> <span class="hljs-title">example::getId</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span></span>{
       <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>-&gt;m_impl-&gt;m_id;
   }
   <span class="hljs-function"><span class="hljs-keyword">const</span> <span class="hljs-keyword">float</span> <span class="hljs-title">getRate</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span></span>{
       <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>-&gt;m_impl-&gt;m_rate;
   }
</code></pre>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[C++中const对象引用的一些限制]]></title><description><![CDATA[先上示例代码：
class Test {
public:
 void doConst() const {
//
}
void doNoConst() {
//
}
};

int main(int argc,char **argv){
Test t;
const &ct=t;
//error: passing xxx as 'this' argument of xxx discards qualifiers [-fpermissive]
ct.doNoConst();

//Correct;
c...]]></description><link>https://www.leiex.com/cppconstobject</link><guid isPermaLink="true">https://www.leiex.com/cppconstobject</guid><category><![CDATA[C++]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Thu, 19 Sep 2024 09:45:46 GMT</pubDate><content:encoded><![CDATA[<p>先上示例代码：</p>
<pre><code class="lang-cpp"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Test</span> {</span>
<span class="hljs-keyword">public</span>:
 <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">doConst</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span> </span>{
<span class="hljs-comment">//</span>
}
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">doNoConst</span><span class="hljs-params">()</span> </span>{
<span class="hljs-comment">//</span>
}
};

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc,<span class="hljs-keyword">char</span> **argv)</span></span>{
Test t;
<span class="hljs-keyword">const</span> &amp;ct=t;
<span class="hljs-comment">//error: passing xxx as 'this' argument of xxx discards qualifiers [-fpermissive]</span>
ct.doNoConst();

<span class="hljs-comment">//Correct;</span>
ct.doConst();

<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>代码说明：</p>
<ul>
<li><p>const引用的值不可改变（废话）</p>
</li>
<li><p>只有声明为const的成员函数才能被const对象调用（重要，上面代码报错的原因）</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Windows 10机械硬盘（HD）使用率100%的解决方法]]></title><description><![CDATA[原因：Sysmain服务导致
解决方法：

将虚拟内存（分页文件大小）从默认的”系统管理的大小“设置为固定的大小，最大和最小大小保持一致

关闭且禁用Sysmain服务（过去叫superfetch）


使用管理员权限打开CMD（或用services.msc打开服务管理器关闭后禁用Sysmain）：
sc stop "SysMain" & sc config "SysMain" start=disabled


禁用Edge更新

需禁用的服务有：

MicrosoftEdgeElevation...]]></description><link>https://www.leiex.com/windows-10hd100</link><guid isPermaLink="true">https://www.leiex.com/windows-10hd100</guid><category><![CDATA[Windows 10]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Fri, 06 Sep 2024 14:02:05 GMT</pubDate><content:encoded><![CDATA[<p>原因：Sysmain服务导致</p>
<p>解决方法：</p>
<ol>
<li><p>将虚拟内存（分页文件大小）从默认的”系统管理的大小“设置为固定的大小，最大和最小大小保持一致</p>
</li>
<li><p>关闭且禁用Sysmain服务（过去叫superfetch）</p>
</li>
</ol>
<p>使用管理员权限打开CMD（或用<code>services.msc</code>打开服务管理器关闭后禁用Sysmain）：</p>
<pre><code class="lang-bash">sc stop <span class="hljs-string">"SysMain"</span> &amp; sc config <span class="hljs-string">"SysMain"</span> start=disabled
</code></pre>
<ol start="3">
<li>禁用Edge更新</li>
</ol>
<p>需禁用的服务有：</p>
<ul>
<li><p>MicrosoftEdgeElevationService</p>
</li>
<li><p>edgeupdate</p>
</li>
<li><p>edgeupdatem</p>
</li>
</ul>
<p>需禁用的计划任务有：</p>
<ul>
<li><p>MicrosoftEdgeUpdateTaskMachineCore</p>
</li>
<li><p>MicrosoftEdgeUpdateTaskMachineUA</p>
</li>
</ul>
<ol start="4">
<li>可以考虑禁用Windows Update服务</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Windows下编译Qt6]]></title><description><![CDATA[编译环境
操作系统： Windows 11 Home 22H2
编译器：Visual Studio 2022 Community
CPU：Intel Core i7-12700 @ 2.10GHz
内存：16GB
参考官方文档： https://wiki.qt.io/Building_Qt_6_from_Git https://doc.qt.io/qt-6.5/qtwebengine-platform-notes.html#windows https://wiki.qt.io/QtWebEngi...]]></description><link>https://www.leiex.com/windowsqt6</link><guid isPermaLink="true">https://www.leiex.com/windowsqt6</guid><category><![CDATA[Qt]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Wed, 28 Aug 2024 11:43:22 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-57yw6kr546v5akd">编译环境</h2>
<p>操作系统： Windows 11 Home 22H2</p>
<p>编译器：Visual Studio 2022 Community</p>
<p>CPU：Intel Core i7-12700 @ 2.10GHz</p>
<p>内存：16GB</p>
<p>参考官方文档： <a target="_blank" href="https://wiki.qt.io/Building_Qt_6_from_Git">https://wiki.qt.io/Building_Qt_6_from_Git</a> <a target="_blank" href="https://doc.qt.io/qt-6.5/qtwebengine-platform-notes.html#windows">https://doc.qt.io/qt-6.5/qtwebengine-platform-notes.html#windows</a> <a target="_blank" href="https://wiki.qt.io/QtWebEngine/Qt6Build">https://wiki.qt.io/QtWebEngine/Qt6Build</a></p>
<h2 id="heading-5yeg5ash5bel5l2c5yk5l6d6lww">准备工作及依赖</h2>
<p>编译Qt6所需依赖：</p>
<ul>
<li><p>Git (&gt;= 1.6.x)</p>
</li>
<li><p>CMake (&gt;= 3.16, &gt;= 3.18.4 for Ninja Multi-Config, &gt;= 3.19 for WebEngine, &gt;= 3.21.1 for static Qt builds in Qt 6.2+, or builds for Apple platforms in Qt 6.6+)</p>
</li>
<li><p>Ninja</p>
</li>
<li><p>C++ compiler supporting C++ 17</p>
</li>
<li><p>Perl (&gt;=5.14, optional for Qt &gt;= 6.5)</p>
</li>
<li><p>Python (&gt;=2.6.x)</p>
</li>
<li><p>libclang (&gt;=10, optional when QDoc should be built, prebuilt versions for each OS can be downloaded here or installed through the libclang-dev package on Linux)</p>
</li>
<li><p>Visual Studio 2022, Visual Studio 2019, MinGW 11.2</p>
</li>
<li><p>如果需要 Make 本地文档，则需要安装 LLVM ，而且需要的是 Qt Company 预构建的 LLVM 。LLVM Qt Prebuilt: <a target="_blank" href="https://download.qt.io/development_releases/prebuilt/libclang/qt/">https://download.qt.io/development_releases/prebuilt/libclang/qt/</a> 编译WebEngine所需依赖：</p>
</li>
<li><p>CMake 3.19 or newer</p>
</li>
<li><p>Python 3 with html5lib library，由于使用了imp库的关系不支持3.12，最高可用3.11</p>
</li>
<li><p>Bison, Flex，偷懒的话，可以从qt5的源码中copy，自己下的话记得要手动处理libiconv和libintl的依赖，确保命令行下不报错就行</p>
</li>
<li><p>GPerf</p>
</li>
<li><p>Node.js version 12 or later，用最后的12.x版本即可</p>
</li>
<li><p>OpenSSL，可从源代码安装</p>
</li>
</ul>
<pre><code class="lang-bash">perl Configure VC-WIN64A --prefix=D:\Libraries\OpenSSL\3.0.12
nmake
nmake install
</code></pre>
<p>我自己写了个bat把环境变量都设置好，放在解压后的源码目录运行即可：</p>
<pre><code class="lang-bash"><span class="hljs-built_in">set</span> _ROOT=%<span class="hljs-built_in">cd</span>%
<span class="hljs-built_in">set</span> PATH=%_ROOT%/qtbase/bin;%PATH%
<span class="hljs-built_in">set</span> PATH=%PATH%;D:/Tools/bison-2.4.1-bin/bin
<span class="hljs-built_in">set</span> PATH=%PATH%;D:/Tools/flex-2.5.4a-1-bin/bin
<span class="hljs-built_in">set</span> PATH=%PATH%;D:/Tools/gperf-3.0.1-bin/bin
SET PATH=%_ROOT%/qtrepotools/bin;%PATH%
SET PATH=%PATH%;C:/Strawberry/perl/bin
<span class="hljs-built_in">set</span> LLVM_INSTALL_DIR=<span class="hljs-string">"C:/Program Files/LLVM/bin"</span>
<span class="hljs-built_in">set</span> OPENSSL_ROOT_DIR=D:/Libraries/OpenSSL/3.0.12
</code></pre>
<h2 id="heading-5bya5ael57yw6kr">开始编译</h2>
<p>必须使用x64 Native Tools Command Prompt for Visual Studio 2012运行以下命令 运行env.bat设置path后，使用以下配置： 注意事项：</p>
<ul>
<li><p>需使用<code>chcp 65001</code>切换至utf-8 code page开始编译，否则后续webengine中的python脚本会报错</p>
</li>
<li><p>需提前将OpenSSL的两个DLL复制到qtbase/bin中，后续过程有依赖</p>
</li>
<li><p>Qt6无法同时编译debug和release版本，需删除CMakeCache.txt后，再重新configure 编译debug版本：</p>
</li>
</ul>
<pre><code class="lang-bash">configure -opensource -confirm-license -verbose -debug -webengine-proprietary-codecs -nomake tests -nomake examples -prefix D:/Libraries/Qt/6.5.3/msvc2022_x64 -mp -opengl dynamic -openssl-linked OPENSSL_PREFIX=D:/Libraries/OpenSSL/3.0.12 -I D:/Libraries/OpenSSL/3.0.12/include -L D:/Libraries/OpenSSL/3.0.12/lib OPENSSL_LIBS=<span class="hljs-string">"-lUser32 -lAdvapi32 -lGdi32 -llibcrypto -llibssl"</span>
</code></pre>
<p>编译release版本：</p>
<pre><code class="lang-bash">configure -opensource -confirm-license -verbose -release -webengine-proprietary-codecs -nomake tests -nomake examples -prefix D:/Libraries/Qt/6.5.3/msvc2022_x64 -mp -opengl dynamic -openssl-linked OPENSSL_PREFIX=D:/Libraries/OpenSSL/3.0.12 -I D:/Libraries/OpenSSL/3.0.12/include -L D:/Libraries/OpenSSL/3.0.12/lib OPENSSL_LIBS=<span class="hljs-string">"-lUser32 -lAdvapi32 -lGdi32 -llibcrypto -llibssl"</span>
</code></pre>
<p>如果之前编译过不支持ssl的版本，需要把文件删掉重新编译 使用cmake进行并行编译（实际调用的ninja）：</p>
<pre><code class="lang-bash">cmake --build . --parallel
</code></pre>
<p>时间主要花在编译webengine上 在生成文档前，必须先安装，记得将OpenSSL的几个DLL复制到qt安装的路径的bin目录下</p>
<pre><code class="lang-bash">ninja install
</code></pre>
<p>或者使用cmake方式安装</p>
<pre><code class="lang-bash">cmake --install .
</code></pre>
<p>生成文档，此操作需先install后，再将qdoc的路径加入至PATH，可先单独运行一下qdoc看是否报错，如报错，需将libclang.dll复制到qt安装的路径的bin目录下</p>
<pre><code class="lang-bash">cmake --build . --target docs
</code></pre>
<p>安装文档</p>
<pre><code class="lang-bash">cmake --build . --target install_docs
</code></pre>
<p>整个过程很长很痛苦，主要是webengine要编译一个完整的chromium，太久了</p>
]]></content:encoded></item><item><title><![CDATA[Widnows下编译Qt5.15.8]]></title><description><![CDATA[编译环境
操作系统： Windows 10 Professional 22H2
编译器：Visual Studio 2019 Community CPU：Intel Core i5-8300H @ 2.3GHz
内存：16GB
参考官方文档： https://doc.qt.io/qt-5/windows-building.html https://doc.qt.io/qt-6/qtwebengine-platform-notes.html
准备工作及依赖
编译Qt5.15.8依赖现在基本都包含在...]]></description><link>https://www.leiex.com/widnowsqt5158</link><guid isPermaLink="true">https://www.leiex.com/widnowsqt5158</guid><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Wed, 28 Aug 2024 11:40:16 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-57yw6kr546v5akd">编译环境</h2>
<p>操作系统： Windows 10 Professional 22H2</p>
<p>编译器：Visual Studio 2019 Community CPU：Intel Core i5-8300H @ 2.3GHz</p>
<p>内存：16GB</p>
<p>参考官方文档： <a target="_blank" href="https://doc.qt.io/qt-5/windows-building.html">https://doc.qt.io/qt-5/windows-building.html</a> <a target="_blank" href="https://doc.qt.io/qt-6/qtwebengine-platform-notes.html">https://doc.qt.io/qt-6/qtwebengine-platform-notes.html</a></p>
<h2 id="heading-5yeg5ash5bel5l2c5yk5l6d6lww">准备工作及依赖</h2>
<p>编译Qt5.15.8依赖现在基本都包含在源代码里了：</p>
<ul>
<li><p>在qtbase\bin和gnuwin32\bin中</p>
</li>
<li><p>CMake需要自己另行安装，并加入至path环境变量中</p>
</li>
<li><p>如果需要 Make 本地文档，则需要安装 LLVM WebEngine所需依赖：</p>
</li>
<li><p>Python 2.7.5，不支持Python3，此处有坑，不支持2.7.10以上版本，最好就用Python2.7.5，另外，如果path里有python3 ,要去掉。版本正确，还找不到python2的话，copy一份python.exe为python2.exe</p>
</li>
<li><p>Bison, Flex，已经在源码自带的gnuwin32\bin中</p>
</li>
<li><p>GPerf，需自行安装</p>
</li>
<li><p>Node.js version 8 or later (version 12 or later is recommended)，就用12.x就好，太新的不要</p>
</li>
<li><p>OpenSSL 3.0.x 更高版本的不行</p>
</li>
</ul>
<pre><code class="lang-bash">perl Configure VC-WIN64A --prefix=D:\Libraries\OpenSSL\3.0.9
nmake
nmake install
</code></pre>
<p>我自己写了个bat把环境变量都设置好，放在解压后的源码目录运行即可：</p>
<pre><code class="lang-bash"><span class="hljs-built_in">set</span> _ROOT=%<span class="hljs-built_in">cd</span>%
<span class="hljs-built_in">set</span> PATH=%_ROOT%\qtbase\bin;%_ROOT%\gnuwin32\bin;%PATH%
<span class="hljs-built_in">set</span> PATH=%PATH%;C:\Python27
<span class="hljs-built_in">set</span> PYTHONPATH=C:\Python27\DLLs
<span class="hljs-built_in">set</span> PATH=%PATH%;D:\Tools\win_flex_bison
<span class="hljs-built_in">set</span> PATH=%PATH%;D:\Tools\gperf\bin
<span class="hljs-built_in">set</span> PATH=%PATH%;D:\Tools\nasm
<span class="hljs-built_in">set</span> PATH=%PATH%;D:\Tools\ruby-1.9.3-p551-i386-mingw32\bin
<span class="hljs-built_in">set</span> OPENSSL_PREFIX=D:\Libraries\OpenSSL\3.0.9
<span class="hljs-built_in">set</span> PATH=%PATH%;%OPENSSL_PREFIX%\bin
<span class="hljs-built_in">set</span> INCLUDE=%INCLUDE%;%OPENSSL_PREFIX%\include
<span class="hljs-built_in">set</span> LIB=%LIB%;%OPENSSL_DIR%\lib
SET PATH=%_ROOT%\qtrepotools\bin;%PATH%
<span class="hljs-built_in">set</span> LLVM_INSTALL_DIR=C:\Program Files\LLVM
</code></pre>
<h2 id="heading-5bya5ael57yw6kr">开始编译</h2>
<p>必须使用x64 Native Tools Command Prompt for Visual Studio 2019运行以下命令 运行env.bat设置path后，使用以下配置：</p>
<pre><code class="lang-bash">configure -recheck-all -opensource -confirm-license -verbose -debug-and-release -webengine-proprietary-codecs -nomake tests -nomake examples -prefix D:\Libraries\Qt\5.15.9\msvc2019_x64 -mp -opengl dynamic -openssl-linked OPENSSL_PREFIX=D:\Libraries\OpenSSL\3.0.9 -I D:\Libraries\OpenSSL\3.0.9\include -L D:\Libraries\OpenSSL\3.0.9\lib OPENSSL_LIBS=<span class="hljs-string">"-lUser32 -lAdvapi32 -lGdi32 -llibcrypto -llibssl"</span>
</code></pre>
<p>如果之前编译过不支持ssl的版本，需要把文件删掉重新编译 使用jom代替nmake进行并行编译：</p>
<pre><code class="lang-bash">jom -j16
</code></pre>
<p>整个过程大约10小时，主要花在编译webengine上 在生成文档前，必须先安装，记得将OpenSSL的几个DLL复制到qt安装的路径的bin目录下</p>
<pre><code class="lang-bash">jom install
</code></pre>
<p>生成文档，此操作需先install后，再将qdoc的路径加入至PATH，可先单独运行一下qdoc看是否报错，如报错，需将libclang.dll复制到qt安装的路径的bin目录下</p>
<pre><code class="lang-bash">jom docs
</code></pre>
<p>安装文档</p>
<pre><code class="lang-bash">jom install_docs
</code></pre>
<p>整个过程很长很痛苦，主要是webengine要编译一个完整的chromium，太久了</p>
]]></content:encoded></item><item><title><![CDATA[Qt Model-View学习之手动更新Model数据]]></title><description><![CDATA[在使用基于QAbstractListModel的自定义Model时，遇到数据更新后Model不自动刷新数据的问题。通过手动发送更新信号即可解决。 方法，在更新数据时调用
emit beginResetModel();
emit endResetModel();

注意reset model需要成对使用。]]></description><link>https://www.leiex.com/qt-model-viewmodel</link><guid isPermaLink="true">https://www.leiex.com/qt-model-viewmodel</guid><category><![CDATA[Qt]]></category><category><![CDATA[C++]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Fri, 16 Aug 2024 14:37:57 GMT</pubDate><content:encoded><![CDATA[<p>在使用基于QAbstractListModel的自定义Model时，遇到数据更新后Model不自动刷新数据的问题。通过手动发送更新信号即可解决。 方法，在更新数据时调用</p>
<pre><code class="lang-cpp"><span class="hljs-function">emit <span class="hljs-title">beginResetModel</span><span class="hljs-params">()</span></span>;
<span class="hljs-function">emit <span class="hljs-title">endResetModel</span><span class="hljs-params">()</span></span>;
</code></pre>
<p>注意reset model需要成对使用。</p>
]]></content:encoded></item><item><title><![CDATA[Insert an image into a QTextEdit]]></title><description><![CDATA[1. Using html tag
QTextEdit *textEditor = new QTextEdit(0);
QTextDocumentFragment fragment;
fragment = QTextDocumentFragment::fromHtml("");
textEditor->textCursor().insertFragment(fragment);
textEditor->setVisible(true);

2. Using QTextDocument's res...]]></description><link>https://www.leiex.com/insert-an-image-into-a-qtextedit</link><guid isPermaLink="true">https://www.leiex.com/insert-an-image-into-a-qtextedit</guid><category><![CDATA[Qt]]></category><category><![CDATA[C++]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Fri, 16 Aug 2024 14:36:22 GMT</pubDate><content:encoded><![CDATA[<p><strong>1. Using html tag</strong></p>
<pre><code class="lang-cpp">QTextEdit *textEditor = <span class="hljs-keyword">new</span> QTextEdit(<span class="hljs-number">0</span>);
QTextDocumentFragment fragment;
fragment = QTextDocumentFragment::fromHtml(<span class="hljs-string">""</span>);
textEditor-&gt;textCursor().insertFragment(fragment);
textEditor-&gt;setVisible(<span class="hljs-literal">true</span>);
</code></pre>
<p><strong>2. Using QTextDocument's resource</strong></p>
<pre><code class="lang-cpp">QString file = QFileDialog::getOpenFileName(<span class="hljs-keyword">this</span>, tr(<span class="hljs-string">"Select an image"</span>),
<span class="hljs-string">"."</span>, tr(<span class="hljs-string">"Bitmap Files (*.bmp)
"</span>
<span class="hljs-string">"JPEG (*.jpg *jpeg)
"</span>
<span class="hljs-string">"GIF (*.gif)
"</span>
<span class="hljs-string">"PNG (*.png)
"</span>));
<span class="hljs-function">QUrl <span class="hljs-title">Uri</span> <span class="hljs-params">( file )</span></span>;
QImage image = QImageReader ( file ).read();
QTextDocument * textDocument = m_textEdit-&gt;document();
textDocument-&gt;addResource( QTextDocument::ImageResource, Uri, QVariant ( image ) );
QTextCursor cursor = m_textEdit-&gt;textCursor();
QTextImageFormat imageFormat;
imageFormat.setWidth( image.width() );
imageFormat.setHeight( image.height() );
imageFormat.setName( Uri.toString() );
cursor.insertImage(imageFormat);
</code></pre>
<p><strong>3. Subclass QTextEdit (The example below also enabled drag &amp; drop)</strong></p>
<pre><code class="lang-cpp"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TextEdit</span> :</span> <span class="hljs-keyword">public</span> QTextEdit {
<span class="hljs-keyword">public</span>:
    <span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">canInsertFromMimeData</span><span class="hljs-params">( <span class="hljs-keyword">const</span> QMimeData* source )</span> <span class="hljs-keyword">const</span>
    </span>{
        <span class="hljs-keyword">return</span>(source-&gt;hasImage() );
    }


    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">insertFromMimeData</span><span class="hljs-params">( <span class="hljs-keyword">const</span> QMimeData* source )</span>
    </span>{
        <span class="hljs-keyword">if</span> ( source-&gt;hasImage() )
        {
            <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span>    i = <span class="hljs-number">1</span>;
            <span class="hljs-function">QUrl        <span class="hljs-title">url</span><span class="hljs-params">( QString( <span class="hljs-string">"dropped_image_%1"</span> ).arg( i++ ) )</span></span>;
            dropImage( url, qvariant_cast( source-&gt;imageData() ) );
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ( source-&gt;hasUrls() )
        {
            foreach( QUrl url, source-&gt;urls() )
            {
                QFileInfo info( url.toLocalFile() );
                <span class="hljs-keyword">if</span> ( QImageReader::supportedImageFormats().contains( info.suffix().toLower().toLatin1() ) )
                {
                    dropImage( url, QImage( info.filePath() ) );
                }<span class="hljs-keyword">else</span>  {
                    dropTextFile( url );
                }
            }
        }<span class="hljs-keyword">else</span>  {
            QTextEdit::insertFromMimeData( source );
        }
    }
}

<span class="hljs-keyword">private</span>:
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">dropImage</span><span class="hljs-params">( <span class="hljs-keyword">const</span> QUrl &amp; url, <span class="hljs-keyword">const</span> QImage &amp; image )</span>
</span>{
    <span class="hljs-keyword">if</span> ( !image.isNull() )
    {
        document()-&gt;addResource( QTextDocument::ImageResource, url, image );
        textCursor().insertImage( url.toString() );
    }
}


<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">dropTextFile</span><span class="hljs-params">( <span class="hljs-keyword">const</span> QUrl &amp; url )</span>
</span>{
    textCursor().insertText( file.readAll() );
}
};
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Qt TextDocument内容组织方式]]></title><description><![CDATA[Qt的QTextEdit等控件在存储内容的时候是以QTextDocument & QTextBlock & QTextFragment组织内容的。
包含关系为QTextDocument QTextBlock QTextFragment
一般一个控件（如QTextEdit）只包含一个QTextDocument，文档对象可以很容易的保存为HTML或者ODF文件。
其中，QTextBlock是以换行符分隔的，遇到一个换行符就新建一个QTextBlock，因此，一行内容就是一个QTextBlock。
而...]]></description><link>https://www.leiex.com/qt-textdocument-struct</link><guid isPermaLink="true">https://www.leiex.com/qt-textdocument-struct</guid><category><![CDATA[C++]]></category><category><![CDATA[Qt]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Fri, 16 Aug 2024 14:28:33 GMT</pubDate><content:encoded><![CDATA[<p>Qt的QTextEdit等控件在存储内容的时候是以QTextDocument &amp; QTextBlock &amp; QTextFragment组织内容的。</p>
<p>包含关系为QTextDocument QTextBlock QTextFragment</p>
<p>一般一个控件（如QTextEdit）只包含一个QTextDocument，文档对象可以很容易的保存为HTML或者ODF文件。</p>
<p>其中，QTextBlock是以换行符分隔的，遇到一个换行符就新建一个QTextBlock，因此，一行内容就是一个QTextBlock。</p>
<p>而QTextBlock中包含了一个或多个QTextFragment，这些fragment可以是文字，图片或其他多媒体元素，fragment以内容的类型区分。</p>
<p>例如如下内容：</p>
<p>[文本][图片][文本]</p>
<p>上面的内容生成了一个block，这个block包含了3个fragment。</p>
<p>而内容：</p>
<p>[文本]</p>
<p>[图片]</p>
<p>[文本]</p>
<p>则生成了3个block，因为一行内容生成一个block。</p>
<p>这个概念在使用网络发送图文混排的内容时尤其重要，如果不能正确理解document/block/fragment的组织方式，则会丢失原始格式。</p>
]]></content:encoded></item><item><title><![CDATA[QTextEdit动态显示gif动画]]></title><description><![CDATA[原理：使用QMovie播放gif并更新当前帧到QTextEdit中Document的Resource。相关信号：QMovie::frameChanged(int frameNo)实例代码： 初始化QMovie对象：
QMovie*movie=newQMovie(this);
movie->setFileName(img_path);
movie->setCacheMode(QMovie::CacheNone);
connect(movie,SIGNAL(frameChanged(int)),th...]]></description><link>https://www.leiex.com/qtexteditgif</link><guid isPermaLink="true">https://www.leiex.com/qtexteditgif</guid><category><![CDATA[C++]]></category><category><![CDATA[Qt]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Fri, 16 Aug 2024 14:27:00 GMT</pubDate><content:encoded><![CDATA[<p>原理：使用QMovie播放gif并更新当前帧到QTextEdit中Document的Resource。<br />相关信号：QMovie::frameChanged(int frameNo)<br />实例代码： 初始化QMovie对象：</p>
<pre><code class="lang-cpp">QMovie*movie=newQMovie(<span class="hljs-keyword">this</span>);
movie-&gt;setFileName(img_path);
movie-&gt;setCacheMode(QMovie::CacheNone);
connect(movie,SIGNAL(frameChanged(<span class="hljs-keyword">int</span>)),<span class="hljs-keyword">this</span>,SLOT(frameChanged(<span class="hljs-keyword">int</span>)));
movie-&gt;start();
</code></pre>
<p>槽函数:</p>
<pre><code class="lang-cpp">voidMyObject::frameChanged(intframeNumber)
<span class="hljs-keyword">if</span>(frameNumber==<span class="hljs-number">-1</span>)
<span class="hljs-keyword">return</span>;

QMovie*movie=(QMovie*)<span class="hljs-keyword">this</span>-&gt;sender();
QStringname=movie-&gt;fileName().toUtf8().toBase64();
ui-&gt;view-&gt;document()-&gt;addResource(QTextDocument::ImageResource,
name,
QVariant(movie-&gt;currentPixmap()));
ui-&gt;view-&gt;setLineWrapColumnOrWidth(ui-&gt;view-&gt;lineWrapColumnOrWidth());
</code></pre>
<p>关键点：</p>
<p>QMovie对象在播放gif动画时发送frameChanged信号至槽，此处使用QOjbect::sender()方法来得到具体的对象指针，然后调用document的addResource方法更新当前的帧到其图像资源，最后调用setLineWrapColumnOrWidth来刷新显示。这样就实现了gif图片的不断刷新。</p>
]]></content:encoded></item><item><title><![CDATA[MySQL查锁定的表并解锁]]></title><description><![CDATA[查open tables
SHOW OPEN TABLES WHERE in_use>0;

查Process List
SHOW FULL PROCESSLIST;

查Transactions
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

杀死进程
KILL process_ID/transaction_process_ID;]]></description><link>https://www.leiex.com/mysql-lock-table</link><guid isPermaLink="true">https://www.leiex.com/mysql-lock-table</guid><category><![CDATA[Machine Learning]]></category><dc:creator><![CDATA[源赖朝]]></dc:creator><pubDate>Fri, 16 Aug 2024 14:24:57 GMT</pubDate><content:encoded><![CDATA[<p>查open tables</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SHOW</span> <span class="hljs-keyword">OPEN</span> <span class="hljs-keyword">TABLES</span> <span class="hljs-keyword">WHERE</span> in_use&gt;<span class="hljs-number">0</span>;
</code></pre>
<p>查Process List</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SHOW</span> <span class="hljs-keyword">FULL</span> <span class="hljs-keyword">PROCESSLIST</span>;
</code></pre>
<p>查Transactions</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> INFORMATION_SCHEMA.INNODB_TRX;
</code></pre>
<p>杀死进程</p>
<pre><code class="lang-sql"><span class="hljs-keyword">KILL</span> process_ID/transaction_process_ID;
</code></pre>
]]></content:encoded></item></channel></rss>