ImGUI 它是与平台无关的C++轻量级跨平台图形界面库,没有任何第三方依赖,可以将ImGUI的源码直接加到项目中使用,该框架通常会配合特定的D3Dx9等图形开发工具包一起使用,ImGUI常用来实现进程内的菜单功能,而有些辅助开发作者也会使用该框架开发菜单页面,总体来说这是一个很不错的绘图库,如下将公开新版ImGUI如何实现绘制外部菜单的功能。

ImGUI官方下载地址:https://github.com/ocornut/imgui/releases

在使用ImGUI页面之前需要先来实现一个简单的附着功能,即如何将一个窗体附着到另一个窗体之上,其实代码很简单,如下所示当用户输入进程PID时,会自动跟随窗体并附着在窗体顶部。

#include <Windows.h>
#include <iostream> struct handle_data
{
unsigned long process_id;
HWND best_handle;
}; // By: LyShark
BOOL IsMainWindow(HWND handle)
{
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
} BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam)
{
// By: LyShark
handle_data& data = *(handle_data*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (data.process_id != process_id || !IsMainWindow(handle)) {
return TRUE;
}
data.best_handle = handle;
return FALSE;
} // By: LyShark
HWND FindMainWindow(unsigned long process_id)
{
handle_data data;
data.process_id = process_id;
data.best_handle = 0;
EnumWindows(EnumWindowsCallback, (LPARAM)&data);
return data.best_handle;
} int main(int argc, char* argv[])
{
DWORD pid = 28396; std::cout << "输入进程PID: " << std::endl;
std::cin >> pid; // 获取屏幕宽和高
int iWidth = ::GetSystemMetrics(SM_CXSCREEN);
int iHeight = ::GetSystemMetrics(SM_CYSCREEN); // 根据PID寻找游戏窗口
HWND hwnd = FindMainWindow(pid); while (1)
{
SetTimer(hwnd, 1, 150, NULL); // 实现透明必须设置WS_EX_LAYERED标志
LONG lWinStyleEx = GetWindowLong(hwnd, GWL_EXSTYLE);
lWinStyleEx = lWinStyleEx | WS_EX_LAYERED; SetWindowLong(hwnd, GWL_EXSTYLE, lWinStyleEx);
SetLayeredWindowAttributes(hwnd, 0, RGB(40, 40, 40), LWA_ALPHA); // 去掉标题栏及边框
LONG_PTR Style = GetWindowLongPtr(hwnd, GWL_STYLE);
Style = Style & ~WS_CAPTION & ~WS_SYSMENU & ~WS_SIZEBOX;
SetWindowLongPtr(hwnd, GWL_STYLE, Style); // 至顶层窗口 最大化
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, iWidth, iHeight, SWP_SHOWWINDOW); // 设置窗体可穿透鼠标
SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT | WS_EX_LAYERED); // 绘图
HDC hdc = ::GetDC(hwnd);
HDC mdc = ::CreateCompatibleDC(hdc); // 创建画笔
HPEN hpen = CreatePen(PS_SOLID, 10, RGB(0, 255, 0));
// DC 选择画笔
SelectObject(hdc, hpen);
// (画笔)从初始点移动到 50,50
MoveToEx(hdc, 100, 100, NULL);
// (画笔)从初始点画线到 100,100
LineTo(hdc, 1000, 1000); RECT rect = {0}; rect.bottom = 10;
rect.left = 20;
rect.right = 20;
rect.top = 15; DrawText(hdc, L"hello lyshark.com", strlen("hello lyshark.com"), &rect, DT_CALCRECT | DT_CENTER | DT_SINGLELINE);
} return 0;
}

绘制效果图:

接着我们使用Imgui绘制一个动态菜单,首先下载imgui并打开项目中的examples目录,找到example_win32_directx9打开后自己配置好dx9SDK开发工具包。

代码直接调用,并附加到Counter-Strike Source游戏窗体之上即可,这段代码也很简单。

#include "imgui.h"
#include "imgui_impl_dx9.h"
#include "imgui_impl_win32.h" #include <d3d9.h>
#include <tchar.h>
#include <iostream> #pragma execution_character_set("utf-8") // 全局变量
// lyshark.com
static HWND hwnd;
static HWND GameHwnd;
static RECT WindowRectangle;
static int WindowWide, WindowHeight; static LPDIRECT3D9 g_pD3D = NULL;
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
static D3DPRESENT_PARAMETERS g_d3dpp = {}; // 单选框设置状态
bool show_another_window = false; // imgui 回调函数
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // By: LyShark
bool CreateDeviceD3D(HWND hWnd)
{
if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
{
return false;
} ZeroMemory(&g_d3dpp, sizeof(g_d3dpp));
g_d3dpp.Windowed = TRUE;
g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
g_d3dpp.EnableAutoDepthStencil = TRUE;
g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; if (g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pd3dDevice) < 0)
{
return false;
}
return true;
} void CleanupDeviceD3D()
{
if (g_pd3dDevice)
{
g_pd3dDevice->Release();
g_pd3dDevice = NULL;
} if (g_pD3D)
{
g_pD3D->Release();
g_pD3D = NULL;
}
} void ResetDevice()
{
ImGui_ImplDX9_InvalidateDeviceObjects();
HRESULT hr = g_pd3dDevice->Reset(&g_d3dpp);
if (hr == D3DERR_INVALIDCALL)
{
IM_ASSERT(0);
}
ImGui_ImplDX9_CreateDeviceObjects();
} LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
{
return true;
} switch (msg)
{
case WM_SIZE:
if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED)
{
g_d3dpp.BackBufferWidth = LOWORD(lParam);
g_d3dpp.BackBufferHeight = HIWORD(lParam);
ResetDevice();
}
return 0; case WM_SYSCOMMAND:
if ((wParam & 0xfff0) == SC_KEYMENU)
{
return 0;
}
break; case WM_DESTROY:
PostQuitMessage(0);
return 0;
} return DefWindowProc(hWnd, msg, wParam, lParam);
} // 绘制主方法
// www.cnblogs.com/lyshark
void DrawImGUI()
{
// 启动IMGUI自绘
ImGui_ImplDX9_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame(); static float f = 0.0f;
static int counter = 0;
static char sz[256] = { 0 }; ImGui::Begin("LyShark 辅助GUI主菜单");
ImGui::Text("这是一段测试字符串");
ImGui::Checkbox("弹出子窗口", &show_another_window);
ImGui::SliderFloat("浮点条", &f, 0.0f, 1.0f); ImGui::InputText("输入内容", sz, 256, 0, 0, 0); if (ImGui::Button("点我触发"))
counter++;
ImGui::SameLine();
ImGui::Text("触发次数 = %d", counter); ImGui::Text("当前FPS: %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::End(); if (show_another_window)
{
ImGui::Begin("我是子窗体", &show_another_window);
ImGui::Text(" 您好,LyShark !");
if (ImGui::Button("关闭窗体"))
show_another_window = false;
ImGui::End();
}
ImGui::EndFrame();
} // 自身窗口循环事件
void WindowMessageLoop()
{
bool done = false;
while (!done)
{
// 每次都将窗体置顶并跟随游戏窗体移动
GetWindowRect(GameHwnd, &WindowRectangle);
WindowWide = (WindowRectangle.right) - (WindowRectangle.left);
WindowHeight = (WindowRectangle.bottom) - (WindowRectangle.top);
DWORD dwStyle = GetWindowLong(GameHwnd, GWL_STYLE);
if (dwStyle & WS_BORDER)
{
WindowRectangle.top += 23;
WindowHeight -= 23;
} // 跟随窗口移动
MoveWindow(hwnd, WindowRectangle.left + 8, WindowRectangle.top + 8, WindowWide - 11, WindowHeight - 11, true); // 开始消息循环
MSG msg;
while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
{
done = true;
}
} if (done)
{
break;
} // 开始绘制
DrawImGUI(); g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1.0f, 0); if (g_pd3dDevice->BeginScene() >= 0)
{
ImGui::Render();
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
g_pd3dDevice->EndScene();
} HRESULT result = g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
if (result == D3DERR_DEVICELOST && g_pd3dDevice->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
{
ResetDevice();
}
}
} int main(int argc, char *argv[])
{
// 注册窗体类
WNDCLASSEX wc; // 附加到指定窗体上
wc.cbClsExtra = NULL;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = NULL;
wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0));
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hIconSm = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.lpszClassName = L" ";
wc.lpszMenuName = L" ";
wc.style = CS_VREDRAW | CS_HREDRAW; RegisterClassEx(&wc); // 得到窗口句柄
GameHwnd = FindWindowA(NULL, "Counter-Strike Source");
GetWindowRect(GameHwnd, &WindowRectangle);
WindowWide = WindowRectangle.right - WindowRectangle.left;
WindowHeight = WindowRectangle.bottom - WindowRectangle.top; // 创建窗体
hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TOOLWINDOW, L" ", L" ", WS_POPUP, 1, 1, WindowWide, WindowHeight, 0, 0, wc.hInstance, 0); // 显示窗口
SetLayeredWindowAttributes(hwnd, 0, RGB(0, 0, 0), LWA_ALPHA);
SetLayeredWindowAttributes(hwnd, 0, RGB(0, 0, 0), LWA_COLORKEY);
ShowWindow(hwnd, SW_SHOW); // 初始化D3D
if (!CreateDeviceD3D(hwnd))
{
CleanupDeviceD3D();
UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
} // 更新窗体
UpdateWindow(hwnd); // 初始化ImGUI
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.Fonts->AddFontFromFileTTF("c:/windows/fonts/simhei.ttf", 13.0f, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); ImGui::StyleColorsDark();
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX9_Init(g_pd3dDevice); // 开始执行绘制循环事件
WindowMessageLoop(); ImGui_ImplDX9_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext(); CleanupDeviceD3D();
DestroyWindow(hwnd);
UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}

绘制效果如下:

另外,Imgui也支持绘制到整个屏幕上,也可以当作全局GUI界面来使用。

#include "imgui.h"
#include "imgui_impl_dx9.h"
#include "imgui_impl_win32.h" #include <d3d9.h>
#include <tchar.h>
#include <iostream> #pragma execution_character_set("utf-8") // 全局变量
static HWND hwnd;
static HWND GameHwnd;
static RECT WindowRectangle;
static int WindowWide, WindowHeight; static LPDIRECT3D9 g_pD3D = NULL;
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
static D3DPRESENT_PARAMETERS g_d3dpp = {}; // 单选框设置状态
bool show_another_window = false; // imgui 回调函数
// By: LyShark
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); bool CreateDeviceD3D(HWND hWnd)
{
if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
{
return false;
} ZeroMemory(&g_d3dpp, sizeof(g_d3dpp));
g_d3dpp.Windowed = TRUE;
g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
g_d3dpp.EnableAutoDepthStencil = TRUE;
g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; if (g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pd3dDevice) < 0)
{
return false;
}
return true;
} void CleanupDeviceD3D()
{
if (g_pd3dDevice)
{
g_pd3dDevice->Release();
g_pd3dDevice = NULL;
} if (g_pD3D)
{
g_pD3D->Release();
g_pD3D = NULL;
}
}
// https://www.cnblogs.com/lyshark
void ResetDevice()
{
ImGui_ImplDX9_InvalidateDeviceObjects();
HRESULT hr = g_pd3dDevice->Reset(&g_d3dpp);
if (hr == D3DERR_INVALIDCALL)
{
IM_ASSERT(0);
}
ImGui_ImplDX9_CreateDeviceObjects();
} LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
{
return true;
} switch (msg)
{
case WM_SIZE:
if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED)
{
g_d3dpp.BackBufferWidth = LOWORD(lParam);
g_d3dpp.BackBufferHeight = HIWORD(lParam);
ResetDevice();
}
return 0; case WM_SYSCOMMAND:
if ((wParam & 0xfff0) == SC_KEYMENU)
{
return 0;
}
break; case WM_DESTROY:
PostQuitMessage(0);
return 0;
} return DefWindowProc(hWnd, msg, wParam, lParam);
} // 绘制主方法
// lyshark.com
void DrawImGUI()
{
// 启动IMGUI自绘
ImGui_ImplDX9_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame(); static float f = 0.0f;
static int counter = 0;
static char sz[256] = { 0 }; ImGui::Begin("LyShark 辅助GUI主菜单");
ImGui::Text("这是一段测试字符串");
ImGui::Checkbox("弹出子窗口", &show_another_window);
ImGui::SliderFloat("浮点条", &f, 0.0f, 1.0f); ImGui::InputText("输入内容", sz, 256, 0, 0, 0); if (ImGui::Button("点我触发"))
counter++;
ImGui::SameLine();
ImGui::Text("触发次数 = %d", counter); ImGui::Text("当前FPS: %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::End(); if (show_another_window)
{
ImGui::Begin("我是子窗体", &show_another_window);
ImGui::Text(" 您好,LyShark !");
if (ImGui::Button("关闭窗体"))
show_another_window = false;
ImGui::End();
}
ImGui::EndFrame();
} // 自身窗口循环事件
void WindowMessageLoop()
{
bool done = false;
while (!done)
{
// 每次都将窗体置顶并跟随游戏窗体移动
GetWindowRect(GameHwnd, &WindowRectangle);
WindowWide = (WindowRectangle.right) - (WindowRectangle.left);
WindowHeight = (WindowRectangle.bottom) - (WindowRectangle.top);
DWORD dwStyle = GetWindowLong(GameHwnd, GWL_STYLE);
if (dwStyle & WS_BORDER)
{
WindowRectangle.top += 23;
WindowHeight -= 23;
} // 跟随窗口移动
MoveWindow(hwnd, WindowRectangle.left + 8, WindowRectangle.top + 8, WindowWide - 11, WindowHeight - 11, true); // 开始消息循环
MSG msg;
while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
{
done = true;
}
} if (done)
{
break;
} // 开始绘制
DrawImGUI(); g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1.0f, 0); if (g_pd3dDevice->BeginScene() >= 0)
{
ImGui::Render();
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
g_pd3dDevice->EndScene();
} HRESULT result = g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
if (result == D3DERR_DEVICELOST && g_pd3dDevice->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
{
ResetDevice();
}
}
} int main(int argc, char *argv[])
{
// 注册窗体类
WNDCLASSEX wc; // 附加到整个屏幕上
wc.cbClsExtra = NULL;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = NULL;
wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0));
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hIconSm = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.lpszClassName = L" ";
wc.lpszMenuName = L" ";
wc.style = CS_VREDRAW | CS_HREDRAW;
::RegisterClassEx(&wc); // 屏幕宽度和高度
WindowWide = GetSystemMetrics(SM_CXSCREEN);
WindowHeight = GetSystemMetrics(SM_CYSCREEN); // 创建窗体
HWND hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TOOLWINDOW, L" ", L" ", WS_POPUP, 1, 1, WindowWide, WindowHeight, 0, 0, wc.hInstance, 0); // 显示窗口
SetLayeredWindowAttributes(hwnd, 0, 1.0f, LWA_ALPHA);
SetLayeredWindowAttributes(hwnd, 0, RGB(0, 0, 0), LWA_COLORKEY);
ShowWindow(hwnd, SW_SHOW); // 初始化D3D
if (!CreateDeviceD3D(hwnd))
{
CleanupDeviceD3D();
UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
} // 更新窗体
UpdateWindow(hwnd); // 初始化ImGUI
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.Fonts->AddFontFromFileTTF("c:/windows/fonts/simhei.ttf", 13.0f, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); ImGui::StyleColorsDark();
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX9_Init(g_pd3dDevice); // 开始执行绘制循环事件
WindowMessageLoop(); ImGui_ImplDX9_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext(); CleanupDeviceD3D();
DestroyWindow(hwnd);
UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}

绘制效果如下:

ImGUI 1.87 绘制D3D外部菜单的更多相关文章

  1. Revit中绘制带坡度管道

    激活管道绘制命令出现绘制管道上下文菜单,可以根据需要设置管道坡度值,是向上坡度还是向下坡度,其中两个命令非常有用,一个是继承高程,一个是忽略坡度以连接.在Revit建模中尝尝碰到一些带有坡度的管道,比 ...

  2. Delphi如何在Form的标题栏绘制自定义文字

    Delphi中Form窗体的标题被设计成绘制在系统菜单的旁边,如果你想要在标题栏绘制自定义文本又不想改变Caption属性,你需要处理特定的Windows消息:WM_NCPAINT.. WM_NCPA ...

  3. 一步一步跟我学ImGui.第一讲.配置OpenGl2+ImGui环境

    目录 搭建ImGui例子中的第一个OpenGl2环境 一丶搭建OpenGL2环境 1.下载GLFW库 2.解压GLFW库. 3.将GLFW库拷贝到你的工程文件下. 4.配置到Vs2013中. 5.测试 ...

  4. 如何在ChemDraw 15.1 Pro中添加模板

    ChemDraw化学绘图工具为了方便用户的使用,特地开发了众多的各种类型模板.用户在绘制一些简单或复杂的化学结构式时,可以直接从ChemDraw模板库里直接调用使用,虽然ChemDraw模板非常的丰富 ...

  5. 前端之JQuery:JQuery扩展和事件

    jQuery之jQuery扩展和事件 一.jQuery事件 常用事件 blur([[data],fn]) 失去焦点 focus([[data],fn]) 获取焦点( 搜索框例子) change([[d ...

  6. HTML5 中的 canvas 画布(二)

    绘制图片 一.绘制图片 context.drawImage()(即把图片放到canvas里) var image = new Image();  // 先创建图片对象 image.src = '图片的 ...

  7. 翻译:常见问题——ABAP Development Tools for Eclipse

    ABAP Development Tools for Eclipse(简称ADT)是一个基于Eclipse的全新ABAP IDE,这篇文档试图回答有关ADT的最重要的常见问题.这只是一个开始,如果你对 ...

  8. 【CityHunter】游戏进度总控,及需求设计

    需求列表 序号 标题 描述 进度 更新日期 1 游戏主界面 游戏进入的主操作界面,     2 基础定位功能 实现自身定位功能,     3 特殊地点的Marker 搜索周边银行(资产保护).医院(状 ...

  9. DrawableLayout

    提供一个在窗口顶层显示,可从窗口边缘拖出的container组件. DrawableLayout本身作为整个容器,先进行默认显示内容的布局,再进行拖出菜单的内容布局.也就是一个DL包含两个或三个子控件 ...

随机推荐

  1. javaweb 03: jsp

    JSP 我的第一个JSP程序: 在WEB-INF目录之外创建一个index.jsp文件,然后这个文件中没有任何内容. 将上面的项目部署之后,启动服务器,打开浏览器,访问以下地址: http://loc ...

  2. OpenMP入门

    OpenMP入门 前情提要:并行(parallel):需要多个运算核心同时完成 其中有多处理器和单处理器多核两种实现方式,其中差异如下: 同一芯片上的多核通信速度更快 同一芯片上的多核能耗更低 Ope ...

  3. TCP协议调试工具TcpEngine V1.3.0使用教程

    简介   这里说的TCP协议调试定义是在开发长连接TCP协议应用时,为了验证代码流程或查找bug,需要与对端交互数据过来,当需要时可以暂停发送:单条发送:跳过发送:正常发送:发送时修改数据等.   T ...

  4. 从零开始在centos搭建博客(一)

    本篇为安装篇. 基于centos 7.9,大部分东西使用docker安装. 软件列表:docker + mysql + wordpress 安装docker yum install -y yum-ut ...

  5. odoo14 编辑状态和非编辑状态下隐藏

    1 <div class="oe_edit_only"> 2 <a name="remove_group_id" type="obj ...

  6. 并发刺客(False Sharing)——并发程序的隐藏杀手

    并发刺客(False Sharing)--并发程序的隐藏杀手 前言 前段时间在各种社交平台"雪糕刺客"这个词比较火,简单的来说就是雪糕的价格非常高!其实在并发程序当中也有一个刺客, ...

  7. 项目经验记录丨Modbus转EtherNET/IP协议转换应用

    使用电脑通过软件来进行模拟 EtherNET/IP主站连接Mdodbus从站设备的项目记录.使用软件为EIPScan 模拟主站,通过Modbus转EtherNET/IP网关连接Modbus Slave ...

  8. 43%非常看好TypeScript…解读“2022前端开发者现状报告”

    摘要:近日,The Software House 发布了"2022前端开发者现状报告",笔者在此对报告内容进行解读,供大家参考. 本文分享自华为云社区<"2022前 ...

  9. 使用CSS实现多种Noise噪点效果

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 在插画中添加噪点肌理可以营造出一种自然的氛围.噪点肌理可以用于塑造阴影.高 ...

  10. Spring源码 10 IOC refresh方法5

    本文章基于 Spring 5.3.15 Spring IOC 的核心是 AbstractApplicationContext 的 refresh 方法. 其中一共有 13 个主要方法,这里分析第 5 ...