请问采用 webkit进行vscode (WSL ubuntu C++ imgui)进行在imgui控件上加载网页(html)如下为main.cpp #include "web_view.h"
#include <stdlib.h>
#include <GLFW/glfw3.h>
#include <epoxy/gl.h>
#include "imgui_impl_opengl3.h" // OpenGL3渲染器后端
#include "imgui_impl_glfw.h" // GLFW平台后端
// 定义 ImGui 使用 epoxy 作为 OpenGL 加载器
#define IMGUI_IMPL_OPENGL_LOADER_EPOXY
int main() {
// 设置环境变量
setenv("GDK_BACKEND", "x11", 1);
setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", 1);
// 初始化GLFW
if(!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
return -1;
}
// 设置 OpenGL 版本和配置文件
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(1280, 720, "Map Viewer", NULL, NULL);
if (!window) {
fprintf(stderr, "Failed to create GLFW window\n");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // 启用垂直同步
// 初始化ImGui
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
// 检查 ImGui OpenGL3 后端是否初始化成功
if (!ImGui_ImplGlfw_InitForOpenGL(window, true)) {
fprintf(stderr, "Failed to initialize ImGui GLFW backend\n");
return -1;
}
if (!ImGui_ImplOpenGL3_Init("#version 130")) {
fprintf(stderr, "Failed to initialize ImGui OpenGL3 backend\n");
return -1;
}
// 设置中文字体
io.Fonts->AddFontFromFileTTF("./Newfonts/msyh.ttc", 16.0f, nullptr, io.Fonts->GetGlyphRangesChineseFull());
// 创建Web视图
WebView mapView(1200, 700);
//mapView.load_url("https://www.baidu.com");
mapView.load_local_file("resources/map.html");//("./resources/map.html");
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// 创建地图窗口
ImGui::Begin("Baidu Map");
mapView.render(ImGui::GetContentRegionAvail());
ImGui::End();
// 渲染
ImGui::Render();
int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
}
// 清理资源
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
以下为webview.cpp #include "web_view.h"
#include <iostream>
#include <epoxy/gl.h>
#include <filesystem> // C++17 或更高版本
#include <webkit2/webkit2.h>
WebView::WebView(int width, int height) :load_failed(false),texture(0),window(nullptr), webview0(nullptr)
{
// // 初始化GTK环境
gtk_init(nullptr, nullptr);
// 创建WebKit组件
webview0 = webkit_web_view_new();
window = gtk_offscreen_window_new();
gtk_container_add(GTK_CONTAINER(window), webview0);
// 设置初始尺寸
gtk_window_resize(GTK_WINDOW(window), width, height);
// 显示窗口 - 这是关键步骤
gtk_widget_show_all(window);
// 等待窗口映射完成
while (!gtk_widget_get_mapped(window)) {
gtk_main_iteration();
}
// 确保窗口已映射
gtk_widget_realize(window);
// 启用JavaScript和硬件加速
WebKitSettings* settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webview0));
webkit_settings_set_enable_javascript(settings, TRUE);
webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS);
// 创建OpenGL纹理
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 连接加载失败信号
g_signal_connect(webview0, "load-failed", G_CALLBACK(on_load_failed), this);
ImGui::StyleColorsLight();
// 允许加载本地资源
WebKitWebContext* context = webkit_web_view_get_context(WEBKIT_WEB_VIEW(webview0));
webkit_web_context_set_web_extensions_directory(context, "");
// 设置跨域策略
WebKitSecurityManager* security = webkit_web_context_get_security_manager(context);
webkit_security_manager_register_uri_scheme_as_local(security, "file");
}
WebView::~WebView() {
// 清理资源
if (window) {
gtk_widget_destroy(window);
}
if (texture) {
glDeleteTextures(1, &texture);
}
}
void WebView::load_url(const char* url) {
// 异步加载URL
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview0), url);
// 启用JavaScript(百度地图需要)
WebKitSettings* settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webview0));
webkit_settings_set_enable_javascript(settings, TRUE);
}
void WebView::render(const ImVec2& size) {
// 验证尺寸,确保大于0
float render_width = std::max(1.0f, size.x);
float render_height = std::max(1.0f, size.y);
// 更新窗口尺寸
gtk_window_resize(GTK_WINDOW(window), render_width, render_height);
// 确保窗口已显示
if (!gtk_widget_get_visible(window)) {
gtk_widget_show_all(window);
}
// 强制GTK重绘和处理事件
gtk_widget_queue_draw(window);
for (int i = 0; i < 10; i++) { // 多次处理事件以确保加载
while (gtk_events_pending()) {
gtk_main_iteration();
}
}
// 获取像素数据
GdkWindow* gdk_window = gtk_widget_get_window(window);
if (gdk_window) {
pixbuf = gdk_pixbuf_get_from_window(gdk_window, 0, 0, size.x, size.y);
if (pixbuf) {
// 检查Pixbuf格式(应为RGBA)
int channels = gdk_pixbuf_get_n_channels(pixbuf);
if (channels != 4) {
std::cerr << "Warning: Pixbuf has " << channels << " channels, expected 4 (RGBA)" << std::endl;
}
// 更新OpenGL纹理
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
gdk_pixbuf_get_width(pixbuf),
gdk_pixbuf_get_height(pixbuf),
0, GL_RGBA, GL_UNSIGNED_BYTE,
gdk_pixbuf_get_pixels(pixbuf));
// 在ImGui中显示纹理
ImGui::Image((void*)(intptr_t)texture, size);
g_object_unref(pixbuf);
} else {
std::cerr << "Failed to get pixbuf from window" << std::endl;
}
} else {
std::cerr << "Failed to get GdkWindow" << std::endl;
// 如果获取失败,尝试显示窗口并再次获取
gtk_widget_show_all(window);
gdk_window = gtk_widget_get_window(window);
if (!gdk_window) {
std::cerr << "Failed to get GdkWindow even after showing window" << std::endl;
return;
}
}
// 错误处理
if (load_failed) {
ImGui::TextColored(ImVec4(1,0,0,1), "Failed to load page");
if (ImGui::Button("Retry")) {
load_failed = false;
webkit_web_view_reload(WEBKIT_WEB_VIEW(webview0));
}
}
// 在render方法中添加映射检查
if (!gtk_widget_get_mapped(window)) {
std::cout << "Window not mapped, forcing realization..." << std::endl;
gtk_widget_realize(window);
// 等待窗口映射
for (int i = 0; i < 10; i++) {
while (gtk_events_pending()) {
gtk_main_iteration();
}
if (gtk_widget_get_mapped(window)) {
break;
}
}
}
}
void WebView::load_local_file(const std::string file_path) {
gchar* cwd = g_get_current_dir();
if (cwd) {
gchar* full_path = g_build_filename(cwd, file_path.c_str(), NULL);
std::cout << "Loading file: " << full_path << std::endl; // 调试输出
if (g_file_test(full_path, G_FILE_TEST_EXISTS)) {
gchar* uri = g_filename_to_uri(full_path, NULL, NULL);
if (uri) {
std::cout << "URI: " << uri << std::endl; // 调试输出
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview0), uri);
g_free(uri);
} else {
std::cerr << "无法创建URI" << std::endl;
load_default_map();
}
} else {
std::cerr << "文件不存在: " << full_path << std::endl;
load_default_map();
}
g_free(full_path);
g_free(cwd);
} else {
std::cerr << "无法获取当前工作目录" << std::endl;
load_default_map();
}
}
void WebView::load_default_map() {
const char* default_html =
"<!DOCTYPE html>"
"<html>"
"<head>"
" <meta charset='utf-8'>"
" <title>本地地图</title>"
" <style>"
" body, html { margin: 0; padding: 0; width: 100%; height: 100%; }"
" #map { width: 100%; height: 100%; background: #f0f0f0; }"
" .info { position: absolute; top: 10px; left: 10px; background: white; padding: 10px; }"
" </style>"
"</head>"
"<body>"
" <div id='map'></div>"
" <div class='info'>"
" <h2>本地地图查看器</h2>"
" <p>这是一个自动创建的地图文件</p>"
" </div>"
"</body>"
"</html>";
webkit_web_view_load_html(WEBKIT_WEB_VIEW(webview0), default_html, nullptr);
}
void WebView::resize(int width, int height) {
this->width = width;
this->height = height;
gtk_widget_set_size_request(GTK_WIDGET(webview0), width, height);
}
GLuint WebView::get_texture()
{
return texture;
}
void WebView::on_load_failed(WebKitWebView* webView, WebKitLoadEvent load_event, gchar* failing_uri, GError* error, gpointer user_data) {
WebView* view = static_cast<WebView*>(user_data);
view->load_failed = true;
std::cerr << "Failed to load: " << failing_uri << ", error: " << error->message << std::endl;
}
如下为CMakeList.txt cmake_minimum_required(VERSION 3.10)
project(ImGuiMapViewer)
set(CMAKE_CXX_STANDARD 17)
find_package(PkgConfig REQUIRED)
pkg_check_modules(WEBKIT2GTK REQUIRED webkit2gtk-4.0)
pkg_check_modules(EPOXY REQUIRED epoxy) # 添加epoxy的pkg-config查找
add_executable(${PROJECT_NAME}
main.cpp
web_view.cpp
imgui/imgui.cpp
imgui/imgui_draw.cpp
imgui/imgui_tables.cpp
imgui/imgui_widgets.cpp
imgui/backends/imgui_impl_glfw.cpp
imgui/backends/imgui_impl_opengl3.cpp
)
target_include_directories(${PROJECT_NAME} PRIVATE
${WEBKIT2GTK_INCLUDE_DIRS}
${EPOXY_INCLUDE_DIRS}
imgui
imgui/backends
)
target_link_libraries(${PROJECT_NAME} PRIVATE
${WEBKIT2GTK_LIBRARIES}
${EPOXY_LIBRARIES}
glfw
GL
dl
pthread
) 以下为html文件:<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>本地地图</title>
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #f0f0f0;
}
#map {
width: 100%;
height: 100%;
background: linear-gradient(45deg, #e0e0e0, #f0f0f0);
position: relative;
}
.info {
position: absolute;
top: 10px;
left: 10px;
background: white;
padding: 10px;
border-radius: 5px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.marker {
position: absolute;
width: 20px;
height: 20px;
background: red;
border-radius: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<div id="map">
<div class="info">
<h2>本地地图查看器</h2>
<p>这是一个简单的本地地图实现</p>
</div>
<div class="marker" style="top: 40%; left: 40%;"></div>
<div class="marker" style="top: 60%; left: 60%;"></div>
<div class="marker" style="top: 30%; left: 70%;"></div>
</div>
<script>
// 简单的交互逻辑
const map = document.getElementById('map');
let scale = 1;
let offsetX = 0;
let offsetY = 0;
let isDragging = false;
let lastX, lastY;
map.addEventListener('mousedown', (e) => {
isDragging = true;
lastX = e.clientX;
lastY = e.clientY;
map.style.cursor = 'grabbing';
});
map.addEventListener('mousemove', (e) => {
if (isDragging) {
offsetX += (e.clientX - lastX) / scale;
offsetY += (e.clientY - lastY) / scale;
lastX = e.clientX;
lastY = e.clientY;
// 更新标记位置
document.querySelectorAll('.marker').forEach(marker => {
const top = parseFloat(marker.style.top);
const left = parseFloat(marker.style.left);
marker.style.top = `${top + (e.clientY - lastY) / scale}%`;
marker.style.left = `${left + (e.clientX - lastX) / scale}%`;
});
}
});
map.addEventListener('mouseup', () => {
isDragging = false;
map.style.cursor = 'grab';
});
map.addEventListener('mouseleave', () => {
isDragging = false;
map.style.cursor = 'grab';
});
map.addEventListener('wheel', (e) => {
e.preventDefault();
const delta = e.deltaY > 0 ? 0.9 : 1.1;
scale *= delta;
// 更新标记大小
document.querySelectorAll('.marker').forEach(marker => {
const size = 20 * scale;
marker.style.width = `${size}px`;
marker.style.height = `${size}px`;
});
});
// 初始光标样式
map.style.cursor = 'grab';
</script>
</body>
</html>
请问 为何运行时没有加载进html文件。是哪里没有渲染吗
最新发布