Skip to content

Instantly share code, notes, and snippets.

@Willy-JL
Last active March 27, 2022 17:39
Show Gist options
  • Save Willy-JL/6f58dda1f6953c5be85880e0cb052602 to your computer and use it in GitHub Desktop.
Save Willy-JL/6f58dda1f6953c5be85880e0cb052602 to your computer and use it in GitHub Desktop.
PyImGui + Aiohttp example, with main sync thread for window and second thread for asyncio
from imgui.integrations.glfw import GlfwRenderer
import OpenGL.GL as gl
import traceback
import threading
import asyncio
import aiohttp
import imgui
import glfw
import sys
url = "https://google.com/"
html = ""
async def fetch_url():
global url, html
html = ""
try:
async with aiohttp.ClientSession() as cs:
async with cs.get(url) as req:
html = await req.text()
except Exception:
html = "The request failed:\n" + "".join(traceback.format_exception(*sys.exc_info()))
def impl_glfw_init():
# This initializes the window backend
# No need to understand this function
# Taken from https://github.com/pyimgui/pyimgui/blob/master/doc/examples/integrations_glfw3.py
width, height = 560, 680
window_name = "PyImGui Aiohttp Example"
if not glfw.init():
print("Could not initialize OpenGL context")
sys.exit(1)
# OS X supports only forward-compatible core profiles from 3.2
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, gl.GL_TRUE)
# Create a windowed mode window and its OpenGL context
window = glfw.create_window(int(width), int(height), window_name, None, None)
glfw.make_context_current(window)
if not window:
glfw.terminate()
print("Could not initialize Window")
sys.exit(1)
return window
def main():
global url, html
# Setup window:
imgui.create_context()
window = impl_glfw_init()
impl = GlfwRenderer(window)
while not glfw.window_should_close(window):
# Process events and inputs, so GUI is responsive:
glfw.poll_events()
impl.process_inputs()
imgui.new_frame()
# Your actual code for the window goes here
# Setup main fullscreen window:
imgui.set_next_window_position(0, 0)
imgui.set_next_window_size(*impl.io.display_size, imgui.ALWAYS)
with imgui.begin(
# All ImGui widgets and items need to have labels. You cannot have "". Prefix with ## to hide them:
"##Main Window",
flags=(
imgui.WINDOW_NO_MOVE |
imgui.WINDOW_NO_RESIZE |
imgui.WINDOW_NO_COLLAPSE |
imgui.WINDOW_NO_TITLE_BAR |
imgui.WINDOW_NO_SAVED_SETTINGS |
imgui.WINDOW_HORIZONTAL_SCROLLING_BAR
)
):
# Main window content
# The render loop runs every frame. Because of this you give widgets their initial value and they
# give back their new value. Many widgets return two things: a bool for whether the value changed
# this frame, and the actual new value:
url_changed, url = imgui.input_text("##URL", url, 999)
# By default each widget is on its own line. This sets the render cursor to stay on the same line.
# You can also do imgui.same_line(123) to set the horizontal position of the next element:
imgui.same_line()
# Buttons return one thing: whether they were pressed or not in this frame. This makes adding
# callbacks to them as easy as putting them in an if check:
if imgui.button("Fetch!"):
# Run async coroutine in separate async thread:
asyncio.run_coroutine_threadsafe(fetch_url(), loop)
# Render the html as plain text:
imgui.text(html)
# Clear previous frame and add background color:
gl.glClearColor(0.0, 0.0, 0.0, 1)
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
# Render and show the new frame:
imgui.render()
impl.render(imgui.get_draw_data())
glfw.swap_buffers(window)
# Cleanup:
impl.shutdown()
glfw.terminate()
if __name__ == "__main__":
# Setup async loop in separate thread:
loop = asyncio.new_event_loop()
threading.Thread(target=lambda: [asyncio.set_event_loop(loop), loop.run_forever()], daemon=True).start()
# Start ImGui render loop in main sync thread:
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment