Resizing Window in Kivy Android App on softkeyboard with SDL2 - python

I am currently working on an Android App using the Python and the Kivy Framework. The majority of the screen's real estate is used by a text_input widget. I would like to resize this text_input when the android soft keyboard pops ups so that the text_input ends right at the top of the keyboard.
To accomplish this I tried to use Window.softinput_mode='resize' and when that didn't work, reference the Window.keyboard_height to do my own resize and positioning. As per the documentation and comment in the Window source code I see that both are not supported when using SDL2 on Android (Kivy 1.9 - 1.10).
I tested Window.softinput_mode='below_target' which doesn't seem to do anything and Window.softinput_mode='pan' which works but doesn't give me the correct functionality.
The last thing I tried is to set Window.softinput_mode='pan' and with a function call that is bound to the on_keyboard event print out the value of Window.top so that if the panning simply shifted the Window location upward, I could use that point of reference to do my positioning and resizing. However the value of Window.top does not apear to change when panning up.
The only other stack flow that referenced this issue and gave a working example made use of resize mode which doesn't work using SDL2.
Properly resize main kivy window when soft keyboard appears on android
Is there any work-around to accomplish this functionality or a different provider than SDL2 that will work well on Android?

It seems to be a bug, so I think first step would be to report it here. May be someone will fix it or prompt you workaround.
While googling subject I found this get_keyboard_height() implementation. Since it's part of android module, try to add this recipe to your buildozer requirements. It may fix Window.keyboard_height or may just provide get_keyboard_height() function to get correct high manually.

Related

HIGH DPI Tkinter re scaling when I run it in Spyder and when I run it direct in terminal

this is probably not much of a coding question.
I developed an application in Tkinter which consists pretty much in a canvas where I load images on (matplots).
When I run it from Spyder or Jupyter notebook I obtain 143 DPI and when I run it directly in terminal I obtain 95 DPI instead.
The most weird thing is that once I run it from terminal it shows as if it was a 143 DPI application but when I load the image the app decides to resize completely and then change the DPI of my screen. So the whole thing resizes, buttons, pop up boxes and etc...
It is very important to me that I can run it from terminal, because afterwards I will transform it into a .exe application.
My first approach was to use the tkinter method .winfo_fpixel() and try to ratio the DPIs and multiply it to every dimension in the application.
Later I tried to find python.exe and pythonw.exe in order to change the compatibility with HIGH DPI Scale.
Do you thing there is a way to solve this without resizing everything?
I would like to insist that I'm 100% sure this has nothing to do with the code, therefore I might not post any coding samples.
Thanks.
obs: I use Windows 10
ps: I tried to run the app with two screens, what happened was really funny, when I use it on an adequate screen it runs normally, but when I slide it to the other screen and make any action/event it will resize it automatically.
selbie's answer is correct.
Also,You could use winapi to set DPI aware in python directly(this could work in tkinter):
import ctypes, tkinter
try: # >= win 8.1
ctypes.windll.shcore.SetProcessDpiAwareness(2)
except: # win 8.0 or less
ctypes.windll.user32.SetProcessDPIAware()
root = tkinter.Tk()
....
MSDN doc: SetProcessDpiAwareness, MSDN doc: SetProcessDPIAware
And this is another answer which mentioned about DPI awareness.
DPI is largely influenced by your PC's resolution settings - specifically the setting on "Scale and layout". 100% is 96 DPI and 150% is 144 DPI. I'm guessing it's just a rounding error from your app that's showing 95 and 143. Laptops tend to have higher resolution screens, so OEM's default to >100% setting so that you don't have to squint to see your apps. Whereas, your typical 1080p display defaults to 100% DPI. But when you "remote desktop" into a PC, Windows may re-adapt and re-stretch the DPI settings to match the local display if its DPI and resolution are different.
Windows will auto-scale most applications that haven't explicitly set their "DPI awareness" with the OS. That's typically fine for most application (although they can appear "blurry"). Applications can be compiled to be dpi aware are not stretched except in certain multi-monitor situations. This is especially likely for graphics applications. And that's where bugs like the one you are seeing tend to show up. You can often change this behavior by right clicking on the EXE, clicking Properties, and finding the setting the compatibility tab:
The most weird thing is that once I run it from terminal it shows as if it was a 143 DPI application but when I load the image the app decides to resize completely and then change the DPI of my screen. So the whole thing resizes, buttons, pop up boxes and etc...
When you remoted into your PC, the system DPI changed. Applications can get confused - especially if they aren't adapting to a changing DPI setting. Or worse, the application registers with Windows that it is DPI aware, but doesn't handle the corner case of when the monitor is swapped out - which is effectively what happens when you remoted into it. You can however, override this behavior with some combination of the Properties dialog above and the available APIs to control dpi-awareness.
I don't much about TKinter (Does it use the Python process or is it its own exe?). If you can compile it yourself, you can use the various Windows APIs and manifest settings to get the DPI behavior you want. My shot in the dark guess is that TKinter( is declaring itself per-monitor dpi-aware, but has a bug that doesn't account for the DPI changing on the fly. Typical fix for this situation is to just restart the application.
Everything you need to know at the links below:
https://learn.microsoft.com/en-us/windows/desktop/hidpi/high-dpi-desktop-application-development-on-windows
https://learn.microsoft.com/en-us/windows/desktop/api/shellscalingapi/nf-shellscalingapi-setprocessdpiawareness
https://msdn.microsoft.com/en-us/C9488338-D863-45DF-B5CB-7ED9B869A5E2
You can also read my previous answers regarding DPI awareness in Windows apps:
https://stackoverflow.com/search?q=user%3A104458+dpi

PyQt5 Resize app for different displays

I am using PyQt5 and Python 3.6.4 to design a ui for a program. It was made on a 720p monitor however now using the same code on a 4k monitor, everything is tiny apart from the text. How would I go about resizing the whole app to look the same on all monitors: (720p, 1080p, 4k, etc.)
The program is to be run on windows through an executable created through compiling the python code.
Cheers
Simple 1 line fix for any who need
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
This is somewhat system dependent, so it would help if you mentioned your target platform(s).
Because PyQt5 is just a wrapper around Qt5, I think High DPI Displays from the Qt manual applies. Citing the relevant bit (but you should read the whole thing):
In order to get an application designed for low DPI values running on a high resolution monitors quickly, consider one of the scaling options (let the application run as DPI Unaware on Windows or set the environment variable QT_AUTO_SCREEN_SCALE_FACTOR to "1". These options may incur some scaling or painting artifacts, though.
In the longer term, the application should be adapted to run unmodified:
Always use the qreal versions of the QPainter drawing API.
Size windows and dialogs in relation to the screen size.
Replace hard-coded sizes in layouts and drawing code by values calculated from font metrics or screen size.
In a shell, you would do something like:
$ export QT_AUTO_SCREEN_SCALE_FACTOR=1
$ python my_application.py

Mitigating the misbehaviour of the non-client portion of an application window

I have a program that has some rather bad window handling. I can provide scripting to the client portion of the application but have no control over the non-client portion, apart from some simple movement/resizing commands (that don't help).
The main problem is that when the windows "maximize" button is pressed the WS_MAXIMIZE style is not set. The window is positioned correctly, and helpfully respects the taskbar settings but the application icon/title and "windows buttons" are misplaced and the borders show up on any other screens.
Using winspy++ I was able to set the WS_MAXIMIZE style fixing these graphical annoyances. but this also led into a secondary issue. The "restore" button also does nothing, when pressed it simply reverts the style and does not take the application back to it's pre-maximized position and size.
I was going to make a launcher for this program in Python anyway, to handle some .ini stuff and alterable executable parameters.
I would like to extend this launcher to silently run behind the application, fixing these issues.
These things were intended to be handled by the operating system and the developers of the application do not seem to be focused on working on these problems, but more on increasing the library of application scripting and porting to other systems.
My assumption is that when the launcher is commanded to run the program it needs to have access to the thread/process so that it can poll the position and size of the application window and set the appropriate style when it is required, and more importantly (I guess), have access to it's memory.
Example: [-8,-8] to [1374,776] on a 1366x768 screen with a minimized taskbar.
If there is an asynchronous method to detect when the window has been moved/resized/windows buttons pressed, that would be preferable to polling every step.
Supplying the window with "restore" information to make use of the restore button seems a bit less trivial. I have been reading as much reference as I can find but have not found anything on this. Where is this memory stored? How do I access it? Is it read-only, and only set by the OS?
I'm new to Python, and SO, so I apologize if my question doesn't fit here, I've tried.

Kivy Look and Feel

I am trying to build a Kivy application with a sharp, crisp look and feel but the default Kivy UI is not exactly what I had in mind? Is there any way to create a custom theme to give your Kivy app style?
This app here is called Pithon and it was made from Kivy. I have searched everywhere but I can not find anything on how the developer managed such a clean look. Does anyone have any ideas?
A kivy developer called Andrés Rodríguez released a set of widgets based on google's material design principles. I am currently using them myself and they have surely saved me from alot of work. You can find KivyMD here (see bottom of this answer for more info). Their are some themes also based on the same principles but am yet to try them out one is FlatKivy and another is kivy material ui by Federico Curzel.
Some screenshots for kivyMD,flatkivy and kivy material ui respectively are here.
Click the highlighted links you will find a lot more info about the three projects.
The original KivyMD project by Andrés Rodríguez is no longer maintained but there is active fork of KivyMD by HeaTTheatR.
(Almost) all widgets have properties that can be used to set aspects of their style. For instance, with a Button you can change the background colour, the background image when pressed or released, and the size of the border region (it's scaled like in CSS border images). You can check the documentation for the specifics of a given widget.
An theme like in the screenshot you posted could be achieved by turning off background images for the buttons and just using solid colours, with the non-button text being normal Labels and the circle being drawn directly with a kivy canvas instruction or via an Image widget (along with an image of the circle).
I notice you mentioned padding in a comment but I'm not sure what you mean by it - do you mean the distance between the buttons? They may well be placed in a GridLayout which has a padding property controlling this, so you could set it to whatever you like.
I recognise that you're asking a more general question than 'how does this screenshot do it?', but the key point is that just about everything is customisable and it doesn't take many changes to go from the default theme to your image.
Edit: One useful feature that helps this kind of customisation is that you can use kv language to override styles for widget classes very easily, so you don't need to manually change every button etc.

Programmatically launching standalone Adobe flashplayer on Linux/X11

The standalone flashplayer takes no arguments other than a .swf file when you launch it from the command line. I need the player to go full screen, no window borders and such. This can be accomplished by hitting ctrl+f once the program has started. I want to do this programmatically as I need it to launch into full screen without any human interaction.
My guess is that I need to some how get a handle to the window and then send it an event that looks like the "ctrl+f" keystroke.
If it makes any difference, it looks like flashplayer is a gtk application and I have python with pygtk installed.
UPDATE (the solution I used... thanks to ypnos' answer):
./flashplayer http://example.com/example.swf & sleep 3 && ~/xsendkey -window "Adobe Flash Player 10" Control+F
You can use a dedicated application which sends the keystroke to the window manager, which should then pass it to flash, if the window starts as being the active window on the screen. This is quite error prone, though, due to delays between starting flash and when the window will show up.
For example, your script could do something like this:
flashplayer *.swf
sleep 3 && xsendkey Control+F
The application xsendkey can be found here: http://people.csail.mit.edu/adonovan/hacks/xsendkey.html
Without given a specific window, it will send it to the root window, which is handled by your window manager. You could also try to figure out the Window id first, using xprop or something related to it.
Another option is a Window manager, which is able to remember your settings and automatically apply them. Fluxbos for example provides this feature. You could set fluxbox to make the Window decor-less and stretch it over the whole screen, if flashplayer supports being resized. This is also not-so-nice, as it would probably affect all the flashplayer windows you open ever.
I've actually done this a long time ago, but it wasn't petty. What we did is use the Sawfish window manager and wrote a hook to recognize the flashplayer window, then strip all the decorations and snap it full screen.
This may be possible without using the window manager, by registering for X window creation events from an external application, but I'm not familiar enough with X11 to tell you how that would be done.
Another option would be to write a pygtk application that embedded the standalone flash player inside a gtk.Socket and then resized itself. After a bit of thought, this might be your best bet.
nspluginplayer --fullscreen src=path/to/flashfile.swf
which is from the [http://gwenole.beauchesne.info//en/projects/nspluginwrapper](nspluginwrapper project)
Another option would be to write a pygtk application that embedded the standalone flash player inside a gtk.Socket and then resized itself. After a bit of thought, this might be your best bet.
This is exactly what I did. In addition to that, my player scales flash content via Xcomposite, Xfixes and Cairo. A .deb including python source be found here:
http://www.crutzi.info/crutziplayer
I've done this using openbox using a similar mechanism to the one that bmdhacks mentions. The thing that I did note from this was that the standalone flash player performed considerably worse fullscreen than the same player in a maximised undecorated window. (that, annoyingly is not properly fullscreen because of the menubar). I was wondering about running it with a custom gtk theme to make the menu invisible. That's just a performance issue though. If fullscreen currently works ok, then it's unneccisarily complicated. I was running on an OLPC XO, performance is more of an issue there.
I didn't have much luck with nspluginplayer (too buggy I think).
Ultimately I had the luxury of making the flash that was running so I could simply place code into the flash itself. By a similar token, Since you can embed flash within flash, it should be possible to make a little stub swf that goes fullscreen automatically and contains the target sfw.
You have to use Acton script 3 cmd:
stage.displayState = StageDisplayState.FULL_SCREEN;
See Adobe Action script 3 programming.
But be careful : in full screen, you will lose display performances!
I've got this problem ... more under Linux!!!

Categories