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. Wpf 多指应用开发解析

    1  首先分析多指事件与单指事件,以及执行顺序 2  事件阻断 订阅多指事件后,在TouchDown时 采用e.handle = true,阻断多指事件,或在ManipulationStarting. ...

  2. 20220724-Java的封装相关

    目录 含义 常见使用方法 个人理解 含义 封装 (encapsulation) 指隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读取和修改的访问级别. 常见使用方法 class Pers ...

  3. Spring源码 20 手写模拟源码

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  4. leetcode之二叉树

    专题:二叉树遍历 987. 二叉树的垂序遍历 给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列. 对位于 (row, col) 的每个结点而言,其左右子结点分别位于 (row ...

  5. Spring mvc源码分析系列--前言

    Spring mvc源码分析系列--前言 前言 距离上次写文章已经过去接近两个月了,Spring mvc系列其实一直都想写,但是却不知道如何下笔,原因有如下几点: 现在项目开发前后端分离的趋势不可阻挡 ...

  6. ARC122D XOR Game(博弈论?字典树,贪心)

    题面 ARC122D XOR Game 黑板上有 2 N 2N 2N 个数,第 i i i 个数为 A i A_i Ai​. O I D \rm OID OID(OneInDark) 和 H I D ...

  7. 【Java】学习路径59-多个连接的服务器端

    ServerSocket可以对接多个Socket对象,利用这点,就可以实现:一台服务器对多个客户端. import java.io.IOException; import java.net.*; pu ...

  8. Linux安装Jenkins及配置svn使用

    目录 1. 下载 2. 创建文件夹 3. 安装 4. 修改端口,不用这步 5. 安装插件提速 6. 启动 7. 页面访问 8. 新建用户 9. 安装Subversion插件 10. 安装maven插件 ...

  9. ansible 003 常用模块

    常用模块 file 模块 管理被控端文件 回显为绿色则,未变更,符合要求 黄色则改变 红色则报错 因为默认值为file,那么文件不存在,报错 改为touch则创建 将state改为directory变 ...

  10. 【设计模式】Java设计模式 - 动态代理

    [设计模式]Java设计模式 - 动态代理 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 最近工作比较忙,没啥时间学习 目录 [设计模 ...