So I just started coding GUI in python and after coding some stuff in tkinter i felt like I might as well use imgui as I know some stuff about it from C++.
Now starting to read the docs and somehow the imgui window isn't showing up. I just see a console pop open for a milisecond but no gui.
# initilize imgui context (see documentation)
imgui.create_context()
imgui.get_io().display_size = 100, 100
imgui.get_io().fonts.get_tex_data_as_rgba32()
# start new frame context
imgui.new_frame()
# open new window context
imgui.begin("Your first window!", True)
# draw text label inside of current window
imgui.text("Hello world!")
# close current window context
imgui.end()
# pass all drawing comands to the rendering pipeline
# and close frame context
imgui.render()
imgui.end_frame()
I feel like I didn't choose any engine to render but I'm not sure.
Yes, if you don't select a backend renderer for pyimgui, it won't render anything. I think you might find an imgui.ini file with imgui's interpretation of what you've asked for, in the current directory, but you won't get any graphical output.
To get graphical output, select a renderer, like in this file in the master pyimgui repository:
https://github.com/swistakm/pyimgui/blob/master/doc/examples/integrations_pygame.py
Note that, as I write this, most but not all of the examples in this directory work:
https://github.com/swistakm/pyimgui/tree/master/doc/examples
The "all in one" example did not work for me, and the SDL2 example required changing:
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 16)
to:
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4)
as my GPU doesn't seem to do 16-point multisampling.
Also, these examples don't play well with Python3 in that the error prints() are wrong, and will fail instead of printing a useful error:
print("Error: SDL could not initialize! SDL Error: " + SDL_GetError())
should be:
print("Error: SDL could not initialize! SDL Error: ", SDL_GetError())
So, if you get any errors at these lines, you know what to do. :-)
Finally, for future searchers, here is a quick cut and paste of the pygame version which works for me (from https://github.com/swistakm/pyimgui/blob/master/doc/examples/integrations_pygame.py ). I ran it with python 3.6:
#!/usr/bin/env python3
from __future__ import absolute_import
import sys
import pygame
import OpenGL.GL as gl
from imgui.integrations.pygame import PygameRenderer
import imgui
def main():
pygame.init()
size = 800, 600
pygame.display.set_mode(size, pygame.DOUBLEBUF | pygame.OPENGL | pygame.RESIZABLE)
imgui.create_context()
impl = PygameRenderer()
io = imgui.get_io()
io.display_size = size
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
impl.process_event(event)
imgui.new_frame()
if imgui.begin_main_menu_bar():
if imgui.begin_menu("File", True):
clicked_quit, selected_quit = imgui.menu_item(
"Quit", 'Cmd+Q', False, True
)
if clicked_quit:
exit(1)
imgui.end_menu()
imgui.end_main_menu_bar()
imgui.show_test_window()
imgui.begin("Custom window", True)
imgui.text("Bar")
imgui.text_colored("Eggs", 0.2, 1., 0.)
imgui.end()
# note: cannot use screen.fill((1, 1, 1)) because pygame's screen
# does not support fill() on OpenGL sufraces
gl.glClearColor(1, 1, 1, 1)
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
imgui.render()
impl.render(imgui.get_draw_data())
pygame.display.flip()
if __name__ == "__main__":
main()
Related
Would like your opinion and support on an issue i am trying to overcome. This will be the last piece of puzzle for completion of a small project i am building. Its based on OCR. I am reading text from a live screen ( using below python script ) and able to get the results logged into a file. However, the output is only getting logged once i make the python console window ( in which the script prints the output ) is active/focused by keyboad using alt+tab.
But doing this halts the software from where i am reading the text, breaking the whole process. Toggling the window to the front of the software is a failure to the scripts purpose.
So, i added code after searching from other users about keeping the python console window on top always no matter what the software is doing. I am not able to keep this python console window on top of this sw screen. The SW uses all screen for its purpose of work.
Is there an alternative to this? How can i make the python console become on top of any other window no matter what is on the screen? If not this, please suggest an alternative.
import numpy as nm
from datetime import datetime
import pytesseract
import cv2
import PIL
from PIL import ImageGrab
import win32gui, win32process, win32con
import os
hwnd = win32gui.GetForegroundWindow()
win32gui.SetWindowPos(hwnd,win32con.HWND_TOPMOST,0,0,100,300,0)
#Define function for OCR to enable on multiple screens.
def imToString():
# Path of tesseract executable
pytesseract.pytesseract.tesseract_cmd ='C:\\Tesseract-OCR\\tesseract.exe'
while(True):
# ImageGrab-To capture the screen image in a loop.
# Bbox used to capture a specific area.
#screen base
cap1 = PIL.ImageGrab.grab(bbox =(0, 917, 1913, 1065), include_layered_windows=False, all_screens=True)
date = datetime.now().strftime("%Y-%m-%d %I:%M:%S")
#str config - OCR Engine settings for ONLY text based capture.
config1 = ('-l eng --oem 2 --psm 6')
#configuring tesseract engine for OCR
tess1 = pytesseract.image_to_string(
cv2.cvtColor(nm.array(cap1), cv2.COLOR_BGR2GRAY),
config=config1)
#Defining log pattern to generate
a = [ date, " State: ", tess1 ]
#writing logging output to file
file1 = open("C:\\Users\\User\\Desktop\\rev2.log", "a", encoding='UTF8')
file1.writelines(a)
file1.writelines("\n")
file1.close()
#OUTPUT on colse for Logging verification
print (date, "State: ", tess1)
# Calling the function
imToString()
By requirement, i am not allowed to use a keyboad while operating the screen. I am fairly new to python and have been seeing similar solutions and adding it to the script to make a proper solution.
Please advise.
Here is the tkinter method:
from tkinter import Tk, Text
import subprocess
import threading
from queue import Queue, Empty
filename = 'test.py'
def stream_from(queue):
command = f'python {filename}'
with subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as process:
for out in process.stdout:
queue.put(out.decode())
def update_text(queue):
try:
data = queue.get(block=False)
except Empty:
pass
else:
text.config(state='normal')
text.insert('end', data.strip() + '\n')
text.config(state='disabled')
finally:
root.after(100, update_text, queue)
def loop():
root.attributes('-topmost', True)
root.after(1, loop)
root = Tk()
text = Text(root, state='disabled')
text.pack()
data_queue = Queue()
threading.Thread(target=stream_from, args=(data_queue, ), daemon=True).start()
update_text(data_queue)
loop()
root.mainloop()
Just change the filename to the name of the file you are running and place this script in the same directory
Change delay_in_ms (delay in milliseconds so each 1000 units is one second) and see if that helps (could also leave the 10 seconds and see if it works now, if not there is still another thing to try)
If you are using print to output then this should work (tho I maybe didn't exactly get what you want), if you use logging then there is a slightly different solution
I have a Python script which creates an instance of an application and shows the application's window.
I'm trying to activate/focus the window so that it brings it to the foreground/top and has the keyboard input focus.
The code below usually works, but when the task manager's window is opened and focused before the code is executed, the application's window appears below the task manager and the task manager keeps the keyboard input focus.
The comments in the code are my attempts to circumvent the specific problem which didn't worked either. Only when using SwitchToThisWindow with False or SetWindowPos with HWND_TOPMOST (which sets the window as top most), does the window appear on top of the task manager's window, but the task manager still keeps the keyboard input focus.
def bring_window_to_top(window_handle):
import ctypes
# import win32com.client
# from win32con import HWND_TOP, HWND_TOPMOST, SWP_NOMOVE, SWP_NOSIZE
current_thread_id = ctypes.windll.kernel32.GetCurrentThreadId()
foreground_window_handle = ctypes.windll.user32.GetForegroundWindow()
foreground_thread_id = ctypes.windll.user32.GetWindowThreadProcessId(foreground_window_handle, None)
ctypes.windll.user32.AttachThreadInput(current_thread_id, foreground_thread_id, True)
ctypes.windll.user32.BringWindowToTop(window_handle)
# ctypes.windll.user32.SwitchToThisWindow(window_handle, True)
# ctypes.windll.user32.SwitchToThisWindow(window_handle, False)
# ctypes.windll.user32.SetWindowPos(window_handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
# ctypes.windll.user32.SetWindowPos(window_handle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
# wscript_shell = win32com.client.Dispatch('WScript.Shell')
# wscript_shell.SendKeys('%')
# ctypes.windll.user32.SetForegroundWindow(window_handle)
# ctypes.windll.user32.SetFocus(window_handle)
# ctypes.windll.user32.SetActiveWindow(window_handle)
# ctypes.windll.user32.AttachThreadInput(current_thread_id, foreground_thread_id, False)
I have also attempted using the functions AllowSetForegroundWindow, LockSetForegroundWindow and SystemParametersInfoW to set SPI_SETFOREGROUNDLOCKTIMEOUT to 0 but I get the error Access denied. from ctypes.FormatError().
Is there any way to accomplish it?
You need to set UIAccess to true in the manifest to support accessibility features.
A process that is started with UIAccess rights has the following
abilities:
Set the foreground window.
Drive any application window by using the SendInput function.
Use read input for all integrity levels by using low-level hooks, raw input, GetKeyState, GetAsyncKeyState, and GetKeyboardInput.
Set journal hooks.
Use AttachThreadInput to attach a thread to a higher integrity input queue.
First, set the uiAccess=true in the manifest.
Then, sign the code.
Finally, put it in a secure location on the file system:
\Program Files\ including subdirectories
\Windows\system32\
\Program Files (x86)\ including subdirectories for 64-bit versions of
Windows
You could refer to this document and this answer.
UPDATE:
To set UIAccess to the python script:
Install PyInstaller: pip install pyinstaller.
Generate executable from Python Script using Pyinstaller.
Here is my testing sample, it sets a 5sec timer to bring the window to top.
hello.pyw:
import win32api, win32con, win32gui
import ctypes
class MyWindow:
def __init__(self):
win32gui.InitCommonControls()
self.hinst = win32api.GetModuleHandle(None)
className = 'MyWndClass'
message_map = {
win32con.WM_DESTROY: self.OnDestroy,
win32con.WM_TIMER: self.OnTimer,
}
wndcls = win32gui.WNDCLASS()
wndcls.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW
wndcls.lpfnWndProc = message_map
wndcls.lpszClassName = className
win32gui.RegisterClass(wndcls)
style = win32con.WS_OVERLAPPEDWINDOW
self.hwnd = win32gui.CreateWindow(
className,
'Title',
style,
win32con.CW_USEDEFAULT,
win32con.CW_USEDEFAULT,
500,
500,
0,
0,
self.hinst,
None
)
win32gui.UpdateWindow(self.hwnd)
win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW)
ctypes.windll.user32.SetTimer(self.hwnd,1,5000,0)
def OnDestroy(self, hwnd, message, wparam, lparam):
win32gui.PostQuitMessage(0)
return True
def OnTimer(self, hwnd, message, wparam, lparam):
current_thread_id = ctypes.windll.kernel32.GetCurrentThreadId()
foreground_window_handle = ctypes.windll.user32.GetForegroundWindow()
foreground_thread_id = ctypes.windll.user32.GetWindowThreadProcessId(foreground_window_handle, None)
ctypes.windll.user32.BringWindowToTop(hwnd)
return True
w = MyWindow()
win32gui.PumpMessages()
use --manifest <FILE or XML> option or use pyinstaller --uac-uiaccess hello.pyw directly, then the exe file is located in dist\\hello
Create the certificate and sign the application, sample(and don't forget to install the certificate to the Trusted Root Certication Authorities): https://stackoverflow.com/a/63193360/10611792
Place it in a secure location on the file system, for example I put the dist\\hello in the C:\\Program Files
Result:
Source code
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
app = Application(backend='uia').start("C:\\Program Files (x86)\\Advantech\\AdamApax.NET Utility\\Program\\AdamNET.exe")
win = app['Advantech Adam/Apax .NET Utility (Win32) Version 2.05.11 (B19)']
win.wait('ready')
win.menu_select("Setup->Refresh Serial and Ethernet")
win.top_window().print_control_identifiers(filename="file.txt")
# win.top_window().OKButton.click_input() ---------This is what I hope to do
else
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
Problem Statement
I had to run this application with elevation rights. The above is my code. The problem is I can't identify the window (view in output image) that pops up after selection from menu. I need to close the window. Please excuse the line
win.top_window().print_control_identifiers(filename="file.txt")
It was meant write the identifiers into a text file because the structure of this code does not display the outputs for me to view. However, since nothing is appended, I guess pywinauto couldn't identify the dialog.
For a clearer understanding, please view the image (input) of when it selects the menu.
Input
Now, it pops up with this dialog (output)
Output
I've also used spy to identify the caption and it gives:
(Handle: 004E07D4,
Caption: Information,
Class: #32770(Dialog),
Style: 94C801C5)
Other things I've tried:
Besides using win.topwindow() to identify the dialog, I've used
win[Information].OKButton.click_input()
win[Information].OK.click_input()
win[Information].OK.close()
win[Information].OK.kill(soft=false)
win.Information.OKButton.click_input()
win.Information.OK.click_input()
win.Information.OK.close()
win.Information.OK.kill(soft=false)
app[Information] ...... curious if I could discover the new window from original application
I've also send keys like enter, space, esc & alt-f4 to close the dialog with libraries like keyboard, pynput & ctypes. It still doesn't work.
Link to download the same application: http://downloadt.advantech.com/download/downloadsr.aspx?File_Id=1-1NHAMZX
Any help would be greatly appreciated !
I finally found a thread that demonstrated the way multi thread works to solve this issue. I tried it myself and it works. It's a little different as a few parts of the code have depreciated. Here is the link to the solution:
How to stop a warning dialog from halting execution of a Python program that's controlling it?
Here are the edits I made to solve the problem:
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
def __init__(self, window_name, quit_event):
threading.Thread.__init__(self)
self.quit_event = quit_event
self.window_name = window_name
def run(self):
while True:
try:
handles = windows.find_windows(title=self.window_name)
except windows.WindowNotFoundError:
pass
else:
for hwnd in handles:
app = Application()
app.connect(handle=hwnd)
popup = app[self.window_name]
popup.close()
if self.quit_event.is_set():
break
time.sleep(1)
quit_event = threading.Event()
mythread = ClearPopupThread('Information', quit_event)
mythread.start()
application = Application(backend="uia").start("C:\\Program Files (x86)\\Advantech\\AdamApax.NET Utility\\Program\\AdamNET.exe")
time.sleep(2)
win = application['Advantech Adam/Apax .NET Utility (Win32) Version 2.05.11 (B19)']
win.menu_select("Setup->Refresh Serial and Ethernet")
quit_event.set()
else:
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
The best thing is this solution works for every other dialog that halts the main script from working & I could use them to do different actions like clicking buttons, inserting values, by adding more multi threads.
I'm writing a Python script using Pygame and OSC that will allow me to control the music tracker software Renoise (version 3.0.0) by doing things in a Pygame (1.9.1) environment and sending messages to the software via OSC. If you're wondering, the purpose of this script is for live performance and generative music creation. I'm having a pretty annoying issue, however: when I try to close the Pygame window, it just hangs - doesn't even respond to Control+C - but this only happens if Renoise is open, or has been opened at least once during the session. If I reboot and run the script without opening Renoise, it works as intended. What could possibly be the issue here?
I'm using Python version 2.7.6, Pygame version 1.9.1, and Renoise version 3.0.0. This is all running on an Xubuntu 14.04 laptop.
Code for my main script (the imported OSC module is simply OSC.py available in many places on the internet):
#!/usr/bin/python
import sys
import pygame
import OSC
from pygame.locals import *
class Pot:
def __init__(self, ip, port):
self.clk = pygame.time.Clock()
self.screen = pygame.display.set_mode( (1600, 900) )
self.fillColor = pygame.Color(255,255,255)
pygame.display.set_caption("Pygame OSC Test")
self.client = OSC.OSCClient()
self.client.connect( (ip, port) )
def oscsend(self, addr, *data):
msg = OSC.OSCMessage()
msg.setAddress("/renoise" + str(addr))
for d in data:
msg.append(d)
try:
self.client.send(msg)
except OSC.OSCClientError, err:
print err
def tick(self):
# clear the screen
self.screen.fill(self.fillColor)
#TODO: other drawing stuff here
# process events
for event in pygame.event.get():
if event.type == QUIT:
self.client.close()
del(self.client)
return False
pygame.display.update()
self.clk.tick(10)
return True
if __name__ == "__main__":
p,f = pygame.init()
print "Num modules passed:", p
print "Num modules failed:", f
pot = Pot("localhost", 8000)
running = True
while running:
running = pot.tick()
pygame.quit()
sys.exit(0)
I managed to fix my problem by making sure pygame.mixer wasn't initialized. I assume it was causing some problems with Renoise by them both using the sound hardware at the same time.
To only initialize certain modules of pygame, just call their initialization methods individually. For instance, pygame.display.init() will initialize the Display module. Calling pygame.init() is simply a shortcut to initializing all the currently loaded modules. Hope this helps somebody!
Edited version after a closer look: You are returning False when the programme is quitted. But the variable "running" still remains true! Your loop is still going about his business and happily looping there...
I'd change it this way:
for event in pygame.event.get():
if event.type == QUIT:
self.client.close()
del(self.client)
pygame.quit()
sys.exit()
2nd option:
return False
Change this part that "running" is set to false. i'd go with the first option though.
If that doesn't solve the problem, please let me know, that would be an interesting issue to have a closer look at.
I'm trying to draw an image with PyGame, and I copied this code from Adafruit. It's strange, seems nothing displays on the screen until I Ctrl-C, at which time it shows the image. Then the image stays on the screen until I press Ctrl-C again. I then get the following message:
Traceback (most recent call last):
File "RaspiDisplay.py", line 60, in
time.sleep(10)
KeyboardInterrupt
What's going on? By the way, I'm running this via ssh on a raspberry pi, with Display set to 0 (my TV) If I put a print statement in init, that also doesn't print until I press Ctrl-C.
import os
import pygame
import time
import random
class pyscope :
screen = None;
def __init__(self):
"Ininitializes a new pygame screen using the framebuffer"
# Based on "Python GUI in Linux frame buffer"
# http://www.karoltomala.com/blog/?p=679
disp_no = os.getenv("DISPLAY")
if disp_no:
print "I'm running under X display = {0}".format(disp_no)
# Check which frame buffer drivers are available
# Start with fbcon since directfb hangs with composite output
drivers = ['fbcon', 'directfb', 'svgalib']
found = False
for driver in drivers:
# Make sure that SDL_VIDEODRIVER is set
if not os.getenv('SDL_VIDEODRIVER'):
os.putenv('SDL_VIDEODRIVER', driver)
try:
pygame.display.init()
except pygame.error:
print 'Driver: {0} failed.'.format(driver)
continue
found = True
break
if not found:
raise Exception('No suitable video driver found!')
size = (pygame.display.Info().current_w, pygame.display.Info().current_h)
print "Framebuffer size: %d x %d" % (size[0], size[1])
self.screen = pygame.display.set_mode(size, pygame.FULLSCREEN)
# Clear the screen to start
self.screen.fill((0, 0, 0))
# Initialise font support
pygame.font.init()
# Render the screen
pygame.display.update()
def __del__(self):
"Destructor to make sure pygame shuts down, etc."
def test(self):
# Fill the screen with red (255, 0, 0)
red = (255, 0, 0)
self.screen.fill(red)
# Update the display
pygame.display.update()
# Create an instance of the PyScope class
scope = pyscope()
scope.test()
time.sleep(10)
You're not running an event loop anywhere. Instead, you're just initializing everything, and then going to sleep for 10 seconds. During that 10 seconds, your code is doing nothing, because that's what you told it to do. That means no updating the screen, responding to mouse clicks, or anything else.
There are a few different ways to drive pygame, but the simplest is something like this:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
# any other event handling you need
# all the idle-time stuff you want to do each frame
# usually ending with pygame.display.update() or .flip()
See the tutorial for more information.
As a side note, your initialization code has a bunch of problems. You iterate through three drivers, but you only set SDL_VIDEODRIVER once, so you're just trying 'fbcon' three times in a row. Also, you've got code to detect the X display, but you don't allow pygame/SDL to use X, so… whatever you were trying to do there, you're not doing it. Finally, you don't need a found flag in Python for loops; just use an else clause.